Как определить конфликтующие коммиты по хешу во время git rebase?

Когда я сталкиваюсь с конфликтом слияния с использованием git rebase, как я могу определить источник конфликта с точки зрения коммитов, а не просто различий в файлах?

Я уже знаю, как (базовое) использовать git mergetool или git add до git rebase --continue, но иногда различий между файлами просто недостаточно: я хочу увидеть журнал фиксации и различие фиксации, которую просто не удалось применить к рабочему дерево.

В других вопросах я читал, что git log --merge покажет родительские коммиты, если я использую git merge. Я все равно попробовал, когда столкнулся с конфликтом, и мне сказали fatal: --merge without MERGE_HEAD?.

Как я могу определить проблемную фиксацию?


person RobM    schedule 22.01.2010    source источник
comment
Не забудьте команду Git 2.17+ от марта 2018 года git am --show-current-patch. См. мой ответ ниже.   -  person VonC    schedule 04.11.2019


Ответы (8)


Короткий ответ

Если это говорит

Patch failed at 0001 commit message for F

Тогда беги

$ head -1 .git/rebase-apply/0001
From ad1c7739c1152502229e3f2ab759ec5323988326 Mon Sep 17 00:00:00 2001

Чтобы получить SHA ad1c77 неудачной фиксации, а затем используйте git show ad1c77, чтобы посмотреть на него.

Длинный ответ

Начнем с этого дерева:

A---B---C---D
     \
      E---F---G

$ git checkout G
$ git rebase D

Когда возникает конфликт перебазирования, это конфликт между

  • восходящие изменения (C--D) от общего предка (B) PLUS уже измененные изменения и уже разрешенный конфликт (E') против
  • патч следующего коммита (F)

Давай посмотрим что происходит:

1) A---B---C---D---E'          <- E patched and committed successfully as E'
2) A---B---C---D---E'---       <- failed to patch F onto E'

Вот сообщение об ошибке:

First, rewinding head to replay your work on top of it...
Applying: commit message for F
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging 1.txt
CONFLICT (content): Merge conflict in 1.txt
Failed to merge in the changes.
Patch failed at 0001 commit message for F

Во-первых, вы можете видеть, что это было F, потому что появляется сообщение о фиксации. Однако, если все ваши сообщения о фиксации выглядят как «foo», «documentation» или «some fixes», это не поможет, и вам действительно нужен SHA id ad1c77 или содержимое патча.

Вот как узнать настоящую личность F:

Когда он перечисляет конфликт перебазирования, он говорит что-то вроде:

Patch failed at 0001 commit message for F

Теперь загляните в .git/rebase-apply/, где вы найдете файл патча 0001:

$ ls .git/rebase-apply
0001          head-name     msg           orig-head     sign
0002          info          msg-clean     patch         threeway
apply-opt     keep          next          quiet         utf8
final-commit  last          onto          rebasing

Файл патча включает исходный идентификатор фиксации

$ head -1 .git/rebase-apply/0001
From ad1c7739c1152502229e3f2ab759ec5323988326 Mon Sep 17 00:00:00 2001

Затем вы можете посмотреть на это.

Должен быть способ попроще, но он работает.

Обратите внимание, что сбой патча может быть связан с другой фиксацией (если вы выполняете перебазирование на общего предка HEAD и цели перебазирования). Найти эту фиксацию намного сложнее, хотя вы можете попробовать выполнить перебазирование в обратном порядке, чтобы найти ее:

$ git checkout D
$ git rebase G
person Alex Brown    schedule 22.01.2010
comment
Хороший ответ! Для меня темы коммитов достаточно, чтобы идентифицировать вещи (особенно потому, что ссылка еще не обновлена), но всегда хорошо знать, что вы можете посмотреть на rebase-apply для резервной копии. - person Cascabel; 22.01.2010
comment
Отличный ответ! Что делать, если вы потеряли сбой исправления в сообщении 0001 фиксации для сообщения F (прокрутка, сеанс SSH умер и т. Д.)? - person RobM; 22.01.2010
comment
Загляните в .git / rebase-apply-old / рядом, чтобы найти номер патча 1 патча, который он пытается в данный момент. Обратите внимание, что у него нет ведущих нулей. - person Alex Brown; 22.01.2010
comment
Очень полезно! Вы также можете использовать head -1 .git/rebase-apply/0001 | awk '{ print $2 }', если вам просто нужен SHA, и git show $(head -1 .git/rebase-apply/0001 | awk '{ print $2 }'), если хотите сразу показать фиксацию. - person Dan; 12.12.2012
comment
Большое спасибо! Я ломал голову над получением полного сообщения о фиксации, потому что фрагмента строки, которую он показывает мне, недостаточно, чтобы сказать мне, что нужно сделать, чтобы исправить конфликт правильно. - person DerfK; 17.07.2013
comment
Это кажется такой очевидной необходимостью, я не могу поверить, что что-то вроде акробатики Азриэля «git show» не встроено в инструменты. Спасибо! - person zultron; 27.01.2014
comment
Это очень полезно. Спасибо (у) - person Dzung Nguyen; 02.02.2014

