48

当我使用 遇到合并冲突时git rebase,如何根据提交来识别冲突的来源,而不仅仅是文件差异?

我已经知道如何(基本)使用git mergetoolor git addbefore git rebase --continue,但有时文件之间的差异还不够:我想查看提交日志和刚刚未能应用于工作树的提交的差异。

我读过其他问题,git log --merge如果我使用git merge. 当我遇到冲突并被告知时,我还是尝试了它fatal: --merge without MERGE_HEAD?

如何识别有问题的提交?

4

8 回答 8

41

简答

如果它说

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

当发生 rebase 冲突时,它是

  • C--D来自共同祖先 ( ) 的上游更改 ( )B加上已经重新定位的更改和已经解决的冲突 ( 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”、“文档”或“一些修复”,那么这将无济于事,并且您确实需要 SHA idad1c77或补丁的内容。

以下是如何找出 的真实身份F

当它列出 rebase 冲突时,它会说:

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

补丁文件包含原始的 commit-id

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

然后你可以看看那个。

必须有一个更简单的方法,但这有效。

请注意,补丁失败的事实可能是由于不同的提交(如果您要重新定位到HEAD和重新定位目标的共同祖先)。找到该提交相当复杂,尽管您可以尝试反向执行 rebase 来找到它:

$ git checkout D
$ git rebase G
于 2010-01-22T15:54:00.473 回答
11

git rebase停止解决冲突期间,以下命令将显示冲突的提交(全部,而不仅仅是冲突的文件),也就是说,您的提交当前正在重播​​/重新定位到新的基础上,无论您在哪里-至:

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

如果您只想查看特定冲突文件(您正在解决的文件)的冲突,请隔离:

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

在构建这个答案时没有滥用猫:)。

于 2017-01-18T03:21:35.617 回答
9

显示当前/失败的提交

这可能是一项新功能,但REBASE_HEAD会为您提供当前停止的提交(例如,如果提交未能应用)。如果您想查看完整的提交,您可以使用

git show REBASE_HEAD

作为更详细的替代方案,您可以使用git rebase --show-commit-patch. 文档说它们是等价的。

显示自您开始工作以来发生的变化

如果您想查看变基的位置和变基的位置之间发生了什么变化,您可以获得两个分支之间的差异。例如,如果你从 on 变基,masterorigin/master可以使用:

git diff master..origin/master

或者,如果您想将更改视为单个提交:

git log -p master..origin/master

如果您更喜欢使用散列或者可能在一段时间后回到变基并且不记得您正在变基的分支,您可以使用git status查看两个分支。例如:

您目前正在“b5284275”上重新设置分支“master”

然后,要查看发生了什么变化,您可以使用:

git diff master..b5284275
于 2018-10-03T16:46:19.823 回答
6

从 Git 2.17(2018 年 3 月)开始,您不需要使用rebase-apply.

当“ ”(和“ ”)因冲突而停止时,新的“ --show-current-patch”选项提供了一种面向最终用户的方式来获得diff应用。git rebasegit am

请参阅Nguyễn Thái Ngọc Duy ( )的提交 fbd7a23提交 6633529提交 984913a(2018 年 2 月 11 日) 。(由Junio C Hamano 合并——提交 9ca488c中,2018 年 3 月 6 日)pclouds
gitster

am:添加--show-current-patch

签字人:Nguyễn Thái Ngọc Duy

指向用户$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 <vonc@vonc.com>
  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 年第一季度)中,它学习了一个仅显示补丁部分的新选项。

请参阅Paolo Bonzini ( ) 的提交 aa416b2提交 f3b4822提交 e8ef1e8提交 bc8620b提交 62e7a6f(2020 年 2 月 20 日(由Junio C Hamano 合并 -- --提交 0e0d717中,2020 年 3 月 9 日)bonzini
gitster

am: 支持 --show-current-patch=diff 检索 .git/rebase-apply/patch

报告人:J. Bruce Fields
签字人:Paolo Bonzini

git am --show-current-patch提交 984913a210 (" am: add --show-current-patch", 2018-02-12, Git v2.17.0-rc0 -- merge列在批次 #7中) 中添加 " " 时, " git am" 开始将其推荐为替换为.git/rebase-merge/patch.

不幸的是,这个建议有些误导。例如,如果“”的输出被编码为quoted-printable 或base64,git am --show-current-patch则不能将其传递给“ ”。git apply

为“ ”添加新模式git am --show-current-patch以理顺建议。

模式diff

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

显示git am因冲突而停止的消息。
如果raw指定,则显示电子邮件消息的原始内容;如果diff,仅显示差异部分。
默认为raw.

和:

am: 支持--show-current-patch=raw作为同义词--show-current-patch

签字人:Paolo Bonzini

为了简化工作树操作并避免用户戳入.git,如果“ git am”也提供一种复制.git/rebase-merge/patch到标准输出的模式会更好。

一种可能性是拥有完全独立的选项,例如引入--show-current-message(for .git/rebase-apply/NNNN) 和--show-current-diff(for .git/rebase-apply/patch),同时可能弃用 --show-current-patch。

这甚至可以消除对系列中前两个补丁的需求。但是,长的公共前缀会阻止使用诸如“ --show”之类的缩写选项。

因此,我选择将字符串参数添加到--show-current-patch.

于 2019-11-04T17:11:18.310 回答
2

不知道为什么我没有.git/rebase-apply在我的情况。对于那些处于相同情况的人,这是我的变化。

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

或者作为别名...

git config --global alias.sp='!git show $(cat .git/rebase-merge/stopped-sha)'
于 2014-12-25T00:31:21.960 回答
2
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 是这样

于 2014-09-03T12:04:52.890 回答
1

要查看发生冲突时正在应用的提交,请使用...

git am --show-current-patch
于 2019-12-17T20:35:23.083 回答
0

很多时候,您将处于 rebase 的中间并希望跳过那些不需要的提交。

不幸的是,虽然git status告诉您正在提交并建议使用git rebase --continue git rebase --skipor git rebase --abort,但它并没有告诉您当前正在进行的提交。

因此,通常很难知道您是否应该这样做git rebase --skip

但是,仍然有一种方法可以通过运行来找出您正在进行的提交:

git log -1 $(< .git/rebase-apply/original-commit)
于 2018-05-28T01:46:55.750 回答