Как получить хеш для текущего коммита в Git?

1934

Я хотел бы сохранить (на данный момент) возможность связывать наборы изменений Git с рабочими элементами, хранящимися в TFS.

Я уже написал инструмент (используя хук из Git), в котором я могу добавить рабочие идентификаторы в сообщение набора изменений Git.

Однако я также хотел бы сохранить идентификатор коммита Git (хеш) в настраиваемом поле рабочего элемента TFS. Таким образом, я могу проверить рабочий элемент в TFS и посмотреть, какие наборы изменений Git связаны с рабочим элементом.

Как я могу легко получить хеш из текущего коммита из Git?

Sardaukar
источник

Ответы:

2810

Чтобы превратить произвольную расширенную ссылку на объект в SHA-1, используйте просто git-rev-parse , например

git rev-parse HEAD

или

git rev-parse --verify HEAD

Sidenote: Если вы хотите превратить ссылки ( ветви и теги ) в SHA-1, естьgit show-refиgit for-each-ref.

Якуб Наребски
источник
81
--verifyподразумевает, что:The parameter given must be usable as a single, valid object name. Otherwise barf and abort.
Линус Уннебекк
648
git rev-parse --short HEADвозвращает короткую версию хэша, на случай, если кому-то интересно.
Тейн Бримхолл
55
Помимо сказанного Тейном, вы также можете добавить определенную длину --short, например --short=12, чтобы получить определенное количество цифр из хеша.
Тайсон Фалп
32
@TysonPhalp: --short=Nо минимальном количестве цифр; git использует большее количество цифр, если укороченная будет неотличима от другой укороченной фиксации. Попробуйте например git rev-parse --short=2 HEADили git log --oneline --abbrev=2.
Якуб Наребски
36
В дополнение к словам Тейна, Тайсона и Якуба вы можете напечатать полный хеш, но выделите гекситы, необходимые для идентификации синего коммитаgit rev-parse HEAD | GREP_COLORS='ms=34;1' grep $(git rev-parse --short=0 HEAD)
Zaz
424

Если вы хотите только сокращенный хеш:

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

Кроме того, использование% H - это еще один способ получить длинный хэш.

outofculture
источник
107
Или, кажется, добавление --short к команде rev-parse выше работает.
outofculture
15
Я думаю, git logэто фарфор и git rev-parseсантехника.
Амеди Ван Гасс
Одним из преимуществ этого метода является то, что он возвращает короткую версию хэша с правильной длиной, скорректированной с учетом коллизий хэшей, которые происходят для больших репо. По крайней мере, в последних версиях Git.
Илья Сидоренко
4
Это плохой / неправильный способ сделать это, потому что этот метод даст вам неправильный хеш, если у вас отсоединенная голова. Например, если текущий коммит 12ab34 ... а предыдущий коммит был 33aa44 ... тогда, если я сделаю 'git checkout 33aa44' и затем введу вашу команду, я все равно вернусь обратно 12ab34 ... несмотря на то, что моя голова фактически указывает на 33aa44 ...
TheMuestionMan
3
@ theQuestionMan Я не испытываю поведение, которое вы описываете; git checkout 33aa44; git log -n 1дает мне 33aa44. Какую версию Git вы используете?
outofculture
150

Еще один, используя git log:

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

Это очень похоже на @outofculture, но немного короче.

Пол Пладийс
источник
И результат не в кавычках.
crokusek
5
Это правильный ответ, так как он работает, даже если вы извлекаете конкретный коммит вместо HEAD.
Parsa
1
@Parsa: при проверке конкретных коммитов HEADуказывает на этот коммит, а не на именованную ветку, известную как отдельная голова .
ChristofSenn
125

Чтобы получить полный SHA:

$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537

Чтобы получить сокращенную версию:

$ git rev-parse --short HEAD
cbf1b9a
Александр
источник
Если необходимы два git commitхэша, например, один из тех, с branchкоторыми вы сейчас работаете, и a master branch, вы также можете использовать его, git rev-parse FETCH_HEADесли вам нужен хеш для того, master commitчто вы mergeдобавили в свой текущий branch. например, если у вас есть branches masterи feature/new-featureдля данного репо., в то время как feature/new-featureвы могли бы использовать, git fetch origin master && git merge FETCH_HEADа затем, git rev-parse --short FETCH_HEADесли вам нужен commitхеш из только что использованных masterвами mergeсценариев.
EVAL
72

Для полноты, так как никто еще не предложил это. .git/refs/heads/masterэто файл, который содержит только одну строку: хэш последней фиксации master. Так что вы можете просто прочитать это оттуда.

Или как команда:

cat .git/refs/heads/master

Обновить:

Обратите внимание, что git теперь поддерживает сохранение некоторых ссылок в файле pack-ref, а не в виде файла в папке / refs /head /. https://www.kernel.org/pub/software/scm/git/docs/git-pack-refs.html

