Чтобы узнать это, попробуйте.
Если вы делаете , попробуйте, вы обнаружите, что git log -- file
(с или без --follow
) действительно сохраняетищу.
Примечание:
С правильными git log
параметрами я все еще могу отслеживать историю изменений [конкретного файла] ...
Здесь важно помнить, что Git не хранит историю file .Git хранит коммитов , а коммиты - и их графы - являются историей.
Когда вы запускаете git log -- file
или git log --follow -- file
, Git синтезирует история файлов, показывая некоторые выбранные подмножества фактической истории.Фактическая история - это, конечно, просто каждый коммит, начинающийся в некоторой конечной точке и работающий в обратном направлении, следуя всем родителям слияний, если только --first-parent
не используется, чтобы следовать только за первыми родителями слияний .
Синтетическая ограниченная история , созданная путем пропуска некоторых коммитов и показа других коммитов, будет, конечно, зависеть от того, какие коммиты показаны, а какие пропущены.Здесь становится важным проводить различие между двумя отдельными процессами:
- Как Git решает, какие коммиты пройти?
- Пройдя эти коммиты, как Git решает, какие коммиты show?
Неограниченное, по умолчанию git log
действие - пройти все достижимо коммитов и показать все пройденные коммиты, что делает оба вопроса синонимичными.Вам просто нужно понять идею достижимости , поэтому я привел здесь ссылку на Думайте как (а) Git .Но как только вы включите то, что в документации git log
называется Упрощение истории , они станут отдельными.Документация использует то, что я считаю плохой формулировкой:
одна часть выбирает коммиты, а другая - как это сделать
Чтоздесь они означают:
одна часть выбирает коммиты , которые будут показаны (добавлены слова мои, выделены мои): это моевторая точка пули выше.После или во время обхода некоторого подмножества коммитов, достижимых из начальной точки, мы показываем некоторое подмножество из этих коммитов.
другой - как сделать [обход]: «это» является здесь особенно бесполезным местоимением, относящимся к общей идее упрощения истории.Это равносильно тому, что метод, используемый для упрощения истории, - это метод, используемый для упрощения истории , что, ну ... тогда ладно!
В любом случаеосновная идея, которая применима ко всему, кроме опции --ancestry-path
, заключается в том, чтобы начать с концепции, которую они называют TREESAME.Чтобы применить эту идею, мы также должны взглянуть на родителей или родителей каждого коммита.
Мы, конечно, знаем, что для любого вида обхода коммит-графа нам нужно, чтобы Git извлекал коммит из объектабазы данных и изучить его и собрать его родительские хэш-идентификаторы.Большинство коммитов имеют только одного родителя, поэтому очевидно, куда двигаться дальше.Несколько коммитов - хотя бы один - это root коммитов, который определяется как коммит с no родителей, и здесь тоже очевидно, что делать: просто прекратить обход.Оставшиеся коммиты, ни root, ни обычные, являются merge коммитами, и по умолчанию, без упрощения истории, Git будет просматривать всех родителей каждого коммита слияния.
Когда чХотя упрощение истории включено, Git не смотрит на всех родителей.Вместо этого он использует эту идею TREESAME.Чтобы решить, являются ли коммиты C (дочерние) и P i (i-й родитель) TREESAME, Git сравнивает содержимое всех файлов, которые нас интересуют, в этом коммите - и теперь --follow
и / или -- path
part имеет значение, потому что это объявляет , какие файлы мы находим интересными прямо сейчас .Итак, Git делает вид, что фиксирует C и P i , имеют только те файлы в них и говорит: файлы идентичны или различны?
Если файлы разные, два коммита не являются TREESAME.Если файлы имеют одинаковое содержимое, эти два коммита имеют имя TREESAME.
Git выберет коммит C, который будет показан , если он не-TREESAME для любого родительского элемента,то есть, если файл (ы) в C, после любого извлечения, отличаются от тех в любом P i .Но если коммит является коммитом слияния - имеет более одного родителя - родитель будет следовать , по умолчанию, чтобы найти больше коммитов для возможного показа возможно последующего, это один из родителей, который is TREESAME to C.
Существует несколько опций (всего пять, включая значение по умолчанию) для изменения способа работы следующих за коммитом.Один из них, --sparse
, также изменяет набор отображаемых коммитов, в противном случае это правило "not-TREESAME-to-any-parent" является правилом, используемым для отображения пройденных коммитов.
Наконец, мыможно посмотреть на --follow
сам.То, что это делает, просто - вероятно, слишком просто, поскольку, к примеру, оно не работает с --full-history
.Как и при любой операции git log -- <em>paths</em>
, она включает упрощение истории, поэтому отображаются только те коммиты, которые «касаются» заданного пути.Тем не менее, он также позволяет Git обнаружение переименования и одновременно требует, чтобы был указан только один путь .
Когда Git переходит от дочернего к родителю, выполняя упрощениешаги, чтобы определить (а) какой родитель (ы) следовать и (б) который фиксирует для отображения, Git также проверяет случай, когда diff, от родителя к ребенку, говорит, что файл на path у дочернего объекта - результат переименования из другого пути в родительском.Если это так, то, как только Git переключается с проверки коммита C на проверку родительского коммита P, он также переключает , какой путь он использует для упрощения истории .Теперь вместо path/to/file.ext
он может искать, например, old/path/to/file.txt
.
Если в вашем графе коммитов есть коммиты, в которых есть нет копии какого-либо файла по некоторому путитакие как path/to/file.ext
, git log
все еще проходят эти коммиты.Просто эти коммиты, очевидно, не изменяют этот файл - у них даже нет этого файла - и поэтому каждый дочерний коммит является TREESAME для каждого из его родительских коммитов.В какой-то момент во время этого обхода, если появляется коммит, в котором path/to/file.ext
равен в родительском, а не в дочернем элементе, обход может, а может и нет, в зависимости от выбранного вами упрощения истории, перейти к этомуродитель.Если файл добавляется или удаляется в обычном коммите с одним родителем, поведение легко понять, так как нет особой причуды TREESAME для применения.Если файл добавлен или удален в коммите C, который является слиянием и имеет несколько родителей P 1 … P n , правила TREESAME по умолчанию отменят коммит Git.-граф пути, который не имеет файл!
Чтобы действительно все это понять, изучите документацию журнала git .Ответы есть в этом - как только вы сможете обойти не очень хорошую формулировку, в любом случае.
Примечание: git blame
отличается
Оба git log
иd git blame
будет проходить по графу фиксации, но git blame
(или его менее заряженный синоним git annotate
) имеет довольно разные алгоритмы для принятия решения, какой файл (ы) искать в каких коммитах.Его цель - определить, какой недавний коммит изменил любую строку любого файла.Когда вы попадаете в точку, в которой файл не существует в родительском коммите, но существует в дочернем, каждая строка добавляется , и на этом шаг по дереву останавливается.
Чтобы продолжить до этого момента, необходимо найти более ранний коммит, который имеет файл - что легко сделать с помощью git log
, упрощение истории и родительский элемент, который не имеет коммитв качестве отправной точки.Затем вы можете запустить операцию git blame
в том месте, где файл существовал, и работать в обратном направлении.