Posso 'git confirmar' um arquivo e ignorar suas alterações de conteúdo?

355

Cada desenvolvedor da minha equipe tem sua própria configuração local. Essas informações de configuração são armazenadas em um arquivo chamado devtargets.rbque é usado em nossas tarefas de criação de rake. Eu não quero que os desenvolvedores espancem o arquivo de devtargets um do outro.

Meu primeiro pensamento foi colocar esse arquivo na .gitignorelista para que ele não se comprometa com o git.

Então comecei a me perguntar: é possível confirmar o arquivo, mas ignorar as alterações no arquivo? Então, eu confirmaria uma versão padrão do arquivo e, quando um desenvolvedor a alterasse em sua máquina local, o git ignoraria as alterações e não apareceria na lista de arquivos alterados quando você executasse um status ou uma confirmação do git .

Isso é possível? Certamente seria um bom recurso ...

Derick Bailey
fonte
11
Consulte também stackoverflow.com/questions/3318043/… sobre um tópico semelhante.
VonC 23/07
possível duplicata dos arquivos de configuração específicos da máquina de
confirmação

Respostas:

458

Claro, eu faço exatamente isso de tempos em tempos usando

git update-index --assume-unchanged [<file> ...]

Para desfazer e começar a rastrear novamente (se você esqueceu quais arquivos não foram rastreados, consulte esta pergunta ):

git update-index --no-assume-unchanged [<file> ...]

Documentação relevante :

- [no-] assume-inalterado
Quando esse sinalizador é especificado, os nomes de objetos registrados para os caminhos não são atualizados. Em vez disso, esta opção define / desativa o bit "assumir inalterado" para os caminhos. Quando o bit "assumir inalterado" está ativado, o usuário promete não alterar o arquivo e permite ao Git assumir que o arquivo da árvore de trabalho corresponde ao que está registrado no índice. Se você deseja alterar o arquivo da árvore de trabalho, desative o bit para informar ao Git. Às vezes, isso é útil ao trabalhar com um grande projeto em um sistema de arquivos que possui uma lstat(2)chamada de sistema muito lenta (por exemplo, cifs).

O Git falhará (normalmente) caso precise modificar esse arquivo no índice, por exemplo, ao mesclar em um commit; portanto, caso o arquivo assumido não rastreado seja alterado a montante, você precisará lidar com a situação manualmente.

Falhar normalmente neste caso significa que, se houver alguma alteração a montante desse arquivo (alterações legítimas etc.) quando você fizer um pull, ele dirá:

$ git pull
…
From https://github.com/x/y
   72a914a..106a261  master     -> origin/master
Updating 72a914a..106a261
error: Your local changes to the following files would be overwritten by merge:
                filename.ext

e se recusará a mesclar.

Nesse ponto, você pode superar isso revertendo suas alterações locais, eis uma maneira:

 $ git checkout filename.ext

em seguida, puxe novamente e modifique novamente o arquivo local ou pode definir –no-assume-unchangede você pode fazer stash e mesclagem normais, etc.

Rob Wilkerson
fonte
10
este comando faz localmente na pasta .git? Quero dizer, se eu executar este comando para um arquivo config.php, ele será propagado para outros usuários que estão usando o repositório?
Magus
16
@ Magus: Não. Isso funcionará apenas para você.
Rob Wilkerson
3
E logo depois, você vai querer saber como determinar se um arquivo é assumido inalterada: stackoverflow.com/questions/2363197/...
Ciro Santilli郝海东冠状病六四事件法轮功
10
As alterações nos arquivos ignorados dessa maneira são perdidas quando o "git stash" é usado. Existe uma maneira de contornar isso?
Alexis #
5
Não é para isso que git update-index --assume-unchangedserve. public-inbox.org/git/…
jsageryd
97

A maneira preferida de fazer isso é usar git update-index --skip-worktree <file>, conforme explicado nesta resposta :

