我该如何拆分历史记录中的Git提交?


292

我摸索了自己的历史,并希望对其进行一些更改。问题是,我的提交有两个不相关的更改,并且此提交被我的本地(非推送)历史记录中的其他一些更改所围绕。

我想在提交之前拆分此提交,但是我看到的大多数指南都与拆分最近的提交或未提交的本地更改有关。这样做对埋在历史中的提交进行此操作是否可行,而此后不必“重做”我的提交呢?


Answers:


450

在rebase联机帮助页中有一个拆分提交的指南。快速摘要是:

  • 执行包括目标提交(例如git rebase -i <commit-to-split>^ branch)在内的交互式变基,并将其标记为要编辑。

  • 当rebase到达该提交时,可使用git reset HEAD^来在提交之前重置为,但保持工作树完好无损。

  • 增量添加更改并提交,并根据需要进行任意数量的提交。add -p在给定文件中仅添加部分更改可能很有用。使用commit -c ORIG_HEAD,如果你想重新使用原来的提交信息有一定承诺。

  • 如果要测试要提交的内容(好主意!),git stash以隐藏未提交的部分(或stash --keep-index什至在提交之前),请进行测试,然后git stash pop将其余部分返回工作树。继续进行提交,直到完成所有修改为止,即拥有干净的工作树。

  • 运行git rebase --continue以在立即拆分的提交之后继续应用提交。


17
...但是如果您在提交拆分后就已经推送了历史记录,则不要执行任何操作。
wilhelmtell

29
@wilhelmtell:我省略了我通常的“潜在危险;请参阅'从上游变基中恢复'”样板,因为OP明确表示他没有推动这一历史。
卡斯卡贝尔

2
您读了很完美。当我指定尚未共享历史记录时,我试图避免使用“样板” :)无论如何,我对您的建议都取得了成功。事后做这件事是一个很大的痛苦。我在这里学到了一个教训,那就是确保从一开始就正确地提交提交!

2
第一步可能更好地表示为git rebase -i <sha1_of_the_commit_to_split>^ branch。而git gui对于拆分任务,可用于将一个文件的不同部分加入到不同的提交一个很好的工具。
徐强

3
@QiangXu:首先是一个合理的建议。第二个正是我建议的原因git add -p,它可以比git gui本部门做得更多(特别是编辑块,暂存从当前块开始的所有内容以及通过正则表达式搜索块)。
卡斯卡贝尔2012年

3

这是使用Magit的方法

假设ed417ae是您要更改的;它包含两个无关的更改,并被掩埋在一个或多个提交中。点击ll以显示日志,并导航到ed417ae:

初始日志

然后点击r打开变基弹出窗口

重新设置弹出窗口

m在点修改提交。

请注意,@您现在想拆分的提交上是如何存在的-这意味着HEAD现在位于该提交上:

修改提交

我们要将HEAD移到父级,因此导航到父级(47e18b3)并点击xmagit-reset-quicklyo如果使用的话,绑定到evil-magit),然后输入“是的,我的意思是在点提交”。您的日志现在应如下所示:

重置后记录

现在,打q去正规Magit状态,然后使用常规的unstage u命令unstage什么不会在第一次提交去,提交c其余像往常一样,然后s踏歌而commit发生的事情在第二次提交,并在完成后:点击r打开重新设置弹出窗口

重新设置弹出窗口

另一个r继续,您就完成了!ll现在显示:

全部完成日志


1

要拆分提交<commit>在此提交之前添加新提交,并保存作者的日期<commit>,请执行以下步骤:

  1. 之前编辑提交 <commit>

    git rebase -i <commit>^^
    

    注意:也许也需要编辑<commit>

  2. 樱桃入选<commit>指数

    git cherry-pick -n <commit>
    
  3. 以交互方式重置索引中不需要的更改并重置工作树

    git reset -p && git checkout-index -f -a
    

    另外,也可以交互地存储不需要的更改: git stash push -p -m "tmp other changes"

  4. 进行其他更改(如果有)并创建新的提交

    git commit -m "upd something" .
    

    (可选)重复项目2-4以添加更多中间提交。

  5. 继续重新定基

    git rebase --continue
    

0

如果您只想从一个文件中提取内容,则有一个更快的版本。之所以更快,是因为交互式变基实际上不再是交互式的(而且,如果您想从上一次提交中提取内容,那么它甚至更快,那么根本就不需要变基)

  1. 使用编辑器并删除要从中提取的行the_file。关闭the_file。那是您唯一需要的版本,其余的只是git命令。
  2. 在索引中进行该删除:

    git  add  the_file
    
  3. 将刚删除的行恢复到文件中,而不会影响索引

    git show HEAD:./the_file > the_file
    
  4. “ SHA1”是您要从中提取行的提交:

    git commit -m 'fixup! SHA1' 
    
  5. 创建第二个全新提交,其内容要提取到步骤3中还原的内容:

    git commit -m 'second and new commit' the_file 
    
  6. 不要编辑,不要停止/继续-只接受所有内容:

    git rebase --autosquash -i SHA1~1
    

当然,如果要提取的提交是最后的提交,则速度更快:

4. git commit -C HEAD --amend
5. git commit -m 'second and new commit' thefile
6. no rebase, nothing

如果使用,magit则第4、5和6步是单个操作:提交,即时Fixup


-2

如果尚未推送,请使用git rebase。更好的是,用于git rebase -i以交互方式移动提交。您可以将有问题的提交移至最前面,然后根据需要将其拆分,然后将补丁移回(如果需要)。


14
无需将其移动到任何地方。拆分它在哪里。
卡斯卡贝尔

1
不幸的是,这对我不起作用,因为提交后的某些历史记录依赖于此,因此我受到一些限制。但是,这将是我的首选。

@Ben:没关系-此后的提交完全不需要更改(假设您保留所有更改,而不是将其中一些更改丢弃)。这里更多信息- stackoverflow.com/questions/1440050/...
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.