Como recuperar o hash para o commit atual no Git?

1934

Gostaria de manter (por enquanto) a capacidade de vincular conjuntos de alterações do Git a itens de trabalho armazenados no TFS.

Eu já escrevi uma ferramenta (usando um gancho do Git) na qual posso injetar identificadores de trabalho na mensagem de um conjunto de alterações do Git.

No entanto, eu também gostaria de armazenar o identificador do commit do Git (o hash) em um campo de item de trabalho TFS personalizado. Dessa forma, posso examinar um item de trabalho no TFS e ver quais conjuntos de alterações do Git estão associados ao item de trabalho.

Como posso recuperar facilmente o hash do commit atual do Git?

Sardaukar
fonte

Respostas:

2810

Para transformar referência arbitrária de objeto estendido em SHA-1, use simplesmente git-rev-parse , por exemplo

git rev-parse HEAD

ou

git rev-parse --verify HEAD

Nota: Se você deseja transformar referências ( ramificações e tags ) em SHA-1, existegit show-refegit for-each-ref.

Jakub Narębski
fonte
81
--verifyimplica que:The parameter given must be usable as a single, valid object name. Otherwise barf and abort.
Linus Unnebäck 24/07
648
git rev-parse --short HEADretorna a versão curta do hash, caso alguém esteja se perguntando.
precisa
55
Além do que Thane disse, você também pode adicionar um comprimento específico para --short, por exemplo --short=12, obter um número específico de dígitos do hash.
Tyson Phalp
32
@TysonPhalp: --short=Ntrata-se de um número mínimo de dígitos; O git usa um número maior de dígitos se um menor for indistinguível de outro commit reduzido. Tente, por exemplo, git rev-parse --short=2 HEADou git log --oneline --abbrev=2.
Jakub Narębski
36
Somando-se o Thane, Tyson, e Jakub disse, você pode imprimir o hash completo, mas destacar as hexits necessário identificar a cometer azul comgit rev-parse HEAD | GREP_COLORS='ms=34;1' grep $(git rev-parse --short=0 HEAD)
Zaz
424

Se você deseja apenas o hash reduzido:

git log --pretty=format:'%h' -n 1

Além disso, o uso de% H é outra maneira de obter o hash longo.

fora da cultura
fonte
107
Ou, ao que parece, adicionar --short ao comando rev-parse acima parece funcionar.
Outfculture
15
Eu acho que git logé porcelana e git rev-parseé encanamento.
Amedee Van Gasse
Um dos benefícios desse método é que ele retornará a versão curta do hash com o comprimento certo ajustado às colisões de hash que acontecem para repositórios maiores. Pelo menos nas versões recentes do git.
Ilia Sidorenko
4
Essa é uma maneira incorreta / incorreta, porque esse método fornecerá o hash errado se você tiver uma cabeça desanexada. Por exemplo, se o commit atual é 12ab34 ... e o commit anterior foi 33aa44 ... então, se eu fizer 'git checkout 33aa44' e executar o seu comando, continuarei recebendo 12ab34 ... apesar de minha cabeça realmente apontar para 33aa44 ...
theQuestionMan
3
@theQuestionMan Não tenho o comportamento que você descreve; git checkout 33aa44; git log -n 1me dá 33aa44. Qual versão do git você está usando?
Outcultura
150

Outro, usando o git log:

git log -1 --format="%H"

É muito semelhante ao da @outofculture, embora um pouco mais curto.

Paul Pladijs
fonte
E o resultado não é citado.
26417 crokusek
5
Esta é a resposta correta, pois funciona mesmo se você fizer o checkout de um commit específico em vez de HEAD.
Parsa
1
@Parsa: ao verificar um commit específico, HEADaponte para esse commit em vez de um branche nomeado conhecido como head desanexado .
ChristofSenn
125

Para obter o SHA completo:

$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537

Para obter a versão abreviada:

$ git rev-parse --short HEAD
cbf1b9a
Alexander
fonte
Se dois git commithashes forem necessários, como um do qual branchvocê está trabalhando no momento e a master branch, você também poderá usá- git rev-parse FETCH_HEADlo se precisar do hash para o master commitque você mergeencontrou no seu atual branch. por exemplo, se você tem branches mastere feature/new-featurepara um determinado repositório., enquanto estiver usando, feature/new-featurevocê pode usar git fetch origin master && git merge FETCH_HEADe, em seguida, git rev-parse --short FETCH_HEADse precisar do commithash do qual mastervocê acabou de se mergededicar a qualquer script que possa ter.
EVAL
72

Para ser completo, já que ninguém o sugeriu ainda. .git/refs/heads/masteré um arquivo que contém apenas uma linha: o hash da confirmação mais recente emmaster . Então você pode ler a partir daí.

Ou, como comando:

cat .git/refs/heads/master

Atualizar:

Note que o git agora suporta o armazenamento de algumas referências de cabeça no arquivo pack-ref em vez de como um arquivo na pasta / refs / heads /. https://www.kernel.org/pub/software/scm/git/docs/git-pack-refs.html

Deestan
fonte
10
Isso pressupõe que o ramo atual seja master, o que não é necessariamente verdadeiro.
Gavrie
12
De fato. Por isso disse explicitamente que é para isso master.
Deestan
20
.git/HEADnormalmente aponta para um juiz, se você tiver um SHA1 lá, você está no modo de cabeça desanexada.
Eckes
8
Isso não é muito robusto em comparação com outras abordagens, principalmente porque pressupõe que existe um .gitsubdiretório, o que não é necessariamente o caso. Veja a --separate-git-dirbandeira na git initpágina de manual.
Jb0bs
16
+1 porque às vezes você não quer executável git instalado (por exemplo, em sua Dockerfile)
Wim
50

Confirmar hash

git show -s --format=%H

Hash de confirmação abreviado

git show -s --format=%h

Clique aqui para mais git showexemplos.

ecwpz91
fonte
50

Sempre há git describetambém. Por padrão, ele fornece -

john@eleanor:/dev/shm/mpd/ncmpc/pkg (master)$ git describe --always
release-0.19-11-g7a68a75
John Tyree
fonte
18
O Git description retorna o primeiro TAG acessível a partir de uma confirmação. Como isso me ajuda a obter o SHA?
Sardaukar
42
Eu gosto git describe --long --dirty --abbrev=10 --tagsque isso me dará algo do tipo 7.2.0.Final-447-g65bf4ef2d4447 confirmado após a tag 7.2.0.Final e os 10 primeiros resumos do SHA-1 global no HEAD atual são "65bf4ef2d4". Isso é muito bom para cadeias de versão. Com --long, ele sempre adiciona a contagem (-0-) e o hash, mesmo que a tag coincida exatamente.
Eckes
14
Se existir, em seguida, nenhuma tag git describe --alwaysvai "mostrar exclusivamente abreviado cometer objeto como fallback"
Ronny Andersson
Eu uso git describe --tags --first-parent --abbrev=11 --long --dirty --always. A --alwaysopção significa que ele fornece um resultado (hash), mesmo que não haja tags. Os --first-parentmeios que não são confundidos por confirmações de mesclagem e seguem apenas itens na ramificação atual. Observe também que --dirtyserá anexado -dirtyao resultado se a ramificação atual tiver alterações não confirmadas.
ingyhere 31/01
30

Usar git rev-list --max-count=1 HEAD

Robert Munteanu
fonte
3
git-rev-list é sobre gerar lista de objetos de confirmação; é git-rev-parse para traduzir nome de objecto (por exemplo CABEÇA) em SHA-1
Jakub Narębski
21

Se você precisar armazenar o hash em uma variável durante um script, poderá usar

last_commit=$(git rev-parse HEAD)

Ou, se você quiser apenas os 10 primeiros caracteres (como o github.com)

last_commit=$(git rev-parse HEAD | cut -c1-10) 
Henk
fonte
26
Também existem os parâmetros --shortou --short=numberpara git rev-parse; não há necessidade de usar um cachimbo e cut.
Julian D.
15

Se você quiser uma maneira super hacky de fazer isso:

cat .git/`cat .git/HEAD | cut -d \  -f 2`

