Как получить хеш для текущего коммита в Git?
Я хотел бы сохранить (на данный момент) возможность связывать наборы изменений Git с рабочими элементами, хранящимися в TFS.
Я уже написал инструмент (используя хук из Git), в котором я могу добавить рабочие идентификаторы в сообщение набора изменений Git.
Однако я также хотел бы сохранить идентификатор коммита Git (хеш) в настраиваемом поле рабочего элемента TFS. Таким образом, я могу проверить рабочий элемент в TFS и посмотреть, какие наборы изменений Git связаны с рабочим элементом.
Как я могу легко получить хеш из текущего коммита из Git?
26 ответов
Чтобы превратить произвольную расширенную ссылку на объект в SHA-1, используйте просто git-rev-parse, например
git rev-parse HEAD
или же
git rev-parse --verify HEAD
Sidenote: Если вы хотите превратить ссылки (ветви и теги) в SHA-1, есть git show-ref
а также git for-each-ref
,
Если вам нужен только сокращенный хеш:
git log --pretty=format:'%h' -n 1
Кроме того, использование%H - это еще один способ получить длинный хэш.
Еще один, используя git log:
git log -1 --format="%H"
Это очень похоже на @outofculture, но немного короче.
Чтобы получить полный SHA:
$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537
Чтобы получить сокращенную версию:
$ git rev-parse --short HEAD
cbf1b9a
Зафиксируйте хеш
git show -s --format=%H
Сокращенный коммит хеш
git show -s --format=%h
Нажмите здесь для более git show
Примеры.
Для полноты, так как никто еще не предложил это. .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
Всегда есть git describe
также. По умолчанию это дает вам -
john@eleanor:/dev/shm/mpd/ncmpc/pkg (master)$ git describe
release-0.19-11-g7a68a75
Если вам нужно сохранить хеш в переменной во время скрипта, вы можете использовать
last_commit=$(git rev-parse HEAD)
Или, если вы хотите только первые 10 символов (как это делает github.com)
last_commit=$(git rev-parse HEAD | cut -c1-10)
Если вы хотите супер-хакерский способ сделать это:
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
Мне нужно было что-то немного другое: отобразить полный sha1 коммита, но добавить звездочку в конец, если рабочий каталог не чистый. Если я не хотел использовать несколько команд, ни один из вариантов в предыдущих ответах не работает.
Вот один лайнер, который делает:git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Результат: f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*
Объяснение: описывает (используя аннотированные теги) текущую фиксацию, но только с тегами, содержащими "НЕ A TAG". Так как у тегов не может быть пробелов, это никогда не соответствует тегу, и так как мы хотим показать результат --always
, команда возвращается с отображением полного (--abbrev=0
) sha1 коммита и добавляет звездочку, если рабочий каталог --dirty
,
Если вы не хотите добавлять звездочку, это работает как все остальные команды в предыдущих ответах:git describe --always --abbrev=0 --match "NOT A TAG"
Результат: f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe
git rev-parse HEAD
делает свое дело.
Если вам нужно сохранить его для возврата позже, чем сохранение фактической ветки, если таковая может быть предпочтительнее:
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
Возможно, вам нужен псевдоним, поэтому вам не нужно запоминать все изящные детали. Выполнив одно из следующих действий, вы сможете просто набрать:
$ 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
показать хэш последнего коммита.
Самый краткий путь, который я знаю:
git show --pretty=%h
Если вам нужно конкретное количество цифр хеша, вы можете добавить:
--abbrev=n
Вот одна строка в оболочке Bash, использующая прямое чтение из файлов git:
(head=($(<.git/HEAD)); cat .git/${head[1]})
Вам нужно выполнить указанную выше команду в вашей корневой папке git.
Этот метод может быть полезен, когда у вас есть файлы репозитория, но git
Команда не была установлена.
Если не получится, зарегистрируйся .git/refs/heads
Папка, какие у вас есть головы.
git show-ref --head --hash head
Если вы идете на скорости, хотя, подход, упомянутый Дестаном
cat .git/refs/heads/<branch-name>
значительно быстрее, чем любой другой метод, перечисленный здесь до сих пор.
В вашем домашнем каталоге в файле ".gitconfig" добавьте следующее
[alias]
sha = rev-parse HEAD
тогда вам будет легче запомнить команду:
$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600
В git bash просто запустите $ git log -1
вы увидите эти строки после вашей команды.
commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)
d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.
Красивая печать основного репозитория git и подмодулей:
echo "Main GIT repo:"
echo $(git show -s --format=%H) '(main)'
echo "Sub-modules:"
git submodule status | awk '{print $1,$2}'
Пример вывода:
3a032b0992d7786b00a8822bbcbf192326160cf9 (main)
7de695d58f427c0887b094271ba1ae77a439084f sub-module-1
58f427c0887b01ba1ae77a439084947de695d27f sub-module-2
d58f427c0887de6957b09439084f4271ba1ae77a sub-module-3
Как бы я сделал это на питоне (на основе ответа @kenorb на bash)
def get_git_sha():
# Which branch are we on?
branch = open(".git/HEAD", "r").read()
# Parse output "ref: refs/heads/my_branch" -> my_branch
branch = branch.strip().split("/")[-1]
# What's the latest commit in this branch?
return open(f".git/refs/heads/{branch}").read().strip()
Получите хэш текущего коммита и посмотрите, является ли он «чистым» или «грязным».
Я хочу увидеть72361c8
или72361c8-dirty
для использования в моей системе сборки номера версий, внедренные в исполняемые файлы моей программы. Вот как:
Краткое резюме
# get a short commit hash, and see whether `git status` is clean or dirty
test -z "$(git status --porcelain)" \
&& echo "$(git rev-parse --short HEAD)" \
|| echo "$(git rev-parse --short HEAD)-dirty"
Пример вывода, когда он чист (нет незафиксированных изменений):
72361c8
Пример вывода, когда он грязный (есть какие-либо незафиксированные изменения):
- Значение: есть какие-либо незафиксированные изменения, будь то непроиндексированные изменения в отслеживаемых файлах, проиндексированные (
git add
ред) изменения в отслеживаемых файлах или добавление новых файлов.
72361c8-dirty
Подробности
Точно так же, как при использовании Git Submodules будет показано, когда подмодуль является «чистым» или «грязным» , я действительно хочу увидеть свой короткий хеш коммита со словом-dirty
после этого, еслиgit status
грязный! Я использую это в своей системе сборки в качестве номера версии моего программного обеспечения, поэтому я могу легко увидеть, какую именно версию программного обеспечения я использую в любой момент!
Итак, я объединил этот ответ (git rev-parse --short HEAD
) @Jakub Narębski и этот ответ: (test -n "$(git status --porcelain)"
) от @Benzado в их ответе на вопрос «Проверка грязного индекса или неотслеживаемых файлов с помощью Git» я смог найти свое «однострочное» решение выше.
The &&
часть выполняется только в том случае, если код возврата предыдущей команды () равен0
, что означает «успех» (в данном случае чистый), а||
часть выполняется только в том случае, если код возврата предыдущей команды (git status --porcelain
) — любой другой код ошибки, означающий «ошибку» (в данном случае «грязный»).
Идти дальше
См. мой файл bash/git_get_short_hash.sh в моем репозитории
Оберните это в функцию Bash:
# Get a short commit hash, and see whether `git status` is clean or dirty.
# Example outputs:
# 1. Not in a git repo: `(not a git repo)`
# 2. In a repo which has a "dirty" `git status`: `72361c8-dirty`
# - Note that "dirty" means there are pending uncommitted changes.
# 3. In a repo which has a "clean" `git status`: `72361c8`
git_get_short_hash() {
# See: https://stackoverflow.com/a/16925062/4561887
is_git_repo="$(git rev-parse --is-inside-work-tree)"
if [ "$is_git_repo" != "true" ]; then
echo "(not a git repo)"
return $RETURN_CODE_SUCCESS
fi
# See my answer here: https://stackoverflow.com/a/76856090/4561887
test -z "$(git status --porcelain)" \
&& echo "$(git rev-parse --short HEAD)" \
|| echo "$(git rev-parse --short HEAD)-dirty"
}
Более того, вот целая программа, которую вы можете запустить или использовать:
#!/usr/bin/env bash
# This file is part of eRCaGuy_hello_world: https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world
RETURN_CODE_SUCCESS=0
RETURN_CODE_ERROR=1
# Get a short commit hash, and see whether `git status` is clean or dirty.
# Example outputs:
# 1. Not in a git repo: `(not a git repo)`
# 2. In a repo which has a "dirty" `git status`: `72361c8-dirty`
# - Note that "dirty" means there are pending uncommitted changes.
# 3. In a repo which has a "clean" `git status`: `72361c8`
git_get_short_hash() {
# See: https://stackoverflow.com/a/16925062/4561887
is_git_repo="$(git rev-parse --is-inside-work-tree)"
if [ "$is_git_repo" != "true" ]; then
echo "(not a git repo)"
return $RETURN_CODE_SUCCESS
fi
# See my answer here: https://stackoverflow.com/a/76856090/4561887
test -z "$(git status --porcelain)" \
&& echo "$(git rev-parse --short HEAD)" \
|| echo "$(git rev-parse --short HEAD)-dirty"
}
main() {
git_get_short_hash
}
# Determine if the script is being sourced or executed (run).
# See:
# 1. "eRCaGuy_hello_world/bash/if__name__==__main___check_if_sourced_or_executed_best.sh"
# 1. My answer: https://stackoverflow.com/a/70662116/4561887
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
# This script is being run.
__name__="__main__"
else
# This script is being sourced.
__name__="__source__"
fi
# Only run `main` if this script is being **run**, NOT sourced (imported).
# - See my answer: https://stackoverflow.com/a/70662116/4561887
if [ "$__name__" = "__main__" ]; then
main "$@"
fi
Пример команды запуска и вывода при ее запуске:
eRCaGuy_hello_world$ bash/git_get_short_hash.sh
fddb4ef-dirty
Пример запуска и вывода путем его поиска (см. мой ответ здесь, если вы не знаете, что это значит), а затем запускаmain
илиgit_get_short_hash
напрямую:
eRCaGuy_hello_world$ . bash/git_get_short_hash.sh
eRCaGuy_hello_world$ main
fddb4ef-dirty
eRCaGuy_hello_world$ git_get_short_hash
fddb4ef-dirty
Версию указанной выше программы на Python см. в моем файле здесь: python/git_get_short_hash.py в моем репозитории eRCaGuy_hello_world.eRCaGuy_hello_world .
Пример использования:
- Используйте эту функцию, например, в другой вашей программе.
- Сначала скопируйте
git_get_short_hash.py
сценарий в другой ваш проект git. - Затем используйте его следующим образом:
import git_get_short_hash
import textwrap
# Alias the function to a shorter name
git_get_short_hash = git_get_short_hash.git_get_short_hash3
git_short_hash = git_get_short_hash()
program_info_str = textwrap.dedent(f"""\
My other program details here...
Program version: {git_short_hash}
""")
print(program_info_str)
mylogfile.write(program_info_str)
Вот еще одна реализация прямого доступа:
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
Вот еще один способ сделать это с:)
git log | grep -o '\w\{8,\}' | head -n 1
Мне нужен был самый новый коммит наorigin/main
ветка, поэтому я использую
git ls-remote origin | grep main$ | cut -f 1
Вот шаги, которые работали для меня, используя хэш коммита:
- Войдите в свою ссылку на GIT HUB, например:
https://github.<xyz.abc>.com
После входа в систему в текстовом поле "Искать или перейти к..." введите как:
hash:<GIT COMMIT HASH>
Выберите между "Все GitHub Enterprise" или "В этой организации" в зависимости от ваших потребностей
- Нажмите Enter.