交互式rebase后删除了空提交,即使使用了--keep-empty

时间:2017-08-15 11:06:35

标签: git git-rebase

我在使用--keep-empty的{​​{1}}选项时遇到了一些问题,而且我很陌生 不确定我是否误解了这个选项的作用,或者是否存在错误。

这是一个最小的例子:

设置

  1. 创建一个新的Git存储库和一个初始的,无关的提交。

    git rebase
  2. 创建一个新的提交,添加两个新文件。

    $ git init
    $ echo something >base.txt
    $ git add base.txt
    $ git commit -m 'some base commit to not run into the root corner case'
    
  3. 修改其中一个文件。

    $ echo A >a.txt; echo B >b.txt
    $ git add a.txt b.txt
    $ git commit -m 'add A and B'
    
  4. 修改其他文件。

    $ echo A1 >a.txt
    $ git add a.txt
    $ git commit -m 'change A'
    
  5. 衍合

    $ echo B1 >b.txt
    $ git add b.txt
    $ git commit -m 'change B'
    

    ...选择$ git checkout -b rebased master $ git rebase --keep-empty -i :/base 添加editA的提交,并更改它以便仅添加B(在实际情况中,原因可能是B是机密的):

    A

    当然,现在修改$ git rm a.txt $ git commit --amend $ git rebase --continue 的下一次提交会产生冲突:

    A

    ...选择不添加error: could not apply 182aaa1... change A When you have resolved this problem, run "git rebase --continue". If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort". Could not apply 182aaa1701ad100fc02a5d5500cacebdd317a24b... change A 的修改版本:

    a.txt

    修改$ git mergetool Merging: a.txt Deleted merge conflict for 'a.txt': {local}: deleted {remote}: modified file Use (m)odified or (d)eleted file, or (a)bort? d 的提交现在为空:

    A

    ......并完成了变革:

    $ git diff --cached
    # nothing
    

    问题

    所以现在我的历史记录有两个版本,区别在于其中一个版本中没有$ git rebase --continue Successfully rebased and updated refs/heads/rebased. 的痕迹。但是,因为我选择了A选项,我仍然期望--keep-empty中存在空提交,这会告诉我rebased会被修改,如果它存在的话。

    但显然情况并非如此:

    A

    这不是$ git log --oneline master f893569 change B 182aaa1 change A 3340b71 add A and B 38cb5da some base commit to not run into the root corner case $ git log --oneline rebased 73a2c05 change B 55f502b add A and B 38cb5da some base commit to not run into the root corner case 应该做的,或者它不起作用 正确?

    相关:Rebase on the root and keep empty commits是一个非常相似的问题,但它涉及我在这里明确避免的--keep-empty极端情况。它没有答案,只有一些评论表明我在这里展示的内容应该有效。另一个区别是,在另一个问题中,提交首先是空的,而在解决冲突后它只会变空。

3 个答案:

答案 0 :(得分:5)

这是一种错误,因为某种功能。 : - )

当您运行交互式rebase并且它“暂停”时,实际上它完成,但是留下一些文件让 new git rebase意识到毕竟,它更像是一种延续。这样就好了;你需要稍后运行git rebase --continue来开始一个新的rebase并告诉它:你不是真的很新,去阅读状态并表现得就像你继续原来的rebase。 < / p>

而且,让我们来看看“互动式反思”。实际上,这主要是一系列的挑选操作:pick命令逐字地指示旧的rebase shell脚本 - 现在正逐步淘汰 - 运行git cherry-pick

好的,到目前为止没什么大不了的。但是让我们考虑为什么交互式rebase停止。有两个原因:

  1. 您标记了提交“编辑”。它实际上提交了樱桃选择,并停止让你修改提交或以其他方式大惊小怪。

  2. 或者,有一个问题 - 例如合并冲突 - 迫使停止。

  3. 如果是(1),当你运行git rebase --continue时,Git应该进行自己的提交。

    在情况(2)中,当您运行git rebase --continue时,Git 应该进行自己的提交。也就是说,它应该除非 - 这是功能部分 - 您首先进行自己的提交。在这种情况下,对于case(2),Git应该进行自己的提交。

    Git可以,也许应该,记录停止的原因,以便将这两种情况分开......但事实并非如此。相反,它只是查看--continue上的状态。

    对于 - 交互式rebase,Git知道它只会在冲突时停止,因此它知道尝试进行提交,并且如果没有提交则会抱怨。这是--keep-empty-k标志有用的地方。 (在内部,非交互式案例默认使用git format-patchgit am,但您可以强制它使用带--preserve-merges的交互式机制。我在这里提到它,因为它是< em>实现原因 Git必须知道你是否是“互动的”:正如经常发生的那样,Git让实现决定了行为。如果Git不需要这种区别,那么{{1}可以只使用相同的代码进行交互式和非交互式rebase,但Git 需要区分,因此不使用相同的代码。)

    但是,对于交互式rebase,Git 允许在运行--continue之前(例如,功能部分)在情况(2)中进行自己的提交。如果是这样,git rebase --continue步骤应该继续进行下一次提交。所以--continue只是检查是否有东西要提交,而不是早期的交互式rebase是否退出case(1)vs case(2)。这个简单的实现技巧支持该功能,但也意味着--continue 无法在这里工作:Git只是不知道其中的区别。

    解决方法是在解决合并后执行自己的--keep-empty。换句话说,使用“您可以自己提交”功能将case(2)转换为模拟案例(1)。

答案 1 :(得分:4)

  

但是,因为我选择了--keep-empty选项,我仍然期望在rebased中存在空提交,这会告诉我A会被修改,如果它已经存在。

     

但显然情况并非如此:

仔细检查Git 2.18(2018年第二季度),如果另一方包含空提交(由于“git rebase --keep-empty”检查,“does an equivalent patch exist already?”仍然删除空提交, 已更正

commit 3d94616commit 76ea235commit bb2ac4fPhillip Wood (phillipwood)(2018年3月20日)。
Junio C Hamano -- gitster --合并于commit d892bee,2018年4月25日)

  

rebase -i --keep-empty:不修剪空提交

     

如果$upstream...HEAD左侧有空提交,则我们要保留的右侧空提交将被--cherry-pick修剪。
  通过使用--cherry-mark代替--cherry-pick并保持空的提交或未标记为樱桃选择来解决此问题。

  

rebase --keep-empty:始终使用交互式rebase

rebase --merge接受--keep-empty,但只是忽略它,使用 隐式交互式rebase用户仍然可以进行重命名检测 基于合并的rebase但具有--keep-empty支持。

  

如果没有--keep-empty--interactive的rebase --merge停止   用户解决合并冲突,然后“git rebase --continue”将   失败。这是因为它使用了不同的代码路径   创建$git_dir/rebase-apply
  由于rebase --keep-empty是使用cherry-pick实现的,因此它从未支持am选项,现在交互式rebase支持--signoff,使用隐式交互式rebase不会丢失任何功能。

注意:这是Git 2.18中添加到git rebase的更大功能的一部分:
请参阅“What exactly does Git's “rebase --preserve-merges” do (and why?)” 使用git --rebase-merges(最终将替换旧的git --preserve-merges),您现在可以在其他地方重新定义提交图的整个拓扑。

答案 2 :(得分:0)

我也遇到了这个问题。

  • 3328dbe - 为jpa添加你好世界测试代码 - Minghui Ma(HEAD) - (14分钟前)
  • 3fd2d95 - init empty commit

当我使用cmd“git rebase -i --root --keep-empty”  没有提交“3fd2d95 - init empty commit”

所以我强行在第一行插入一行“pick 3fd2d95 init empty commit”。