В Git, как я могу записать текущий хеш хеширования в файл в одной и той же фиксации

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

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

Любые идеи?

Ответ 1

Я бы рекомендовал сделать что-то похожее на то, что вы имеете в виду: размещение SHA1 в необработанном файле, сгенерированном как часть процесса сборки/установки/развертывания. Это, очевидно, легко сделать (git rev-parse HEAD > filename или, возможно, git describe [--tags] > filename), и он избегает делать что-то сумасшедшее, например, заканчивая файлом, отличным от того, что отслеживает git.

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

Ответ 2

Кто-то указал мне на раздел "man gitattributes" на идентификаторе, который имеет следующее:

идент

Когда идентификатор атрибута задается для пути, git заменяет $Id $в блобе с помощью $Id:, затем 40-символьное шестнадцатеричное имя объекта blob, за которым следует знак доллара $при выписке. Любая последовательность байтов, которая начинается с $Id: и заканчивается с $в файле worktree, при регистрации происходит замена $Id $.

Если вы думаете об этом, это то, что делают CVS, Subversion и т.д. Если вы посмотрите на репозиторий, вы увидите, что файл в репозитории всегда содержит, например, $Id $. Он никогда не содержит расширения этого. Это только при проверке того, что текст расширен.

Ответ 3

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

Однако есть три варианта:

  • Используйте script для увеличения "commit id" и включите его где-нибудь. Гадкий
  • .gitignore файл, в который вы собираетесь хранить хэш. Не очень удобно
  • В pre-commit сохраните предыдущий хеш фиксации:). Вы не изменяете/вставляете фиксации в 99,99% случаях, поэтому эта работа будет работать. В худшем случае вы все еще можете идентифицировать исходную версию.

Я работаю над hook script, выведет его здесь "когда это будет", но все же - раньше, чем выпущен Duke Nukem Forever:))

UPD: код для .git/hooks/pre-commit:

#!/usr/bin/env bash
set -e

#=== 'prev-commit' solution by o_O Tync
#commit_hash=$(git rev-parse --verify HEAD)
commit=$(git log -1 --pretty="%H%n%ci") # hash \n date
commit_hash=$(echo "$commit" | head -1)
commit_date=$(echo "$commit" | head -2 | tail -1) # 2010-12-28 05:16:23 +0300

branch_name=$(git symbolic-ref -q HEAD) # http://stackoverflow.com/questions/1593051/#1593487
branch_name=${branch_name##refs/heads/}
branch_name=${branch_name:-HEAD} # 'HEAD' indicates detached HEAD situation

# Write it
echo -e "prev_commit='$commit_hash'\ndate='$commit_date'\nbranch='$branch'\n" > gitcommit.py

Теперь нам нужно только инструмент, который преобразует пару prev_commit,branch в реальный хеш фиксации:)

Я не знаю, может ли этот подход сказать, что объединение сливается. Скоро проверит его

Ответ 4

Это может быть достигнуто с помощью атрибута filter в gitattributes. Вам нужно будет предоставить команду smudge, которая вставляет идентификатор фиксации и команду clean, которая удаляет ее, так что файл, в который она вставлена, не изменится только из-за идентификатора фиксации.

Таким образом, идентификатор фиксации никогда не сохраняется в блоке файла; он просто расширился в вашей рабочей копии. (Фактически вставка идентификатора commit в blob станет бесконечно рекурсивной задачей.) Любой, кто клонирует это дерево, должен будет настроить атрибуты для себя.

Ответ 5

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

Ответ 6

Позвольте мне рассказать, почему это сложная проблема, используя внутренние элементы git. Вы можете получить sha1 текущего фиксации с помощью

#!/bin/bash
commit=$(git cat-file commit HEAD) #
sha1=($((printf "commit %s\0" $(echo "$commit" | wc -c); echo "$commit") | sha1sum))
echo ${sha1[0]}

По существу, вы запускаете контрольную сумму sha1 в сообщении, возвращаемом git cat-file commit HEAD. Две вещи сразу выпрыгивают из-за проблемы при рассмотрении этого сообщения. Одним из них является дерево sha1, а второе - время фиксации.

Теперь время фиксации легко позаботится, изменив сообщение и угадав, сколько времени потребуется для фиксации или планирования для фиксации в определенное время. Настоящей проблемой является дерево sha1, которое вы можете получить из git ls-tree $(git write-tree) | git mktree. По существу, вы выполняете контрольную сумму sha1 в сообщении из ls-tree, которое представляет собой список всех файлов и их контрольную сумму sha1.

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

С менее безопасными контрольными суммами было показано, что можно записать контрольную сумму файла в файл непосредственно с помощью грубой силы; однако я не знаю никакой работы, которая выполнила эту задачу с помощью sha1. Это не невозможно, но практически невозможно с нашим нынешним пониманием (но кто знает, может быть, через пару лет это будет тривиально). Тем не менее, это еще сложнее для грубой силы, так как вам нужно написать контрольную сумму (commit) контрольной суммы (дерева) контрольной суммы (blob) в файл.