gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 13:30:27 25 4
gpt4 key购买 nike

我在使用 git rebase--keep-empty 选项时遇到了一些问题,我不确定我是否误解了此选项的作用,或者存在错误。

这是一个最小的例子:

设置

  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'
  2. 创建一个添加两个新文件的新提交。

    $ echo A >a.txt; echo B >b.txt
    $ git add a.txt b.txt
    $ git commit -m 'add A and B'
  3. 修改其中一个文件。

    $ echo A1 >a.txt
    $ git add a.txt
    $ git commit -m 'change A'
  4. 修改其他文件。

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

rebase

$ git checkout -b rebased master
$ git rebase --keep-empty -i :/base

…选择编辑添加了AB的提交,并更改它以便只有B 添加(在实际场景中,原因可能是 A 是 secret 的):

$ 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

...并完成 rebase :

$ 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

这不是 --keep-empty 应该做的,还是它不起作用正确吗?


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

最佳答案

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

当你运行 interactive rebase 并且它“暂停”时,实际上,它完成了,但留下了一些文件让 new git rebase 意识到它毕竟更像是一个延续。就目前而言,这很好;你将需要稍后运行 git rebase --continue 来开始一个新的 rebase 并告诉它:你不是新手,去阅读状态并表现得就像你在继续原来的 rebase 。

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

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

  1. 您将提交标记为“编辑”。它实际上提交了 cherry-pick,然后停下来让您修改提交或以其他方式大惊小怪。

  2. 或者,存在强制停止的问题(例如 merge 冲突)。

在情况 (1) 中,当您运行 git rebase --continue 时,Git 应该自己提交。

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

Git 可以,也许应该记录停止的原因,以便区分这两种情况……但它没有。相反,它只查看 --continue 上的状态。

对于交互式 rebase ,Git 知道它只在发生冲突时停止,所以它知道尝试提交,如果没有什么可提交则提示。这就是 --keep-empty-k 标志有用的地方。 (在内部,非交互式案例默认使用 git format-patchgit am,尽管您可以通过 --preserve 强制它使用交互式机制-merges 例如。我在这里提到这个是因为这是 Git 必须知道您是否正在“交互”的实现原因:正如经常发生的那样,Git 在这里让实现指示行为。如果 Git 不需要这种区别,--continue 可以只对交互式和非交互式 rebase 使用相同的代码,但是 Git 确实需要这种区别,因此不使用相同的代码。)

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

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

关于git - 交互式 rebase 后删除了空提交,即使使用了 --keep-empty,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45691594/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com