将以前的提交分成多个提交

如果不创build一个分支并在一个新的分支上进行一些时髦的工作,在一个提交被提交到本地存储库后,是否有可能将一个提交分成几个不同的提交?

git rebase -i会做到这一点。

要拆分最近的提交,首先:

 $ git reset HEAD~ 

现在按通常的方式分别执行这些部分,根据需要生成尽可能多的提交。

那么,如果它在树的后面

 $ git rebase -i HEAD~3 

其中3是多less提交它是。

那么,如果它在树的后面比你想要数的更远

 $ git rebase -i 123abcd^ 

其中123abcd是要分离的提交的SHA1。

当你得到分配编辑屏幕时,find你想分离的提交。 在该行的开始处,将pickreplace为edit (简称e )。 保存缓冲区并退出。 现在,Rebase将在您要编辑的提交之后停止。 然后:

 $ git reset HEAD~ 

然后以通常的方式单独提交这些作品,然后根据需要生成尽可能多的提交

 $ git rebase --continue 

从git-rebase手册(SPLITTING COMMITS部分)

在交互模式下,您可以使用“编辑”操作标记提交。 但是,这并不一定意味着git rebase期望这个编辑的结果只是一个提交。 事实上,您可以撤销提交,也可以添加其他提交。 这可以用来将一个提交分成两部分:

  • git rebase -i <commit>^开始一个交互式rebase,其中<commit>是你想要分割的提交。 实际上,只要包含该提交,任何提交范围都会执行。

  • 使用“编辑”操作标记要分割的提交。

  • 当编辑提交时,执行git reset HEAD^ 。 其效果是HEAD被倒回一个,索引也是如此。 但是,工作树保持不变。

  • 现在将更改添加到您想要在第一次提交中使用的索引中。 你可以使用git add (可能交互式地)或者git gui (或者两者)来做到这一点。

  • 用现在提交的任何提交消息来提交当前的索引。

  • 重复最后两个步骤,直到你的工作树干净。

  • git rebase --continue继续rebase – 继续。

使用git rebase --interactive编辑早期的提交,运行git reset HEAD~ ,然后用git add -p添加一些,然后进行提交,然后再添加一些提交,然后再进行一次提交,只要你喜欢。 当你完成后,运行git rebase --continue ,你将在堆栈中提前完成所有的分离提交。

重要提示 :请注意,您可以四处游戏并进行所有您想要的更改,而不必担心丢失旧的更改,因为您始终可以运行git reflog来查找项目中包含所需更改的点(让我们打电话它a8c4ab ),然后git reset a8c4ab

这里有一系列命令来显示它是如何工作的:

mkdir git-test; cd git-test; git init

现在添加一个文件A

vi A

添加这一行:

one

git commit -am one

然后将此行添加到A:

two

git commit -am two

然后将此行添加到A:

three

git commit -am three

现在文件A看起来像这样:

 one two three 

