Как устранить двусмысленный сокращенный sha1 в git

Я был заинтригован Джошем Стоуном для анализа столкновений аббревиатуры sha1.

Скажем, кто-то записал сокращенный идентификатор commit, 8b82547e33, в то время, когда он был однозначным. Но с тех пор другие объекты были созданы с тем же префиксом, так что теперь git сообщает вам (дважды по какой-то причине):

$ git show 8b82547e33
error: short SHA1 8b82547e33 is ambiguous.
error: short SHA1 8b82547e33 is ambiguous.
fatal: ambiguous argument '8b82547e33': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

Теперь, как человек, я мог бы, вероятно, сказать, какой объект я имел в виду, если git просто покажет мне неоднозначные объекты. Как я могу добиться чего-то вроде следующего?

$ git objects-starting-with 8b82547e33
8b82547e33e: commit: l2tp: Restore socket refcount when sendmsg succeeds
8b82547e338: tree [2 files, 26 subtrees]

(Примечание: приведенные выше примеры используют относительно текущий клон http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git.)

Ответ 1

Вы можете использовать git rev-parse, если у вас есть хотя бы четырехзначный префикс полного хэша.

git rev-parse --disambiguate=8b82547e33

Ответ 2

С Git 2.11+ (Q4 2016) вам даже не придется вводить git rev-parse --disambiguate=....

Git отобразит список возможных кандидатов!

См. commit 5b33cb1 (27 сентября 2016 г.) и commit 1ffa26c, commit fad6b9e, commit 16ddcd4, commit 0c99171, commit 59e4e34, commit 0016043, commit 5d5def2, commit 8a10fea, commit 7243ffd, commit 259942f (26 сентября 2016 г.) Джефф Кинг (peff).
(слияние Junio ​​C Hamano - gitster - в commit 66c22ba, 06 Oct 2016)

get_short_sha1: список неоднозначных объектов при ошибке

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

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

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

  $ git rev-parse b2e1
  error: short SHA1 b2e1 is ambiguous
  hint: The candidates are:
  hint:   b2e1196 tag v2.8.0-rc1
  hint:   b2e11d1 tree
  hint:   b2e1632 commit 2007-11-14 - Merge branch 'bs/maint-commit-options'
  hint:   b2e1759 blob
  hint:   b2e18954 blob
  hint:   b2e1895c blob
  fatal: ambiguous argument 'b2e1': unknown revision or path not in the working tree.
  Use '--' to separate paths from revisions, like this:
  'git <command> [<revision>...] -- [<file>...]'

Мы показываем тэг для тегов, а также дату и объект для фиксации.
Для деревьев и капель, в теории, мы могли бы копать в истории, чтобы найти пути, по которым они были. Но это очень дорого (порядка 30 секунд для ядра), и вряд ли это будет полезно. Большинство коротких ссылок - это фиксации, поэтому полезная информация обычно будет заключаться в том, что объект, о котором идет речь, не является фиксацией. Так что глупо тратить много процессора, предварительно выкапывая путь; пользователь может сделать это сам, если им действительно нужно.

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

Мы также ограничиваем список теми, которые соответствуют любому намеку на неоднозначность. Например:.

  $ git rev-parse b2e1:foo
  error: short SHA1 b2e1 is ambiguous
  hint: The candidates are:
  hint:   b2e1196 tag v2.8.0-rc1
  hint:   b2e11d1 tree
  hint:   b2e1632 commit 2007-11-14 - Merge branch 'bs/maint-commit-options'
  fatal: Invalid object name 'b2e1'.

не беспокоит сообщения о блобе, потому что они не могут работать как дерево.


Обновление от 2017 года (через год), это значение будет еще быстрее с Git 2.16 (Q1 2018):
См. зафиксировать 0e87b85 Деррик Столе, изначально обсуждается здесь.

sha1_name: минимизировать сопоставление OID во время значений

Сведение к минимуму сопоставлений OID при неоднозначности идентификаторов OID пакетов.

Научите Git использовать двоичный поиск с полным OID, чтобы найти объект позиции (или позиции вставки, если нет) в индексе упаковки. Объект до и сразу после (или тот, который находится во вставке позиция) дают максимальный общий префикс. Последующий линейный поиск не требуется.

Позаботьтесь о том, какие два проверить, если идентификатор объекта существует в packfile.

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

Эта фиксация завершает серию из трех изменений в аббревиатуре OID кода, а общее изменение можно увидеть, используя стандартные команды для большой РЕПО. Ниже мы сообщаем статистику эффективности для перфекционного теста 4211.6 от p4211-line-log.sh с использованием трех копий репо для Linux:

| Packs | Loose  | HEAD~3   | HEAD     | Rel%  |
|-------|--------|----------|----------|-------|
|  1    |      0 |  41.27 s |  38.93 s | -4.8% |
| 24    |      0 |  98.04 s |  91.35 s | -5.7% |
| 23    | 323952 | 117.78 s | 112.18 s | -4.8% |