Как получить хеш для текущего коммита в 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

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

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

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

echo "вывод идентификатора последнего коммита для текущей ветки:";

       git reflog

Вот шаги, которые работали для меня, используя хэш коммита:

  1. Войдите в свою ссылку на GIT HUB, например: https://github.<xyz.abc>.com
  2. После входа в систему в текстовом поле "Искать или перейти к..." введите как:

    hash:<GIT COMMIT HASH>
    
  3. Выберите между "Все GitHub Enterprise" или "В этой организации" в зависимости от ваших потребностей

  4. Нажмите Enter.
Другие вопросы по тегам