和我们的git log如下所示(好吧,我使用git log --pretty=oneline --pretty="%h %cn %cr ---- %s"

 bfb8e46 Rose Perrone 4 seconds ago ---- three 2b613bc Rose Perrone 14 seconds ago ---- two 9aac58f Rose Perrone 24 seconds ago ---- one 

假设我们想分割第二个提交, two

git rebase --interactive HEAD~2

这会产生一个如下所示的消息:

 pick 2b613bc two pick bfb8e46 three 

将第一个pick改为e以编辑该提交。

git reset HEAD~

git diff告诉我们,我们刚刚取消了我们为第二次提交所做的提交:

 diff --git a/A b/A index 5626abf..814f4a4 100644 --- a/A +++ b/A @@ -1 +1,2 @@ one +two 

让我们把这个改变,并在文件A添加“和第三”到该行。

git add .

这通常是交互式rebase中的一个地方,我们将运行git rebase --continue ,因为我们通常只想回到我们的提交栈来编辑早期的提交。 但是这一次,我们要创build一个新的提交。 所以我们将运行git commit -am 'two and a third' 。 现在我们编辑文件A并添加行two and two thirds

git add . git commit -am 'two and two thirds' git rebase --continue

我们与我们的承诺有冲突, three ,让我们来解决它:

我们会改变的

 one <<<<<<< HEAD two and a third two and two thirds ======= two three >>>>>>> bfb8e46... three 

 one two and a third two and two thirds three 

git add .; git rebase --continue

现在我们的git log -p如下所示:

 commit e59ca35bae8360439823d66d459238779e5b4892 Author: Rose Perrone <roseperrone@fake.com> Date: Sun Jul 7 13:57:00 2013 -0700 three diff --git a/A b/A index 5aef867..dd8fb63 100644 --- a/A +++ b/A @@ -1,3 +1,4 @@ one two and a third two and two thirds +three commit 4a283ba9bf83ef664541b467acdd0bb4d770ab8e Author: Rose Perrone <roseperrone@fake.com> Date: Sun Jul 7 14:07:07 2013 -0700 two and two thirds diff --git a/A b/A index 575010a..5aef867 100644 --- a/A +++ b/A @@ -1,2 +1,3 @@ one two and a third +two and two thirds commit 704d323ca1bc7c45ed8b1714d924adcdc83dfa44 Author: Rose Perrone <roseperrone@fake.com> Date: Sun Jul 7 14:06:40 2013 -0700 two and a third diff --git a/A b/A index 5626abf..575010a 100644 --- a/A +++ b/A @@ -1 +1,2 @@ one +two and a third commit 9aac58f3893488ec643fecab3c85f5a2f481586f Author: Rose Perrone <roseperrone@fake.com> Date: Sun Jul 7 13:56:40 2013 -0700 one diff --git a/A b/A new file mode 100644 index 0000000..5626abf --- /dev/null +++ b/A @@ -0,0 +1 @@ +one 

git rebase --interactive可以用来将提交拆分成更小的提交。 关于rebase的Git文档有一个简明的stream程演示 – 分裂提交 :

在交互模式下,您可以使用“编辑”操作标记提交。 但是,这并不一定意味着git rebase期望这个编辑的结果只是一个提交。 事实上,您可以撤销提交,也可以添加其他提交。 这可以用来将一个提交分成两部分:

  • git rebase -i <commit>^开始一个交互式rebase,其中<commit>是你想要分割的提交。 实际上,只要包含该提交,任何提交范围都会执行。

  • 使用“编辑”操作标记要分割的提交。

  • 当编辑提交时,执行git reset HEAD^ 。 其效果是HEAD被倒回一个,索引也是如此。 但是,工作树保持不变。

  • 现在将更改添加到您想要在第一次提交中使用的索引中。 你可以使用git add (可能交互式地)或者git gui(或者两者)来做到这一点。

  • 用现在提交的任何提交消息来提交当前的索引。

  • 重复最后两个步骤,直到你的工作树干净。

  • git rebase --continue继续rebase – 继续。

如果你不确定中间修订是否一致(它们编译,通过testing套件等),你应该使用git stash来在每次提交,testing和修改提交(如果修复)之后将尚未提交的更改存储起来是必要的。

你可以做互动rebase git rebase -i 。 手册页正是你想要的:

http://git-scm.com/docs/git-rebase#_splitting_commits

请注意,还有git reset --soft HEAD^ 。 它类似于git reset (默认为--mixed ),但是它保留了索引内容。 所以,如果你已经添加/删除文件,你已经在索引中。

在巨大的承诺的情况下变得非常有用。

以前的答案已经覆盖了使用git rebase -i来编辑你想要分割的提交,并在部分提交。

当将文件拆分成不同的提交时,这种方式很好,但是如果要分开更改单个文件,还需要了解更多内容。

有了你想要分裂的提交,使用rebase -i并将其标记为edit ,你有两个select。

  1. 使用git reset HEAD~之后,使用git add -p分别select你想要的补丁

  2. 编辑工作副本以删除不需要的更改; 犯下过渡状态; 然后再撤回下一轮的全部承诺。

如果您正在拆分大型提交,则选项2非常有用,因为它可以让您检查临时版本是否作为合并的一部分进行构build和正确运行。 这进行如下。

使用rebase -iedit提交后,使用

git reset --soft HEAD~

撤销提交,但将提交的文件留在索引中。 您也可以通过省略–soft来进行混合重置,具体取决于您最初的提交将会如何接近最终结果。 唯一的区别是你是从所有的变化开始还是全部变成未分阶段的。

现在进入并编辑代码。 您可以删除更改,删除添加的文件,并执行任何您想要构build您正在查找的系列的第一个提交。 您也可以构build它,运行它,并确认您拥有一组一致的源代码。

一旦你快乐,根据需要放置/取消文件的放置(我喜欢使用git gui ),并通过UI或命令行提交更改

git commit

这是第一次提交。 现在,您要将工作副本恢复到您分裂后的提交状态,以便您可以为下一次提交进行更多更改。 要find正在编辑的提交的sha1,请使用git status 。 在状态的前几行中,您将看到当前正在执行的rebase命令,您可以在其中find原始提交的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的forms来git checkout我的工作目录上的提交内容,它同时提交一个提交和一个文件位置。 我在这里使用. 作为replace整个工作副本的文件位置:

git checkout 65dfb6a .

不要错过最后的点!

这将检查并分阶段执行你正在编辑的提交之后的文件,但相对于你之前的提交,所以你已经提交的任何改变将不会是提交的一部分。

现在可以继续进行,直接完成拆分,或者再次执行,在进行另一个临时提交之前删除提交的某些部分。

如果你想重用一个或多个提交的原始提交信息,你可以直接从rebase的工作文件中使用它:

git commit --file .git/rebase-merge/message

最后,一旦你做了所有的改变,

git rebase --continue

将继续并完成重组工作。

现在在Windows上最新的TortoiseGit,你可以很容易地做到这一点。

打开rebase对话框,进行configuration ,然后执行以下步骤。

  • 右键单击要分割的提交,然后select“ Edit ”(在选取,压扁,删除…之间)。
  • 点击“ Start ”开始rebasing。
  • 一旦到达提交分裂,检查“ Edit/Split ”button,并直接点击“ Amend ”。 提交对话框打开。
    编辑/分割提交
  • 取消select要放在单独提交中的文件。
  • 编辑提交消息,然后单击“ commit ”。
  • 在提交文件之前,提交对话框将一次又一次地打开。 当没有更多的文件提交,它仍然会问你是否要添加一个提交。

非常有帮助,谢谢TortoiseGit!

最简单的事情是没有交互式rebase(可能是)在提交之前创build一个新的分支,然后select提交,重置,隐藏,提交文件移动,重新应用存储提交更改,然后与前一个分支合并,或者select后面的提交。 (然后把前面的分支名称改为当前的头)。(最好遵循MBO的build议,并做一个交互式分配。)

我认为这是我使用git rebase -i的最好方法。 我创build了一个video来显示拆分提交的步骤: https : //www.youtube.com/watch?v = 3EzOz7e1ADI

如果你有这个:

 A - B <- mybranch 

在提交B中提交了一些内容的地方:

 /modules/a/file1 /modules/a/file2 /modules/b/file3 /modules/b/file4 

但是你想把B分解成C – D,并得到这个结果:

 A - C - D <-mybranch 

你可以像这样分割内容(不同目录中的内容在不同的提交中)…

将分支重置回分割之前的提交:

 git checkout mybranch git reset --hard A 

创build第一个提交(C):

 git checkout B /modules/a git add -u git commit -m "content of /modules/a" 

创build第二个提交(D):

 git checkout B /modules/b git add -u git commit -m "content of /modules/b"