如果不创建一个分支并在一个新分支上做一堆奇怪的工作,那么在将一个提交提交到本地存储库之后,是否有可能将其分解为几个不同的提交?


当前回答

之前的回答已经介绍了使用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

将继续并完成重新启动操作。

其他回答

使用git-rebase--interactive编辑先前的提交,运行git-resetHEAD~,然后git-add-p添加一些,然后进行提交,然后再添加一些,再进行另一次提交,次数尽可能多。完成后,运行git rebase--continue,您将在堆栈中更早地获得所有拆分提交。

重要提示:请注意,您可以四处游玩并进行所有所需的更改,而不必担心丢失旧的更改,因为您可以始终运行git reflog来找到项目中包含所需更改的点(我们称之为a8c4ab),然后git重置a8c4aa。

下面是一系列命令来说明它的工作原理:

mkdir git测试;cd git测试;初始化

现在添加文件a

vi A

添加此行:

one

gitcommit-我是一个

然后将此行添加到A:

two

gitcommit-am二

然后将此行添加到A:

gitcommit-am三

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

one
two
three

我们的git日志如下所示(好吧,我使用的是git log--prett=oneline--prett=“%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

假设我们想将第二次提交分成两份。

git-rebase--交互式HEAD~2

这将显示如下消息:

pick 2b613bc two
pick bfb8e46 three

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

git重置HEAD~

gitdiff告诉我们,我们刚刚取消了第二次提交的提交:

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

让我们进行更改,并在文件a中的行中添加“和第三个”。

git添加。

这通常是在交互式rebase期间,我们将运行gitrebase--continue,因为我们通常只想回到提交堆栈中编辑先前的提交。但这一次,我们希望创建一个新的提交。所以我们将运行gitcommit-am“二加三”。现在我们编辑文件A,并添加第二行和第三行。

git添加。gitcommit-am“二分之二”git rebase—继续

我们的承诺有冲突,三,所以让我们解决它:

我们会改变的

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

to

one
two and a third
two and two thirds
three

git添加。;git rebase—继续

现在我们的gitlog-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

gitrebase——交互式可用于将提交拆分为较小的提交。关于rebase的Git文档对这个过程进行了简要的演练-拆分提交:

在交互模式下,您可以使用“编辑”操作标记提交。然而,这并不一定意味着gitrebase希望这次编辑的结果正好是一次提交。实际上,您可以撤消提交,也可以添加其他提交。这可用于将提交分为两部分:使用gitrebase-i<commit>^启动交互式rebase,其中<commit’是要拆分的提交。事实上,任何提交范围都可以,只要它包含该提交。使用“编辑”操作标记要拆分的提交。在编辑提交时,执行git-resetHEAD^。结果是HEAD被重绕了一圈,索引也随之改变。然而,工作树保持不变。现在,将更改添加到第一次提交时所需的索引中。您可以使用gitadd(可能以交互方式)或gitgui(或两者都使用)来实现这一点。使用现在合适的提交消息提交当前索引。重复最后两个步骤,直到工作树干净。使用git-rebase继续rebase--Continue。如果您不能绝对确定中间版本是否一致(编译、通过测试套件等),则应在每次提交、测试和修改提交后使用git stash来隐藏尚未提交的更改。

git rebase-我会做的。

首先,从一个干净的工作目录开始:git状态应该显示没有挂起的修改、删除或添加。

现在,您必须决定要拆分哪些提交。

A) 拆分最近的提交

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

$ git reset HEAD~

现在,以通常的方式单独提交这些片段,根据需要生成任意数量的提交。

B) 将提交拆分到更远的位置

这需要重新定基,即重写历史。要指定正确的提交,您有几个选项:

如果是三次提交,那么$git rebase-i头~3其中3是返回的提交数。如果它在树上比你想数的更远,那么$git rebase-i 123abcd~其中123abcd是要拆分的提交的SHA1。如果您位于要合并到主节点的其他分支(例如,要素分支)上:$git rebase-i主

当您获得rebase编辑屏幕时,找到您想要拆分的提交。在该行的开头,用edit(简称e)替换pick。保存缓冲区并退出。在您要编辑的提交之后,回扣将立即停止。然后:

$ git reset HEAD~

以通常的方式单独提交各个部分,根据需要生成多个提交。

最后

$ git rebase --continue

我是用rebase做的。编辑提交对我来说不起作用,因为它已经选择了提交文件并允许您对其进行修改,但我想将所有文件添加为未跟踪的文件,这样我就可以选择其中的一些文件。步骤如下:

git rebase-i HEAD~5(我想拆分我历史上第五次提交)复制目标提交ID(稍后需要)用d标记提交以删除它;在提交之后立即添加一行b,以停止重定基础过程,稍后继续。即使这是最后一次提交,这也为您提供了一些空间,让您只需git rebase——在发生错误时中止并重置所有内容。当重新定基达到断点时,使用gitcherry-pick-n<COMMIT ID>。这将在不选择提交本身的情况下选择提交更改,从而使其未被跟踪。在第一次提交时添加所需的文件(或使用gitadd-i和补丁,以便添加特定的块)提交您的更改。决定如何处理剩余的更改。在我的情况下,我希望他们在历史结束时,没有冲突,所以我做了git stash,但你也可以直接提交。gitrebase—继续选择其他更改

作为一个交互式数据库的超级粉丝,这是我能想到的最简单、最直接的一套步骤。我希望这对任何人都有帮助!

您可以执行交互式rebase git rebase-i。手册页完全符合您的要求:

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