由于整个开源圈在技术界已经有了无可比拟的地位和影响, 不管是为了个人情怀, 还是提高个人影响, 都应该积极的参与开源, 推广我为人人, 人人为我的精神.
不管由于种种原因, 开源圈最早主要是技术大牛在参与, 因此有一些普通人并不好理解上手的习惯和门槛, 这篇文章主要说一下参与开源过程中, 与git相关的事项. 主要包括Github, Gitlab 与 JIRA (Apache生态), 而关于Git的一些棘手问题, 参考以前篇
0x01. Github相关
很常规的问题直接参考github官方文档. Gitlab后面会单独说
注意: 因为Github的客户端 操作基本是一键/智能化的, 方便查看对比和自动暂存恢复/回滚, 理解了手工步骤之后, 建议还是直接用客户端, 更简洁易用
1. Github PR
注意, 在Github上, 普通人参与开源的第一步就是fork 开源项目, 然后提交pr(pull request)了. 那么这里有个很让人觉得繁琐的事, 就是fork 后的代码是不会自动更新的, 需要定时的手动同步合并一下, 往上很多写法过于繁琐, 我实践后总结了以下步骤:
- 下载代码:
git clone git@github.com:xxx/yourusername/x.git(注意这里地址就是自己fork后的仓库地址) - (可选)
git remote -v查看状态(会有一个你fork地址的fetch&push,执行步骤3后可再对比看看). - 添加remote库 :
git remote add xx https://github.com/xxxx/autorName/x.git(这里xx是指的对方版本的名字, 随意取 ,地址就是对方仓库地址) git fetch xx拉分支到本地 (可以看到* [new branch] master -> up/master提示)git rebase xx/master合并操作(如果无更新也会提示。也可用merge,具体区别待补充)- 4和5步可以合并为一个命令,
git pull --rebase xx master(推荐)
- 4和5步可以合并为一个命令,
- (可选)然后走
git add-->git commit-->git push-f (rebase/amend可能修改提交记录, 所以需要强制推送) - 最后在你fork后的项目界面手动提PR,等待原项目作者确认 (在一个PR中可提交多个不同的
commit, 合并时可只选取一条)
第一次初始化好了之后,以后直接跳到第4步,之前不用重复做,具体如下:
先每次git remote update xx 获取更新(xx是3中设置的名字).然后rebase合并(如果有多个分支注意checkout 切换)
2. 快速更新
上面讲的是正常的PR/更新流程, 你可能觉得更新一次怎么这么麻烦, 这还有更简单粗暴的.. 如果 fork 的项目本地是毫无修改的, 在确定我们可以直接覆盖的前提下, 可以用 reset 大法实现三板斧更新:
1 | #1.更新全部远端分支 |
**提醒: **如果本地有修改切勿这样操作.
3. 清理本地多余分支
很多时候, 远端的仓库会经常删除开发的分支, 此时你只是git pull 并不会更新本地的其它不存在的分支, 也不想手动去一个个删, 应该这样做:
1 | # 检测有哪些分支远端已经不存在了.dry-run只是告诉你, 不会实际执行 |
至此就简单说了一下如何 “fork –> 添加代码 –> 提交PR –> 更新” 的脉络, 比较基础, 但是足以应付入门的操作.
至于可能会涉及到的冲突解决, rebase , 或者修改错误提交的相关问题, 这也是 git 进阶的重要操作 — “回滚/撤回“ , 详细参考下一篇Git 常用操作
0x02. Gitlab相关
首先, 如果是 V10 以上的gitlab, 基本是和github 大致相同的, 这部分可以参考上面的情况. 但是考虑到不同环境 gitlab 版本各不相同, 加上内网环境也有一些限制, 导致这里会有许多内网专属的使用问题.
比如迁移仓库, 新旧版本 gitlab 的配置如果可以直接导出导入, 那就会非常傻瓜化, 但是如果 git仓库并不能这样创建, 那就需要手动去从API层面写爬虫去迁移. 这个之后我会贴一下之前写的 python 脚本. 帮助快速做跨平台/版本迁移.
先说一下最关键的几个问题:
- 跟进社区
- 大版本升级
A. 多次cherry-pick
跟进社区最常用的就是 cherry-pick ,因为大版本肯定是用 merge 了. 这里关键是比如 HDFS 的一个新功能, 不大不小, 可能有几千行代码, 跨度也有半年以上, 而且因为 JIRA 或者 Github 并不能保证在一个 issue 中汇总所有相关Patch, 所以如何高效合并就是个重要问题
B. 大版本的Merge
这里主要还是要依赖 IDEA 的强大多窗口合并功能
未完待续, 之后迁移
0x03. Git Flow
说完了两大主流git远程仓库. 再说一下 git 的工作流 (git glow), 原本 git 就不是给几个人设计的系统, 它面向的场景其实是多分支, 多版本, 多人合作的环境, 先说说基本原则, 再说说其他事项
A. 原则
- master分支不允许直接改动, 开发必须新建分支, 然后合并到master (dev可选)
- master分支必须打tag, 提交信息需按规范书写
B. 核心步骤
- 如果需要下载的代码不是主分支,使用
git clone -b branchName https://xxx即可.不需要下master - 创建新的分支(比如dev) :
git checkout -b dev(等同于先git branch dev 再git checkout dev) - 然后git add –>commit ,然后有两种选择,一是直接push到远端git仓库,二是合并到master
- 推送dev分支,
git push dev(当然第一次可能需要带上--set-upstream) - 合并dev到master :
git checkout master,git merge --no-ff dev,这时候也有两种情况, 冲突否?- 冲突,人工解决冲突文件,删掉冲突标记.然后再add->commit->push
- 不冲突,fast-forward
- 推送dev分支,
- 当从git仓库clone代码的时候,git就会自动把本地的master分支和仓库端对应起来,仓库端默认名是
origin,git remote -v可以查看详细信息. (正常权限会有fetch 和 push [拉取])
C. 想把master内容合并到其他分支
大部分流程说的都是如何把dev/其他分支合并到master,但是实际开发中还有个常见需求,就是不希望影响master分支,但是希望合并到自己的分支,master–>dev ,步骤如下:
- (可选)如果dev有改动未提交,先提交改动,不然会禁止切到master
git checkout mastergit pull- (可选) 如有冲突,这里需先解决,然后
git add.–>git commit -m "merge master to dev" git checkout devgit merge master(这一步是核心,把 master 改动合并过来,在 master 如果没提交这会自动补充msg)git push(推送到远程仓库的dev)
0x04. 仓库合并
在项目从普通 org 迁移到类似 Linux/Apache 基金会的时候, 由于原本的 org 无法存在, 所以常会考虑合并数个功能类似的项目, 网络上对 git 的项目合并有简单说明, 但是不够细致和清晰, 也没有涉及 github 的相关 ci/actions 操作, 这里记录一下:
- 假设把 A, B 两个仓库合为一个, 先选择一个 base (例如 A), 然后 B 往 A 合入
- 要求保留 B 的提交记录, 方便回溯和延续
- 独立让 A, B 变成一个 root 下的两个子模块, 然后各自独立 (这里有几个其他方式, 暂且略过)
- 修改根下的 README 说明
- 合并
.github中的 actions, 包括去重, 适配路径等
其中, 修改 README/actions 等配置属于独立操作, 建议独立 PR 操作, 更加清晰, 也方便回滚, 然后如果有多个项目合并为一个, 建议也是每个单独开一个分支/PR, 而不要一起操作, 出问题会很麻烦.
HugeGraph 仓库 (实战)
下面以具体的 HugeGraph 案例做例子, 需求是要把 loader, tools, hubble, client 合并为一个新的仓库 toolchains, 以 loader 作为基本仓库, 其他往 loader 中合入, 首先我们把 hubble 合到 loader 中
A. 合入 Hubble
重命名 loader 目录为
toolchains, 方便理解在 toolchains 下创建 4 个新目录, 方便后续使用
- hugegraph-loader
- hugegraph-hubble
- hugegraph-client
- hugegraph-tools (后续考虑改名)
使用
git mv xx hugegraph-loader后(移动原loader 代码, 最好不要直接使用 mv), 目录应该是这样的结构, LICENSE/gitignore 等可只在根下放一份即可1
2
3
4
5
6
7
8├── .github # 先也移入子仓库 (避免后续冲突)
├── .gitignore # 可保留, 直接解决冲突
├── LICENSE # 可保留, 无冲突
├── hugegraph-client
├── hugegraph-hubble
├── hugegraph-loader
├── hugegraph-tools
└── pom.xml # 后续新增作为根 pom (暂时先不要存在, 否则后续有冲突)在新分支
merge-hubble先提交一次commit, 方便后续回滚 (git status 确认绝大部分是 rename)正式开始合入 hubble
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#0. 不在 master 分支操作, 先创建一个 merge-hubble 分支
git checkout -b merge-hubble
# 1. 先把 hubble 加到当前 remote (注: 如果下载慢, 请自行使用 git 地址加速)
git remote add hubble https://github.com/hugegraph/hugegraph-hubble.git
# 2. 拉取代码 (注: 这里只选择 master, 所有分支保留会很麻烦, 单独再说)
git fetch hubble master
# 3. (关键) 创建一个新的分支, 切换到上面拉取的 hubble 代码
git checkout -b hb hubble/master
# 4. 切回原分支然后使用 merge 命令合并
git checkout merge-hubble && git merge hb --allow-unrelated-histories
# 5. 解决冲突后可先commit一次, 然后 mv hubble 文件
git mv hubble-* hugegraph-hubble # 先移动文件夹
git mv .travis.yml ...(所有单文件) hugegraph-hubble
# 6. 修改提交信息后提交一次 PR, 文件迁移部分则至此完成 (后续解决兼容/合并依赖等单独说)
B. 合入 Tools
由于 A 中已经做好了核心铺垫, 后续就直接从 step5 开始了, 首先基于 merge-hubble 创建一个merge-tools 分支
1 | # 1. 先把 hubble 加到当前 remote (注: 如果下载慢, 请自行使用 git 地址加速) |
C. 合入 Client
同上, 基于 merge-tools 建一个新分支 merge-client
1 | # 1. 先把 hubble 加到当前 remote (注: 如果下载慢, 请自行使用 git 地址加速) |
D. 处理冲突
未完待续
0x0n.更新补充
开源协作里这篇最实用的结论仍成立:fork + upstream 是基础套路。但现在建议把“强制推送”默认替换为 --force-with-lease,降低覆盖他人提交的风险。
flowchart LR
A["fork 仓库"] --> B["add upstream"]
B --> C["fetch upstream"]
C --> D["rebase 本地分支"]
D --> E["push --force-with-lease"]
E --> F["发起 PR"]
另外,GitHub 已提供比较完整的“配置上游仓库 + 同步 fork”文档,建议团队新人统一按官方流程走,减少“口口相传脚本化命令”带来的误操作。
待核验:文中含部分内网/社区混合流程(GitLab + JIRA + 多仓库合并)示例,仍需结合具体组织规范做裁剪和模板化。
参考资料:
- Github官方文档
- Git 合并两个仓库为一个
- GitHub - Configuring a remote repository
- GitHub - Syncing a fork
- git-push –force-with-lease