某个项目来自于开源项目的二次开发
项目本身有两个 remote
origin : 该项目我自己的私有 remote
upstream : 依赖的开源项目本身的 remote
项目有两个分支 master 和 dev,dev 用来开发,master 分支只合并 dev 上线分支。
现在是大部分时候我和 upstream 开源项目作者可能同时进行开发,如果我本地没有任何 commit 还好,一旦我本地有若干 commit (甚至已经合并到 master 并且已经 push 了)之后,我此时从 upstream 开源项目 pull 最新代码下来合并后,git log 就会分叉,并且会产生多余的一条 commit:Merge branch 'master' of https://xxx into dev 。
请问有办法避免分叉和产生这个多余的 commit 吗? rebase 似乎不行,求大神指教 另外这是我的强迫症作祟,如果能避免,避免分叉真的好吗,还是我无病呻吟 应该改掉这个强迫症,继续让他保持分叉。
1
msg7086 2020-12-20 20:15:03 +08:00 2
你用 merge pull 当然会产生 merge 。用 rebase 就行了。
|
4
saberlong 2020-12-20 20:21:18 +08:00 via Android
简述书上有个"如何使用 Git Rebase",我觉得不错
|
5
nightwitch 2020-12-20 20:23:45 +08:00
|
6
msg7086 2020-12-20 20:26:23 +08:00
首先,我相信你是在做类似 mod 一样的工作。
这样的话,你所有的修改,应该都是在 upstream 上追加,对不对。 那么假设有 upstream 版本 v1,然后你在上面加了一堆 commit 做成了 v1mod 。 看上去是这样: v1 ↳ v1mod 现在 upstream 更新到了 v2 v1 → ...... → v2 ↳ v1mod 那这里就很简单啊,你签出 v2,然后把 v1mod 上所有的提交搬过去不就得了。 v1 → ...... → v2 ↳ 旧 v1mod ↳ 搬走的 v1mod 最后应该是类似这样的结构: https://vip1.loli.net/2020/12/20/R9Juo3MjUqgidTy.png 你不如先看看你的下游分支是不是结构干净整洁。不整洁的分支历史是很难处理的。 |
7
msg7086 2020-12-20 20:28:09 +08:00
|
8
shawndev 2020-12-20 20:32:23 +08:00
不如换一个思路,将原始项目作为 submodule,你的所有修改导出为 patch 文件。
|
9
hantsy 2020-12-20 20:42:04 +08:00
我是日常使用方式:
上游的项目 Fork 到你账号。 git clone github.com/your/project git remote add origin your project url git remote add upstream upstream project url 同步:(我的本地 Master 只作同步,相当只读方式) git checkout master git pull upstream master git push origin master feat 开发: git checkout master // make sure you are branching from master. git checkout -b feat1 git commit -am "feat: my feat" gh pr create // use Github CLI to push to my origin/feat and create PR base on upstream/master // 可能再次 Commit git commit -am "commit" //合并上面的没 Push 的 Commit git commit --amend -am "commit " //可能 push 了, 再次 Commit git push -u git commit -am "another commit" //想合并一些 Comment,重整一下 Commit log 。 git rebase -i Head~3 //上游 Master 太多更新了,想同步一下。 // 先按上面的 同步 说明,切换到本地 Master,上游 Master 更新到本地 Master,Push 到 origin/master, 切换回 feat1 git rebase -i master //最后你的 Pr 合并到上游 //可以是 Rebase (没冲突),也可能是 Merge (+Squash ) gh pr list gh pr merge 55 |
10
liuxey 2020-12-20 20:54:58 +08:00
核心就是 变基( rebase ) ,好好研究一下吧,rebase 的使用姿势很多
|
11
tlerbao OP @msg7086
@ysc3839 @saberlong @nightwitch @msg7086 @hantsy @liuxey 我看了下简书那个如何使用 rebase 有点收获,我现在是 在 dev 分支这样操作 首先 git pull --rebase upstream master,没冲突最好,有冲突合并,或者还未 commit 的冲突先存储 成功 pull 后然后 rebase 到 master git rebase master 然后 git checkout master && git merge dev 然后 push master 这样似乎我的时间线清楚了也没有分叉,但是在 git log 的时候,上游的 log 好像还是出了一个小叉这是正常的把,入下图 https://talent-miaoqiang.oss-cn-hongkong.aliyuncs.com/markdown/20201220/D1UA54.png |
12
YouLMAO 2020-12-20 22:26:19 +08:00 via Android
好好用 git,不要提一些不合理要求,rebase 不建议在生产的仓库使用,个人玩耍就随便
|
13
cnnblike 2020-12-20 22:33:58 +08:00 via iPad
@YouLMAO 没明白,我们工作的主 repo 有大概几百个 commit,历史两年多,rebase 用得好好的,另一个历史更长
|
14
saberlong 2020-12-20 22:44:42 +08:00 via Android
@tlerbao
确实会存在。rebase 方案这个地方确实不完美。只要分支开发提交到上游就会有。确认没问题后,删除这个分支也不影响。但是一般会保留用于追溯。由于基变导致 commit log 编号不同,需要靠 commit 说明来对比。虽然有瑕疵对比 merge 方案,我更喜欢 rebase 。 |
15
saberlong 2020-12-20 22:47:05 +08:00 via Android
@tlerbao 另外多个分支并行开发时。rebase 方案操作步骤会更多,我会使用本地临时分支
|
16
YouLMAO 2020-12-20 22:47:43 +08:00 via Android
@cnnblike 为了追求 Git 的线好看,在团队合作中使用 rebase 说轻点是舍本逐末,说重了是对团队不负责任。个人玩耍项目无所谓。非 Apache 项目不管你。
|
17
saberlong 2020-12-20 22:58:23 +08:00 via Android
@tlerbao 另外要说明的是,团队使用 rebase 方案,需要培训和约束的。否则请用 merge 方案。
|
18
msg7086 2020-12-20 23:33:15 +08:00 1
@YouLMAO 菜不是弃用一个优秀功能的理由。
Git 线好看怎么就是舍本逐末了。版本管理系统里,「版本管理」自然就包括对历史的把控。一个清晰的历史记录可以方便地追溯代码的变更,也方便把某个或者某组提交拿出来做 revert 或者 cherry pick 。 因为某些开发人员水平太菜,导致该 rebase 的地方滥用 merge,最后版本管理记录变成一大坨犬牙交错的屎山,这才叫舍本逐末,这才叫不负责任。 不懂可以去学,可以让同事教,没人会怪你的。 怎么不说因为有些人写不好 C++所以大家都去改用 VB6 呢。 当然,还有一种可能,你们团队太大了,不可避免地遇到坑队友而且没人愿意培训。 这种情况下最好的方法既不是 rebase 也不是 merge,而是 squash 。 我们团队现在就是推荐用 squash,虽然主线上一坨坨的 squash 谁都不知道里面到底有哪些东西,但是老板开心就好了呗,反正出问题也轮不到我背锅,我一点儿也不想操心。 |
19
msg7086 2020-12-20 23:38:04 +08:00
@tlerbao #11 你这个看上去不太对。
rebase 完以后应该是一条直线,像是: e723 → 1219 → 你的项目的 4 次提交 你看我 7 楼贴的图,upstream (mainline) 到 mod (sb-master) 之间应该是一条线。 |
22
msg7086 2020-12-21 01:31:15 +08:00
@YouLMAO 其实我不太明白你提 Apache PMC 和你提出的团队里用 Rebase 是对团队不负责任有什么关系。
在我看来,Good practice 应该是对团队负责任的行为,只不过是因为需要妥协一些现实中无法解决的情况(例如队友太菜)而不得不采取变通的措施。 从你前面的观点,即「用 Rebase 」→「对团队不负责任」这个论点来看,我觉得有两种可能。 1. 你觉得 Rebase 让版本历史保持清晰不属于 Good practice ; 2. 你觉得 Good practice 是对团队不负责任的行为。 你想说的是其中的哪个呢? 我司姑且不算很小,但是我不代表我司发言,所以就不报名号了。 但是我司要求每个 MR 都使用 Squash 方式合并,这样既不会有 Merge 也不会有 Rebase 。 说白了只是为了省事,省得培训每个员工罢了。 我自己的个人项目是不会去用这么 low standard 的做法的。 |
23
ooops 2020-12-21 02:00:26 +08:00
PR/MR 没 merge 之前随便 rebase,有什么好纠结的。如果开发分支也多人协作那就定好了标准,做 rebase 完就即时同步给小伙伴就可以了。你 rebase,他也 rebase 没有太多问题。稍微配合下 cherry-pick 让提交历史好看一些也是不错的。
合并之后再改历史是大忌。 |
24
cnnblike 2020-12-21 02:14:47 +08:00
@YouLMAO 这不就典型的菜怪工具不好用么? squash+rebase 逻辑很清晰的,git blame 一下整个历史清清楚楚
|
25
cnnblike 2020-12-21 02:19:53 +08:00
squash+rebase 之后拿工具就可以方便的检测出整个系统的依赖关系,通过把 interface 写在一个独立的 repo 里面,可以很方便的实现多个 pipeline 同时自动回滚,如果是多个 branch merge 过来的话,回滚到哪个 branch 的哪里去?
|
26
chchwy 2020-12-21 09:29:04 +08:00
rebase 唯一解答,只要在本地端還沒推送上去的內容,沒有什麼理由不能 rebase 。
|
27
hantsy 2020-12-21 10:00:13 +08:00 1
@tlerbao 你这样用,本地 Master 还是 Origin Master,还是 Dev 分支内容都是一锅粥。现在你看到只是自己一个人的几次提交 Log,等你在项目有多个人的时候,提交了几个月再去看你的 Log 吧。
我使用的原则:我的 Master (本地或者 Origin 上)尽可能与 Upstream Master 致。每次创建分支前,都是必须要同步操作,保持与上游一致。 而且我的经验是是大部分情况下,我的开发分支不需要中途 Rebase,绝大多数情况下,在 PR Merge 的选择 rebase 是可以合并进 Upstream Master 的(冲突的时候,直接在 Github Web 界面上修改冲突,合并即可)。Git 不仅仅是配置管理一部分,分支与任务颗粒度大小匹配,这与软件开发管理经验和实实在在软件架构的设计也很大关系,尽可能是一个分支对应的任务快速完成( 4 小时到一天内最好,超过了一天,就应该考虑这个 Issue 是不是包含太多的内容),而且有清晰依赖关系(不要依赖没完成的任务)。 这个 Flow 不是我发明的,Github 最初版本的 Flow 包含这个步骤的。只是现在看到的 Github Flow 版本官方教程,省略了 Fork,简化了很多。而 Fork 在 Github 最初的理念正是体现了 Social Coding 。 |
28
Achieve7 2020-12-21 10:15:40 +08:00
我一般是本地 rebase 一遍 rebase -i, 然后 Squash, 最后再推上去 主干永远是一条线
|
30
geying 2020-12-21 11:19:35 +08:00
git stash
git fetch git stash pop git push |