Git rebase,提交重复。

6

我正在处理代码库的另一个分支,并需要将主分支的更改合并到该分支。我通常使用 git rebase master,一切正常。然而,在最近的几个项目中,我发现提交记录会重复出现在日志中,进行 rebase 操作时会出现错误提示:

$ git log --graph --abbrev-commit --decorate ...
*   4988d49 - (2 hours ago) Merge branch 'branchname' of ... 3
|\
| * e979be1 - (2 days ago) change verbiage 10
| *   93a1c80 - (2 days ago) Merge branch 'branchname' of ... 2
| |\
| | *   4e4e790 - (2 weeks ago) Merge branch 'branchname' of ... 1
| | |\
| | | * 87cc232 - (8 weeks ago) change verbiage 3
| | | * 3d5cf09 - (8 weeks ago) change verbiage 2
| | | * aea4cbd - (9 weeks ago) change verbiage 1
| | * | a7043ef - (2 weeks ago) change verbiage 6
| | * | fa3413b - (2 weeks ago) change verbiage 5
| | * | be038a7 - (2 weeks ago) change verbiage 4
| | * | 37cb1e6 - (8 weeks ago) change verbiage 3
| | * | 1ab71c6 - (8 weeks ago) change verbiage 2
| | * | c4560f4 - (9 weeks ago) change verbiage 1
| * | | d3211fd - (2 weeks ago) change verbiage 6
| * | | 72a2a4a - (2 weeks ago) change verbiage 5
| * | | ae1c123 - (2 weeks ago) change verbiage 4
| * | | 8328c08 - (8 weeks ago) change verbiage 3
| * | | e52588f - (8 weeks ago) change verbiage 2
| * | | 114cbec - (9 weeks ago) change verbiage 1
* | | | 38bd6ce - (2 hours ago) change verbiage 9
* | | | 5aaf360 - (2 hours ago) change verbiage 8
* | | | 2745790 - (2 days ago) change verbiage 7
* | | | 7bb613f - (2 weeks ago) change verbiage 6
* | | | 726a312 - (2 weeks ago) change verbiage 5
* | | | 771dd7f - (2 weeks ago) change verbiage 4
* | | | b451926 - (8 weeks ago) change verbiage 3
* | | | 484d5dc - (8 weeks ago) change verbiage 2
* | | | 630df34 - (9 weeks ago) change verbiage 1

(为了简单起见,我更改了提交消息。尽管有四个“管道流”,但这里实际上只显示了一个分支。) 我在这个项目上做了几次变基,根据修改措辞1的重复次数,我认为它们可以被简单地追踪到。

我以为通过变基合并进行项目工作流程是一个“最佳实践”,但我认为之前的变基中至少有一个是使用了 -no-ff,但我看不到行为上的区别。

当提交被重新播放时,它们会发生冲突(显然,将一个提交放在自己的顶部是有问题的),所以我被迫进行交互式变基,删除所有重复的提交。

没有访问仓库本身,这是否是我的工作流程存在问题?这是否表明分支中存在其他问题?

1个回答

9

为什么?

看起来你使用了变基修改了已经有一个分支指向的旧提交。所以发生了以下情况:

你拥有一个如下图的dag:

* abc123 (master) Most recent commit
|
| * f00ba12 (foo, HEAD) Some feature you're working on
| |
|/
* 192837 Fix the things
|
* 348cc87 Remove Peter's garbage code
|
* 000a0a WOOOORRRDDDDDSSSS

你现在正在foo上做一些事情,但是你发现还有一些Peter的垃圾代码需要清除。作为一个好的程序员,你想将这些更改与其他更改一起提交到348cc87。所以你进行了变基操作,回到那个时间点并进行修改。

这看起来很不错,但问题是你已经改变了348cc87,所以它不再是348cc87了。现在它是111222,因为记住提交哈希值是从项目树以及其他因素计算出来的,其中之一就是父提交哈希值(000a0a)。因此,由于348cc87现在是111222,'192837'被重新计算为999999,而f00ba12则变为ba12f00。因此,现在你的日志从HEAD看起来像:

* ba12f00 (foo, HEAD) Some feature you're working on
|
|
* 999999 Fix the things
|
* 111222 Remove Peter's garbage code
|
* 000a0a WOOOORRRDDDDDSSSS

这会成为一个问题,因为abc123仍然指向192837,这是有效的,因为提交对象192837仍然存在于git中。这是因为从git的角度来看,192837abc123是截然不同的提交,只是恰巧具有相同的日志消息。

所以现在您的git dag看起来像:

* abc123 (master) Most recent commit
|
| * f00ba12 (foo, HEAD) Some feature you're working on
| |
| * 999999 Fix the things
* | 192837 Fix the things
| | 
| * 111222 Remove Peter's garbage code
* | 348cc87 Remove Peter's garbage code
|/
* 000a0a WOOOORRRDDDDDSSSS

现在,当您完成对foo分支的工作并准备合并时,会出现以下情况:

* 5f93da (master) Merge 'foo' into 'master'
|\
* | abc123 Most recent commit
| |
| * f00ba12 (foo, HEAD) Some feature you're working on
| |
| * 999999 Fix the things
* | 192837 Fix the things
| | 
| * 111222 Remove Peter's garbage code
* | 348cc87 Remove Peter's garbage code
|/
* 000a0a WOOOORRRDDDDDSSSS

经常这么做,你最终会陷入当前的情况。

但是Kyle,我该怎么解决呢?慢着r2evans,我在处理中。

解决方法

有几种方法可以解决这个问题,但在某些情况下,所有我所知道的方法都有一定的复杂性。

  • 您可以将许多提交压缩在一起,以便减少提交次数,但这样会损失一些历史记录,我不太喜欢。

  • 您可以执行一些额外的rebase操作,将您的“abc123”提交更改为具有较新999999提交的父级。您可以使用--onto参数进行此操作。这可能会因情况而异而具有挑战性。

  • 您可以按原样保留它。只要master的末尾处于正确状态,这并不是非常糟糕的,但使回顾您的历史记录变得非常困难。

这是一个问题吗?

是的。这似乎是您的工作流程存在问题。由于这个原因,编辑历史往往不是一个好主意,通常应避免这样做。

对于我来说,master跟踪公共内容。这是我和我的团队成员都基于其进行更改的代码。我从不修改master中的提交记录。首先,因为我们的内部git仓库不允许我推送这样的更改(即使使用了--force),其次,那会影响我的团队成员的代码(并导致他们陷入您的境地)。

我为特定功能创建从master派生的功能分支,因此我将foobarfizzbuzz作为从主分支分离出来的单独分支,而不是相互分离的分支。这使我可以单独处理每个功能。我通常不会从功能分支另外再创建分支,但是当我这样做时,我通常不会编辑提交历史记录。那是因为我通常会在合并之前清理该分支,所以我不需要这样做。


1
非常好的回答,谢谢Kyle。另一个问题(我忘了提)是我在仓库服务器上有分支,所以git push origin几乎总是需要强制提交才能推送。也许我对我的DAG最大的“问题”是它显示了四个分支,而实际上只有一个;我更喜欢保持一个“干净”的DAG,没有明显重复的提交消息。知道这是“正常行为”是有帮助的。 - r2evans
1
如果整个历史记录已经公开并且人们正在使用它,那就让它保持不变。这并不是很好,但您不应该搞乱公共存储库,因为这会伤害其他开发人员。因此,一旦您推送到源,您应该创建新的提交而不是将其合并到旧的提交中。 - Kyle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接