比较 Git 中 rebase 的差异
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12465184/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Comparing differences across a rebase in Git
提问by Kevin Reid
Suppose that I just rebased the branch foo
on master
, with conflicts. I want to make sure that I did not accidentally damage the content of foo
during conflict resolution by introducing extra changes or losing changes (other than that which is appropriate for the conflict resolution). I have done this via:
假设我只是将分支重新建立foo
在 上master
,但存在冲突。我想确保我没有foo
在冲突解决期间通过引入额外的更改或丢失更改(除了适合解决冲突的更改)而意外损坏 的内容。我是通过以下方式完成的:
diff -u <(git diff `git merge-base master foo@{1}` foo@{1}) \
<(git diff `git merge-base master foo ` foo )
(update: or the equivalent ...
syntax for git-diff
which I have just been reminded of:)
(更新:或我刚刚被提醒的等效...
语法git-diff
:)
diff -u <(git diff master...foo@{1}) <(git diff master...foo) | mate
This shows me all the changes that have occurred to master..foo
considered as a patch, which is exactly what I want to check for being minimal. However, the invocation is complex and the output is not entirely straightforward to interpret.
这向我展示了master..foo
被视为补丁的所有更改,这正是我想要检查的最小更改。但是,调用很复杂,输出也不是很容易解释。
Is there a better way to accomplish this task — to provide the same information, but with a better method or format — or should I just take the above and wrap it up in a script?
有没有更好的方法来完成这个任务——提供相同的信息,但使用更好的方法或格式——或者我应该把上面的内容打包成一个脚本?
回答by Jake
What we really want to show is the conflict combined diff that is generated as if we had done a merge to get from (a) to (b) where (a) was previously based on (upstream-old) and (b) is now based on (upstream-new).
我们真正想展示的是生成的冲突组合差异,就好像我们已经完成了从 (a) 到 (b) 的合并,其中 (a) 以前基于(上游旧)而 (b) 现在是基于(上游新)。
We don't want just a straight diff.
我们不想要一个直接的差异。
Instead, we can essentially do the merge but force the resulting tree to be $b^{tree} which we already know is the correct "end" point of what we want.
相反,我们基本上可以进行合并,但强制生成的树为 $b^{tree} 我们已经知道这是我们想要的正确“结束”点。
More or less, let's assume that we have
或多或少,让我们假设我们有
newcommit -> the new version of the series
oldcommit -> the old version of the series
upstream -> the (new) version of the base of the series
We can generate the merge via
我们可以通过生成合并
git commit-tree newcommit^{tree} -p oldcommit -p upstream -m "message"
and then show the result with "git show" and this will generate a combined diff format that shows all the necessary bits as a conflict resolution which automatically ignores changes that weren't actually part of resolving conflicts.
然后用“git show”显示结果,这将生成一个组合的差异格式,显示所有必要的位作为冲突解决方案,自动忽略实际上不是解决冲突的一部分的更改。
This even works for simply ammending a change as well, and you can do a bit more work to ensure that the generated merge commit has exact author and commit timestamps so that it's consistent over multiple calls (since we arestoring a loose ref into the object database).
这甚至适用于只是ammending的变化,以及,你可以做一些更多的工作,以确保产生的合并提交有确切的作者和提交时间戳,以使得它在多次调用一致(因为我们都存储一个松散的裁判到对象数据库)。
Unfortunately I have not been able to figure out how to just get "git diff" to diff the same way without actually generating a tree yet. I'm not sure what arguments we'd have to pass to get to that point.
不幸的是,我还没有弄清楚如何在不实际生成树的情况下让“git diff”以相同的方式进行 diff。我不确定我们必须通过什么论点才能达到这一点。
回答by VonC
Even better than interdiff
, now with Git 2.19 (Q3 2018) you have git range-diff
.
See "Git diff - two disjoint revision ranges"
甚至比 更好interdiff
,现在使用 Git 2.19(2018 年第三季度),您拥有git range-diff
.
参见“ Git diff - 两个不相交的修订范围”
The git range-diff
documentation includes the following example:
When a rebase required merge conflicts to be resolved, compare the changes introduced by the rebase directly afterwardsusing:
$ git range-diff @{u} @{1} @
A typical output of
git range-diff
would look like this:------------ -: ------- > 1: 0ddba11 Prepare for the inevitable! 1: c0debee = 2: cab005e Add a helpful message at the start 2: f00dbal ! 3: decafe1 Describe a bug @@ -1,3 +1,3 @@ Author: A U Thor <[email protected]> -TODO: Describe a bug +Describe a bug @@ -324,5 +324,6 This is expected. -+What is unexpected is that it will also crash. ++Unexpectedly, it also crashes. This is a bug, and the jury is ++still out there how to fix it best. See ticket #314 for details. Contact 3: bedead < -: ------- TO-UNDO ------------
In this example, there are 3 old and 3 new commits, where the developer:
- removed the 3rd,
- added a new one before the first two, and
- modified the commit message of the 2nd commit as well its diff.
When the output goes to a terminal, it is color-coded by default, just like regular
git diff
's output. In addition, the first line (adding a commit) is green, the last line (deleting a commit) is red, the second line (with a perfect match) is yellow like the commit header ofgit show
's output, and the third line colors the old commit red, the new one green and the rest likegit show
's commit header.
当 rebase 需要解决合并冲突时,使用以下命令直接比较 rebase 引入的更改:
$ git range-diff @{u} @{1} @
的典型输出
git range-diff
如下所示:------------ -: ------- > 1: 0ddba11 Prepare for the inevitable! 1: c0debee = 2: cab005e Add a helpful message at the start 2: f00dbal ! 3: decafe1 Describe a bug @@ -1,3 +1,3 @@ Author: A U Thor <[email protected]> -TODO: Describe a bug +Describe a bug @@ -324,5 +324,6 This is expected. -+What is unexpected is that it will also crash. ++Unexpectedly, it also crashes. This is a bug, and the jury is ++still out there how to fix it best. See ticket #314 for details. Contact 3: bedead < -: ------- TO-UNDO ------------
在此示例中,有 3 个旧提交和 3 个新提交,其中开发人员:
- 删除了第三个,
- 在前两个之前添加了一个新的,并且
- 修改了第二次提交的提交消息及其差异。
当输出到达终端时,默认情况下它是彩色编码的,就像常规
git diff
的输出一样。另外,第一行(添加一个commit)是绿色的,最后一行(删除一个commit)是红色的,第二行(有完美匹配的)是黄色的就像git show
输出的commit header一样,第三行是颜色旧的提交是红色的,新的是绿色的,其余的就像git show
的提交标头一样。
With Git 2.20, colors are better supported for the new kind of (range) diff
使用 Git 2.20,新的(范围)差异可以更好地支持颜色
See commit 2543a64, commit 8d5ccb5, commit 7648b79(17 Aug 2018), and commit 4441067, commit f103a6f, commit 29ef759, commit 017ac45, commit 9d1e16b, commit 84120cc, commit c5e64ca, commit 991eb4f(14 Aug 2018) by Stefan Beller (stefanbeller
).
(Merged by Junio C Hamano -- gitster
--in commit 30035d1, 17 Sep 2018)
见提交2543a64,提交8d5ccb5,提交7648b79(2018年8月17日),以及提交4441067,提交f103a6f,提交29ef759,提交017ac45,提交9d1e16b,提交84120cc,提交c5e64ca,提交991eb4f(2018年8月14日)由斯蒂芬贝勒(stefanbeller
)。
(由Junio C gitster
Hamano合并-- --在commit 30035d1,2018 年 9 月 17 日)
range-diff
: indent special lines as contextThe range-diff coloring is a bit fuzzy when it comes to special lines of a diff, such as indicating new and old files with
+++
and---
, as it would pickup the first character and interpret it for its coloring, which seems annoying as in regular diffs, these lines are colored bold viaDIFF_METAINFO
.By indenting these lines by a white space, they will be treated as context which is much more useful, an example on the range diff series itself:
git range-diff pr-1/dscho/branch-diff-v3...pr-1/dscho/branch-diff-v4
range-diff
: 缩进特殊行作为上下文范围-DIFF着色是有点模糊,当涉及到一个diff的特殊线路,如表明新和旧文件以
+++
和---
,因为它会皮卡的第一个字符并把它解释为它的颜色,这似乎恼人的,因为在常规的diff , 这些线通过DIFF_METAINFO
.通过用空格缩进这些行,它们将被视为更有用的上下文,例如范围差异系列本身:
git range-diff pr-1/dscho/branch-diff-v3...pr-1/dscho/branch-diff-v4
(from repository github.com/gitgitgadget/git
)
(来自存储库github.com/gitgitgadget/git
)
[...] + diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt + new file mode 100644 + --- /dev/null + +++ b/Documentation/git-range-diff.txt +@@ ++git-range-diff(1) [...] + diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile [...]
The first lines that introduce the new file for the man page will have the '
+
' sign colored and the rest of the line will be bold.The later lines that indicate a change to the
Makefile
will be treated as context both in the outer and inner diff, such that those lines stay regular color.
[...] + diff --git a/Documentation/git-range-diff.txt b/Documentation/git-range-diff.txt + new file mode 100644 + --- /dev/null + +++ b/Documentation/git-range-diff.txt +@@ ++git-range-diff(1) [...] + diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile [...]
介绍手册页新文件的第一行将带有“
+
”符号,其余行将是粗体。后面指示更改的
Makefile
行将被视为外部和内部差异中的上下文,以便这些行保持常规颜色。
回答by user1338062
Differences between master and rebased foo:
master 和 rebase foo 之间的差异:
git diff master..foo
git diff master..foo
vs.
对比
Differences of pre-rebase foo after branching off master (note three dots):
从 master 分支后的 pre-rebase foo 的差异(注意三个点):
git diff master...foo@{1}
git diff master...foo@{1}
?
?
回答by manu
Since it's s rebase and not a merge, you might want to compare foo
with itself but before the merge. If I recall correctly foo@{1}
will yield the parent of the current commit for foo
, and maybe this is not what you are looking for.
由于它是变基而不是合并,因此您可能希望foo
在合并之前与自身进行比较。如果我没记错的话foo@{1}
会产生当前提交的父级foo
,也许这不是你要找的。
I think you can do something like the following (assuming you haven't done a git gc
):
我认为您可以执行以下操作(假设您还没有完成git gc
):
On the branch foo
after the rebase:
在foo
变基后的分支上:
$ git reflog
This will show how your branch's HEAD has been moved. You should see some records like this (depending if you rebase interactively or not):
这将显示您的分支的 HEAD 是如何移动的。您应该会看到一些这样的记录(取决于您是否以交互方式变基):
64d3c9e HEAD@{15}: rebase -i (finish): returning to refs/heads/master
64d3c9e HEAD@{16}: rebase -i (fixup): Fixes external dependencies
049169e HEAD@{17}: rebase -i (fixup): updating HEAD
d4c2e69 HEAD@{18}: rebase -i (pick): Fixes external dependencies
049169e HEAD@{19}: rebase -i (fixup): Imports futures
e490bed HEAD@{20}: rebase -i (fixup): updating HEAD
...
etc
...
Look forward to the last of commit of foo
before the merge. Depending on what you have done this may be difficult or not. That's why I have not provided a do-it script.
期待foo
合并前的最后一次提交。根据您所做的工作,这可能会很困难,也可能不会。这就是我没有提供 do-it 脚本的原因。
Pick up the commit id that have the last commit for foo
before the rebase and then compare to that commit id. Say that commit id is: XXXX
:
foo
在变基之前选择具有最后一次提交的提交 ID,然后与该提交 ID 进行比较。假设提交 ID 是XXXX
::
git diff XXXX...foo
Maybe that's what you want.
也许这就是你想要的。
回答by Thomas Leonard
git-cherry
searches for commits on one branch that aren't on another. You'd use it as:
git-cherry
在一个分支上搜索不在另一个分支上的提交。您可以将其用作:
git cherry -v OLDTIP TIP UPSTREAM
i.e. look for commits that were on OLDTIP
but which aren't on UPSTREAM..TIP
. It looks at the patch signature to see whether a patch is included, so if a patch got added, dropped or modified during the rebase then it will show up in the list. Things that got applied without changes won't appear.
即查找已启用OLDTIP
但未启用的提交UPSTREAM..TIP
。它查看补丁签名以查看是否包含补丁,因此如果在 rebase 期间添加、删除或修改了补丁,那么它将显示在列表中。没有改变就应用的东西不会出现。
A similar effect can be achieved by going back to OLDTIP
and doing git rebase -i TIP
, since that uses the same logic to populate the list of commits.
通过返回OLDTIP
并执行可以实现类似的效果git rebase -i TIP
,因为它使用相同的逻辑来填充提交列表。
回答by Thomas Leonard
A slightly different approach: Git has good support for showing this in the case of merges. i.e. "what changed relative to parent-1 which can't be explained by parent-2?"
一种稍微不同的方法:Git 很好地支持在合并的情况下显示这一点。即“父母2无法解释的相对于父母1的变化是什么?”
There are a couple of ways you could leverage that support for your rebase:
有几种方法可以利用这种支持来实现 rebase:
Option 1:
选项1:
Do a throw-away merge first (instead of a rebase). Then the normal merge display will show what the merge changed. Check this is what you wanted.
Go back and rebase, and compare the rebased tip against the merge result - they should be identical.
首先进行一次性合并(而不是变基)。然后正常合并显示将显示合并更改的内容。检查这是你想要的。
返回并重新定位,并将重新定位的提示与合并结果进行比较 - 它们应该是相同的。
Option 2 (if rebasing is easier than merging):
选项 2(如果变基比合并更容易):
- Do the rebase.
- Use a graft to make it look like a merge locally/temporarily.
- 做rebase。
- 使用嫁接使其看起来像本地/临时合并。
To do that, create a .git/info/grafts with a single line:
为此,请使用一行创建 .git/info/grafts:
TIP UPSTREAM OLDTIP
Where TIP is the commit ID of your rebased branch and the others are the two desired parents (i.e. the two things you would have merged, had you been doing a merge). Then examine it as if it were a real merge.
其中 TIP 是您重新定位的分支的提交 ID,其他是两个所需的父级(即,如果您进行了合并,您将合并的两件事)。然后像真正的合并一样检查它。
I'm not sure about automating it; I tend to do this stuff with gitk open, because it makes comparing the right revisions easy (using the right-click menu).
我不确定是否要自动化;我倾向于在 gitk open 的情况下做这些事情,因为它使比较正确的修订变得容易(使用右键单击菜单)。
If you really want to compare two diffs then you might want to look at interdiff(1), but I'm not sure how well it will cope with the base files being different.
如果您真的想比较两个差异,那么您可能需要查看 interdiff(1),但我不确定它如何处理不同的基本文件。