git 中重用提交(reuse commit)主要有两种方式:一种是git cherry-pick(摘樱桃), 另一种是git patch(打补丁).
git cherry-pick
-
方式一:指定某个分支的提交id作为摘取的目标
将一个分支上的某个commit合并到另一个分支,可用使用cherry-pick命令实现。
比如将dev分支上commit_id为abcdefg1234567的提交合并到master分支:- 切换到master分支:git checkout master
- 执行cherry-pick命令:git cherry-pick abcdefg1234567
- 推送到远程master仓库:git push
注意master上新的commit id与dev上的id并不相同,即只是将dev上的修改拷贝过来作为一个新的提交,这就会带来一个问题:cherry-pick之后,dev想再次merge到master,要先对dev分支进行rebase变基。
-
方式二:指定某一个分支
a - b - c - d Master \ e - f - g Feature
操作的步骤差不多雷同,同样是需要先切换分支,再次cherry-pick分之名即可
# 切换到 master 分支 $ git checkout master # Cherry pick 操作 $ git cherry-pick f
a - b - c - d - f Master \ e - f - g Feature
git cherry-pick在某些使用场景上和git merge比较相似,但是cherry-pick更强调某一个瞬间的摘取
git patch
git patch有不同的方案:主要分别是diff/apply方案,format-patch/am方案
为什么有了diff还要有format-patch呢?主要还是使用场景的不同:
- diff仅保留了文件重A状态变成B状态的差别,而不会保留commit记录消息等信息,而format-patch则是完整保留了每次提交的完成信息,这也解释了diff可以多个commit生成单个patch,而format-patch则是每个commit都生成一个patch文件。
- 两者是成对使用的,即git apply使用的补丁必须是git diff生成的;git am的补丁必须是git format-patch生成的。当然补丁检查都是用git apply –check/–stat。
# 生成补丁
git diff > commit.patch
# 检查补丁
git apply --check commit.patch
# 应用补丁
git apply commit.patch
diff本质上是对两个版本之间文件做数据比较得出差异,重点在于两个版本。没有指定任何版本,那默认就是对lastCommit和working copy之间作比较。
diff apply
希望把修改的内容生成patch,可以如下操作:
git diff > commit.patch
对于已经add但是未commit的修改:
git diff --cached > commit.patch
本地修改已commit,希望把最近一次的修改生成patch:
# 注意:commitId为倒数第二个提交ID
git diff commitId > commit.patch
生成patch文件后,我们切换到希望应用patch的分支,然后按下面的步骤操作:
# 检查patch是否可以应用
git apply --check commit.patch
# 打单个补丁
git apply commit.patch
# 打多个补丁
git apply ../patch/*.patch
format-patch am
# 生成patch
git format-patch -1
# 检查patch
git apply --check 0001-made-some-change.patch
# 应用patch
git am 0001-made-some-change.patch
# 当前分支所有超前master的提交
git format-patch -M master
# 某次提交以后的所有patch
git format-patch commitId
# 从根到指定提交的所有patch
git format-patch --root commitId
# 某两次提交之间的所有patch
git format-patch commitId1..commitId2
# 某次提交(含)之前的几次提交
# -n指patch数
git format-patch -n commitId
# 比如单次提交,生成commitId这次提交的patch
git format-patch -1 commitId
# 生成commitId前一次到commitId这两次修改的patch
git format-patch -2 commitId
git am可以一次合并一个文件,或者批量合并一个目录下所有的patch。在使用git am之前, 你要首先git am –abort一次,来放弃掉以前的am信息,这样才可以进行一次全新的am。不然会遇到这样的错误:
.git/rebase-apply still exists but mbox given.
单个补丁
# 先检查patch文件:
git apply --stat newpatch.patch
# 检查能否应用成功:
git apply --check newpatch.patch
# 打补丁:使用-s或--signoff选项,可以commit信息中加入Signed-off-by信息
git am --signoff < newpatch.patch
批量补丁
git am --abort
git am patch/*.patch