Здесь есть ряд проблем:
Все, что после опции --
принимается за имя файла. (Это позволяет вам искать, например, файл с именем 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
находится на обеих ветвях.