Есть ли способ увидеть метку времени изменений в файле при запуске diff во время конфликта слияния? - PullRequest
1 голос
/ 28 марта 2020

Иногда я оказываюсь в ситуации, когда мне нужно знать, когда (как в дате и времени) было задано конкретное c изменение конфликтного файла при разрешении конфликта слияния, чтобы я мог решить, хочу взять один поверх другого или отредактировать файл.

В этих ситуациях я использую git blame для соответствующего файла в их соответствующих ветвях и получаю дату и время для указанных c изменений I ' Меня это интересует. Это прекрасно работает, однако я чувствую, что должен быть более простой способ сделать это.

У кого-нибудь есть предложения относительно лучшего способа добиться этого? Я проверил git документацию, но не смог найти ничего, что могло бы облегчить этот процесс. Не обязательно быть в git Я был бы рад найти альтернативные подходы / инструменты .. и т.д. c

Ответы [ 2 ]

0 голосов
/ 02 апреля 2020

Чтобы найти все коммиты, сделанные в указанном c файле, мы можем использовать

git имя файла журнала

, мы можем получить все различия в файле между двумя коммитами

git diff commit1 commit2 - имя файла

0 голосов
/ 28 марта 2020

Нет. Нет, потому что коммиты не содержат изменения , они содержат снимки . Операция слияния рассматривает только три снимка: базовая фиксация слияния и две ветки подсказки ветвления.

Я могу обойти это, запустив git blame для этих файлов в соответствующих ветвях ...

Это, по крайней мере, в Git, принципиально иная операция. Команда git blame (или git annotate) просматривает граф по одному коммиту за раз, как обычно, в обратном направлении, сравнивая некоторые файлы и строки внутри каждой пары родительских и дочерних коммитов. Это находит указанный c более ранний коммит в цепочке, в котором указанная c строка, которая появляется в последнем коммите в цепочке, все еще появляется в этом более раннем коммите. Обвинение в действительности делает это один раз для каждой исходной строки в начальном коммите - ну, latest commit; возможно, вы бы назвали это end , а не start one, но оптимизировали, чтобы сделать его go быстрым.

Давайте нарисуем это как конкретный (но простой ) example— git blame обрабатывает более сложные случаи, которые включают подграфы ветвления и слияния, но мы будем игнорировать их при создании примера. Предположим, у нас есть следующее:

          I--J   <-- branch1 (HEAD)
         /
...--G--H
         \
          K--L   <-- branch2

, т.е. ваш текущий коммит - коммит J, и вы запускаете git merge branch2. Git найдет базу слияния коммит, H самостоятельно и, по сути, запустит два git diff s:

git diff --find-renames <hash-of-H> <hash-of-J>   # what we changed
git diff --find-renames <hash-of-H> <hash-of-L>   # what they changed

Git теперь попытаться объединить два набора изменений. Если файл F появляется во всех трех коммитах, H и J и L, но отличается во всех трех коммитах, два отдельных выхода diff будут иметь некоторые изменения для F в обоих случаях. Эти изменения должны быть объединены в одно изменение, которое может быть применено к копии F , которая появляется в коммите H.

Когда эти изменения перекрываются ( коснитесь тех же строк F в H) или около (конец изменения одной из сторон находится на краю начала другого изменения на другой стороне, снова ссылаясь на копию F в H), это конфликт слияния .

Я думаю, что вам нужен инструмент, который будет, если мы знаем H - vs- J и H -vs- L оба "касаются" некоторых строк в F , запускают git blame -L<range> H^@..J и git blame -L<range> H^@..L для соответствующих диапазонов строк (на основе копия F в H с изменениями в J и L соответственно). Два выражения <range> могут отличаться, если J и L имеют в общем добавленные или удаленные строки над точкой, в которой эти строки появляются в H.

Эти два git blame будут проверять фиксирует J, затем I, затем H (для первого случая) и L, затем K, затем H (для второго). Эти проверки в значительной степени симметричны c, поэтому, думая о проблеме, мы можем просто взглянуть на одну «сторону». Мы повторим операцию - но, возможно, с другими номерами строк, как отмечено выше - для другой. Поскольку был конфликт слияния, мы знаем, что рассматриваемые строки изменили в H -vs- J. Следовательно, они:

  • изменились в H -vs- I, а не в I -vs- J, или
  • не изменились в H -vs- I но изменилось в I -vs- J или
  • изменилось в оба H -vs- I и I -vs- J

, поэтому git blame будет для каждой строки в диапазоне назначать ее для фиксации I или фиксации J.

Отметки времени коммитов I и J здесь не являются предметом интереса. Скорее интересны хэши коммитов : они определяют, какие коммиты (ы) способствовали изменению.

Самым большим осложнением является то, что для каждой строки в диапазоне возможен вклад происходит от другого коммита . Поскольку git merge смотрит только на H -vs- J, возможно, изменение в две строки:

-first
-second
+1st
+2nd

- это действительно однострочное изменение, которое заменяет «first» на «1st» в I, а затем однострочное изменение, заменяющее «second» на «2nd» в J.

Когда диапазоны фиксации в слиянии больше, как в:

          A--B--C--D--...--Y--Z   <-- branch1 (HEAD)
         /
...--o--*
         \
          o--...--o   <-- branch2

diff из базового коммита слияния * для фиксации Z может иметь 30-строчное "изменение" с вклады, скажем, 15 из 26 коммитов, представленных последовательностью A-B-...-Z. Таким образом, вам, по крайней мере, потенциально потребуется много информации.

Было бы неплохо, если бы вы могли git merge запустить соответствующий git blame для вас, но вы не можете. Что вы можете сделать, так это написать свой собственный инструмент для автоматизации этого:

  • Учитывая, что вы знаете подходящий спецификатор для текущего (HEAD) коммита (это HEAD), и у вас есть спецификатор для other commit - L в нашем простом примере выше - доступный во время конфликтующего слияния под именем MERGE_HEAD, вы должны найти объединить базу совершить га sh. Команда, которая делает это: git merge-base.

    Существует сложность: может быть более одной базы слияния. Используйте git merge-base --all, чтобы найти все базы слияния (как и git merge по умолчанию). Если их больше одного, решите, как с этим справиться. По умолчанию Merge объединяет базы слияния, передавая результат как временный коммит, у которого ha sh ID недоступен для вас. (Было бы неплохо, если бы git merge где-то сохранил этот идентификатор ha sh на время конфликтующего слияния, но это не так. Временная фиксация может даже не быть привязана к графу фиксации в первую очередь; Я не проверял. В любом случае, он недоступен, так что нет смысла идти по этому пути, если вы не измените Git, чтобы сделать его доступным.) Я не знаю, каким образом можно справиться с этим, кроме как, возможно, выбрать все базы слияния в качестве стоп-точек для git blame.

  • В любом случае, найдя базу или базы слияния (и выяснив, что делать в случае более одного ) теперь вы можете запустить инструмент git blame. Сложная часть состоит в том, чтобы найти правильные номера строк.

  • Магический c -похожий синтаксис H^@ в H^@..HEAD или H^@..MERGE_HEAD просто говорит git blame, что он может перестать смотреть, когда достигнет любого из родительских коммитов H, что потенциально ускоряет его работу. Учитывая соответствующие -L ограничения, это может быть ненужным. Это, вероятно, все еще хорошая идея - и на самом деле, вы можете использовать --ancestry-path и здесь, если git blame подчиняется --ancestry-path. (Я не проверял это.) Это не позволит git blame спускаться по любым тупикам, которые могут появиться на более сложном графике.

Инструмент, вероятно, может просто оставить вас с Выход git blame неизменен.

...