Como restaurar as permissões de arquivos e diretórios no git, se eles foram modificados?

278

Eu tenho um check-out do Git. Todas as permissões de arquivo são diferentes do que o git pensa que deveria ser, portanto, todas aparecem como modificadas.

Sem tocar no conteúdo dos arquivos (apenas quero modificar as permissões), como defino todas as permissões de arquivos para o que o git pensa que elas devem ser?

Dale Forester
fonte

Respostas:

572

O Git controla a permissão de arquivo e expõe as alterações de permissão ao criar patches usando git diff -p. Então, tudo o que precisamos é:

  1. criar um patch reverso
  2. inclua apenas as alterações de permissão
  3. aplique o patch à nossa cópia de trabalho

Como uma linha:

git diff -p -R --no-ext-diff --no-color \
    | grep -E "^(diff|(old|new) mode)" --color=never  \
    | git apply

você também pode adicioná-lo como um alias à sua configuração do git ...

git config --global --add alias.permission-reset '!git diff -p -R --no-ext-diff --no-color | grep -E "^(diff|(old|new) mode)" --color=never | git apply'

... e você pode invocá-lo via:

git permission-reset

Observe que, se você bashusar o shell , use aspas ao 'invés de "aspas !git, caso contrário ele será substituído pelo último gitcomando que você executou.

Agradecemos ao @Mixologic por apontar que, simplesmente usando -Ron git diff, o sedcomando complicado não é mais necessário.

muhqu
fonte
3
Estou no OS X, isso não está funcionando. Eu identifiquei o problema está no git apply. Não aplica as alterações nas permissões de arquivo.
pepper_chico
15
Ah, funcionou, eu estava tentando aplicar a partir de um diretório diferente da raiz do repositório. O git apply funciona apenas lá.
pepper_chico
6
Existe alguma razão para você não fazer "git diff -p -R" em vez de fazer o sed para fazer a reversão?
Mixologic
6
@RobQuist minhas alterações locais não foram removidos ao usar muhqu de comando
logion
17
Estou ficandofatal: unrecognized input
Tieme
120

Experimentar git config core.fileMode false

Na git configpágina do manual:

core.fileMode

Se falso, as diferenças de bits executáveis ​​entre o índice e a cópia de trabalho são ignoradas; útil em sistemas de arquivos quebrados como o FAT. Veja git-update-index (1) .

O padrão é true, exceto que o git-clone (1) ou o git-init (1) analisará e definirá core.fileMode false, se apropriado, quando o repositório for criado.

Tim Henigan
fonte
Obrigado, foi isso que acabei fazendo. Muito usado para cvs que não rastreiam permissões, portanto isso funciona.
Dale Forester
3
@ shovas: Fico feliz que isso tenha ajudado. Ocorreu um problema semelhante ao compartilhar repositórios entre Linux e Windows. BTW: se isso respondeu à sua pergunta, marque a resposta como correta.
Tim Henigan
É possível que git checkout origin/masterdefina permissões de arquivo confirmadas no servidor para minha cópia de trabalho local? Porque sempre que eu construo a V8 para ArangoDB, as permissões de arquivo são alteradas para que o acesso seja negado a toda a pasta de compilação (mesmo com direitos elevados; Windows 7 ou superior). Preciso corrigir todas as permissões de arquivo local antes de poder continuar o processo de compilação. core.filemode falseTambém pode consertar isso? Eu suspeito que o git defina as permissões do Linux na minha máquina Windows. Os scripts de construção só poderia preservá-los e aplicar as mesmas permissões para arquivos recém-criados ...
CodeManX
Im querendo saber se há alguma desvantagem para definir filemodea false!
kevoroid 19/02
11

O Git não armazena permissões de arquivo além de scripts executáveis. Considere usar algo como git-cache-meta para salvar a propriedade e as permissões do arquivo.

O Git pode armazenar apenas dois tipos de modos: 755 (executável) e 644 (não executável). Se seu arquivo fosse 444, o git armazenaria ele tem 644.

