Git: см. изменения в конкретном файле с помощью фиксации

Я хочу увидеть, какие изменения были внесены в этот файл в строке 147. Поэтому я запросил файл строка за строкой для коммитов:

git blame include/svl/itemset.hxx

Вот урезанный вывод git blame:

4b3a535ae3 include/svl/itemset.hxx         (Michael Stahl      2015-04-08 15:02:47 +0200 145)     SfxItemPool*                GetPool() const { return m_pPool; }
4b3a535ae3 include/svl/itemset.hxx         (Michael Stahl      2015-04-08 15:02:47 +0200 146)     const sal_uInt16*           GetRanges() const { return m_pWhichRanges;
 }
d210c6ccc3 svl/inc/svl/itemset.hxx         (Xiaofei Zhang      2010-07-29 10:56:19 +0800 147)     void                        SetRanges( const sal_uInt16 *pRanges );
d210c6ccc3 svl/inc/svl/itemset.hxx         (Xiaofei Zhang      2010-07-29 10:56:19 +0800 148)     void                        MergeRange( sal_uInt16 nFrom, sal_uInt16 nTo );
4b3a535ae3 include/svl/itemset.hxx         (Michael Stahl      2015-04-08 15:02:47 +0200 149)     const SfxItemSet*           GetParent() const { return m_pParent; }

Теперь я хочу посмотреть, какие изменения произошли с SHA d210c6ccc3 в этих строках. В основном я хочу видеть изменения, сделанные этим коммитом в файл. Так я и сделал:

'git show d210c6ccc3 include/svl/itemset.hxx'

Но это, похоже, не дает мне правильного вывода, на самом деле ничего не выводит. Может ли кто-нибудь предложить, что я могу пропустить? Или, может быть, есть какой-то другой лучший способ узнать, какие изменения были внесены в файл выбранным коммитом?

Ответ 1

eftshift0 ответ правильный (и я проголосовал за него). Вот почему, хотя - наряду с еще одной вещью, которая может пойти не так, как надо здесь.

В большинстве случаев git show commit -- path будет правильным и покажет вам:

  • сообщение журнала для указанного коммита и
  • патч для этого конкретного файла, созданный путем сравнения этого коммита с его родителем.

Патч будет таким же, как и у git diff commit^1 commit -- path. (Обратите внимание, что здесь суффикс ^1 является литеральным текстом, а часть commit - заменяемым идентификатором хеша. Синтаксис суффикса означает "найти первого родителя". Вы можете добавить этот суффикс для большинства селекторов фиксации, но не для селекторов, которые используют определенные шаблоны поиска. См. документацию gitrevisions.)

Есть два важных исключения. Здесь применимо только одно из них, потому что git blame обычно не обвиняет слияние, оно пытается отследить источник изменений, внесенных в слияние. Тем не менее, я хочу упомянуть об этом, потому что поведение git show при слияниях... интересно. :-)

Если вы посмотрите на коммит слияния с помощью git show, вы увидите, по умолчанию, комбинированный diff ("все родители" против контента коммитов слияния). В этом случае вы можете обратиться к git diff, чтобы указать родителя, которого хотите сравнить (^1, ^2 и даже больше, если это слияние осьминога). Причина в том, что комбинированные diff намеренно опускают любой файл, который соответствует версии в одном из родительских коммитов: это означает, что все, что находится в хранилище с этого момента, было получено одним из двух (или N, если N> 2) " стороны "слияния.

С git blame, вы ищете "кто что изменил". Человек, который сделал слияние, часто не тот, кто внес изменение, поэтому вы должны продолжать идти "за слиянием", чтобы выяснить, кто действительно изменил его.

Второе исключение - это то, что вызвало у вас проблему здесь, и это скорее пример того, как работает git blame когда файлы переименовываются во время разработки.

Когда git blame анализирует изменения в файле, такие как include/svl/itemset.hxx, он делает шаг назад на один коммит за раз, начиная с любого коммита, который вы укажете. Если вы не выбрали свою собственную начальную точку, она начинается с HEAD, то есть с текущего коммита. Затем он смотрит на родительский коммит (как, например, с помощью git show). Например, если текущий коммит 922e935c8812 является обычным коммитом, а его родитель - 22c6554c98e2, он сравнивает коммит 922e935c8812 с 22c6554c98e2. Если 22c6554c98e2 имеет файл с тем же именем, то, вероятно, тот же файл... но если нет, Git пытается выяснить, какой файл в 22c6554c98e2 является тем же файлом, что и include/svl/itemset.hxx.

