Git: mostra todas as várias mudanças em uma única linha em um arquivo especificado ao longo de todo o histórico do git

112

Eu olhei em volta e não tenho certeza se isso é possível, mas aqui vai:

Eu tenho um arquivo (javascript) (digamos /lib/client.js) no qual tenho um identificador exclusivo atribuído a uma variável, assim: var identifier = "SOME_IDENTIFIER";

Você pode pensar no identificador como um número de versão: Periodicamente, mudaremos essa variável para um novo identificador.

O que eu gostaria de fazer é encontrar todos os identificadores exclusivos que já usamos. Como posso fazer isso com o git?

Eu imagino que possa haver uma maneira de pesquisar no histórico do git e imprimir a correspondência de linha "var identifier =". Eu poderia desduplicar essa lista manualmente.

De qualquer forma, eu apreciaria qualquer insight aqui. Obrigado.

findchris
fonte

Respostas:

106

Desde o git 1.8.4 , existe uma maneira mais direta de responder à sua pergunta.

Supondo que essa linha 110seja a linha que diz var identifier = "SOME_IDENTIFIER";, faça o seguinte:

git log -L110,110:/lib/client.js

Isso retornará todos os commits que tocaram nessa linha de código.

[ Documentação Git (consulte o parâmetro de linha de comando "-L")]

Alexander Bird
fonte
49

Consulte a página do manual para git-loge gitdiffcore. Eu acredito que este comando faria isso, mas pode não ser muito certo:

git log -G "var identifier =" file.js

EDIT: Aqui está um começo preliminar para um script bash para mostrar as linhas reais. Isso pode ser mais o que você está procurando.

for c in $(git log -G "something" --format=%H -- file.js); do
    git --no-pager grep -e "something" $c -- file.js
done

Ele usa git log -Gpara encontrar os commits interessantes, usando --format=%Hpara produzir uma lista de hashes de commit. Em seguida, itera sobre cada commit interessante, pedindo git greppara mostrar as linhas desse commit e arquivo que contém a regex, prefaciada com o hash de commit.


EDIT: Alterado para usar em -Gvez de -Ssugerido nos comentários.

roubar
fonte
@Rob - obrigado por isso - pequena edição em seu script - colocar apenas o nome do arquivo mostra apenas os commits que apenas afetam aquele arquivo - se um commit referenciou outros arquivos, ele não está listado
Adrian Cornish
@AdrianCornish - Que bom que foi útil. Acho que o OP queria apenas olhar para um arquivo, mas você está certo ao dizer que remover o nome do arquivo é provavelmente um script mais útil em geral.
roubar
Eu tenho uma situação mais difícil. O arquivo em questão foi movido de paht_a / file para path_b / file. Agora, quando faço isso no path_b, ele só mostra as alterações até quando o arquivo muda de path_a para path_b. Se eu fizer isso em path_a, ele me diz fatal: argumento ambíguo 'arquivo': revisão desconhecida ou caminho que não está na árvore de trabalho.
Andy Song
@AndySong - Se a string que você está procurando for única o suficiente, talvez você possa simplesmente ignorar o nome do arquivo e ainda obter o que está procurando.
roubo de
Foi mais conveniente para mim - coloque uma linha em branco após cada confirmação, enumere as linhas:sfile=path/to/some_file; sfind='string_to_find'; for c in $(git log -G $sfind --format=%H -- $sfile); do git --no-pager grep -e $sfind -n $c -- $sfile; echo; done
John_West
14

Você também pode fazer isso com gitk:

gitk file.js

Na lista suspensa "commit", escolha "adicionando / removendo string:" e na caixa de texto próxima a ele, digite "var identifier =", e quaisquer commits que adicionam ou removem linhas que contenham aquela string serão destacados.

Ethan Brown
fonte
Isso ajudou a localizar o commit no qual a linha contendo "var identifier =" foi adicionada, mas não está mostrando os commits subsequentes que modificaram esta linha.
findchris
2
Você já tentou git blame file.jsou git gui blame file.js?
Ethan Brown
1
Eu sei o que o git blame faz; Estou procurando um histórico completo de revisões, nem uma única diferença.
findchris
1
git gui blame file.jsfará isso ... mostrará todas as revisões de um arquivo e quem o alterou; você pode simplesmente clicar para trás no histórico.
Ethan Brown
Acabei avançando visualmente com o gitk. Imagino que exista alguma técnica git elegante para fazer isso, mas o gitk era bom o suficiente. Obrigado.
findchris,
9

Se você adaptar a resposta de @ rob um pouco, git logbasicamente fará isso por você, se tudo o que você precisa é uma comparação visual:

git log -U0 -S "var identifier =" path/to/file

-U0significa saída no modo patch ( -p) e mostra linhas zero de contexto ao redor do patch.

Você pode até mesmo fazer isso entre branches:

git log -U0 -S "var identifier =" branchname1 branchname2 -- path/to/file

Pode haver uma maneira de suprimir o cabeçalho diff, mas não conheço nenhuma.

Andrew
fonte
Funcionou para mim! Obrigado.
Roberto Bonini
3

No magit , você pode fazer isso com

l, =L

Em seguida, ele solicitará o arquivo e as linhas inicial e final.

favelas
fonte