assume-unchangedfoi projetado para casos em que é caro verificar se um grupo de arquivos foi modificado; Quando você define o bit, o git (claro) assume que os arquivos correspondentes a essa parte do índice não foram modificados na cópia de trabalho. Portanto, evita uma confusão de chamadas de estatísticas. Este bit é perdido sempre que a entrada do arquivo no índice é alterada (portanto, quando o arquivo é alterado upstream).

skip-worktreeé mais do que isso: mesmo onde o git sabe que o arquivo foi modificado (ou precisa ser modificado por uma redefinição - difícil ou semelhante), ele fingirá que não foi, usando a versão do índice. Isso persiste até que o índice seja descartado.

Para desfazer isso, use git update-index --no-skip-worktree <file>

Desde a versão 2.25.1 do git, essa não é mais a maneira recomendada, citando:

Os usuários geralmente tentam usar os bits assumir-inalterado e ignorar-árvore de trabalho para dizer ao Git para ignorar as alterações nos arquivos rastreados. Isso não funciona conforme o esperado, pois o Git ainda pode verificar os arquivos da árvore de trabalho em relação ao índice ao executar determinadas operações. Em geral, o Git não fornece uma maneira de ignorar as alterações nos arquivos rastreados, portanto, soluções alternativas são recomendadas.

Por exemplo, se o arquivo que você deseja alterar for algum tipo de arquivo de configuração, o repositório poderá incluir um arquivo de configuração de amostra que poderá ser copiado no nome ignorado e modificado. O repositório pode até incluir um script para tratar o arquivo de amostra como um modelo, modificando e copiando-o automaticamente.

1615903
fonte
Isso funciona com todos os usuários que fazem checkout no repositório? Eles conseguirão determinados arquivos, mas não poderão mais adicionar alterações, por engano, a menos que explicitamente o digam?
mmm
2
@ momomo a flag é armazenada no índice, então não, é apenas para um único usuário. Veja a resposta da erjiang para algo que funcione em todos os usuários.
1615903
Estou tentando descobrir qual deve ser o conteúdo do arquivo. Comentei a resposta a que você se referiu, mas não obteve resposta. Onde ele deve estar localizado e qual é o seu conteúdo? Você sabe?
mmm
Eu não estou seguindo. O comando é usado para ignorar um arquivo específico que você especificar no comando. O conteúdo desse arquivo não é relevante.
1615903
11
A documentação do Git diz especificamente não usar git update-index --skip-worktreepara esse fim.
bk2204 28/04
43

Parece que a prática comum é criar devtargets.default.rbe confirmar e instruir cada usuário a copiar esse arquivo para devtargets.rb(que está na lista .gitignore). Por exemplo, o CakePHP faz o mesmo com o arquivo de configuração do banco de dados, que muda naturalmente de máquina para máquina.

erjiang
fonte
6
Você não pode .gitignore um arquivo que está sendo rastreado. .gitignore afeta apenas os arquivos que não estão no índice.
CB Bailey
11
Eu estava tentando evitar fazer isso, apesar de realmente não ter um bom motivo. estamos fazendo isso agora e acho difícil lembrar que preciso criar minha própria versão sem ".default" no nome.
Derick Bailey
11
@DerickBailey Mas, para ser justo, é mais fácil lembrar de copiar o arquivo do que lembrar de usar a --assume-unchangedopção para todos que clonam o repositório.
Dan
11
@DerickBailey, você também pode configurar o rake build como padrão, devtargets.default.rbse devtargets.rbnão existir.
Luke
@erjang, o que há nesse arquivo devtargets.default.rb? Um exemplo?
mmm
2

Para usuários do IntelliJ IDEA: Se você deseja ignorar as alterações de um arquivo (ou arquivos), você pode movê-lo para diferente Change Set.

  • Vá para Local Changes( Cmd + 9)
  • Selecione o (s) arquivo (s) que você deseja ignorar
  • F6 para movê-los para outro Change Set
Eugene
fonte