297

我弄乱了我的历史,想对它做一些改变。问题是,我有一个包含两个不相关更改的提交,并且这个提交被我的本地(非推送)历史记录中的一些其他更改所包围。

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

4

6 回答 6

454

在 rebase 手册页中有拆分提交的指南。快速总结是:

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

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

  • 增量添加更改并提交它们,根据需要进行尽可能多的提交。add -p仅在给定文件中添加一些更改可能很有用。如果commit -c ORIG_HEAD您想为某个提交重新使用原始提交消息,请使用。

  • 如果您想测试您正在提交的内容(好主意!),请使用git stash隐藏您尚未提交的部分(或stash --keep-index在您提交之前),测试,然后git stash pop将其余部分返回到工作树。继续提交,直到你提交所有修改,即有一个干净的工作树。

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

于 2010-11-29T19:14:53.997 回答
6

这是使用Magit的方法。

说 commit ed417ae 是您要更改的那个;它包含两个不相关的更改,并隐藏在一个或多个提交下。点击ll以显示日志,并导航到 ed417ae:

初始日志

然后点击r打开rebase弹出窗口

变基弹出窗口

m在此时修改提交。

注意@你想要拆分的提交现在是如何存在的——这意味着 HEAD 现在在那个提交上:

修改提交

我们想将 HEAD 移动到父级,因此导航到父级 (47e18b3) 并点击x( ,如果你正在使用,则magit-reset-quickly绑定到) 并输入说“是的,我的意思是在点提交”。您的日志现在应该如下所示:oevil-magit

重置后登录

现在,点击q进入常规 Magit 状态,然后使用常规 unstageu命令取消暂存第一次提交中未出现的内容,像往常一样提交c其余部分,然后标记sc省略第二次提交中的内容,完成后:点击r打开rebase弹出窗口

变基弹出窗口

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

所有完成的日志

于 2018-11-12T10:11:15.900 回答
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
    
于 2018-10-03T11:50:35.263 回答
1

如果您只想从一个文件中提取内容,则有一个更快的版本。它更快,因为交互式 rebase 实际上不再是交互式的(如果你想从最后一次提交中提取它当然更快,那么根本不需要 rebase)

  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 是单个操作:提交、即时修复

于 2019-11-06T21:39:40.103 回答
0

通过樱桃采摘手动更正历史记录也适用于某些情况。

我更喜欢使用我的 git GUI(而不是命令行),我的有问题的提交只有 3 次提交,我还没有推送任何,以下的也不是很整洁,所以我选择完全重建所有通过挑选它们,它比通过命令行使用交互式变基编辑更快,但方法相似。

以下是我在我最喜欢的 git GUI 中的做法(我个人使用 SourceTree):

  1. 在当前状态上创建一个标签,这样它就不会丢失。
  2. 现在您的实际本地分支指针移动到混乱的提交。
  3. 重置(混合)到前一个,以便保留(2)中提交的文件。
  4. 您现在可以通过暂存需要的文件并使用正确的消息提交,将提交拆分为两个或更多,直到没有未暂存的文件。
  5. Cherry 选择下一个提交(从您标记的历史中)。您可以通过右键单击所需的提交并选择“cherry pick”来执行此操作。转到(4),直到没有更多未计入的提交。
  6. 如果结果是你有一些最好压缩成一个的提交,请不要​​担心。您可以在 GUI 中使用可选的交互式变基来压缩它们。就像在混乱之前右键单击提交并单击“交互式变基”然后将提交相互拖动以压缩(修复提交消息以使其简单)一样简单,或者根据需要向上或向下移动它们。
  7. 删除在 (1) 中创建的标签。
于 2020-09-22T04:42:07.273 回答
-2

如果您还没有推送,只需使用git rebase. 更好的是,用于git rebase -i交互式地移动提交。您可以将有问题的提交移到前面,然后根据需要将其拆分并将补丁移回(如果需要)。

于 2010-11-29T19:11:36.280 回答