Git log 2 tag и фильтр коммитов для определенного пути - PullRequest
1 голос
/ 03 ноября 2019

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

Я пробовал git log --oneline -- ${folder path} tag1 tag2, и он, кажется, фильтрует только коммиты в указанном пути к папке, но, похоже, показывает больше коммитов, чем diff между тегом 1 и тегом 2.

Есть ли способ перечислить коммиты между 2 различными тегами для определенного указанного пути к папке?

Ответы [ 2 ]

2 голосов
/ 04 ноября 2019

Здесь есть ряд проблем:

  • Все, что после опции -- принимается за имя файла. (Это позволяет вам искать, например, файл с именем master.) Так что tag1 и tag2 здесь рассматриваются как имена файлов - они не относятся к каким-либо коммитам. Решить эту проблему легко, поскольку вам просто нужно переместить tag1 и / или tag2 на другую сторону --.

  • Вся концепция между хитрая, потому что коммиты не обязательно все в хорошем аккуратном ряду. Решить это потенциально гораздо сложнее: вы должны решить, что вы означает между .

  • Когда вы задаете имена путей для git log, это включает то, что называется Упрощение истории . Является ли это проблемой вообще для вашего конкретного использования, это также сложный вопрос, но решить ее, , если это проблема, на самом деле довольно легко: просто добавьте --full-history, чтобы отключить упрощение истории.

Итак, вы, вероятно, захотите:

git log --oneline --full-history <something with the tags> -- <folder-name>

с --full-history, необходимым только в том случае, если в результате отсутствуют некоторые коммиты.

Давайтевзяться за something part

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

Каждый коммит имеет уникальный, большой уродливый хэш-идентификатор. По сути, это истинное имя коммита. Все другие имена, будь то имена веток, такие как master, имена тегов, такие как v2.1, или относительные имена, такие как HEAD~3, - это просто способ заставить Git найти необработанный хэш-идентификатор. Между тем каждое имя, включая имена веток и тегов, содержит один хэш-идентификатор. Когда этот один хэш-идентификатор является конкретным коммитом, 1 - это коммит, названный веткой или тегом. Мы говорим, что имя указывает на коммит.

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

              H   <-- master

Между тем, хотя commit H содержит хеш-идентификатор своего родительского коммита. Давайте назовем это G, так что H указывает на G:

          G <-H   <-- master

Конечно, G имеет своего родителя. Давайте назовем это F, который также имеет своего собственного родителя и так далее:

... <-F <-G <-H   <-- master

Это хорошая простая линейная цепочка коммитов. Если в репозитории всего восемь коммитов, все подряд, как это, мы можем нарисовать их как:

A--B--C--D--E--F--G--H   <-- master

Для лени и отсутствия стрелок под углом, я теперь использую линии вместострелки для соединения коммитов, но помните, что все они на самом деле - стрелки, указывающие назад. Мы можем перейти от коммита H назад к A, но не вперед с A до H, используя внутренние стрелки.

(Коммит A является особенным: как самый первый коммит, который кто-то сделал, он не может иметь родителя, поэтому его нет. Git называет это root commit . -impty Git-репозиторий имеет по крайней мере один корневой коммит. Вот где мы можем перестать возвращаться, когда смотрим историю.)

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

...--G   <-- master

до:

...--G--H   <-- master

Git justнаписал новый коммит H с родительским хешем G, затем записал фактический хеш H в имя master.

Но история Git часто не является линейной, какэто. Люди создают новые ветви, а затем делают новые коммиты на этих ветвях, что приводит к рисункам, подобным этому:

          I--J   <-- br1
         /
...--G--H--L   <-- master
         \
          K   <-- br2

Кто-то может впоследствии сделать git checkout master; git merge br1, чтобы повторно объединить ветку 1 вmaster, который производит:

          I--J   <-- br1
         /    \
...--G--H--L---M   <-- master
         \
          K   <-- br2

Новый коммит слияния M указывает на оба L (в качестве первого родителя) и J (как его второй родитель).

Вопрос с подвохом: Какая ветвь является коммитом H?

Ответ: Этона самом деле на все три ветви. Git здесь своеобразен: многие системы управления версиями сохраняют, для какой ветки коммит сделан , и это ветвь, на которой зафиксирован коммит, всегда. Git нигде не сохраняет эту информацию. Фиксация на ветке, если вы можете достичь , который фиксирует на , начиная с коммит, на который указывает имя ветви. Таким образом, с master мы можем вернуться к H за один переход с L или с двумя прыжками с M, как только мы добавим M. С br1 мы можем вернуться к H в два прыжка: начиная с J, затем до I, затем H. С br2 мы идем K, затем H. Таким образом, H находится на всех трех ветвях.


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


