Как получить хэш коммита

Обновлено: 21.11.2024

В информатике a – это функция "многие к одному", которая принимает длинные входные данные, обрабатывает их и выдает гораздо более короткие выходные данные фиксированной длины, называемые . В то время как вывод выглядит случайным, функция не имеет случайности, и реальная функция хорошо известна всем. Идентичные входы всегда будут давать один и тот же результат. Но если два входа отличаются даже незначительно, они будут иметь совершенно разные результаты — это критерий проектирования для большинства хеш-функций. Точно так же мы могли бы потребовать, чтобы, если мы знаем хеш (выход), было бы очень сложно создать входные данные для хеш-функции для получения этого вывода. Для хеш-функции, используемой в git, крайне маловероятно, что два разных ввода (фиксации) будут давать один и тот же вывод (хэш). Таким образом, хэш фиксации похож на то, как мы используем отпечатки пальцев или сканирование сетчатки глаза для идентификации людей. Если вы хотите узнать больше, git использует хеш-функцию, защищенные от несанкционированного доступа свойства которой были разработаны для использования в криптографических приложениях. Он больше не считается безопасным для этой цели, но отлично подходит для использования в git .

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

Вернитесь к приведенному выше слиянию, чтобы увидеть, что не было абсолютно никаких изменений в информации для каждой фиксации и не было нарушения последовательности (цепочки) коммитов. Как объяснялось, единственное, что произошло на самом деле, это то, что указатель основного блока был изменен, чтобы указывать на новую фиксацию, кончик ветви героини.

Сравните это с тем, когда мы перебазировали ветку hero на ветку master, содержащую исправление опечатки. git перематывал коммиты на герое до старой точки ветвления, но затем переигрывал их в коммит (наконечник master ) с другим хешем коммита. Для всех воспроизведенных коммитов из ветки hero (у нас только что была одна) хэши коммитов будут пересчитаны, и они будут радикально отличаться, поскольку хэш кончика мастера является входом для первого коммита ветки с перемоткой. Предыдущие хеши бессмысленны (и потеряны во времени). Обратите внимание, что git обновляет герой указателя ветки, чтобы использовать новый хеш из кончика воспроизведенной ветки.

Это принцип, который будет важен, когда мы начнем общаться и работать с другими.

Принцип 2.3.1. Rebase изменяет хэши, а слияние — нет.

Перебазирование всегда меняет некоторые хэши коммитов, а слияние никогда не меняет хэши коммитов.

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

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

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

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

23 ответа 23

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

Вы также можете получить краткую версию следующим образом

Примечание. Если вы хотите преобразовать ссылки (ветки и теги) в SHA-1, воспользуйтесь git show-ref и git for-each-ref .< /p>

--verify подразумевает, что: Заданный параметр должен использоваться как единственное действительное имя объекта. В противном случае вырвать и прервать.

Добавив к тому, что сказал Тейн, вы также можете добавить определенную длину к --short , например --short=12 , чтобы получить определенное количество цифр из хеша.

@TysonPhalp: --short=N — это минимальное количество цифр; git использует большее количество цифр, если укороченный один будет неотличим от укороченного другого коммита. Попробуйте, например. git rev-parse --short=2 HEAD или git log --oneline --abbrev=2 .

Добавив к тому, что сказали Тейн, Тайсон и Якуб, вы можете напечатать полный хэш, но выделить шестнадцатеричные значения, необходимые для идентификации фиксации, синим цветом с помощью git rev-parse HEAD | GREP_COLORS='ms=34;1' grep $(git rev-parse --short=0 HEAD)

Если вам нужен только укороченный хэш коммита:

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

Это плохой/неправильный способ сделать это, потому что этот метод даст вам неправильный хэш, если у вас есть отсоединенная голова. Например, если текущий коммит — 12ab34. а предыдущий коммит был 33aa44.тогда, если я сделаю «git checkout 33aa44», а затем запущу вашу команду, я все равно верну 12ab34. несмотря на то, что моя голова указывала на 33aa44.

@theQuestionMan Я не сталкиваюсь с описанным вами поведением; git checkout 33aa44; git log -n 1 дает мне 33aa44 . Какую версию git вы используете?

