Редактировать: я добавил некоторый (длинный) фон ниже для общей полезности.
(Чтобы найти коммиты, сделанные определенным пользователем, используйте --author=
. Это работает с большинством ревизий-ходячие операции, так как они реализованы git log
и git rev-list
, и другие команды Git используют их.)
Рассмотрите возможность использования git log --ancestry-path --graph <em>[options]</em> <em>automated-commit</em>..HEAD
, но с некоторыми оговорками:
- Возможноне be путь между автоматической фиксацией и
HEAD
фиксацией. - Если есть путь, он может пойти другим путем, если фиксация
HEAD
находится позади автоматическойcommit.
Обратите также внимание, что Git пропустит фиксацию границы (точки останова), то есть в A..B
Git действительно выполняет B ^A
, поэтому он включает в себя фиксацию B
, ноисключает коммит A
.Если вы также хотите включить коммит A
, у вас есть несколько вариантов:
Резервное копирование одного коммита для остановки: используйте ^A^
, предполагая, что A
имеет только одинparent или ^A^@
, если A
может быть коммитом слияния (A^@
означает «все родители A
», а ведущим ^
является расширение формы A..B
до внутренней формы B ^A
для общности здесь).
Или, используйте --boundary
, чтобы Git включал граничные коммиты. Git имеет тенденцию добавлять слишком много граничных коммитов, по моему опыту, но --ancestry-path
может устранить этопоскольку --ancestry-path
увеличивает обычный A..B
, требуя, чтобы отображаемые коммиты имели A
в качестве предка.
(Итог: это должно работать, пока существует путь иВы получаете правильный заказ. Делать его действительно полезным и обрабатывать различные крайние случаи сложнее.)
Справочная информация: как git log
и его сестра git rev-list
работают
коммитов, вGit, известны и найдены по их истинным именам, которые являются их хэш-идентификаторами.Хэш-ID каждого коммита представляет собой большую уродливую строку, такую как 8a0ba68f6dab2c8b1f297a0d46b710bb9af3237a
(что является коммитом в репозитории Git для самого Git .) Каждый ID уникален: ни один другой коммит никогда не может иметь этот ID.Они на самом деле не случайные, но они кажутся случайными и бесполезны для людей, поэтому мы используем такие имена, как master
и develop
.Git постоянно обновляет таблицу, в которой, например, master
означает 8a0ba68f6...
и т. Д.
Используя эти записи в таблице, мы говорим, что master
указывает на некоторый коммит.Допустим, master
указывает на некоторый коммит, чей ID хеша мы сократили до одной заглавной буквы, G
:
G <--master
(через мгновение вы поймете, почему я поставил master
вправо).
Добавление нового коммита в ветку просто обновляет сопоставление имени с хеш-идентификатором: вы создаете новый коммит, Git назначает ему уникальный хэш-идентификатор, и если вы включены master
, Git обновляет запись таблицы для master
для хранения этого нового хэш-идентификатора:
H <--master
Это означает, что фиксация, на которую указывает какое-либо имя ветви - стрелка, хранящаяся в имени ветви - меняется со временем.Вот как Git находит последний коммит для этой ветки.По определению, любой хеш коммита сохраняется для этого имени ветви, этот коммит является вершиной этой ветки.
Теперь каждый коммит также содержит некоторое количество parent идентификаторы хеша - обычно ровно один.* * * * * * * * * * * * * * * * * * * * * * * * * * *} * * * * * * * * * * * * *} * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 10 * * * ”[110] * *1104* * 'мой родитель * 0f987...
110 6 *, Git знает, чтоa1234...
- это последний коммит на мастере.Затем Git читает commit a1234...
, чтобы найти второй-последний коммит на master, который равен 0f987...
.Так что master
указывает на последний коммит, a1234...
, и этот коммит указывает на его родителя, а его родитель указывает на деда и т. Д.
Это означает, что, начиная с конца , Git может работать в обратном направлении через цепочку коммитов:
... <-F <-G <-H <--master
ThИмя master
позволяет Git найти коммит H
, который находит коммит G
, который находит F
и т. д. в обратном направлении по истории. History - это просто строка всех коммитов, начинающихся в конце и работающих в обратном направлении.
Специальное имя HEAD
обычно содержит имя ветка .Есть два довольно очевидных способа нарисовать это: один с HEAD
, указывающим на имя ветви, а затем с именем ветви, указывающим на коммиты:
HEAD
|
v
... <-F <-G <-H <--master
Это в некоторых отношениях более точно, но не оченькомпактный.Для компактности я люблю опускать стрелки внутри самих коммитов.Они никогда не могут измениться (в отличие от стрелок с названиями веток) - ничто в любой коммит не может измениться.Поэтому, если мы видим:
...--F--G--H
, мы знаем, что H
указывает на G
, G
указывает на F
и так далее.Тогда у меня есть стрелка, идущая от master
, чтобы найти H
:
...--F--G--H <-- master
и к этому я прикрепляю слово HEAD
, чтобы сказать, что это текущая ветвь , так что если у нас есть больше ветвей, мы можем видеть, что происходит:
...--F--G--H <-- master (HEAD)
\
I--J <-- develop
Здесь у нас есть две ветви;имя develop
указывает на коммит J
, чей родитель I
, что ведет к G
и F
и т. д., в то время как имя master
указывает на H
, что приводит кG
и F
и т. Д.
Кроме того: какая ветвь (-и) является коммитом "on"?
Если мы посмотрим на вышесказанное, мы можем сказать, что коммит H
включен master
и J
включен develop
.Это довольно естественно, поскольку эти имена указывают непосредственно на эти коммиты.Но как насчет коммита G
, на какой ветке или ветвях он находится?
Некоторые системы выбирают один ответ и придерживаются его.Git отличается.Git говорит, что G
находится на каждой ветви, которая может добраться до G
, поэтому она на и master
и develop
.Чтобы добраться до G
с master
, мы возвращаемся на один прыжок.Чтобы добраться до G
с develop
, вернемся на два прыжка.В любом случае, мы приземлимся на G
.
git log
и git rev-list
, просто следуя этим стрелкам
Учитывая некоторую отправную точку, такую как master
или develop
или даже HEAD
, что git log
делает, говоря проще:
- Показать коммит, который он имеет прямо сейчас, что бы это ни было.
- Переход к родительскому коммиту.
- Повторяйте, пока у нас не закончится фиксация.
Это описание не неверно , но в нем отсутствует много важных деталей.Первое осложнение возникает при слияниях.Давайте возьмем наш пока что график и объединяем develop
обратно в master
, используя:
$ git checkout master
$ git merge develop
Не вдаваясь в , как работает git merge
- это отдельный вопрос и ответ (но он уже задавался много раз) - в итоге мы получим следующий график:
...--F--G--H---K <-- master (HEAD)
\ /
I--J <-- develop
Commit K
- это merge commit , что означает егоимеет по крайней мере двух родителей.Два родителя K
: H
(как обычно), а также J
(потому что мы объединили коммит J
, найденный через имя develop
).
После git log
показываетcommit K
, на какой коммит он должен перейти?Это может выбрать любой из них.Что он действительно делает, так это помещает оба в очередь, затем выбирает один и показывает его, а затем помещает его родителя в очередь, если он этого еще не сделал.Затем он выбирает еще один из очереди и повторяет:
- Первоначально поместите коммиты, перечисленные в командной строке, в очередь.Если вы не указали какие-либо конкретные коммиты,
git log
использует HEAD
.Затем в цикле: - Показать коммит, находящийся в начале очереди.
- Если родители коммита еще не поставлены в очередь и еще не были показаны, поместите их все вочередь.
- Повторять цикл до тех пор, пока очередь не станет пустой (или пользователь не выйдет).
Поскольку есть очередь, есть какое-то волшебство, чтобы управлять тем, кто на фронте .По умолчанию это выполняется с помощью сортировки по дате / отметке времени, но вы можете изменить это с помощью различных параметров сортировки.
Это означает, что Git по умолчанию сначала будет git log
, show commit K
, затем один из H
или J
, затем один из H
или I
, затем другой из H
или I
, и теперь очередь содержит только G
, поэтому порядок ясен (G
, затем F
).Обратите внимание, что Git не может добраться до I
, не пройдя J
, поэтому J
определенно выйдет раньше, чем I
, но Git может добраться до H
двумя способами, поэтому мы не знаем точно, гдеH
выходит.
Ограничения на то, что ставится в очередь и / или показывается
Независимо от того, что вы делаете, git log
и git rev-list
всегда должныпройти через эту приоритетную очередь, выбрать следующий коммит, который нужно показать, добавить родительские коммиты в очередь и выполнить цикл.Но вы можете контролировать , какие родители добавляются и / или , какие коммиты действительно отображаются .
, какие родители ручки управления:
--first-parent
: это говорит о том, что когда ходовой код попадает в коммит слияния, он должен добавить только первый родительский объект этого слияния.В нашем примере коммит слияния K
имеет двух родителей, H
является первым, поэтому с --first-parent
, git log
происходит переход с K
до H
до G
, игнорируя коммиты, которые мы слили сбоковая ветвь.
--no-walk
: это говорит о том, что прогулочный код ничего не должен делать: никогда не добавлять родителей.Это делает цикл довольно быстрым: мы видим только коммиты, перечисленные в командной строке.
, который показывает ручки , гораздо сложнее, так каких очень много.Здесь я собираюсь игнорировать все ориентированные на pathspec и смотреть только на --author
и --committer
, а также на --max-count
/ -n
число.Первые два сообщают Git: Показать коммит, только если в списке указан автор или коммиттер. (Вы можете перечислить более одного --author
или --committer
; Git покажет коммит, если он соответствует любомуиз указанных вами имен.)
Обратите внимание, что walk по-прежнему основан на графике.Просто вы не видите коммиты, у которых нет нужного автора или коммиттера.
Между тем число --max-count
aka -n
сообщает Git, что он должен выйти изцикл после показывает некоторое количество коммитов.Например, при -n 5 --author automatic@local
Git будет выполнять все коммиты как обычно, показывая, какие из них созданы automatic@local
, но как только будет показано пять таких коммитов, остановитесь.Конечно, он остановится рано, если будет меньше коммитов.
Когда использовать git log
против git rev-list
Команда git log
- это то, что Git называет фарфор: все должно быть чистым, блестящим и привлекательным для пользователей.Таким образом, это то, что пользователи могут настроить.Вы можете установить цвета вывода, такие параметры, как log.decorate
и другие полезные (для человека) элементы.
Команда git rev-list
гораздо более строгая и скучная.Это то, что Git называет слесарным делом: программа, предназначенная для получения результатов, которые не обязательно хороши для людей, но полезны для других компьютерных программ .Он ведет себя одинаково, независимо от того, кто запускает , поэтому программа, которой требуется некоторая информация, которую может предоставить git rev-list
, может получить ее согласованным образом.(Если хотите, эта программа может быть все более причудливой и ориентированной на человека.) То, что git rev-list
производит по умолчанию, представляет собой просто последовательность хэшей коммитов, которые представляют собой идентификаторы хешей коммитов, которые одинаковы *Команда 1381 * показала бы.
По какой-то причине git log
начнется с HEAD
по умолчанию, а git rev-list
- нет.Итак, чтобы преобразовать команду git log
(которую вы тестируете, чтобы убедиться, что получаете правильные коммиты) в git rev-list
(которую вы будете использовать в какой-то другой программе), вам иногда нужно добавить HEAD
к аргументам.