如果不创建分支并在新分支上进行大量时髦的工作,是否有可能在将一个提交提交到本地存储库之后将其分解为几个不同的提交?
#1楼
使用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
,因为我们通常只想返回到提交堆栈中以编辑较早的提交。 但是这次,我们要创建一个新的提交。 因此,我们将运行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
#2楼
git rebase --interactive
可用于将提交拆分为较小的提交。 Rebase上的Git文档对该过程进行了简要的演练-拆分提交 :
在交互模式下,您可以使用操作“ edit”标记提交。 但是,这并不一定意味着
git rebase
希望此编辑的结果恰好是一次提交。 实际上,您可以撤消提交,也可以添加其他提交。 这可用于将提交分为两部分:
使用
git rebase -i <commit>^
启动交互式rebase,其中<commit>
是要拆分的提交。 实际上,任何提交范围都可以,只要它包含该提交即可。用操作“ edit”标记要拆分的提交。
在编辑提交时,执行
git reset HEAD^
。 结果是HEAD倒退了一个,索引也随之变化。 但是,工作树保持不变。现在,将更改添加到您希望在第一次提交中拥有的索引。 您可以使用
git add
(可能是交互方式)或git gui(或两者)来做到这一点。使用现在合适的提交消息来提交当前索引。
重复最后两个步骤,直到工作树干净为止。
继续使用
git rebase --continue
。如果您不确定中间版本是否一致(它们可以编译,通过测试套件等),则应在每次提交,测试和修订(如果有修正)后使用
git stash
存放尚未提交的更改。是必要的。
#3楼
从git-rebase手册(分割提交部分)
在交互模式下,您可以使用操作“ edit”标记提交。 但是,这并不一定意味着git rebase希望此编辑的结果恰好是一次提交。 实际上,您可以撤消提交,也可以添加其他提交。 这可用于将提交分为两部分:
使用
git rebase -i <commit>^
启动交互式rebase,其中<commit>
是要拆分的提交。 实际上,任何提交范围都可以,只要它包含该提交即可。用操作“ edit”标记要拆分的提交。
在编辑提交时,执行
git reset HEAD^
。 结果是HEAD倒退了一个,索引也随之变化。 但是,工作树保持不变。现在,将更改添加到您希望在第一次提交中拥有的索引。 您可以使用
git add
(可能是交互方式)或git gui
(或两者)来做到这一点。使用现在合适的提交消息来提交当前索引。
重复最后两个步骤,直到工作树干净为止。
继续使用
git rebase --continue
。
#4楼
没有交互性基准库,最简单的操作是(可能)在要拆分的分支之前先提交一个新分支,然后执行Cherry-pick -n提交,重置,存储,提交文件移动,重新应用存储和提交更改,然后与以前的分支合并,或者选择后续的提交。 (然后将以前的分支名称更改为当前的头。)(最好遵循MBO的建议并进行交互式的基准调整。)
#5楼
请注意,还有git reset --soft HEAD^
。 它类似于git reset
(默认为--mixed
),但保留索引内容。 这样,如果您添加/删除了文件,则它们已经在索引中了。
事实证明,在进行大型提交时非常有用。
#6楼
现在,在Windows上最新的TortoiseGit中,您可以非常轻松地完成此操作。
打开变基对话框,对其进行配置 ,然后执行以下步骤。
- 右键单击要拆分的提交,然后选择“
Edit
”(选择,压缩,删除...)。 - 点击“
Start
”开始重新设定基准。 - 一旦到达要拆分的提交,请选中“
Edit/Split
”按钮,然后直接单击“Amend
”。 提交对话框打开。 - 取消选择您要单独提交的文件。
- 编辑提交消息,然后单击“
commit
”。 - 直到有文件要提交,提交对话框才会一次又一次打开。 当没有更多文件要提交时,它仍然会询问您是否要添加一个提交。
非常有帮助,谢谢TortoiseGit!
#7楼
我认为最好的方法是使用git rebase -i
。 我创建了一个视频来展示拆分提交的步骤: https : //www.youtube.com/watch?v=3EzOz7e1ADI
#8楼
如果您有这个:
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
创建第一次提交(C):
git checkout B /modules/a
git add -u
git commit -m "content of /modules/a"
创建第二个提交(D):
git checkout B /modules/b
git add -u
git commit -m "content of /modules/b"
#9楼
先前的答案涵盖了使用git rebase -i
编辑要拆分的提交,并将其分部分提交的问题。
将文件拆分为不同的提交时,这种方法效果很好,但是如果您想将各个文件的更改分开,则需要了解更多信息。
到达要拆分的提交后,使用rebase -i
并将其标记为edit
,您有两个选择。
使用
git reset HEAD~
之后,使用git add -p
逐个浏览补丁,以在每次提交中选择所需的补丁编辑工作副本以删除不需要的更改; 提交临时状态; 然后拉回完整提交以进行下一轮。
如果要拆分大型提交,选项2很有用,因为它使您可以检查过渡版本在合并过程中是否正确构建和运行。 这进行如下。
使用rebase -i
并edit
提交后,请使用
git reset --soft HEAD~
撤消提交,但将提交的文件保留在索引中。 您也可以通过省略--soft来进行混合重置,具体取决于您的初次提交将接近最终结果。 唯一的区别是,是先进行所有已分阶段的更改,还是先进行所有未分阶段的更改。
现在进入编辑代码。 您可以删除更改,删除添加的文件以及执行想要构造的所有提交的所有操作。 您还可以构建,运行它,并确认您拥有一致的源集。
满意后,请根据需要git gui
/取消git gui
文件(为此,我喜欢使用git gui
),然后通过UI或命令行提交更改
git commit
那是第一次完成。 现在,您想将工作副本还原为拆分提交后的状态,以便您可以在下一次提交时进行更多更改。 要找到您正在编辑的提交的sha1,请使用git status
。 在状态的前几行中,您将看到当前正在执行的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 checkout
该提交的内容,该形式既包含提交又包含文件位置。 在这里我用.
作为替换整个工作副本的文件位置:
git checkout 65dfb6a .
不要错过最后的点!
这将签出并暂存文件,并按照您正在编辑的提交后的状态进行登台,但相对于您之前所做的提交,因此,您已经提交的所有更改将不属于提交。
您可以立即进行并按原样提交以完成拆分,也可以再次进行,删除提交的某些部分,然后再进行一次临时提交。
如果您想将原始提交消息重用于一个或多个提交,则可以直接从rebase的工作文件中使用它:
git commit --file .git/rebase-merge/message
最后,一旦您完成所有更改,
git rebase --continue
将进行并完成变基操作。
#10楼
已经超过8年了,但是也许有人会发现它对您有所帮助。 我能够在不使用rebase -i
。 这个想法是使git达到git commit
之前的状态:
# first rewind back (mind the dot,
# though it can be any valid path,
# for instance if you want to apply only a subset of the commit)
git reset --hard <previous-commit> .
# apply the changes
git checkout <commit-you-want-to-split>
# we're almost there, but the changes are in the index at the moment,
# hence one more step (exactly as git gently suggests):
# (use "git reset HEAD <file>..." to unstage)
git reset
此后,您将Unstaged changes after reset:
看到此闪亮的未Unstaged changes after reset:
并且您的存储库处于即将提交所有这些文件的状态。 从现在开始,您可以像平时一样轻松地再次提交它。 希望能帮助到你。
#11楼
您可以进行交互式rebase git rebase -i
。 手册页正是您想要的:
http://git-scm.com/docs/git-rebase#_splitting_commits
#12楼
首先,从一个干净的工作目录开始: git status
应该不显示任何挂起的修改,删除或添加。
现在,您必须确定要拆分的提交。
A)分割最近的提交
要拆分最近的提交,请首先:
$ git reset HEAD~
现在,以通常的方式分别提交片段,产生所需数量的提交。
B)进一步拆分提交
这需要重新定基础 ,即重写历史记录。 要找到正确的提交,您有几种选择:
如果是三次提交,那么
$ git rebase -i HEAD~3
3
是多少个提交。如果它在树中的距离比您想计算的要远,则
$ git rebase -i 123abcd~
其中
123abcd
是要拆分的提交的SHA1。如果您打算合并到母版中的其他分支(例如要素分支)上:
$ git rebase -i master
当您获得rebase编辑屏幕时,找到您想要分解的提交。 在该行的开头,将pick
替换为edit
(简称e
)。 保存缓冲区并退出。 Rebase现在将在您要编辑的提交之后停止。 然后:
$ git reset HEAD~
以通常的方式分别提交片段,生成所需数量的提交,然后
$ git rebase --continue