@AmedeeVanGasse, ах! Я НЕ ПОНИМАЛ, что это аналогия с туалетом! Я много лет видел фарфор на справочных страницах git, но понятия не имел, что это относится к туалету! Фарфор - это унитаз, и он "ближе к пользователю" (который образно сидит на этом унитазе), чем сантехника, которая ниже по уровню и дальше от пользователя - т.е. ниже "фарфора"! С ума сойти.

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

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

@Parsa: при проверке конкретной фиксации HEAD указывает на эту фиксацию, а не на именованную ветвь, известную как отсоединенная голова.

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

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

Если нужны два хэша коммита git, например, один из ветки, с которой вы сейчас работаете, и один из ветки master , вы также можете использовать git rev-parse FETCH_HEAD, если вам нужен хэш для основного коммита, в который вы объединяете d. ваша текущая ветка. например если у вас есть ветка es master и feature/new-feature для данного репозитория, в то время как для feature/new-feature вы можете использовать git fetch origin master && git merge FETCH_HEAD, а затем git rev-parse --short FETCH_HEAD, если вам нужно коммит-хеш от мастера, в который вы только что объединили d для любых сценариев, которые у вас могут быть.

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

Флаг -s аналогичен --no-patch и означает "Подавить вывод различий".

Нажмите здесь, чтобы увидеть больше примеров git show.

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

Или в качестве команды:

Этот метод не очень надежен по сравнению с другими подходами, в частности потому, что он предполагает наличие подкаталога .git, что не всегда так. См. флаг --separate-git-dir на справочной странице git init.

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

Мне нравится gitscribe --long --dirty --abbrev=10 --tags, он выдаст что-то вроде 7.2.0.Final-447-g65bf4ef2d4, что составляет 447 коммитов после тега 7.2.0.Final и первые 10 дайджестов глобального SHA-1 в текущем HEAD — «65bf4ef2d4». Это очень хорошо для строк версии. С --long он всегда будет добавлять количество (-0-) и хэш, даже если тег совпадает точно.

Если теги не существуют, gitscribe --always будет "показывать уникально сокращенный объект коммита как запасной вариант"

Я использую git description --tags --first-parent --abbrev=11 --long --dirty --always . Параметр --always означает, что он предоставляет результат (хэш), даже если нет тегов. --first-parent означает, что он не путается с коммитами слияния и следует только элементам в текущей ветке. Также обратите внимание, что --dirty добавит -dirty к результату, если в текущей ветке есть незафиксированные изменения.

Используйте git rev-list --max-count=1 HEAD

git-rev-list предназначен для создания списка объектов фиксации; это git-rev-parse для перевода имени объекта (например, HEAD) в SHA-1

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

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

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

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

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

Вот одна строка, которая это делает:
git description --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Результат: f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

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

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

Возможно, вы знаете, что git использует хэши SHA-1 для идентификации коммита вместе с полной историей коммитов.Это ловкий прием, позволяющий быть абсолютно уверенным, что две версии репозитория содержат одни и те же файлы с одинаковой историей. Вы можете увидеть эти хэши в своем журнале git или на GitHub, и они обычно используются для идентификации версий репозитория, у которых нет соответствующего тега. Они выглядят как e78e40aa4a2c03bf469ef842d37ec5eeaf49f37b , но обычно префикса вроде e78e40a достаточно, чтобы однозначно идентифицировать их, поскольку таких префиксов уже более 200 миллионов, а SHA-1 обеспечивает довольно равномерное распределение хэшей по этим возможностям.

Гит-хэши в менеджере пакетов Джулии

Однако недавно я наткнулся на другой тип хэша, который использует git и который можно также использовать для идентификации текущей версии репозитория. Во многих моих проектах Modelica мне нужна последняя версия моего пакета Julia MoST.jl, что приводит к таким записям в Manifest.toml, которые Джулия использует для определения версий всех пакетов, установленных для текущего проекта.

Здесь интересна запись git-tree-sha1, которая явно имеет какое-то отношение к Git и SHA-1, но что означает дерево? Этот вопрос стал для меня важным, потому что я хотел определить реальную версию моего пакета, которую я использовал для получения результатов для одной из моих статей. Я знал, что эта информация хранится в файле Manifest.toml, поэтому я не удосужился записать ее в то время. Это означало, что передо мной стояла задача получить хэш SHA-1, идентифицирующий версию коммита, из этого зловещего хэша «дерева».

Хеши дерева Git