Deestan
источник
10
Это предполагает, что текущая ветвь есть master, что не обязательно верно.
Гаври
12
Верно. Вот почему я прямо сказал, что это для master.
Дестан
20
.git/HEADобычно указывает на ссылку, если у вас есть SHA1 там, вы находитесь в режиме отсоединенной головы.
Eckes
8
Это не очень надежно по сравнению с другими подходами, в частности, потому что предполагает наличие .gitподкаталога, что не всегда так. Смотрите --separate-git-dirфлаг на git initстранице руководства .
jub0bs
16
Because1 потому что иногда вы не хотите, чтобы был установлен исполняемый файл git (например, в вашем Dockerfile)
wim
50

Зафиксируйте хеш

git show -s --format=%H

Сокращенный коммит хеш

git show -s --format=%h

Нажмите здесь для большего количества git showпримеров.

ecwpz91
источник
50

Там всегда git describeтак же. По умолчанию это дает вам -

john@eleanor:/dev/shm/mpd/ncmpc/pkg (master)$ git describe --always
release-0.19-11-g7a68a75
Джон Тайри
источник
18
Git description возвращает первый TAG, доступный из коммита. Как это поможет мне получить SHA?
Сардаукар
42
Мне нравится, git describe --long --dirty --abbrev=10 --tagsчто это даст мне что-то вроде 7.2.0.Final-447-g65bf4ef2d4447 коммитов после тега 7.2.0.Final и первые 10 дайджестов глобального SHA-1 в текущем HEAD: «65bf4ef2d4». Это очень хорошо для версий строк. При использовании параметра --long всегда добавляются счетчик (-0-) и хэш, даже если тег точно совпадает.
Eckes
14
Если тегов не существует git describe --always, «покажет однозначно сокращенный объект коммита как запасной вариант»
Ронни Андерссон,
Я использую git describe --tags --first-parent --abbrev=11 --long --dirty --always. Параметр --alwaysозначает, что он предоставляет результат (хэш), даже если нет тегов. Это --first-parentозначает, что он не запутывается коммитами слияния и следует только за элементами в текущей ветке. Обратите внимание, что --dirtyэто добавит -dirtyк результату, если текущая ветвь имеет незафиксированные изменения.
ingyhere
30

использование git rev-list --max-count=1 HEAD

Роберт Мунтяну
источник
3
git-rev-list предназначен для генерации списка объектов коммитов; это git-rev-parse для перевода имени объекта (например, HEAD) в SHA-1
Якуб Наребски
21

Если вам нужно сохранить хеш в переменной во время скрипта, вы можете использовать

last_commit=$(git rev-parse HEAD)

Или, если вы хотите только первые 10 символов (как делает github.com)

last_commit=$(git rev-parse HEAD | cut -c1-10) 
Henk
источник
26
Есть также параметры --shortили --short=numberдля git rev-parse; Не нужно использовать трубу и др cut.
Джулиан Д.
15

Если вы хотите супер-хакерский способ сделать это:

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

По сути, git хранит местоположение HEAD в .git / HEAD в форме ref: {path from .git}. Эта команда считывает это, вырезает «ref:» и считывает любой файл, на который она указала.

Это, конечно, потерпит неудачу в режиме отсоединенной головы, так как HEAD не будет «ref: ...», но сам хэш - но вы знаете, я не думаю, что вы ожидаете, что много умных в вашем bash один -liners. Если вы не думаете, что точки с запятой обманывают ...

HASH="ref: HEAD"; while [[ $HASH == ref\:* ]]; do HASH="$(cat ".git/$(echo $HASH | cut -d \  -f 2)")"; done; echo $HASH
Fordi
источник
1
не нужно устанавливать git, мне это нравится. (мой образ сборки докера не имеет мерзавца)
Хелин Ван
также полезно, потому что вы можете легко запустить это вне git-
репозитория
Я формализовал это для сценария для моей локальной машины. Затем, я подумал: эй: реализация, которую я сделал, достаточно проста, чтобы проиллюстрировать, как решить несвязанную проблему (синтаксический анализ аргументов в необработанных сценариях оболочки POSIX без внешних программ), но достаточно сложна, чтобы обеспечить небольшие вариации и использовать большую часть черты sh. Спустя полчаса комментариев к документации, и вот суть
Fordi
Глядя на это, я сделал более обширную версию для обнаружения Git и SVN и получения ревизии git hash / svn. На этот раз не чистая строка, но легко разбираемая в командной строке, и используемая как тег версии: gist.github.com/Fordi/8f1828efd820181f24302b292670b14e
Fordi
14

Самый краткий путь, который я знаю:

git show --pretty=%h 

Если вам нужно конкретное количество цифр хеша, вы можете добавить:

