Github提交代码及冲突处理

Creative Commons
本作品采用知识共享署名

本文简要说明如何对github上的项目进行代码提交

当要向github上的开源项目提交代码时,一般遵循下面的流程:
本地化仓库(只做一次):fork项目->下载->配置upstream
修改提交(一个分支做一次):建立分支->修改代码->提交分支->创建PR
Review修改(循环该过程):Review/CI验证->从upstream更新代码->本地修改->再次提交

下面已mcuboot为例说明一下整个流程,本文假设使用者已了解git的操作,已流程说明为主。

本地化仓库

当你要为一个使用已久的一个开源项目共享时,例如添加一个新功能或是修正一个bug,首先需要将整个项目仓库一次下载到本地,并设置这个项目仓库的回流仓库(upstream),这个过程只用做

fork项目

在浏览器中打开要准备共享的项目https://github.com/JuulLabs-OSS/mcuboot,点击右上角的fork
fork
mcuboot将会被fork到你的账号下https://github.com/lgl88911/mcuboot,点击绿色的"Clone or download”可以获取仓库地址https://github.com/lgl88911/mcuboot.git
done

下载

通过下面命令下载mcuboot的代码

1
git clone https://github.com/lgl88911/mcuboot.git

下载后执行git remote -v,可以看到

1
2
origin	https://github.com/lgl88911/mcuboot.git (fetch)
origin https://github.com/lgl88911/mcuboot.git (push)

origin是你自己的repo,你的所有操作都是在origin repo上发生的。

配置upstream

upstream是用来拉取最新的代码,可以将upstream的代码sync到origin上,通过下面命令添加当前仓库的upstream

1
git remote add upstream https://github.com/JuulLabs-OSS/mcuboot.git

设置之后执行git remote -v可以看到

1
2
3
4
origin	https://github.com/lgl88911/mcuboot.git (fetch)
origin https://github.com/lgl88911/mcuboot.git (push)
upstream https://github.com/JuulLabs-OSS/mcuboot.git (fetch)
upstream https://github.com/JuulLabs-OSS/mcuboot.git (push)

修改提交

当有了代码仓库后就可以进行修改了,修改时是建立分支,在分支中修改,然后提交分支,将分支向upstream/master merge,一般来说一个bug或者一个新功能只需要建立一次分支只

建立分支

首先确保你的项目处于origin/master分支, 执行git branch,如果看到如下说明是处于origin master下

1
2
frank@:~/work/build/upload/mcuboot$ git branch
* master

在master下执行下面命令,将以master为基础建立出一个test_branch分支,并自动且到该分支下

1
git checkout -b test_branch

修改提交

创建好分支后,就可以修改并测试你的代码。确认代码已经修改完备就可以通过下面命令提交

1
2
3
git add .
git commit -s
git push origin test_branch

有注意到commit时加-s了吗,这会在commit信息中自动加入签名信息,一般项目都会有这个要求,如果不加提交PR后CI检查不过

创建pr

当用git push将分支提交到github后,此时去访问upstream地址https://github.com/lgl88911/mcuboot会提示你有新的branch,点击绿色的"Comapre & pull request”就可以提交PR了
pr

Review修改

一旦PR提交后,项目一般都会有自动的CI(continuous-integration)检查, 如果检查fail需要本地修改并提交,检查过了之后就会有人工review代码,提出修改意见,你需要根据修改意见进行修改或者讨论说明不修改的原因,这个过程将可能执行几次,直到reviewer merge为止

CI/Review检查

不同的项目会检查不同的CI检查内容,诸如commit格式,代码格式,license,自动化编译,自动化测试等等。下面是一个CI检查完但reviewer还没继续检查的状态:
cireview
人工检查通常会对代码修改的功能和方法提出询问和建议,然后根据建议进行修改。无论是根据CI还是人工检查的结果进行修改,都需要先回到本地,在本地分支修改,修改测试完后使用下面命令再次提交

1
2
3
git add .
git commit --amend
git push origin test_branch --force

可以看到这次commit使用了–amend的参数,这是因为一般项目一个分支merge后不希望产生多笔commit记录,–amend只是对上一次提交进行修改,因此不会新产生commit记录。在push的时候是用了–force,也是为了配合只更新commit。
当CI和reviewer通过检查后,代码的owner(通常是reviewer中的一个)会merge代码,到此你的修改就完成了,这个连接就一个已经merge了的branch,有兴趣可以看看https://github.com/zephyrproject-rtos/zephyr/pull/18817

从upstream更新

如果一个pr review过程比较长,此时upstream master的代码可能已经更新过多次,这就需要同步代码到origin的branch并merge测试

master代码同步

通过下面命令进行upstream和origin同步, 第一个动作是从upstream拉取最新的代码,第二个动作是将upstream/master的代码同步给origin/master

1
2
git pull upstream
git merge upstream/master master

branch代码更新

前一个步骤只是保证了你仓库内的master是最新的,test_branch分支中还是老代码,但分支的老代码中又包含了你的修改,这里就要将master中的代码合并到test_branch中去,一般情况下我们都是想到将master merge到test_branch, 但这会让最后提交顺序显得混乱(当然也不排除有工作流会这样做)。我在github上遇到的项目都是使用rebase的方式,命令如下

1
2
git checkout test_branch
git rebase master

此时git会自动merge 将test_branch的基点拉到master的HEAD,并将test_branch的几笔commit merge到HEAD之后产生新的commit,当然事情不总是一帆风顺,因此master中有新的代码,可能会和test_branch中的修改产生冲突,如下示例:

1
2
3
4
5
uto-merging boot/zephyr/Kconfig
CONFLICT (content): Merge conflict in boot/zephyr/Kconfig
Auto-merging boot/bootutil/include/bootutil/bootutil_log.h
CONFLICT (content): Merge conflict in boot/bootutil/include/bootutil/bootutil_log.h
error: Failed to merge in the changes.

去产生冲突的文件中修改冲突,如下示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<<<<<<< HEAD

# Workaround for not being able to have commas in macro arguments
DT_CHOSEN_Z_CONSOLE := zephyr,console

config RECOVERY_UART_DEV_NAME
string "UART Device Name for Recovery UART"
default "$(dt_chosen_label,$(DT_CHOSEN_Z_CONSOLE))" if HAS_DTS
default "UART_0"
depends on BOOT_SERIAL_UART
help
This option specifies the name of UART device to be used for
serial recovery.

=======
endif #BOOT_SERIAL_GPIO_DETECT
>>>>>>> zephyr: support uart detect and go into recovery mode

其中<<<<<<是master的代码,>>>>>>是分支上提交的代码,选择其中之一或者是按照你的需求修改冲突,修改完后执行

1
git rebase --continue

然后再次提交代码即可