В этом случае именно это происходит при b9337e22ce1d. Существует файл с именем include/svl/itemset.hxx в фиксации b9337e22ce1d, но совершить b9337e22ce1d^ или f4e1642a1761, файл с именем svl/inc/svl/itemset.hxx. Git обнаруживает это переименование, когда отступает от коммита b9337e22ce1d для фиксации f4e1642a1761, и git blame переносит новое имя вместе с коммитом f4e1642a1761 для фиксации d210c6ccc3.

Однако когда вы запускаете git show d210c6ccc3, Git переходит непосредственно к d210c6ccc3 (и его родительскому 7f0993d43019). Он больше не знает, что файл с именем include/svl/itemset.hxx в HEAD называется svl/inc/svl/itemset.hxx в d210c6ccc3. Таким образом, вы должны обнаружить это и передать Git более раннее имя.

Вы можете задаться вопросом, как вы можете найти это. Ответ заключается в использовании git log --follow. --follow Код для git log не велик, но это 1 и тот же код, что git blame использует, поэтому он производит те же самые ответы, по крайней мере. Вот что я сделал:

$ git log --oneline --follow --name-status include/svl/itemset.hxx
00aa9f622c29 Revert "used std::map in SfxItemSet"
M       include/svl/itemset.hxx
afaa10da2572 make SfxItemSet with SAL_WARN_UNUSED
M       include/svl/itemset.hxx
[snip]
a7724966ab4f Bin comments that claim to say why some header is included
M       include/svl/itemset.hxx
b9337e22ce1d execute move of global headers
R100    svl/inc/svl/itemset.hxx include/svl/itemset.hxx

Там второе переименование еще раньше. Вот еще один, более короткий способ найти только переименования:

$ git log --oneline --follow --diff-filter=R --name-status include/svl/itemset.hxx
b9337e22ce1d execute move of global headers
R100    svl/inc/svl/itemset.hxx include/svl/itemset.hxx
e6b4345c7f40 #i103496#: split svtools in two libs, depending on whether the code needs vcl or not
R100    svtools/inc/svtools/itemset.hxx svl/inc/svl/itemset.hxx

Если d210c6ccc3 пришел "до" e6b4345c7f40, вам пришлось бы использовать более раннее имя пути, но commit d210c6ccc3 является потомком (приходит после) e6b4345c7f40, а не предком.


1 Когда изменения происходят при слияниях, это действительно, в фундаментальном смысле, требует одновременного выполнения обеих (или всех) входных фиксаций. Тем не менее, Git (в настоящее время?) Не способен сделать это: и git log --follow и git blame действительно только git log --follow родителя окончательная версия файла " git log --follow ". То есть, если мы посмотрим на типичный коммит M слияния, содержащий объединенный файл F, есть два входа M^1:F и M^2:F и один выход M:F Если M:F совпадает с M^1:F, мы должны полностью игнорировать M^2:F: все содержимое M:F принадлежит тем, кто предоставил M^1:F Если M:F совпадает с M^2:F, мы должны полностью игнорировать M^1:F: все содержимое M:F принадлежит тем, кто предоставил M^2:F

Обратите внимание, что это работает только для одного файла за раз, и даже тогда, это работает, только если файл точно соответствует одному из двух входных данных. В противном случае, мы должны посмотреть на объединенную разность, чтобы увидеть, как файл был изменен с обоих входов. Это логика, лежащая в основе комбинированных различий и упрощения истории. Но в некоторых редких случаях он слишком упрощен, и, следовательно, иногда что-то не так.

Ответ 2

Вы должны указать путь в этой ревизии:

git show d210c6ccc3 -- svl/inc/svl/itemset.hxx

Это должно сделать

Ответ 3

Вы можете использовать

git diff d210c6ccc3^ d210c6ccc3 include/svl/itemset.hxx

чтобы просмотреть изменения, сделанные в файле в commit (d210c6ccc3), по сравнению с предшественником (d210c6ccc3^).

Где d210c6ccc3^ - это "база", а d210c6ccc3 - это фиксация, которую вы хотите сравнить с базой.

Если, как упоминалось в комментариях к вашему вопросу, вы смотрите на неправильную фиксацию, затем замените SHA выше.

Это даст вывод diff содержимого файлов, команда git show, которую вы дали, выведет сообщение фиксации - только если этот файл был изменен в указанной фиксации.

Ответ 4

Попробуйте git diff <commit> -- include/svl/itemset.hxx