如果不创建一个分支并在一个新分支上做一堆奇怪的工作,那么在将一个提交提交到本地存储库之后,是否有可能将其分解为几个不同的提交?
当前回答
快速引用必要的命令,因为我基本上知道该做什么,但总是忘记正确的语法:
git rebase -i <sha1_before_split>
# mark the targeted commit with 'edit'
git reset HEAD^
git add ...
git commit -m "First part"
git add ...
git commit -m "Second part"
git rebase --continue
归功于埃马纽埃尔·贝尔纳的博客文章。
其他回答
请注意还有git reset-soft HEAD^。它类似于gitreset(默认为--mixed),但它保留了索引内容。因此,如果您添加/删除了文件,那么索引中已经有了这些文件。
事实证明,在大型犯罪的情况下非常有用。
之前的回答已经介绍了使用gitrebase-i来编辑要拆分的提交,并将其分部分提交。
当将文件拆分为不同的提交时,这很有效,但如果您想拆分对单个文件的更改,则需要了解更多信息。
使用rebase-i并将其标记为编辑,获得了要拆分的提交,您有两个选项。
使用git reset HEAD~后,使用git add-p逐个检查补丁,以选择每次提交所需的补丁编辑工作副本以删除不需要的更改;承诺该临时状态;然后收回下一轮的全部承诺。
如果要拆分大型提交,选项2很有用,因为它允许您检查临时版本是否作为合并的一部分正确构建和运行。这一过程如下。
使用rebase-i并编辑提交后,使用
git reset --soft HEAD~
撤消提交,但将提交的文件保留在索引中。您也可以通过省略--soft来进行混合重置,这取决于您的初始提交距离最终结果有多近。唯一的区别是您是从所有已暂存更改开始,还是从所有未暂存更改开始。
现在进入并编辑代码。您可以删除更改、删除添加的文件,并执行任何您想要构建的系列的第一次提交的操作。您还可以构建它,运行它,并确认您拥有一组一致的源代码。
一旦您满意,根据需要暂存/取消暂存文件(我喜欢使用gitgui),并通过UI或命令行提交更改
git commit
这是第一次提交。现在,您希望将工作副本恢复到提交后的状态,以便在下次提交时进行更多更改。要查找正在编辑的提交的sha1,请使用gitstatus。在状态的前几行中,您将看到当前正在执行的rebase命令,在其中可以找到原始提交的sha1:
$ git status
interactive rebase in progress; onto be83b41
Last commands done (3 commands done):
pick 4847406 US135756: add debugging to the file download code
e 65dfb6a US135756: write data and download from remote
(see more in file .git/rebase-merge/done)
...
在本例中,我正在编辑的提交具有sha1 65dfb6a。知道了这一点,我可以使用git checkout的形式在我的工作目录上检查该提交的内容,git checkback同时接受提交和文件位置。这里我用。作为替换整个工作副本的文件位置:
git checkout 65dfb6a .
不要错过最后的点!
这将在您正在编辑的提交后按原样检出和暂存文件,但与您之前提交的文件相比,因此您已经提交的任何更改都不会成为提交的一部分。
您可以现在继续并按原样提交以完成拆分,也可以再次进行,在进行另一次临时提交之前删除提交的某些部分。
如果您想在一次或多次提交中重用原始提交消息,可以直接从rebase的工作文件中使用它:
git commit --file .git/rebase-merge/message
最后,一旦您提交了所有更改,
git rebase --continue
将继续并完成重新启动操作。
我是用rebase做的。编辑提交对我来说不起作用,因为它已经选择了提交文件并允许您对其进行修改,但我想将所有文件添加为未跟踪的文件,这样我就可以选择其中的一些文件。步骤如下:
git rebase-i HEAD~5(我想拆分我历史上第五次提交)复制目标提交ID(稍后需要)用d标记提交以删除它;在提交之后立即添加一行b,以停止重定基础过程,稍后继续。即使这是最后一次提交,这也为您提供了一些空间,让您只需git rebase——在发生错误时中止并重置所有内容。当重新定基达到断点时,使用gitcherry-pick-n<COMMIT ID>。这将在不选择提交本身的情况下选择提交更改,从而使其未被跟踪。在第一次提交时添加所需的文件(或使用gitadd-i和补丁,以便添加特定的块)提交您的更改。决定如何处理剩余的更改。在我的情况下,我希望他们在历史结束时,没有冲突,所以我做了git stash,但你也可以直接提交。gitrebase—继续选择其他更改
作为一个交互式数据库的超级粉丝,这是我能想到的最简单、最直接的一套步骤。我希望这对任何人都有帮助!
gitrebase——交互式可用于将提交拆分为较小的提交。关于rebase的Git文档对这个过程进行了简要的演练-拆分提交:
在交互模式下,您可以使用“编辑”操作标记提交。然而,这并不一定意味着gitrebase希望这次编辑的结果正好是一次提交。实际上,您可以撤消提交,也可以添加其他提交。这可用于将提交分为两部分:使用gitrebase-i<commit>^启动交互式rebase,其中<commit’是要拆分的提交。事实上,任何提交范围都可以,只要它包含该提交。使用“编辑”操作标记要拆分的提交。在编辑提交时,执行git-resetHEAD^。结果是HEAD被重绕了一圈,索引也随之改变。然而,工作树保持不变。现在,将更改添加到第一次提交时所需的索引中。您可以使用gitadd(可能以交互方式)或gitgui(或两者都使用)来实现这一点。使用现在合适的提交消息提交当前索引。重复最后两个步骤,直到工作树干净。使用git-rebase继续rebase--Continue。如果您不能绝对确定中间版本是否一致(编译、通过测试套件等),则应在每次提交、测试和修改提交后使用git stash来隐藏尚未提交的更改。
大多数现有的答案都建议使用交互式rebase-git rebase-i或类似的方法。对于像我这样害怕“互动”的人来说,下楼梯时喜欢抓住扶手,这里有一个选择。
假设您的历史看起来像…->P–>Q–>R–>…–>Z=mybranch,并且您希望将P–>Q分成两个提交,以P–>Q1–>Q'–>R'–>…Z'=mybranch结束,其中Q'、R'等处的代码状态与Q、R等相同。
在开始之前,如果你是偏执狂,请备份我的分支,这样你就不会冒失去历史的风险:
git checkout mybranch
git checkout -b mybranch-backup
首先,签出P(要拆分的地方之前的提交),并创建一个新的分支来处理
git checkout P
git checkout -b mybranch-splitting
现在,从Q中签出您想要的任何文件,并根据需要进行编辑,以创建新的中间提交:
git checkout Q file1.txt file2.txt
[…edit, stage commit with “git add”, etc…]
git commit -m "Refactored the widgets"
请注意此提交的哈希值,如Q1。现在,在Q1的分离HEAD上检查Q的完整状态,提交这个(创建Q'),并将工作分支向上拉:
git checkout Q
git reset --soft Q1
git commit -m "Added unit tests for widgets"
git branch -f mybranch-splitting
您现在在Q'处执行mybranch拆分,它应该具有与Q完全相同的代码状态。现在将原始分支(从Q到Z)重设为:
git rebase --onto HEAD Q mybranch
现在,mybranch应该看起来像…P->Q1–>Q'–>R'–>…Z',正如您所希望的那样。因此,在检查所有工作正常后,可以删除工作分支和备份分支,并(如果合适)将重写的mybranch推到上游。如果它已经被推了,你需要强制推,所有关于强制推的常见警告都适用。
git push --force mybranch
git branch -d mybranch-splitting mybranch-backup
推荐文章
- 我应该在.gitignore文件中添加Django迁移文件吗?
- 错误:您对以下文件的本地更改将被签出覆盖
- Git rebase—即使所有合并冲突都已解决,仍然会继续报错
- 在Git中,我如何知道我的当前版本是什么?
- 跟踪所有远程git分支作为本地分支
- 自定义SSH端口上的Git
- git如何显示不存在于.gitignore中的未跟踪文件
- Git错误:遇到7个文件应该是指针,但不是
- GitHub克隆与OAuth访问令牌
- 移动(或“撤销”)最后一个git提交到非暂存区域
- 我可以在GitHub上对要点进行拉请求吗?
- Hg:如何做一个像git的rebase
- 如何丢弃远程更改并将文件标记为“已解决”?
- 如何查看远程标签?
- Git:在推送后删除提交的文件