--abbrev=n
Брайан Петерсон
источник
14
Хотя это технически работает, git showэто то, что известно как фарфоровая команда (то есть обращенная к пользователю), и поэтому не должно использоваться в сценариях, потому что ее выходные данные могут быть изменены. Ответ выше ( git rev-parse --short HEAD) следует использовать вместо этого.
jm3
4
@ jm3 это задом наперед. «Фарфоровые» команды имеют стабильные выходные данные, предназначенные для скриптов. Поиск git help showпо porcelain.
Джон Тайри
2
@JohnTyree Это запутанная тема, но jm3 был прав: команды фарфора предназначены не для анализа, а для восприятия человеком. Если вам нужно использовать фарфоровую команду в сценарии и вы хотите иметь стабильный формат, иногда (например, с git status, push и blame) есть опция, которая делает именно это. К сожалению, эта опция называется --porcelain, поэтому это сбивает с толку. Вы можете найти подробности в этом великолепном ответе VonC
Фабио говорит, что восстановите Монику
1
дорогой бог, который решил назвать этот вариант - фарфор, я хочу их найти и ... о, подожди, мне нужно использовать git, чтобы найти их неважно
Бриттон Крейн,
14

Возможно, вам нужен псевдоним, поэтому вам не нужно запоминать все изящные детали. Выполнив одно из следующих действий, вы сможете просто набрать:

$ git lastcommit
49c03fc679ab11534e1b4b35687b1225c365c630

Следуя принятому ответу , вот два способа установить это:

1) Научите git явным образом, отредактировав глобальный конфиг (мой оригинальный ответ):

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

2) Или, если вам нравится ярлык, чтобы научить Git ярлык, как недавно прокомментировал Адриен:

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

С этого git lastcommitмомента используйте, чтобы показать хэш последнего коммита.

miraculixx
источник
3
Адриен де Сентенак отмечает, что вместо ручного редактирования файла конфигурации git вы можете просто сделать:git config --global alias.lastcommit "rev-parse HEAD"
cgmb
12

Мне нужно было что-то немного другое: отобразить полный sha1 коммита, но добавить звездочку в конец, если рабочий каталог не чистый. Если я не хотел использовать несколько команд, ни один из вариантов в предыдущих ответах не работает.

Вот один вкладыш, который делает:
git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Результат:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

Объяснение: описывает (используя аннотированные теги) текущую фиксацию, но только с тегами, содержащими «NOT A TAG». Поскольку у тегов не может быть пробелов, это никогда не соответствует тегу, и поскольку мы хотим показать результат --always, команда возвращается к отображению полного ( --abbrev=0) sha1 коммита и добавляет звездочку, если рабочий каталог есть --dirty.

Если вы не хотите добавлять звездочку, это работает как все остальные команды в предыдущих ответах:
git describe --always --abbrev=0 --match "NOT A TAG"
Результат:f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe

Rado
источник
Спасибо, просто спотыкаюсь об этом, и это избавляет меня от того или иного эха за это :)
hakre
1
Это работает для меня без --match "NOT A TAG". Протестировано в git 2.18.0 и 2.7.4. Есть ли ситуация, когда нужен этот аргумент?
Томас
@ Томас не будет работать, если у вас есть аннотированный тег где-либо в истории текущего коммита. Поддельный тег гарантирует, что команда description не использует тег для описания коммита,
Rado
8
git show-ref --head --hash head

Если вы идете на скорости, хотя, подход, упомянутый Дестаном

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

значительно быстрее, чем любой другой метод, перечисленный здесь до сих пор.

Деннис
источник
show-refмне кажется, лучшим вариантом для написания сценариев, так как это команда водопроводной и , таким образом , гарантируется (или , по крайней мере , весьма вероятно) , чтобы оставаться стабильными в будущих версиях: другие ответы использовать rev-parse, show, describeили log, что все команды фарфора. А в тех случаях, когда скорость не имеет значения, применяется примечание на show-refстранице руководства : «Использование этой утилиты рекомендуется для прямого доступа к файлам в каталоге .git».
Пон
6

Вот одна строка в оболочке Bash, использующая прямое чтение из файлов git:

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

Вам нужно запустить вышеуказанную команду в вашей корневой папке git.

Этот метод может быть полезен, когда у вас есть файлы репозитория, но gitкоманда не установлена.

Если не получится, проверьте в .git/refs/headsпапке, какие у вас головы.

kenorb
источник
5

в вашем домашнем каталоге в файле ".gitconfig" добавьте следующее

[alias]
sha = rev-parse HEAD

тогда вам будет легче запомнить команду:

$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600
Джо_
источник
3

В git bash просто запустите $ git log -1

вы увидите, эти строки следуют вашей команде.

commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)

d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.
тронутый
источник
0

Вот еще одна реализация прямого доступа:

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

Это также работает через http, что полезно для локальных архивов пакетов (я знаю: для общедоступных веб-сайтов не рекомендуется делать каталог .git доступным):

head="$(curl -s "$baseurl/.git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(curl -s "$baseurl/.git/${head#ref: }")"
done
Даниэль Алдер
источник
0

Вот еще один способ сделать это с :)

git log | grep -o '\w\{8,\}' | head -n 1
Марсело Лазарони
источник
0
cat .git/HEAD

Пример вывода:

ref: refs/heads/master

Разобрать это:

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

Если у вас есть окна, то вы можете использовать wsl.exe:

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

Вывод:

refs/heads/master

Это значение может быть использовано позже для git checkout, но оно станет указывать на свой SHA. Чтобы сделать так, чтобы он указывал на текущую текущую ветку по ее имени, выполните:

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

Выходы:

master

Сергей
источник