Basicamente, o git armazena a localização do HEAD em .git / HEAD, no formato ref: {path from .git} . Este comando lê isso, corta o "ref:" e lê o arquivo que ele apontou.

Isso, é claro, falhará no modo de cabeça destacada, pois HEAD não será "ref: ...", mas o próprio hash - mas você sabe, eu não acho que você espere tanta inteligência em seu bash. forros. Se você não acha que ponto e vírgula estão trapaceando, ...

HASH="ref: HEAD"; while [[ $HASH == ref\:* ]]; do HASH="$(cat ".git/$(echo $HASH | cut -d \  -f 2)")"; done; echo $HASH
Fordi
fonte
1
não há necessidade de instalar o git, eu gosto. (minha imagem janela de encaixe de construção não tem git)
Helin Wang
Também útil porque você pode executar este facilmente de fora do repo git
samaspin
Eu formalizei isso em um script para minha máquina local. Então, pensei: ei: a implementação que fiz é simples o suficiente para ilustrar como resolver um problema não relacionado (analisando argumentos em scripts shell POSIX brutos sem programas externos), mas complexa o suficiente para fornecer uma pequena variação e explorar a maioria dos características de sh. Meia hora de comentários de documentação mais tarde, e aqui está uma essência dele: gist.github.com/Fordi/29b8d6d1ef1662b306bfc2bd99151b07
Fordi
Olhando para ele, criei uma versão mais extensa para detectar o Git e o SVN e pegar a revisão git hash / svn. Não é uma string limpa desta vez, mas é facilmente analisada pela linha de comando e utilizável como uma tag de versão: gist.github.com/Fordi/8f1828efd820181f24302b292670b14e
Fordi:
14

A maneira mais sucinta que eu conheço:

git show --pretty=%h 

Se você deseja um número específico de dígitos do hash, pode adicionar:

--abbrev=n
Brian Peterson
fonte
14
Enquanto isso tecnicamente funciona, git showé o que é conhecido como um comando de porcelana (ou seja, voltado para o usuário) e, portanto, não deve ser usado em scripts porque sua saída está sujeita a alterações. A resposta acima ( git rev-parse --short HEAD) deve ser usada.
Jm3 #
4
@ jm3 que está ao contrário. Os comandos "Porcelain" possuem saídas estáveis ​​destinadas a scripts. Pesquise git help showpor porcelain.
precisa
2
@ JohnTyree Este é um assunto confuso, mas o jm3 estava certo: os comandos de porcelana não devem ser analisados, mas sim legíveis por humanos. Caso você precise usar um comando de porcelana em um script e deseje ter um formato estável, algumas vezes (por exemplo, com status git, push and blame) uma opção que faz exatamente isso. Infelizmente, essa opção é chamada --porcelain, e é por isso que isso é confuso. Você pode encontrar os detalhes desta ótima resposta por VonC
Fabio diz Reinstate Monica
1
Querido Deus, que decidiu nomear essa opção --porcelain Quero encontrá-los e ... oh esperar que eu precisaria usar git para encontrá-los Nevermind
Britton Kerin
14

Talvez você queira um pseudônimo para não precisar se lembrar de todos os detalhes bacanas. Depois de executar uma das etapas abaixo, você poderá digitar simplesmente:

$ git lastcommit
49c03fc679ab11534e1b4b35687b1225c365c630

Seguindo a resposta aceita , aqui estão duas maneiras de configurar isso:

1) Ensine o git da maneira explícita editando a configuração global (minha resposta original):

 # open the git config editor
 $ git config --global --edit
 # in the alias section, add
 ...
 [alias]
   lastcommit = rev-parse HEAD
 ...

2) Ou se você gosta de um atalho para ensinar ao git um atalho, como recentemente comentado por Adrien:

$ git config --global alias.lastcommit "rev-parse HEAD"

A partir daqui, use git lastcommitpara mostrar o hash do último commit.

miraculixx
fonte
3
Adrien de Sentenac observa que, em vez de editar manualmente o arquivo de configuração do git, você pode simplesmente fazer o seguinte:git config --global alias.lastcommit "rev-parse HEAD"
cgmb 17/11/2015
12