Между хитростью

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

     tag:v0.7    tag:v0.8
        |           |
        v           v
...--G--H--I--M--N--O--P   <-- branch1
      \
       J--K--L   <-- branch2
          ^
          |
       tag:v0.9

Какие коммиты являются "между тегами v0.7 и v0.8? Я думаю, что большинство людей согласятся с тем, что это I-M-N, или, может быть, H-I-M-N-O, или что-то вроде этого.

Но: какие коммиты находятся "между" тегами v0.7 и v0.9? Какие из них между v0.8 и v0.9? Я думаю, что многие с этим не согласятся.

Что если окажется, что коммит M на самом деле является слиянием, а не обычным коммитом, а рисунок должен выглядеть следующим образом:

     tag:v0.7     tag:v0.8
        |            |
        v            v
...--G--H--I---M--N--O--P   <-- branch1
      \       /
       J--K--L   <-- branch2
          ^
          |
       tag:v0.9

Теперь, какие коммиты находятся "между" различными тегами?

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

Любое имя ветви или тега, которое вы даете git log, считается либо:

  • отправной точкой: коммитом, с которого вы хотите работать в обратном направлении, либо
  • точка остановки: коммит, который вы хотите, чтобы Git включал , а не , , ни кто-либо из его предков .

Например, предположим, что у нас есть первый граф:

     tag:v0.7    tag:v0.8
        |           |
        v           v
...--G--H--I--M--N--O--P   <-- branch1
      \
       J--K--L   <-- branch2

и мыскажите Git: Начните с P, но остановитесь на L. Очевидно, что начиная с P на самом деле мы никогда не получаем до коммит L, потому что мы идем P, O, N, M, I, H, G и т. Д. Но, говоря Git stop на L, мы действительно имеем в виду stop на любом коммите достижимом с L: все L, K,J, G и т. Д. Являются остановочными точками.

Синтаксис, который мы можем использовать для , начинается с P, но останавливается на L:

branch2..branch1

, что означает все коммиты, достижимые с кончика branch1 (т.е. P), исключая все коммиты, достижимые с кончика branch2 (т. Е. L) .

Этот же синтаксис работает для имен тегов. На самом деле, он работает точно так же: просто упоминание имени тега, как в git log v0.8, означает, что считает фиксацию, на которую указывает этот тег, отправной точкой . Упоминание двух имен тегов с двумя точками между ними означает, что рассматривает коммит, на который указывает этот тег, как точку остановки . Итак:

v0.7..v0.8

начнется с O и остановится на H. Это исключит коммит H, то есть он будет смотреть только на коммиты O, затем N, затем M, затем I.

Если имя v0.9 указывает на коммитK, v0.9..v0.8 будет смотреть на коммиты, начиная с O и работая в обратном направлении, пока не остановится на G. Неважно, что 0.9 идет после 0.8. Git не использует эти цифры вообще. Git использует исключительно graph для включения или исключения различных коммитов.

Когда в графе происходят слияния, все становится сложно. Здесь иногда может потребоваться дополнительный флаг --ancestry-path. Но, как и --full-history, это начинает становиться все более сложным, поэтому мы, вероятно, должны остановиться здесь.

Я не могу не упомянуть третий вариант, поскольку некоторые люди захотят этого, когда скажут "между». Помимо синтаксиса с двумя точками stop..start, существует синтаксис с трех точками. Это означает, что все коммиты доступны с любого имени, за исключением всех коммитов, доступных с оба имена . То есть, учитывая:

...--G--H--I--M--N--O--P   <-- branch1
      \
       J--K--L   <-- branch2

синтаксис branch1...branch2 означает коммит H-I-M-N-O-P и коммит J-K-L (но не в этом порядке, поскольку Git должен работать в обратном направлении). исключает фиксация начинается с G и работает в обратном направлении, поскольку G находится на обеих ветвях.

0 голосов
/ 04 ноября 2019

Синтаксис у вас почти правильный.

Чтобы составить список коммитов, используйте tag1..tag2 и поместите все коммиты перед --. Поэтому ваша команда должна выглядеть следующим образом:

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