Оказывается, Git использует хэши для многих вещей, а также всегда использует SHA-1. Хэши «дерева» используются для захвата содержимого дерева каталогов, включая содержимое файлов и права использования. На самом деле с каждым коммитом связаны три хэша SHA-1:

  • Хэш фиксации идентифицирует текущую фиксацию со всей ее историей.
  • родительский хеш — это указатель на родителя текущего коммита.
  • Хэш дерева, который использует Джулия, фиксирует состояние всего дерева каталогов всех файлов в репозитории.

Получение хэша фиксации, связанного с хэшем дерева

Вы можете увидеть это, используя git log --pretty=raw , который выводит примерно следующее:

Поэтому одним из простых способов получить хэш фиксации, связанный с определенным хэшем дерева, является использование

Обратите внимание, что связь хэшей дерева с хэшами фиксации не уникальна. Если, например, фиксация отменяет изменения предыдущей фиксации, новый хэш дерева будет таким же, как хэш дерева до первой фиксации.

Зачем использовать хэши дерева для идентификации коммита?

Теперь остается только один вопрос: какого черта менеджер пакетов Джулии использует хэши дерева вместо хэшей коммитов, когда только последние могут использоваться для уникальной идентификации версии пакета, например, на GitHub?

Ответ настолько же прост, насколько и неприятен: потому что людям нравится переписывать историю гораздо больше, чем следовало бы. Основное преимущество хэшей деревьев заключается в том, что они остаются неизменными после того, как git rebase был использован для «очистки» истории (что, на мой взгляд, более точно описывается как искажение истории 99% время). Таким образом, если разработчик пакета Julia перебазирует свой репозиторий, файл Manifest.toml всех людей, использующих этот пакет, остается действительным до тех пор, пока в истории нового репозитория есть некоторая фиксация, которая предоставляет точно такое же содержимое файла. Это, конечно, совершенно безопасно для определения зависимости от точной версии пакета для установки, но это одна из тех функций, где вы делаете что-то неправильно, если вам это нужно.

Произвольно, но исправлено

В этом блоге я делюсь решениями проблем, с которыми сталкиваюсь на пути к докторской диссертации. Темы произвольны, но в некоторой степени связаны с информатикой и системной биологией.

Это может показаться вам знакомым. Признак коммита, который состоит из нескольких компонентов: хеш коммита — строка длиной 40 символов, за которой следуют автор, дата и, наконец, сообщение коммита.

В этом сообщении блога основное внимание будет уделено хэшу коммита — кажущейся случайной мешанине из букв и цифр, которую иногда приходится копировать и вставлять. Что это такое? Как это делается? Может ли это измениться? На все эти вопросы даны ответы в этом сообщении в блоге (надеюсь).

Читая это, я предполагаю, что вы имеете базовые знания о Git и, по крайней мере, несколько раз совершали коммиты и, надеюсь, использовали ветки.

Эта запись в блоге задумана как введение в хэш фиксации. Существует гораздо больше логики и волшебства за кулисами, которые входят в создание и использование хэша коммитов git, что выходит за рамки этой статьи

Что такое хэш?

Прежде чем мы углубимся в особенности git, я решил дать очень краткий обзор того, что такое хеш.

Существует множество различных алгоритмов хеширования, например MD5 и SHA-1. Хеш позволяет вам взять произвольное количество контента (будь то одно слово, 100 слов или все содержимое библиотеки JavaScript) и создать уникальную фиксированную строку символов, представляющую это. Длина строки зависит от выбранного вами метода.

Строка (в «теоретике») не может быть реконструирована (например, с учетом хэша трудно определить содержимое), но позволит вам сравнить две вещи, чтобы увидеть, являются ли они одинаковыми.

Примечание: я поставил теорию в " , потому что есть обходные пути для хеширования; поэтому будьте осторожны, если вы используете алгоритм хеширования для кодирования паролей

Одним из вариантов использования хэшей является сравнение содержимого двух файлов. Возможно, вы видели, как появляется проверка целостности тегов сценария (документы MDN для справки). Это сохраняет хэш файла, который вы ожидаете, и сравнивает его с хешем файла, который загружает браузер. Если хэши совпадают, вы знаете, что файлы одинаковы. Это избавляет компьютеры (или людей) от тщательной проверки каждой строки файла.

Разные алгоритмы хеширования используют разные методы хэширования (и хеш-суммы разной длины). Конечно, коллизии могут происходить (как упоминалось в Stack Overflow), но они редки и крайне маловероятны в сценарии git (особенно в одном и том же репозитории).