Во время git rebase, который прекращает разрешать конфликты, следующая команда покажет конфликтующую фиксацию (все это, а не только конфликтующие файлы), то есть ваша фиксация в настоящее время воспроизводится / перемещается на новую базу, независимо от того, где вы находитесь. -к:

git show $(< .git/rebase-apply/original-commit)

Если вы хотите видеть конфликты только для определенного конфликтующего файла (того, который вы разрешаете), изолированно:

git show $(< .git/rebase-apply/original-commit) -- /path/to/conflicting/file

При построении этого ответа никто не использовал кошек :).

person javabrett    schedule 18.01.2017

Показать текущую / неудачную фиксацию

Это может быть новая функция, но REBASE_HEAD дает вам фиксацию, на которой вы остановились в данный момент (например, если фиксация не была применена). Если вы хотите увидеть коммит полностью, вы можете использовать

git show REBASE_HEAD

В качестве более подробной альтернативы вы можете использовать git rebase --show-commit-patch. Документы говорят, что они эквивалентны.

Покажите, что изменилось с тех пор, как вы начали свою работу

Если вы хотите увидеть, что изменилось между тем местом, откуда вы перебазируете, и тем местом, куда вы переустанавливаете, вы можете получить разницу между двумя ветвями. Например, если вы перебазируете с master на origin/master, вы можете использовать:

git diff master..origin/master

Или, если вы хотите увидеть изменения как отдельные коммиты:

git log -p master..origin/master

Если вы предпочитаете использовать хэш или, возможно, через некоторое время возвращаетесь к перебазированию и не можете вспомнить, какие ветви вы перебазируете, вы можете использовать git status, чтобы увидеть две ветки. Например:

В настоящее время вы переустанавливаете ветку master на b5284275

Затем, чтобы увидеть, что изменилось, вы можете использовать:

git diff master..b5284275
person redbmk    schedule 03.10.2018
comment
Вы можете использовать diff с тремя точками (master ... origin / master) и журнал с двумя (master..origin / master), см. stackoverflow.com/a/7256391/502126 - person Henrik Karlsson; 22.05.2019

Начиная с Git 2.17 (март 2018 г.), вам не нужно использовать rebase-apply.

Новая опция --show-current-patch дает конечному пользователю возможность применить diff, когда git rebasegit am) останавливается из-за конфликта.

См. фиксацию fbd7a23, зафиксировать 6633529, совершить 984913a (11 февраля 2018 г.), автор: Нгуен Тай Нгок Дуй (pclouds).
< sup> (объединено Junio ​​C Hamano - gitster - в commit 9ca488c, 06 марта 2018 г.)

am: добавить --show-current-patch

Подписано: Нгуен Тхай Нгок Дуй

Указание пользователю на $GIT_DIR/rebase-apply может побудить его возиться там, что не очень хорошо.

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

Дополнительные сведения см. На странице Показать текущую операцию интерактивного перебазирования git

Пример:

C:\Users\VonC\repo\src>git rebase origin/master
First, rewinding head to replay your work on top of it...
Applying: change code
Using index info to reconstruct a base tree...
M       a/src/file
Falling back to patching base and 3-way merge...
Auto-merging a/src/file
CONFLICT (content): Merge conflict in a/src/file
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch' to see the failed patch                  <======
Patch failed at 0001 change code
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

Тогда вы получите:

C:\Users\VonC\rep\src>git am --show-current-patch
  commit xxx (master)
  Author: VonC <[email protected]>
  Date:   Mon Nov 4 13:59:18 2019 +0100

      change code

  diff --git a/a/src/file b/a/src/file
  index yyy..zzz 100644
  --- a/a/src/file
  +++ b/a/src/file
  @@ -13,5 +13,5 @@ file: /a/src
   content line 1
   content line 2
   content line 3
   content line 4
  -content line 5
  -content line 6
  +content bis line 5
  +content bis line 6

