Como encontro o commit git mais recente que modificou um arquivo?

180

Quero encontrar a confirmação mais recente que modificou um arquivo de origem.

Posso usar git blamepara ver todas as datas de confirmações por cada linha, mas é difícil ver exatamente qual confirmação foi a última a tocar no arquivo.

Como posso encontrar o último commit que tocou em um determinado arquivo no meu repositório git?

Cory Klein
fonte

Respostas:

230

git log suporta examinar o histórico de arquivos (e diretórios) específicos, para que você possa chamá-lo assim:

git log my/file.c

Se você realmente só quer listar a um commit mais recente, por exemplo, para usá-lo em um script, use a -n 1opção:

git log -n 1 --pretty=format:%H -- my/file.c

--pretty=format:%hdiz git logpara mostrar apenas o hash de confirmação. O --separador impede que o nome do arquivo seja interpretado como um nome de confirmação, caso seja ambíguo.

Jo Liss
fonte
12
Se você deseja saber a última vez que um arquivo foi modificado, independentemente da ramificação, considere todas as ramificações adicionando a --allopção
KC
44

Se você apenas deseja encontrar a confirmação mais recente, não deseja git-log, git-rev-listque lista os objetos de confirmação que alteram esse arquivo, nesse caminho de confirmação, começando pelo mais recente (cronologicamente). Simplificando:

git rev-list -1 <commit> <filename>

No git-rev-listseu caso, você apenas fornece:

  • O número de confirmações a serem incluídas, ou -1, apenas para as mais recentes,
  • A ramificação (ou ID de confirmação) da qual começar a olhar para trás, HEAD , se você já estiver nela, ou --all, se você quiser todas as confirmações conhecidas, e
  • O caminho relativo para o seu arquivo.

Isso apenas retorna o ID de confirmação mais recente no ramo atual para alterar esse arquivo, por exemplo: 215095e2e338525be0baeeebdf66bfbb304e7270

Para um exemplo mais complexo, você pode usar nomes de tags e até referências remotas e incluir nomes de caminhos relativos com caracteres curinga, por exemplo:

git rev-list origin/user/bob/testbranch -1 src/bfiles/*.txt

... O que lhe diria qual foi a alteração mais recente na correspondência curinga no histórico dessa ramificação. As opções para rev-list são extremas, é um dos comandos de encanamento mais importantes, para que você possa incluir ou excluir praticamente qualquer critério que possa imaginar.

Obviamente, consulte a página de manual do git-rev-list (1) .

Michael Erickson
fonte
Você realmente não explicou por que usar git-logé inferior.
Piotr Dobrogost
7
Eu não diria inferior, apenas que ele fornece informações estranhas por padrão. O git-rev-list retorna apenas o ID de confirmação, que é o que você deseja se deseja alimentar a resposta em um script ou outro processo de automação. O git-log retorna informações sobre as confirmações selecionadas, primeiro usando git-rev-list para reunir os IDs de confirmação e, em seguida, reunindo informações sobre cada confirmação. Se você apenas filtrar as informações de confirmação e usar os IDs, poderá usar o git-rev-list em primeiro lugar. Como o log é baseado na lista de rev, ele usa a maioria dos mesmos parâmetros de filtro.
22616 Michael Erickson
3
git-logé porcelana, git-rev-listé encanamento.
blitzen9872
27

Se você deseja obter apenas o hash da confirmação mais recente para modificar um conjunto específico de arquivos (e deseja evitar awk), você pode usar:

git log -n 1 --pretty=format:%h -- <path>

Isso pode ser útil para obter o hash de confirmação para uso posterior com git describe.

Por exemplo (caso seja útil para qualquer pessoa)…

Criei um ID de versão atual considerando o commit mais recente para alterar qualquer arquivo de origem (supondo que você marque versões com tags como mycode-1.2.1):

COMMIT=$(git log -n 1 --pretty=format:%h -- *.c *.h)
if VN=$(git describe --always --abbrev=5 --match "mycode-*" $COMMIT 2>/dev/null) &&
case "$VN" in
mycode-*)
    git update-index -q --refresh
    test -z "$(git diff-index --name-only HEAD *.c *.h)" ||
    VN="$VN-mod" ;;
*) VN="mycode-unknown-g$VN" ;;
esac
then
    continue
else
VN="mycode-unknown"
fi

Isso produz IDs como:

  • mycode-1.2.1 - quando o estado atual dos arquivos de origem corresponder a uma versão marcada
  • mycode-1.2.1-g3k7s2 - quando o estado atual dos arquivos de origem corresponder à confirmação após uma versão marcada
  • mycode-1.2.1-g3k7s2-mod - quando o estado atual dos arquivos de origem foi modificado desde a última confirmação após uma versão marcada
  • mycode-unknown - quando ainda não houver uma tag de versão criada
TheBamf
fonte
5
$VNparece algum tipo de pesadelo morto-vivo SVN
ThorSummoner
10

Não tenho certeza se é isso que você deseja, mas se você fizer um git log <thefile>para obter os commits que alteraram esse arquivo. Você pode escolher o mais alto. Deve ser o que você está procurando.

Noufal Ibrahim
fonte
4
se você usa git log -n1 -- <thefile>(ou canalizar a saída para head -1se você quer desperdiçar recursos), você não tem que escolher manualmente a linha superior (ver Jo Liss resposta )
Tobias KIENZLER
4
Bom ponto. Eu acho que você também pode pular o -ne usar -1diretamente.
Noufal Ibrahim
3

Para obter apenas o árbitro em uma linha, tente:

git log -n1 --oneline <path> | awk '{print $1;}'
multiplicação rápida
fonte
2

Depois de ter o ID SHA do commit que você deseja usar git log FILENAME, você poderá fazer git show SHA_ID_HEREpara ver o que fez para esse commit específico. Você nem precisa digitar o ID inteiro; os 6 primeiros caracteres devem ser suficientes.

Joe
fonte
4
que é um pouco mais do que o OP pediu, mas FYI você pode combinar isso em uma frase:git show $(git log -1 --pretty="%H" -- FILENAME)
Tobias KIENZLER