Как это делается?

Хэш фиксации — это хэш SHA-1, состоящий из нескольких свойств самой фиксации. Как упоминалось выше, это намного сложнее, чем может быть описано в этом посте, но понимание основ — отличный первый шаг.

Хэш git состоит из следующих элементов:

  • Сообщение о фиксации
  • Файл меняется
  • Автор коммита (и коммиттер — они могут быть разными)
  • Дата
  • Хэш родительского коммита

Когда вы примете все это во внимание, надеюсь, вы начнете понимать, как различные действия могут повлиять на формирование хэша коммита.

Еще одна вещь, на которую стоит обратить внимание, это то, что дерево Git на самом деле не "существует" как таковое - оно построено на основе родительского хэша. Может показаться, что это одно и то же, но есть небольшие нюансы.

Если хэш коммита не содержится в другом хэше коммита в качестве родителя, это может привести к созданию осиротевшего коммита. Исключением являются ветки и HEAD, которые указывают на конкретный хэш коммита.

Git — это полностью текстовая система — в ваших файлах у вас будет папка .git, которая содержит все коммиты, ветки и другую информацию о вашем репозитории в виде текстовых файлов — стоит осмотреться.

Как это может измениться?

Итак, теперь мы знаем и понимаем, из чего состоит хэш, как он может измениться и какое влияние это окажет на репозиторий и историю git.

Изменение коммита

Если вы измените сообщение коммита или файлы в коммите, это изменит хэш git. Вы можете изменить последний коммит, запустив git commit --amend . Это позволяет редактировать сообщение, какие файлы и изменения включены в коммит и даже автора.

Все эти вещи основаны на хеше, поэтому изменение коммита изменит хэш

Сбор вишен

Если вы сделали фиксацию в другой ветке и хотите, чтобы она была в вашей текущей ветке, вам может быть рекомендовано использовать git cherry-pick . Это сработает, однако хеш для коммита изменится. Это связано с тем, что у него будет новый родительский коммит, и поэтому необходимо будет рассчитать новый хэш.

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

Перебазирование

Перебазирование одной ветки на другую будет иметь тот же эффект, что и сбор вишен. Когда вы перебазируете, он по существу удаляет все ваши коммиты в вашей ветке, обновляет их исходной веткой, а затем повторно применяет ваши коммиты.

Это изменяет родительский коммит вашего первого коммита, поэтому всем последующим коммитам также нужны новые хэши, генерируемые по мере изменения их родителя.

Перебазирование может быстро превратиться в беспорядок! Это чрезвычайно мощный инструмент, но с большой силой приходит и большая ответственность.

Сквош

Если вы решите удалить коммиты во время слияния, будет сгенерирован совершенно новый хеш, так как все ваши предыдущие изменения будут объединены в один. Из-за этого. Запросы на слияние/вытягивание могут запутаться и решить, что они еще не были слиты, поскольку они сравнивают хэши между ветвями.

Как это влияет на репозиторий?

Изменить хэш коммита можно, если вы не предоставили общий доступ к коммиту. Git использует эти хэши для навигации по своей временной шкале и истории между различными источниками, поэтому их изменение может иметь нежелательные побочные эффекты. Думайте об этом как о научно-фантастическом фильме, вы можете вернуться в прошлое, но вы не должны влиять на чью-либо временную шкалу.

Если вы внесете изменение и изменится хеш, Git увидит это как новую фиксацию. Если исходный вариант был отправлен и опубликован, Git увидит две разные фиксации на вашей временной шкале и захочет объединить два разных варианта, когда вы позже захотите снова отправить.

если вы работаете в своем собственном или уверены в том, как это может повлиять на вещи, вы можете заставить push ( git push --force ) сообщить целевому репозиторию (обычно origin ), что ваша версия является источником правды.< /p>

Конец

Я надеюсь, что это помогло вам лучше понять Git, и что в следующий раз, когда что-то случится, вы будете знать, почему и как! Дайте мне знать, если у вас есть какие-либо вопросы, вам нужно что-то расширить или у вас есть другие отзывы.

Если вам понравился этот пост, я был бы очень признателен, если бы вы подумали о том, чтобы угостить меня кофе (или пивом!).

В настоящее время на этом веб-сайте проводится полная проверка содержания. Приносим извинения, если какой-то код или содержимое выглядят немного странно!

Читайте также: