在rebase和force push

时间:2018-01-10 08:35:47

标签: git command-line windows-10 git-rebase

在另一个分支上重新分支后,我遇到了一个有趣的问题; git rebase -i HEAD~n不仅显示错误的提交历史(旧分支),还显示错误的提交量。

我想做什么

我希望能够在正确的提交历史记录上执行git rebase -i HEAD~n,以便从基于我的分支的旧分支中压缩剩余的提交。

我做了什么导致问题

# On another Feature branch
git branch -b NewFeautureBranch
# Develop my commit
git add editedfile.extension
git commit -m "Commit message"
# I squashed and merged the feature branch into the development branch, as well as some other feature branches
git fetch --all
git checkout DevelopmentBranch
git pull
git checkout NewFeatureBranch
git rebase DevelopmentBranch
git push -f

运行git loggitk将显示应该的历史记录,这是我当前的提交以及它最初基于的功能分支的旧提交,正如预期的那样。但是,如果我然后运行git rebase -i HEAD~4,我会得到旧分支的历史记录以及11个提交,而不是我要求的4个:

# Git rebase -i HEAD~4 opens up in VIM like this:
pick f79316dc Commit on old Branch base
pick ba742f2f Commit on old Branch base
pick 7577ea7a Commit on old Branch base
pick 91c4088c Commit on old Branch base
pick 98feed6d Commit on old Branch base
pick e8a73d78 Commit on old Branch base
pick 198f79e7 Commit on old Branch base
pick 10bb699c Commit on old Branch base
pick 1d15a926 Commit on old Branch base
pick 0cf569bb Previous commit I want to squash with
pick 470de8d9 Current FeatureBranch commit

git log打印出来:

# As it should be when seeing git log and gitk
commit 470de8d92bb490dd14c31d5741b7edec82ca7597 (HEAD -> FeatureBranch, origin/FeatureBranch)
Author: evFox <evFox@fake-email.com>
Date:   Wed Jan 3 16:08:24 2018 +0100
    Feature commit message

commit 0cf569bba43b5747831a28d6cb42209dab1c2ffa
Author: evFox <evFox@fake-email.com>
Date:   Wed Jan 3 12:09:48 2018 +0100
    Feature from old branch still relevant to this; what I want to merge with the later commit.

commit 982c30d9c3b46539340fe48c241192e377d3e136 (origin/Development, Development)
Merge: ab6e7c9d 1d15a926
Author: evFox <evFox@fake-email.com>
Date:   Tue Jan 9 10:51:06 2018 +0000
    Merged PR XX: Merge OldFeatureBranch to Development

我尝试了什么

我尝试在本地删除分支,并从远程存储库中删除一个新分支:

git checkout DevelopmentBranch
git branch -D NewFeatureBranch
git checkout -b NewFeatureBranch origin/NewFeatureBranch

我试图通过增加git rebase -i中的提交来获取更多历史记录,我可以清楚地看到提交已经过时,属于OldFeatureBranch,就像它更新和合并之前一样:

# Git rebase -i HEAD~20 opens up in VIM like this:
pick bt67f432 Commit on old version DevelopmentBranch
pick 5g67f33s Commit on old version DevelopmentBranch
pick rt53d563 Commit on old version DevelopmentBranch
pick ew5r45fg Commit on old version DevelopmentBranch
pick 9gy3f74f Commit on old version DevelopmentBranch
pick 58u5hh63 Commit on old version DevelopmentBranch
pick 34fdg5d5 Commit on old version DevelopmentBranch
pick n678hcn7 Commit on old version DevelopmentBranch
pick mh7y88dr PR merge of DevelopmentBranch where old Branch base were branched out originally, but not where DevelopmentBranch was when old Branch Base was squashed and merged.
pick f79316dc Commit on old Branch base
pick ba742f2f Commit on old Branch base
pick 7577ea7a Commit on old Branch base
pick 91c4088c Commit on old Branch base
pick 98feed6d Commit on old Branch base
pick e8a73d78 Commit on old Branch base
pick 198f79e7 Commit on old Branch base
pick 10bb699c Commit on old Branch base
pick 1d15a926 Commit on old Branch base
pick 0cf569bb Previous commit I want to squash with
pick 470de8d9 Current FeatureBranch commit

但问题仍然存在。

可能的解决方法

我想我可以尝试进行软复位并修改我想要压缩的提交:

git reset --soft HEAD~1

但这并不能解决我目前使git rebase -i HEAD~n历史搞砸的问题。

3 个答案:

答案 0 :(得分:0)

  

然而,如果我然后运行git rebase -i HEAD~4我得到旧分支的历史记录以及11个提交而不是我要求的4个:

您的一个提交是合并。每当您尝试squash [交互式rebase]时,您将获得所有提交。如果中间有合并,您将获得此合并的所有提交。

答案 1 :(得分:0)

我刚遇到此问题,结果我将编辑器保持打开状态,所以每当我执行重新设置基准时,它都会将其打开到我从先前的重新设置基准开始仍然运行的缓冲区。要解决此问题,只需关闭编辑器窗口或终止该过程。

答案 2 :(得分:0)

  

我刚遇到此问题,结果我将编辑器保持打开状态,所以每当我运行重新设置基准时,它都会将其打开到我从先前的重新设置基准开始仍然运行的缓冲区。

此问题已在Git 2.24(2019年第四季度)中得到修复。
之前,“ git rebase -i”打开编辑器时显示错误的HEAD,如discussed here

请参见commit b0a3186commit a47ba3ccommit 450efe2Phillip Wood (phillipwood)(2019年8月19日)。
(由Junio C Hamano -- gitster --commit 4608a02中合并,2019年10月11日)

  

rebase -i:始终在重写单词之前更新HEAD

     

如果用户在重新提交提交时运行reword,是否有时我们正在修改正在重新编写措辞的提交,而在其他时候根据是否可以快速转发来创建新的提交,则令人困惑是否。
  通过始终提交所选择的提交,然后运行'git log'来进行改写,可以解决此不一致的问题。

     

第一次提交是由定序器执行的,不会分叉git commit --amend,并且不会影响重新设置的速度。
  在测试中改写100次提交

git commit
     

并采取了三个运行中的最佳选择,当前的主设备花费了957ms,而使用此补丁花费了961ms。

     

此更改修复了用GIT_EDITOR=true GIT_SEQUENCE_EDITOR='sed -i s/pick/reword/' \ ../bin-wrappers/git rebase -i --root 重新排列提交时重新措辞新的根提交的问题。

     

请注意,创建根提交后,新代码不再更新--root-我不确定为什么旧代码是在成功提交后创建引用,而其他所有地方在成功提交后都会被删除


它还改进了git rebase的C版本:

  

CHERRY_PICK_HEAD:在rebase -itodo

之后检查更新的squash      

虽然用户停止了rebase来编辑提交消息,但是对于他们来说,也方便编辑reword列表。
  rebase的脚本版本支持此功能,但C版本不支持。

     

我们已经检查了todo命令是否已更新todo列表,因此将其扩展到了改写词和南瓜。
  只需执行一次stat调用即可,这样就不会影响重新设置的速度(尤其是因为它刚刚停止供用户编辑消息)

     

请注意,对于壁球,当我们在链固定和壁球结束时编辑消息时,编辑器可能会以与壁球本身不同的方式打开。


但是最近的修复还包括一个回归:在对多个提交运行“ exec”或“ revert”时,最近的回归错误地检测到“什么也没提交,工作树干净”,而不是重播提交内容,已通过Git 2.25(2020年第1季度)更正。

请参见commit befd4f6SZEDER Gábor (szeder)(2019年11月23日)。
(由Junio C Hamano -- gitster --commit f233c9f中合并,2019年12月6日)

  

sequencer:请勿重读cherry-pick --edittodo的{​​{1}}

     

举报人:Brian Norris
  签名人:SZEDERGábor

     

在多次提交中调用“ revert”或“ cherry-pick”时,在完成第一个提交消息的编辑之后,这两个命令应继续处理第二个提交并为其启动另一个编辑器当然,如果没有冲突,则提交消息。

     

A,这无意间被commit a47ba3c777更改(“ git revert:在git cherry-pick --editrebase -i之后检查更新的todo”,2019-08-19, Git v2.24.0-rc0-merge中列出的batch #8):编辑完第一条提交消息后,“ squash”和“ reword”都退出,并显示错误,声称“什么也没做,工作正常”。

     

更改行为的原因有两个:

     
      
  • commit a47ba3c777之前,git revert列表文件的最新性仅在'git cherry-pick --edit'指令之后才被检查,并且提交将这些检查移到了通用代码路径。
      目的是在指令产生编辑器(“ todo”和“ exec”之后也应执行此检查,因此当用户运行程序时,正在进行的“ squash”会通知您压缩/重新编写提交消息时使用“ reword”。
  •   
     

但是,碰巧的是,即使在涉及编辑提交消息的'rebase -i和'git rebase --edit-todo'指令之后,现在仍会执行检查。
  默认情况下,“ revert”而(可选)“ pick”(带有“ revert”)涉及编辑提交消息。

     
      
  • 在多次提交中调用“ pick”或“ git cherry-pick --edit”时,它们不会读取git revert列表文件,而是会在内存中汇编git cherry-pick --edit列表,因此用于检查文件是否已更新的关联todo数据最初全部清零。
  •   
     

然后,定序器将所有指令(包括第一条指令)写入todo文件,执行第一条'todo'指令,并在用户完成对提交消息的编辑之后,将a47ba3c777的更改踢入,检查stat文件是否已被修改。
  初始全零状态数据显然与revert/pick文件的当前todo数据不同,因此定序器得出的结论是该文件已被修改。
  从技术上讲,这当然没有错,因为文件确实是由音序器本身编写的,尽管文件的内容仍然与开头调用音序器的内容匹配。

     

因此,在重新读取todo文件之后,定序器再次执行相同的第一条指令 ,因此最终陷入了“无可奉告”的境地。

     

在多次提交“ stat”或“ todo”操作期间,从未打算编辑todo列表,因此请执行“已将git revert文件已修改”,仅在将序列器作为交互式资源库的一部分调用时检查。


使用Git 2.25(2020年第一季度),它减少了在定序器操作期间从磁盘读回不必要的状态变量的情况。

这也说明了在重新定级期间“定序器”的作用。

请参见commit 393adf7commit a2dd67fcommit 3f34f2dcommit 3406554commit 8638114Alban Gruin (agrn)(2019年11月24日)。
(由Junio C Hamano -- gitster --commit 37c2619中合并,2019年12月16日)

  

sequencer:直接从cherry-pick呼叫todo

     

签名人:Alban Gruin

     

当前,builtin/rebase.c使用pick_commits()来启动新的变基,调用complete_action()来完成。

     

在前者调用complete_action()之前,它是:

     
      
  • 拨打sequencer_continue() -在这里没有必要,因为我们刚刚在pick_commits()中叫过read_and_refresh_cache()
  •   
  • 调用require_clean_work_tree() -在我们开始新的基准库时这是不必要的,因此'opts'已完全填充
  •   
  • 加载complete_action()列表-这是不必要的,因为我们刚刚在read_populate_opts()中填充了待办事项列表
  •   
  • 提交任何分阶段的更改-在我们开始新的基准库时这是不必要的,因此没有分阶段的更改
  •   
  • 调用todo -在我们开始新的基准测试时,这是不必要的。
  •   
     

这将complete_action()更改为直接调用record_in_rewritten(),以避免这些不必要的步骤。