Смотрите историю восстановленного файла до удаления в Git - PullRequest
0 голосов
/ 25 февраля 2019

У меня есть файл foo.bar с долгой и интересной историей за многие годы.Это было изменено.Это было переименовано.С правильными параметрами git log я все еще могу отслеживать историю изменений.Это важно для меня.

В редакции 33333 Я удаляю foo.bar, потому что казалось, что нам нужна эта функция.Но четыре коммита спустя, в ревизии 77777, оказывается, что нам нужна эта функция, поэтому я хотел foo.bar назад.

Как большинство знает, я могу выдать:

git checkout 3333 -- path/to/foo.bar

Но, похоже, никто точно не знает, увижу ли я еще всю историю, которую я видел раньше при выпуске git log, в редакциях 88888 и далее.

https://stackoverflow.com/a/42287548/421049, например, претензии кответить на этот же вопрос. Но этот ответ неясен относительно того, будет ли история до и после удаления подключаться в журнале, а вопросы в комментариях для пояснения остались без ответа.

Ответы [ 2 ]

0 голосов
/ 25 февраля 2019

Чтобы узнать это, попробуйте.

Если вы делаете , попробуйте, вы обнаружите, что 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 в том месте, где файл существовал, и работать в обратном направлении.

0 голосов
/ 25 февраля 2019

Да, история сохраняется.

Вопрос в комментарии был о git blame foo.bar, а не о git log foo.bar

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