git am --short-current-patch - это способ показать часть сообщения электронной почты для остановленного шага, который не подходит для прямой подачи git apply (он разработан как хороший git am ввод).

В Git 2.26 (первый квартал 2020 г.) появилась новая возможность отображать только часть патча.

См. фиксацию aa416b2, совершить f3b4822, e8ef1e8, совершить bc8620b, совершить 62e7a6f (20 февраля 2020 г.) от Паоло Бонзини (bonzini).
(Объединено Junio ​​C Hamano - gitster - в фиксации 0e0d717, 09 мар 2020 г.)

am: support --show-current-patch = diff для получения .git / rebase -применить / патч

Автор: Дж. Брюс Филдс
Подписан: Паоло Бонзини

Когда git am --show-current-patch был добавлен в commit 984913a210 (am: add --show-current-patch , 2018-02-12, Git v2.17.0-rc0 - объединить, перечисленные в пакет № 7), git am начал рекомендовать его в качестве замены .git/rebase-merge/patch.

К сожалению, это предложение несколько ошибочно; например, вывод git am --show-current-patch не может быть передан в git apply, если он закодирован как quoted-printable или base64.

Добавьте новый режим в git am --show-current-patch, чтобы исправить предложение.

новый режим - это <сильный > diff:

--show-current-patch[=(diff|raw)]:

Показать сообщение, на котором git am остановился из-за конфликтов.
Если указан raw, показать необработанное содержимое сообщения электронной почты; если diff, показывать только часть различий.
По умолчанию raw.

И:

am: поддержка --show-current-patch=raw как синонима --show-current-patch

Подписано: Паоло Бонзини

Чтобы упростить операции с рабочим деревом и избежать попадания пользователей в .git, было бы лучше, если бы git am также предоставил режим, который копирует .git/rebase-merge/patch в стандартный вывод.

Одна из возможностей может заключаться в том, чтобы иметь полностью отдельные параметры, вводя, например, --show-current-message (для .git/rebase-apply/NNNN) и --show-current-diff (для .git/rebase-apply/patch), при этом, возможно, исключая --show-current-patch.

Это даже устранило бы необходимость в первых двух патчах серии. Однако длинный общий префикс не позволил бы использовать сокращенный вариант, такой как --show.

Поэтому я решил вместо этого добавить строковый аргумент к --show-current-patch.

person VonC    schedule 04.11.2019

cat .git/rebase-apply/original-commit

Учитывая это:

A---B---C---D
     \
      E---F---G

$ git checkout G
$ git rebase D

и учитывая, что существует конфликт слияния при попытке применить F:

A---B---C---D--E'--!
     \
      E---F---G

тогда файл original-commit покажет хеш F. Это «их» версия.

Кроме того, в этом случае HEAD (.git / HEAD) будет E '. Это «моя» версия. HEAD ^ будет "базовой" версией.

Это верно как минимум для git 1.7.9

person Alexander Bird    schedule 03.09.2014

Не уверен, почему у меня нет .git/rebase-apply в моей ситуации. Для тех, кто находится в такой же ситуации, вот мой вариант.

git show $(cat .git/rebase-merge/stopped-sha)

Или как псевдоним ...

git config --global alias.sp='!git show $(cat .git/rebase-merge/stopped-sha)'
person Justin C    schedule 25.12.2014
comment
Папка rebase-apply создана для неинтерактивной перебазировки, а rebase-merge - для интерактивной. - person LoKi; 13.12.2015

Чтобы увидеть фиксацию, которая применялась, когда произошел конфликт, используйте ...

git am --show-current-patch
person Wallace Kelly    schedule 17.12.2019

Много раз вы будете в процессе перебазирования и захотите пропустить те коммиты, которые не нужны.

К сожалению, хотя git status сообщает вам, что вы находитесь в середине фиксации и рекомендует использовать git rebase --continue git rebase --skip или git rebase --abort, он не сообщает вам, в какой фиксации вы сейчас находитесь.

Так что часто бывает трудно понять, стоит ли вам git rebase --skip или нет.

Однако есть еще способ узнать, в каком коммите вы находитесь, запустив:

git log -1 $(< .git/rebase-apply/original-commit)
person Senseful    schedule 28.05.2018