O git pode ignorar uma linha específica?


115

Estou usando o git para sincronizar com o phonegap durante o teste no navegador nativo do telefone. Como tal, tenho a seguinte linha:

var isPhoneGap = false;

Obviamente, eu mudo isso durante a compilação, mas há alguma maneira de configurar o git para ignorar essa linha ou tenho que ir e colocá-lo em seu próprio arquivo e ignorá-lo dessa forma?

Estou usando Gitx e o terminal no OSX 10.6.


@ user494461: Filtros Git são a maneira de fazer isso: stackoverflow.com/a/16244970/520162
eckes

1
Você não consegue detectar o ambiente e usar um arquivo de configuração do eniroment?
exussum

Resumindo: Não. Mas escrevi um script de pré-processador que procura por determinado código comentado e o remove antes da publicação no git. Confira aqui: github.com/franklinchou/ahk_config/blob/master/preprocess.sh
franklin

Respostas:


104

Se o seu arquivo for de um tipo específico, você pode declarar um driver de filtro de conteúdo , que pode ser declarado em um .gitattributesarquivo (conforme apresentado na "Expansão de palavras-chave" de " Atributos Git "):

http://git-scm.com/figures/18333fig0702-tn.png

*.yourType filter=yourFilterName

(você pode até definir esse filtro para um arquivo específico , se quiser)

Implemento:

  • yourFilterName.smudge(acionado em git checkout) e

    git config --global filter.yourFilterName.smudge 'sed "s/isPhoneGap = .*/isPhoneGap = true/"'
    
  • yourFilterName.clean(acionado em git add)

    git config --global filter.yourFilterName.clean 'sed "s/isPhoneGap = .*/isPhoneGap = false/"'
    

Seu arquivo pareceria inalterado em git status, mas sua versão em check-out teria o valor correto para isPhoneGap.


