Как найти все "активные" git коммитов в дереве? - PullRequest
0 голосов
/ 03 августа 2020

Я хотел бы получить снимок «активных» git коммитов для дерева каталогов, то есть git коммитов, которые действительно являются частью сборки, а не коммитов, которые были полностью заменены более новыми коммитами.

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

1 Ответ

0 голосов
/ 03 августа 2020

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

Помните, каждый коммит имеет полный снимок каждого файла . Имя ветви определяет последний коммит в некоторой цепочке коммитов. Итак, когда у вас есть:

... <-F <-G <-H   <-- branch

, имя branch содержит необработанный ha sh ID фиксации H. В коммите H много файлов, в каждом из которых много строк. Эти файлы находятся в той форме, в которой они находятся в коммите H, и это все, что нужно сделать - кроме , который H содержит ha sh ID более ранней фиксации G.

Вы можете использовать ha sh ID, чтобы найти фиксацию G и извлечь все его файлы, и когда файл в G полностью совпадает с файлом в H, это означает, что - по крайней мере в терминах git blame - все строки в файле в G относятся к G, если не к какой-то более ранней фиксации. Поэтому файлы, которые разные в G и H, должны быть отнесены к H. Команда git blame работает построчно, приписывая отдельные строки фиксации H, если они различаются, но, возможно, для ваших целей достаточно присвоить весь файл H.

Если вы решите, что файл, возможно, следует отнести к фиксации G, пора извлечь идентификатор F ha sh из фиксации G и использовать его для чтения всех файлы из коммита F. Если какой-либо файл в F совпадает с копией в G, атрибуция возвращается к F; в противном случае он останется на G.

Вы должны повторять этот процесс, пока полностью не исчерпаете все коммиты:

A <-B <-C ... <-H

Так как коммит A имеет нет родитель , любые файлы в A, которые не изменились на протяжении всей последней фиксации, должны быть отнесены к фиксации A. Однако вы можете прекратить обратный переход, как только вы полностью приписали все файлы, существующие в H, некоторому коммиту позже в цепочке. Сравните это с git blame, который должен смотреть назад, пока хотя бы одна строка связана с какой-то более ранней фиксацией: вы, вероятно, остановитесь задолго до того, как git blame должно.

Более того, из-за внутренних структур данных Git очень быстро определить, точно ли файл в какой-то более ранней фиксации точно соответствует файлу с таким же именем в более поздней: каждый файл в каждой фиксации представлен символом ha sh ID. Если идентификатор ha sh совпадает, содержимое файла побитно идентично в двух фиксациях. Если нет, то это не так.

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

...--o--K
         \
          M--o--o--...--o   <-- last
         /
...--o--L

За какими фиксациями вы должны следовать, если файл в M соответствует одному или нескольким файлам в K и / или L? У команды git log есть свой собственный способ сделать это - git log <start-point> -- <path> упростит историю, следуя за одним родителем, выбранным случайным образом из набора таких родителей, который имеет тот же ha sh ID для данного файла.

Обратите внимание, что вы можете использовать git rev-list, возможно, с --parents, чтобы создать набор идентификаторов ha sh, которые вы можете выбрать для проверки. Команда rev-list - это рабочая лошадка для большинства других команд Git, включая сам git blame, для отслеживания подобной истории. (Примечание: команда git log построена из того же источника, что и git rev-list, с некоторыми незначительными различиями в параметрах командной строки и другими выходными данными по умолчанию.)

1 Хотя git log <start-point> -- <path> здесь полезен, запускать его один раз для каждого пути будет слишком медленно, а запускать без указания отдельных путей неэффективно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...