git 重用提交 resue commit

git 中重用提交(reuse commit)主要有两种方式:一种是git cherry-pick(摘樱桃), 另一种是git patch(打补丁).

git cherry-pick

  1. 方式一:指定某个分支的提交id作为摘取的目标

    将一个分支上的某个commit合并到另一个分支,可用使用cherry-pick命令实现。
    比如将dev分支上commit_id为abcdefg1234567的提交合并到master分支:

    1. 切换到master分支:git checkout master
    2. 执行cherry-pick命令:git cherry-pick abcdefg1234567
    3. 推送到远程master仓库:git push

注意master上新的commit id与dev上的id并不相同,即只是将dev上的修改拷贝过来作为一个新的提交,这就会带来一个问题:cherry-pick之后,dev想再次merge到master,要先对dev分支进行rebase变基

  1. 方式二:指定某一个分支

    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