​ 最近在对OAS进行优化的时候,针对一些改动想给上游仓库提出PR(这是我第一次提PR)。对原仓库提出PR后,我继续对Fork出来的仓库进行改动,上周五原作者针对PR提出建议一次改太多了。我寻思着我也没改很多东西,然后打开Github,在提出的PR下方发现,它自动的最终了我后面的更改。这针对原作者的仓库进行合并无意是十分不友好的。通过冲浪发现Git摘樱桃可以提交个别的commit。

一、需求

  • 本地仓库作出了大量修改,但只想把个别提交发送给上游仓库;
  • 上游仓库有一些提交不适合你,你不想把它们一并合并到你的代码库中;
  • 你的项目是完全独立的,只想选择性地接受上游的部分提交。

二、选择个别提交到上游仓库

1.增加远端

在本地项目中增加远端,Git默认的远端仓库叫origin,实际上,它支持添加多个远端仓库。我们把上游仓库添加进来,取名为upstream

1
git remote add upstream <上游仓库地址>

注:请不要直接在上游仓库已存在的分支进行直接的更改,这是一个码喽应有的修养。如果你这样做了,请在所有操作之前将你的工作分支转移至一个新的分支,确保上游仓库的内容不会干扰你的工作分支。

2.根据上游分支建立patch分支

假设我们要同步的上游分支是master。首先把上游仓库同步到本地:

1
git fetch upstream

然后上游仓库master分支的基础上建立一个新的patch-1分支:

1
git checkout -b patch-1 upstream/master

**注意:**如果不事先使用git fetch,则git checkout的过程会失败,提示找不到分支upstream/master

3.找出要pull request的提交

这时就会自动切换到新分支patch_1中。我们可以先切换回本地的工作分支(如master):

1
git checkout master

然后浏览提交日志:

1
git log

在提交日志里,把你需要pull request的提交ID记录下来。下方提交日志的范例中,commit字样后面的十六进制文本就是提交ID,通常只记前七位就可以了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
commit b305a606dff60d9fc2371d3a70535cbedb449bfc (HEAD -> master, origin/master)
Author: AnClark <...>
Date: Tue Feb 9 17:52:39 2021 +0800

Update: 2021-02-09 17:02:39

commit 59435a4b0f3bf9b57ec4ad55a70a6eef6d79ad6b
Author: AnClark <...>
Date: Fri Dec 11 10:30:40 2020 +0800

Update: 2020-12-11 10:12:40

commit 8b442234891085a769f36debf21f0c46da5afb14
Author: AnClark <...>
Date: Thu Dec 10 07:42:45 2020 +0800

Update: 2020-12-10 7:12:45

4.git cherry-pick摘樱桃

这里假设要以上例中第二、第三个提交来发起pull request。

首先切换到patch-1分支:

1
git checkout patch-1

然后运行cherry pick,应用上述两个提交:

1
2
git cherry-pick 8b442234891085a769f36debf21f0c46da5afb14
git cherry-pick 59435a4b0f3bf9b57ec4ad55a70a6eef6d79ad6b

命令的输出结果如下所示,跟平时使用git commit的输出是一样的:

1
2
3
4
5
6
7
8
9
[patch-1 8b44223] Update: 2020-12-10  7:12:45
Date: Thu Dec 10 07:42:45 2020 +0800
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test.txt

[patch-1 59435a4] Update: 2020-12-11 10:12:40
Date: Fri Dec 11 10:30:40 2020 +0800
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 demo.html

注:这里可能会出现冲突,你需要解决所有的冲突,然后继续执行git cherry-pick。具体来说如下:通过git status查看存在冲突的文件,输入git diff在代码中生成冲突提示,之后根据冲突提示开始逐个文件解决冲突。之后直接在IDE中完成修改解决冲突,重新git add . 将解决冲突的文件进行添加,然后git cherry-pick --continue,提示成功即可。

5.推送分支

Cherry pick完成后,把patch-1分支推到GitHub上自己的fork:

1
git push origin patch-1

6.发起pull request

登录GitHub,然后像往常一样,从自己的仓库发起pull request。但要注意,你的仓库一侧用于比较的分支应该选择刚刚创建的patch-1分支

7.删除patch分支

如果上游仓库接受了你的pull request,你就可以把patch-1分支删除了:

1
2
3
4
5
6
7
8
# 首先确保不在patch-1分支中。Git不支持在一个分支里删除自己
git checkout master

# 删除本地分支,不会影响远程分支
git branch -D patch-1

# 删除远程分支
git push origin :patch-1

三、拣选上游仓库的提交

1.增加远端

在本地项目中增加远端,Git默认的远端仓库叫origin,实际上,它支持添加多个远端仓库。我们把上游仓库添加进来,取名为upstream

1
git remote add upstream <上游仓库地址>

注:请不要直接在上游仓库已存在的分支进行直接的更改,这是一个码喽应有的修养。如果你这样做了,请在所有操作之前将你的工作分支转移至一个新的分支,确保上游仓库的内容不会干扰你的工作分支。

2.拉取上游分支

然后从上游仓库拉取所需分支(如master)的内容,保存到本地。

首先,把上游仓库同步到本地:

1
git fetch upstream

然后,把上游仓库的master分支下载下来,保存到一个新分支master-upstream当中:

1
git checkout -b master-upstream upstream/master

拉取后就会自动切换到该新分支下,这样就可以像管理你的分支一样进行操作了,一些适用于本地分支的命令(如git mergegit diffgit cherry-pick)均可使用。

如果之前已经进行过上述步骤,则使用git pull更新本地的上游仓库:

1
git pull upstream master-upstream

3.找出要采用的提交

master-upstream分支下,查看提交记录:

1
git log

然后记下要采用的提交ID。

4.git cherry-pick摘樱桃

重新切换回你的仓库分支,然后使用git cherry-pick应用提交(以下提交ID为示例):

1
2
git checkout master
git cherry-pick <要采用的提交ID>

5.把修改推到你的仓库

完成之后,直接把你的提交推到远程仓库:

1
git push origin master