kroger
fonte
14
Desculpe, mas isso está incorreto. O Git, de fato, rastreia permissões.
Will
4
É aproximadamente preciso, consulte git.wiki.kernel.org/index.php/ContentLimitations . As permissões exatas definidas são baseadas no servidor e possivelmente no cliente umask, além de uma configuração, consulte stackoverflow.com/a/12735291/125150 .
Motti Strom
12
@ Não, não. Não posso acreditar que seu comentário tenha recebido tantos votos.
EIS
@ Will, isso está aproximadamente correto. Por the docs ...a mode of 100644, which means it’s a normal file. Other options are 100755, which means it’s an executable file; and 120000, which specifies a symbolic link. The mode is taken from normal UNIX modes but is much less flexible — these three modes are the only ones that are valid for files (blobs) in Git (although other modes are used for directories and submodules).
esmail 04/12/19
9
git diff -p \
| grep -E '^(diff|old mode|new mode)' \
| sed -e 's/^old/NEW/;s/^new/old/;s/^NEW/new/' \
| git apply

funcionará na maioria dos casos, mas se você possui ferramentas diff externas como o meld instalado, é necessário adicionar --no-ext-diff

git diff --no-ext-diff -p \
    | grep -E '^(diff|old mode|new mode)' \
    | sed -e 's/^old/NEW/;s/^new/old/;s/^NEW/new/' \
    | git apply

era necessário na minha situação

zainengineer
fonte
0

Eu uso o git da cygwin no Windows, a git applysolução não funciona para mim. Aqui está minha solução, execute chmodtodos os arquivos para redefinir suas permissões.

#!/bin/bash
IFS=$'\n'
for c in `git diff -p |sed -n '/diff --git/{N;s/diff --git//g;s/\n/ /g;s# a/.* b/##g;s/old mode //g;s/\(.*\) 100\(.*\)/chmod \2 \1/g;p}'`
do
        eval $c
done
unset IFS

alijandro
fonte
-1

git diff -pusado na resposta de muhqu pode não mostrar todas as discrepâncias.

  • vi isso no Cygwin para arquivos que eu não possuía
  • as alterações de modo são completamente ignoradas se core.filemodefor false(que é o padrão para o MSysGit)

Este código lê diretamente os metadados:

(set -o errexit pipefail nounset;
git ls-tree HEAD -z | while read -r -d $'\0' mask type blob path
do
    if [ "$type" != "blob" ]; then continue; fi;
    case "$mask" in
    #do not touch other bits
    100644) chmod a-x "$path";;
    100755) chmod a+x "$path";;
    *) echo "invalid: $mask $type $blob\t$path" >&2; false;;
    esac
done)

Um one-liner sem grau de produção (substitui totalmente as máscaras):

git ls-tree HEAD | perl -ne '/^10(0\d{3}) blob \S+\t(.+)$/ && { system "chmod",$1,$2 || die }'

(O crédito para "$ '\ 0'" vai para http://transnum.blogspot.ru/2008/11/bashs-read-built-in-supports-0-as.html )

ivan_pozdeev
fonte
-2

A coisa mais fácil a fazer é apenas alterar as permissões novamente. Como o @kroger observou, o git apenas rastreia os bits executáveis. Então você provavelmente só precisa correr chmod -x filenamepara corrigi-lo (ou +xse é isso que é necessário.

Pat Notz
fonte
Aqui está um exemplo de git show: diff --git a / OpenWatch / src / org / ale / OpenWatch / fb / FBUtils.java b / OpenWatch / src / org / ale / OpenWatch / fb / index FBUtils.java cd6fa6a..e5b0935 100644 Isso bit em negrito, existem as permissões de arquivo.
Conrado
Isso me pareceu mais fácil também. Infelizmente, encontrei o mesmo problema que o Conrado - não pude alterar a permissão de 100644para 100755. Eu não acho que você mereça um voto negativo; Git deve ser votado negativamente. É tão quebrado em tantas maneiras em tantos níveis diferentes ...
JWW
-2

A etckeeperferramenta pode manipular permissões e com:

etckeeper init -d /mydir

Você pode usá-lo para outros diretórios diferentes /etc.

Instale usando o gerenciador de pacotes ou obtenha fontes do link acima.

MoreIT
fonte
4
Para que ele define permissões? Se ele não lê os metadados do Git ou invoca o Git, não faz o que o OP solicitou.
ivan_pozdeev