交互式重新设置后,即使使用了--keep-empty,也删除了空提交

mkr*_*er1 4 git git-rebase

使用的--keep-empty选项时遇到一些麻烦git rebase,并且不确定是否误解了该选项的作用,还是有错误。

这是一个最小的示例:

设定

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

    $ git init
    $ echo something >base.txt
    $ git add base.txt
    $ git commit -m 'some base commit to not run into the root corner case'
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一个新的提交,添加两个新文件。

    $ echo A >a.txt; echo B >b.txt
    $ git add a.txt b.txt
    $ git commit -m 'add A and B'
    
    Run Code Online (Sandbox Code Playgroud)
  3. 修改其中一个文件。

    $ echo A1 >a.txt
    $ git add a.txt
    $ git commit -m 'change A'
    
    Run Code Online (Sandbox Code Playgroud)
  4. 修改另一个文件。

    $ echo B1 >b.txt
    $ git add b.txt
    $ git commit -m 'change B'
    
    Run Code Online (Sandbox Code Playgroud)

变基

$ git checkout -b rebased master
$ git rebase --keep-empty -i :/base
Run Code Online (Sandbox Code Playgroud)

…选择要edit在何处添加的提交,A然后对其B进行更改,以使其仅B添加(在实际情况下,原因可能A是机密的):

$ git rm a.txt
$ git commit --amend
$ git rebase --continue
Run Code Online (Sandbox Code Playgroud)

自然,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
Run Code Online (Sandbox Code Playgroud)

…选择不添加的修改版本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
Run Code Online (Sandbox Code Playgroud)

A修改后的提交现在为空:

$ git diff --cached
# nothing
Run Code Online (Sandbox Code Playgroud)

…并完成变基:

$ git rebase --continue
Successfully rebased and updated refs/heads/rebased.
Run Code Online (Sandbox Code Playgroud)

因此,现在我有两个版本的历史记录,区别在于其中一个没有任何痕迹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
Run Code Online (Sandbox Code Playgroud)

这不是--keep-empty应该做的,还是不能正常工作?


相关:基于根目录并保持空提交是一个非常相似的问题,但是它涉及到极端--root情况,在此我明确避免了这种情况。它没有答案,只有一些评论暗示我在这里显示的内容应该起作用。另一个区别是,在另一个问题中,提交首先是空的,而在这里,只有在解决冲突后,提交才为空。

tor*_*rek 5

由于某种功能,它有点像个错误。:-)

实际上,当您运行交互式rebase并“暂停”时,它会完成,但是会留下一些文件,让新的用户 git rebase意识到它毕竟是延续。就目前而言,这很好。您将需要git rebase --continue稍后运行以启动新的基准,并告诉它:您并不是真的新手,请阅读状态并像继续进行原始基准一样工作。

并且,让我们看一下“交互式基础”。实际上,这主要是一系列的Cherry-Pick操作:该pick命令从字面上指示运行现在正在逐步淘汰的旧的rebase shell脚本git cherry-pick

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

  1. 您将提交标记为“编辑”。实际上,它会落实“摘樱桃”,然后停止以让您修改提交或以其他方式大惊小怪。

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

在情况(1),当您运行git rebase --continue,Git的应该不会做出自己的承诺。

在情况(2)中,当您运行时git rebase --continue,Git 应该进行自己的提交。也就是说,除非(这是功能部分),否则您应该先进行自己的提交。在这种情况下,对于情况(2)的Git应该不会做出自己的承诺。

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

对于交互式的基础,Git知道它只会在冲突时停止,因此它知道尝试进行提交,并抱怨没有什么可提交的。这是--keep-emptyor -k标志有用的地方。(在内部,非交互式案例使用,git format-patch并且git am默认情况下,尽管您可以强制它--preserve-merges例如与之一起使用交互式机制。在这里我提到这一点,因为这是Git必须知道您是否在“交互” 的实现原因:正如经常发生,这里的Git让执行规定的行为。如果Git的并不需要这种区别,一个--continue可以只使用交互式和非交互式底垫相同的代码,但Git的 需要区分,因此不会使用相同的代码。)

但是,对于交互式变基,Git 允许您在运行前git rebase --continue(情况二)在情况(2)中进行自己的提交。如果是这样,则该--continue步骤应仅继续进行下一次提交。因此,--continue只需检查现在是否有要提交的内容,而不是检查情况(1)与情况(2)之前的交互式重新基准是否已退出。这个简单的实现技巧可以启用该功能,但也意味着--keep-empty 无法在此工作:Git只是不知道区别。

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


Von*_*onC 5

\n

然而,因为我选择了这个--keep-empty选项,所以我仍然希望 rebase 中存在一个空提交,这将告诉我 A 如果存在的话,就会被修改。

\n\n

但显然,情况并非如此:

\n
\n\n

使用 Git 2.18(2018 年第 2 季度)仔细检查,考虑到git rebase --keep-empty如果另一方包含空提交(由于“ does an equivalent patch exist already?”检查), “”仍然会删除空提交,这一点已得到纠正

\n\n

请参阅Phillip Wood ( )提交的提交 3d94616提交 76ea235提交 bb2ac4f(2018 年 3 月 20 日)。\n (由Junio C Hamano 合并 -- --提交 d892bee中,2018 年 4 月 25 日)phillipwood
gitster

\n\n
\n

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

\n\n

如果左侧有空提交,$upstream...HEAD则我们要保留的右侧空提交将被 修剪--cherry-pick
\n 通过使用--cherry-mark而不是--cherry-pick保留空的或未标记为cherry-picks 的提交来修复此问题。

\n
\n\n

和:

\n\n
\n

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

\n
\n\n

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

\n\n
\n

如果变基--keep-empty没有--interactive--merge停止让\n 用户解决合并冲突,则 \' git rebase --continue\' 将失败。这是因为它使用不同的代码路径,不会创建$git_dir/rebase-apply.
\nrebase --keep-empty使用它实现时cherry-pick从未支持 am 选项,现在交互式变基支持--signoff,使用隐式交互式变基不会丢失功能。

\n
\n\n
\n\n

git rebase注意:这是Git 2.18 中添加的更大功能的一部分:
\n请参阅“ Git 的 \xe2\x80\x9c rebase --preserve-merges\xe2\x80\x9d 到底做了什么(以及为什么?) ”。
\n使用git --rebase-merges(最终将取代旧的git --preserve-merges),您现在可以在其他地方重新建立提交图的整个拓扑。

\n\n
\n\n

在 Git 2.27(2020 年第二季度)中,“ git rebase”(再次)学会尊重“ --no-keep-empty”,这让用户可以丢弃从一开始就为空的提交(而不是由于变基而变空的提交)。

\n\n
\n

交互式变基还empty标记todo.

\n
\n\n

请参阅Elijah Newren ( )的提交 50ed761提交 b9cbd29提交 1b5735f(2020 年 4 月 11 日)。\n (由Junio C Hamano 合并 -- --提交 c7d8f69中,2020 年 4 月 22 日)newren
gitster

\n\n
\n

rebase: 恢复 --no-keep-empty

\n\n

报告人:Bryan Turner
\n 报告人:Sami Boukortt
\n 签署人:Elijah Newren

\n\n

Commit d48e5e21da ("rebase (interactive-backend): make --keep-empty the default", 2020-02-15, Git v2.26.0-rc0 -- merge returned in batch #8 ) Turn --keep-empty(用于保留以空开头的提交) 进入默认值。

\n\n

该提交的逻辑基础是:

\n\n
    \n
  1. \' git commit\' 在创建没有覆盖标志的空提交时出错
  2. \n
  3. 一旦有人确定覆盖是值得的,要求他们采取额外的步骤以保留此类提交(并在每次变基时重复此类步骤)是令人烦恼和/或有害的。
  4. \n
\n\n

虽然做出决定的逻辑是合理的,但结果有点矫枉过正。

\n\n

它没有跳到成为--keep-empty默认行为,而是跳到了--keep-empty唯一可用的行为。

\n\n

不过,有一个简单的解决方法,当时被认为已经足够好了。

\n\n

人们仍然可以删除开始为空的提交,就像删除任何提交一样:通过启动交互式变基并从列表中挑选出他们不想要的提交。

\n\n

然而,在某些情况下,外部工具可能会创建足够多的空提交,将它们全部取出是很痛苦的。

\n\n

因此,拥有一个自动删除开始空提交的标志可能是有益的。

\n\n

为用户提供一种方法来删除使用存在多年的标志开始为空的提交:--no-keep-empty

\n\n

解释--keep-empty为撤销任何先前的--no-keep-empty,但否则保留--keep-empty为默认值。

\n\n

这可能会导致一些轻微的奇怪,因为命令如下:

\n\n
git rebase --empty=drop --keep-empty\ngit rebase --empty=keep --no-keep-empty\n
Run Code Online (Sandbox Code Playgroud)\n\n

尽管完全有道理,但看起来确实很奇怪(第一个将删除变空的提交,但保留开始为空的提交;第二个将保留变空的提交,但删除开始为空的提交)。

\n\n

然而,--no-keep-empty它是几年前命名的,我们主要保留它是为了向后兼容;我们还怀疑它只会很少使用,因为人们已经有了一种简单的方法来通过交互式变基来删除他们不想要的提交。

\n
\n