Будьте осторожны с тем, что вы просите.git log
ложь , но это хорошая вещь!
ОК, "ложь" - преувеличение.Но стоит помнить, git log
показывает вам что-то , но это намеренно глазок в реальность, а не вся реальность сразу.Это немного похоже на утверждение, что время - это способ природы предотвратить все происходящее одновременно : git log
должен показать, что вы совершаете по одному за раз, но они все там.
Коммиты
Во-первых, коммиты имеют две метки времени, а не одну.По умолчанию git log
показывает дату автора.Аргументы --since
и --until
смотрят дату создания.Для большинства коммитов две метки времени совпадают, и это не имеет значения.Для выбранных вишней коммитов или коммитов, сделанных кем-то отличным от оригинального автора, иногда имеет значение .Вот небольшой вывод git log --pretty=fuller
, показывающий такой коммит:
commit 6c6ce21baa9b50d394bb8ed9878944504ffd57d8
Author: Eric Sunshine <sunshine sunshineco.com>
AuthorDate: Fri Aug 31 04:33:42 2018 -0400
Commit: Junio C Hamano <gitster pobox.com>
CommitDate: Fri Aug 31 12:05:24 2018 -0700
config.mak.uname: resolve FreeBSD iconv-related compilation warning
OLD_ICONV has long been needed by FreeBSD so config.mak.uname defines
it unconditionally. However, recent versions do not need it, and its
presence results in compilation warnings. Resolve this issue by defining
Второй - и, возможно, на самом деле более важный - каждый коммит Git хранит, как часть своих собственных данных, хэш-идентификатор своего parent commit или commit.Это означает, что коммиты имеют отношения родитель / потомок.Истинное имя любого коммита Git - это его большой уродливый хеш-идентификатор, такой как 6c6ce21...
выше.
Мы можем найти родителя (ей) коммита, используя git rev-parse
, или посмотрев прямо наобъект фиксации:
$ git rev-parse 6c6ce21baa9b50d394bb8ed9878944504ffd57d8^1
53f9a3e157dbbc901a02ac2c73346d375e24978c
$ git cat-file -p 6c6ce21baa9b50d394bb8ed9878944504ffd57d8
tree 1832fd8f6315732daca5c0523a951d40a8ee7fb2
parent 53f9a3e157dbbc901a02ac2c73346d375e24978c
author Eric Sunshine ...[snip]
Родительские / дочерние отношения определяются исключительно через эти строки parent
: все коммиты замораживаются во времени, и когда вы делаете коммит, он имеет своего родителя, но имеетдетей нет пока .Поскольку вы не можете изменить коммит после его создания, родитель не может вспомнить своих потомков.Но родитель существует, поэтому ребенок может помнить своего родителя.
Давайте нарисуем простую строку коммитов, дав им однобуквенные имена вместо больших уродливых хеш-идентификаторов, где каждый коммит имеет одного родителя и одного потомка, кромедля самого первого или root коммита - у которого нет родителя - и последнего, или tip commit, у которого нет потомка:
A <-B <-C <-D <-E <-F <-G
Если мыначинаем с конца - что обычно делает Git - у нас есть коммит G
в руке.Итак, git log
идет впереди, начиная с коммита, который он сейчас имеет в руке, и показывая коммит G
.G
помните F
большой уродливый хеш-идентификатор, так что теперь git log
возвращается на один шаг назад и показывает F
;затем он возвращается обратно к E
, D
и так далее, пока не достигнет A
.Мы говорим, что каждый коммит указывает на своего родителя, и Git следует этим указателям.
Настоящий трюк Git в том, что он каким-то образом находит G
.На этой диаграмме нет ничего, указывающего на G
, так как Git может его найти?Ответ: названия филиалов .У нас есть имя ветки вроде master
, указывающее на коммит G
:
A--B--C--D--E--F--G <-- master
Поскольку коммиты заморожены, и я немного ленив, :-) Я опустил внутренние стрелки.Мы знаем, что все они указывают назад, поэтому они нам не нужны: линии подойдут. name master
позволяет Git найти коммит G
.Начиная с G
, Git возвращается к F
, затем к E
и т. Д.
Самое интересное в этом - это когда мы добавляем новый коммит.,Допустим, мы git checkout master
, так что мы извлекли G
.Затем мы делаем некоторую работу и запускаем git add
и git commit
.Это делает новый коммит с новым большим уродливым хеш-идентификатором, но мы просто назовем его H
.H
будет указывать на, т. Е. Содержать большой некрасивый хеш-идентификатор, commit G
:
...--G <-- master
\
H
Последнее, что делает Git, - это запись хеш-идентификатора H
вимя master
, поэтому master
теперь указывает на H
(и мы можем снова нарисовать линию прямо):
...--G--H <-- master
Это означает, что коммиты никогда не меняются (они не могут), но имена веток все время меняются! Что Git меняет, это не коммиты, а names .
Ветвление и слияниеи как это влияет и git log
ОК, таку нас есть несколько хороших прямых строк истории коммитов, но что теперь произойдет, когда мы создадим несколько веток и затем объединим их?Ответ в том, что Git делает коммитов слияния , которые просто коммитят с двумя родителями:
I--J <-- branch-A
/
...--G--H
\
K--L <-- branch-B
Если у нас есть Git слияния двух, мы получаем новыйcommit M
, у которого оба J
и L
в качестве его родителей:
I--J
/ \
...--G--H M
\ /
K--L
(Упражнение: здесь я удалил все имена веток.Какие имена веток обновляет Git? Как Git узнает, когда есть два имени branch-A
и branch-B
, над какой ветвью вы работаете? Решение этого упражнения научит вас многому о Git.Или читерство с веб-сайтом, о котором я упоминаю ниже. :-))
Теперь, когда идет git log
, он покажет коммит M
, но затем - какой коммит должен показать следующий, J
, или L
?
Необходимо показать оба коммитов.В идеале, он должен показывать их одновременно, но он не может .Он должен выбрать один, чтобы показать первым.(Время препятствует тому, чтобы все происходило одновременно.) Это когда - и почему - git log
имеет ложь: он должен сначала показать один, даже если J
и L
действительно "вв то же время "как раз перед M
.
Здесь git log
имеет несколько флагов, сообщающих ему как лгать .Ложь по умолчанию - использовать то, что вы хотите: штамп с датой!Но это штамп даты, который git log
не показывает вам по умолчанию, то есть дату коммиттера, здесь.Добавление --author-date-order
заставляет Git выбирать дату автора вместо даты коммиттера.Обратите внимание, что это влияет только на выбор, когда git log
имеет более одного коммита для отображения прямо сейчас - что верно, когда он показывает, скажем, J
вместо L
.После этого у него все еще есть два коммита для показа, а именно I
и L
.Он выберет один из этих двух вариантов, используя ваш вариант сортировки, и еще раз будет отображать два коммита: H
и L
или I
и K
, в зависимости от того, какой из них только что показан.
Это слишком сложно
Ну, да, это так.К сожалению, это реальность.Есть способ заставить git log
до нарисовать график , а также показать коммиты, используя git log --graph
.Это не всегда полезно, но когда это полезно, это чрезвычайно полезно.
Более подробно об этом см. Веб-сайт Думайте, как (а) Git .Вам нужно , чтобы знать все это, в конце концов, чтобы эффективно использовать Git.До тех пор, однако, тот факт, что ложь git log
- она скрывает всю эту сложность по умолчанию, - это хорошо.