我目前正在开发一个分支,并希望将一些提交合并到其他分支中:
a-b-c-d-e-f-g (branchA)
/
--o-x-x-x-x-x-x-x-x-x-x (master)
\
x-x-x-x-x (branchB)
(字母表示提交,“x”是不相关的提交。)
但是我注意到汇总一些提交是个好主意。我想“连接”将a,d,e和g提交到一个补丁中并将其提交给master。提交b和f应该作为一个提交到branchB。是否有一种良好的'git'方法来实现它?
答案 0 :(得分:96)
您要查找的命令是git rebase
,特别是-i/--interactive
选项。
我将假设您希望将commit c保留在分支A上,并且您确实意味着您希望将其他提交移动到其他分支,而不是合并,因为合并很简单。让我们从操纵分支A开始。
git rebase -i <SHA1 of commit a>^ branchA
^
表示先前的提交,因此该命令表示使用“a”之前的提交作为基础来修改分支A. Git将向您显示此范围内的提交列表。重新排序并告诉git压缩适当的:
pick c ...
pick a ...
squash d ...
squash e ...
squash g ...
pick b
squash f
现在历史应该是这样的:
c - [a+d+e+g] - [b+f] (branchA)
/
--o-x-x-x-x-x-x-x-x-x-x (master)
现在,让我们抓住branchB的新压缩提交b + f。
git checkout branchB
git cherry-pick branchA # cherry-pick one commit, the tip of branchA
对于主人的+ d + e + g也一样:
git checkout master
git cherry-pick branchA^
最后,更新branchA,使其指向c:
git branch -f branchA branchA^^
我们现在应该:
c (branch A) - [a+d+e+g] - [b+f] (dangling commits)
/
--o-x-x-x-x-x-x-x-x-x-x-[a+d+e+g] (master)
\
x-x-x-x-x-[b+f] (branchB)
请注意,如果您想要在分支之间移动多个提交,则可以再次使用rebase(非交互式):
# create a temporary branch
git branch fromAtoB branchA
# move branchA back two commits
git branch -f branchA branchA~2
# rebase those two commits onto branchB
git rebase --onto branchB branchA fromAtoB
# merge (fast-forward) these into branchB
git checkout branchB
git merge fromAtoB
# clean up
git branch -d fromAtoB
最后,免责声明:很有可能以某种方式对提交进行重新排序,使某些提交不再适用。这可能是因为您选择了一个错误的订单(在提交引入其修补的功能之前放置一个补丁);在这种情况下,您将要中止rebase(git rebase --abort
)。否则,您将必须智能地修复冲突(就像您对合并冲突一样),添加修复程序,然后运行git rebase --continue
继续。冲突发生时打印的错误消息也提供了这些说明。
答案 1 :(得分:3)
如果您想重新排序最后两次提交,可以使用find . -iname "*foo*" | fgrep -i "foo"
别名:https://stackoverflow.com/a/33388211/338581
答案 2 :(得分:2)
git rebase -i HEAD~3
3
是需要重新排序的提交数(source)。
这将打开vi,列出从最旧(顶部)到最新(底部)的提交。
现在,重新排序行,保存,并退出编辑器。
ddkP
会将当前行上移(source)
ddp
将当前行下移
答案 3 :(得分:0)
git rebase --interactive
是你想要的命令。
示例:
目前的状态如下:
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git status
On branch master
nothing to commit, working tree clean
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git log --oneline
a6e3c6a (HEAD -> master) Fourth commit
9a24b81 Third commit
7bdfb68 Second commit
186d1e0 First commit
我想重新提交提交9a24b81
(第三次提交)和7bdfb68
(第二次提交)。为此,我首先在我们想要更改的第一次提交之前找到提交 。这是提交186d1e0
(第一次提交)。
要执行的命令是git rebase --interactive COMMIT-BEFORE-FIRST-COMMIT-WE-WANT-TO-CHANGE
,在这种情况下:
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git rebase --interactive 186d1e0
这将在默认编辑器中打开一个文件,其中包含以下内容:
pick 7bdfb68 Second commit
pick 9a24b81 Third commit
pick a6e3c6a Fourth commit
# Rebase 186d1e0..a6e3c6a onto 186d1e0 (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
请注意,文件中提交的顺序与git log使用的顺序相反。在git log中,最新的提交位于顶部。在此文件中,最近的提交位于底部。
正如文件底部的注释所解释的,我可以做各种各样的事情,比如压缩,删除和重新排序提交。要重新提交提交,我编辑文件使其看起来像这样(底部注释未显示):
pick 9a24b81 Third commit
pick 7bdfb68 Second commit
pick a6e3c6a Fourth commit
每行开头的pick
命令意味着“使用(即包含)此提交”,当我使用rebase命令保存临时文件并退出编辑器时,git将执行命令并更新存储库和工作目录:
$ git rebase --interactive 186d1e0
Successfully rebased and updated refs/heads/master.
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git log --oneline
ba48fc9 (HEAD -> master) Fourth commit
119639c Second commit
9716581 Third commit
186d1e0 First commit
请注意重写的提交历史记录。
链接:
答案 4 :(得分:0)
git rebase就是你想要的。查看--interactive选项。