Eu precisava de algo um pouco mais diferente: exibir o sha1 completo do commit, mas anexar um asterisco ao final se o diretório de trabalho não estiver limpo. A menos que eu queira usar vários comandos, nenhuma das opções nas respostas anteriores funciona.

Aqui está o liner que faz:
git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Resultado:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

Explicação: descreve (usando tags anotadas) a confirmação atual, mas apenas com tags que contêm "NOT A TAG". Como as tags não podem ter espaços, isso nunca corresponde a uma tag e, como queremos mostrar um resultado --always, o comando retorna exibindo o --abbrev=0sha1 completo ( ) do commit e acrescenta um asterisco se o diretório de trabalho estiver --dirty.

Se você não deseja anexar o asterisco, isso funciona como todos os outros comandos nas respostas anteriores:
git describe --always --abbrev=0 --match "NOT A TAG"
Resultado:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe

Rado
fonte
Obrigado, apenas tropeçando sobre ele e isso me poupa a um ou outro eco para que :)
hakre
1
Funciona para mim sem o --match "NOT A TAG". Testado no git 2.18.0 e também no 2.7.4. Existe alguma situação em que esse argumento é necessário?
Thomas
@ Thomas não funcionará se você tiver uma tag anotada em qualquer lugar do histórico do commit atual. A tag falsa garante que o comando de descrição não use uma tag para descrever a confirmação, #
085 Rado
8
git show-ref --head --hash head

Se você está buscando velocidade, a abordagem mencionada por Deestan

cat .git/refs/heads/<branch-name>

é significativamente mais rápido que qualquer outro método listado aqui até agora.

Dennis
fonte
show-refparece-me ser a melhor opção para scripting, já que é um comando de canalização e assim garantido (ou pelo menos muito provável) de permanecer estável em futuras versões: outras respostas utilizar rev-parse, show, describeou log, que são todos os comandos de porcelana. E nos casos em que a velocidade não é essencial, a nota da página de show-refmanual se aplica: 'O uso deste utilitário é incentivado em favor do acesso direto aos arquivos no diretório .git.'
Pont
6

Aqui está uma linha no shell Bash usando a leitura direta de arquivos git:

(head=($(<.git/HEAD)); cat .git/${head[1]})

Você precisa executar o comando acima na sua pasta raiz do git.

Este método pode ser útil quando você tiver arquivos de repositório, mas o gitcomando não foi instalado.

Se não funcionar, verifique na .git/refs/headspasta que tipo de cabeça você possui.

kenorb
fonte
5

no diretório home no arquivo ".gitconfig", adicione o seguinte

[alias]
sha = rev-parse HEAD

então você terá um comando mais fácil de lembrar:

$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600
jo_
fonte
3

No git bash, basta executar $ git log -1

você verá essas linhas seguindo seu comando.

commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)

d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.
Batty
fonte
0

Aqui está outra implementação de acesso direto:

head="$(cat ".git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(cat ".git/${head#ref: }")"
done

Isso também funciona com http, o que é útil para arquivos de pacotes locais (eu sei: para sites públicos, não é recomendável tornar o diretório .git acessível):

head="$(curl -s "$baseurl/.git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(curl -s "$baseurl/.git/${head#ref: }")"
done
Daniel Alder
fonte
0

Aqui está outra maneira de fazê-lo com :)

git log | grep -o '\w\{8,\}' | head -n 1
Marcelo Lazaroni
fonte
0
cat .git/HEAD

Exemplo de saída:

ref: refs/heads/master

Analise:

cat .git/HEAD | sed "s/^.\+ \(.\+\)$/\1/g"

Se você possui janelas, considere usar o wsl.exe:

wsl cat .git/HEAD | wsl sed "s/^.\+ \(.\+\)$/\1/g"

Resultado:

refs/heads/master

Esse valor pode ser usado para git checkout mais tarde, mas fica apontando para seu SHA. Para fazê-lo apontar para a ramificação atual real por seu nome, faça:

wsl cat .git/HEAD | wsl sed "s/^.\+ \(.\+\)$/\1/g" | wsl sed "s/^refs\///g" | wsl sed "s/^heads\///g"

Saídas:

master

Sergei
fonte