1
Obrigado por isso. fez funcionar. Você sabe como fazer git diff or git status`, ignorar os filtros? Então, ainda consigo ver o que é diferente? Meu caso de uso é para logs de depuração ... que eventualmente desejo excluir ... @jthill @VonC
timh

1
@timh se o filtro estiver funcionando, git status ou git diff não devem mostrar nada.
VonC

1
É uma pena que não haja uma maneira mais simples no GIT. git ignore <filename> <linenumber> seria tão útil!
kiedysktos

22
@kiedysktos Linnumber? E se o número da linha mudar?
VonC

Isso funcionou muito bem, mas os usuários do Windows devem estar atentos, o gitconfig é muito exigente com os caracteres que deseja manter, portanto, ao tentar algumas expressões regulares semi-exóticas, você pode ter problemas. Acabei colocando minhas chamadas de sed em um arquivo helper.sh separado, que chamei de meu gitconfig, sh ".git/helper.sh"certificando-me de passar por quaisquer parâmetros para o sed "$@"(presumo que apenas o caminho do arquivo seja passado).
ohaal

43

Você pode usar

git update-index --assume-unchanged [file]

para ignorar as alterações de um arquivo que você não deseja rastrear. Eu uso essa solução quando preciso ter um arquivo no repositório, mas esse arquivo tem algumas partes que mudam que não preciso rastrear sempre.

Quando o arquivo tem alterações importantes, você deve fazer o seguinte:

git update-index --no-assume-unchanged [file]

Além disso, consulte o índice de atualização do documento Git para obter o --[no-]assume-unchangedparâmetro.

Quando esses sinalizadores são especificados, os nomes de objetos registrados para os caminhos não são atualizados. Em vez disso, essas opções definem e desativam o bit "assumir inalterado" para os caminhos. Quando o bit "assume inalterado" está ligado, git para de verificar os arquivos da árvore de trabalho para possíveis modificações, então você precisa desarmar manualmente o bit para dizer ao git quando você alterar o arquivo da árvore de trabalho.


2
Fazer isso ainda buscará a nova versão quando eu fizer git pull?
Saad Rehman Shah

1
@Caffeine quando você faz git pull você obtém a última versão que foi submetida, esta será a última antes de você mudar para '--assume-unchanged' o arquivo.
Carlos

1
Acredito que --skip-worktreeseja a melhor opção para a maioria dos propósitos. stackoverflow.com/a/39583010/4233593
Jeff Puckett


3
isso ignora atualizações em todo o arquivo, não em uma linha específica
nikoss

6

Gitx deve permitir que você confirme ou ignore linhas individuais (você já deve saber disso), mas você terá que fazer isso toda vez que fizer um commit. Acho que seria melhor ter um arquivo de configuração por destino de implantação (você pode fazer a versão deles) e alguns parâmetros de tempo de execução para o modo como você está iniciando o servidor (como ./myserver --config=whatever.js).


5

Continuando https://stackoverflow.com/a/20574486/4935114 , @Mike propôs a criação de um pre-commitgancho que irá grepnos arquivos de teste para as linhas que alguém pode querer ignorar. O gancho verifica se essas linhas foram encenadas. Em caso afirmativo, é echoum aviso e exitestá com código 1para que o processo de confirmação não continue.

Inspirado pela resposta de @Mike , acabei usando talvez uma versão melhorada de seu gancho que mostra automaticamente reset (com a -pbandeira) a linha específica que queremos ignorar.

Não tenho certeza se este gancho funcionará para uma situação onde você tem muitos arquivos com esta linha para serem ignorados, mas este pre-commitgancho procura uma alteração nesta linha em um arquivo específico buildVars.java. O script de gancho se parecia com isso quando testei em minha máquina.

#!/bin/sh

# this hook looks for lines with the text `var isPhoneGap = false;` in the file `buildVars.java` and it resets these lines to the previous state before staged with `reset -p`

if [[ $(git diff --no-ext-diff --cached buildVars.java | grep --count -e "var\ isPhoneGap[\ ]*=[\ ]*") -ne 0 ]]; then
    cat <<EOW
WARNING: You are attempting to commit changes which are not supposed to be commited according to this \`pre-commit\` hook
This \`pre-commit\` hook will reset all the files containing this line to it's previous state in the last commit.
EOW
    echo /$'\n'isPhoneGap$'\n'y$'\n'q | git reset -p
    # BONUS: Check if after reseting, there is no actual changes to be commited and if so, exit 1 so the commit process will abort.
    if [[ $(git diff --no-ext-diff --cached | wc -l) -eq 0 ]]; then
        echo there are no actual changes to be commited and besides the change to the variable \'isPhoneGap\' so I won\'t commit.
        exit 1
    fi
fi

Explicação

O que fiz foi ecoar uma sequência de controle que procura o regex isPhoneGapdurante um resetprocesso interativo . Emulando assim um usuário que pressiona /para pesquisar isPhoneGap, pressiona yquando questionado se deseja descartar esse patch e finalmente pressiona qpara sair do interativo reset.

O processo de patch reverso interativo está documentado aqui: https://git-scm.com/docs/git-add#git-add-patch


NOTA: O script acima presume que a variável interactive.singleKeyé false. Se você configurou o seu para true, remova qualquer um $'\n'do echocomando logo após o aviso.


3

É assim que você pode fazer isso com filtros git :

  1. Crie / abra o arquivo gitattributes:
    • <raiz do projeto> /. gitattributes (será confirmado no repo)
      OU
    • <raiz do projeto> /. git / info / attribute (não será confirmado no repo)
  2. Adicione uma linha definindo os arquivos a serem filtrados:
    • *.rb filter=gitignore, ou seja, execute o filtro nomeado gitignoreem todos os *.rbarquivos
  3. Defina o gitignorefiltro em gitconfig:
    • $ git config --global filter.gitignore.clean "sed '/#gitignore$/'d", ou seja, exclua essas linhas
    • $ git config --global filter.gitignore.smudge cat, ou seja, não faça nada ao puxar o arquivo do repo

Observações:
Claro, isso é para arquivos ruby, aplicados quando uma linha termina com #gitignore, aplicados globalmente em ~/.gitconfig. Modifique isso como for necessário para seus propósitos.

Aviso!!
Isso deixa seu arquivo de trabalho diferente do repo (é claro). Qualquer check-out ou rebasing significará que essas linhas serão perdidas! Esse truque pode parecer inútil, já que essas linhas são perdidas repetidamente no check-out, no rebase ou no pull, mas tenho um caso de uso específico para fazer uso dele.

Apenas git stash save "proj1-debug" enquanto o filtro está inativo (apenas desativá-lo temporariamente gitconfigou algo assim). Dessa forma, meu código de depuração sempre pode ser adicionado git stash applyao meu código a qualquer momento, sem medo de essas linhas serem confirmadas acidentalmente.

Tenho uma ideia possível para lidar com esses problemas, mas tentarei implementá-la em outra ocasião.

Agradecimentos a Rudi e jw013 por mencionar filtros e atributos git.


2

Um driver de filtro de conteúdo não é uma boa solução. Você pode ocultar essa linha de git status/ etc, mas ela não está sendo realmente ignorada. Assim que você alterar o valor, seu diretório de trabalho será marcado como sujo, embora a alteração possa não estar visível.

Se você realmente deseja esta linha fora do controle de versão, alterá-la para um argumento de linha de comando ou colocá-la em um arquivo de inclusão ou construção ignorado pode ser o único meio prático.


"Assim que você alterar o valor, seu diretório de trabalho será marcado como sujo, embora a alteração possa não ser visível": não deveria, se o script limpo ainda restaura o arquivo em seu conteúdo original.
VonC

Foi o que pensei. Estou usando GitExtensions e ele mostrará o arquivo modificado mesmo que o painel de diferenças esteja em branco. Possivelmente porque o filtro limpo não é executado até o check-in do arquivo. Possivelmente porque é msysgit, não git-git. IDK, YMMV
patricktokeeffe

1

Acho que isso pode ser algo que aparece em mais de uma linha de sua fonte.

Eu acho que seria mais limpo ter um arquivo .userbuildconfig de algum tipo que você acabou de incluir e ter os padrões verificados. Então você pode usar a sugestão de Carlos para marcar esse arquivo sozinho como assumir inalterado. Desta forma, outras alterações no arquivo onde você precisa verificar a configuração não serão perdidas.

Isso pode permitir que você ajuste macros do pré-processador localmente (ou para java, algo como https://stackoverflow.com/a/1813873/1270965 ).


-1

Não. Você só pode ignorar arquivos individuais (e mais), pois as linhas em .gitignore correspondem aos nomes dos arquivos e não ao conteúdo do arquivo. Você já mencionou a solução para isso, ou seja, ignore um único arquivo que contenha o conteúdo que deseja ignorar.


Concordo, no meu caso foi suficiente e possível simplesmente incluir esse conteúdo de um arquivo ignorado. Portanto, movendo todas as configurações ignoráveis. há. Além disso, criei uma cópia desse arquivo ignorado e adicionei-o ao índice como referência, para que as informações sobre o que deve estar naquele arquivo não sejam perdidas.
Urs
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.