























这是一个创建于 531 天前的主题,其中的信息可能已经有所发展或是发生改变。
今天遇到个 git 合并丢代码的场景。 featB->featA->master featA 基于 master 开发,featB 基于 featA 开发。featA 合入 master 后,我直接在 featB 分支上 git merge master ,出了问题。 具体如下 featA 对于 file1 加了 line70 ,featB 对 file1 删了 line70 ,在 featB 上 merge master 后,git 自动 merge 的结果是 line70 依然还在
第 1 条附言 · 2024 年 12 月 30 日
分析了下,问题就在于 featB 合入 master 时,base 是没有 line70 的,featB 没有 line70 ,master 有 line70 ,理所当然 line70 就被加上去了。
第 2 条附言 · 2024 年 12 月 31 日

复现在这:
分支 local/A 增加一行
( local/A ) git co -b local/B
( local/A ) git co main
( main ) git merge local/A --squash
( main ) git co local/B
( local/B ) git ci -m 'rm line'
( local/B ) git merge main
刚才删除的一行就又被加上了。
---
这个场景还比较常见,A 分支是某个产品 1.0 功能,B 分支是另外一个人开发 1.1 功能,从 A 分支上切出,同时开发。
A 分支上需要对某个暂不支持的功能加上禁用,B 分支上放开限制。
在 A 分支合入 master 上线后,gitlab 上用的是 squash commits 。B 分支上线前,本地 git merge master 提交远端,远端再合入。
1 xiaozhu5 2024 年 12 月 30 日git reflog 和 git fsck 两个结合看一下应该找到丢失信息 |
2 gesse 2024 年 12 月 30 日featA 添加了 line70 ,并合并进了 master ,你在 featA 上 fork 出 featB ,featB 上删除了 line70 后,又把 master 合并进 featB ,这不就是在 featB 上添加了 line70 吗? 一点毛病没有。 |
3 mark2025 2024 年 12 月 30 日为什么要在 featB 上面执行 featB 分支上 git merge master ? 这就是混乱的根源 |
4 netabare 2024 年 12 月 30 日 via Android所以不要把 master 合入分支,分支上面只用 rebase 。 |
6 mark2025 2024 年 12 月 30 日@GeruzoniAnsasu 三路合并就是人多嘴杂,你不仔细查看变动就无法确定最终合并结果是否符合预期。所以基于 rebase 的线性合并在团队开发中是最高效的( gitlab 可以设定强制线性合并) |
8 sagaxu 2024 年 12 月 30 日git merge 除非是 fast forward ,在处理多个分支修改同一文件时,不一定符合你的预期。 所以这种情况用 rebase 甚至是 reset --soft ,然后手动处理变更会更好。 |
9 GeruzoniAnsasu 2024 年 12 月 30 日@mark2025 人多嘴杂是其次,问题在用好 merge 要制定的规范(比如不允许 pull-merge ,自己的分支不能 merge 别人分支后再 merge 到 main……等等,它一点也不直观。 你搞不清楚需要哪些规范才能保证不发生 A merge B 然后 B merge A 导致代码没了这种问题 |
10 mark2025 2024 年 12 月 30 日@GeruzoniAnsasu 这是我所有 git 项目钩子自动执行的: git config --global i18n.commitencoding utf-8 if [ -z "$CI" ]; then |
11 leonshaw 2024 年 12 月 30 日 via Androidbase 没有 line70 ,那严格来说 B 并没有基于 A 开发 |
12 leonshaw 2024 年 12 月 30 日 via AndroidB merge master 没有问题,但是不能 merge 没有进 master 的 A |
13 LeeEnzo 2024 年 12 月 30 日强制 rebase 和 squash 开发 |
14 freesun165 2024 年 12 月 30 日 via Android@netabare 话虽如此,但我这个业务场景经常一个分支测一个月以上,一百多个提交,每次 master 更新,我挨个 rebase 下,成本太高了 |
16 freesun165 2024 年 12 月 30 日 via Android@mark2025 俺这规范就是上线前 featB 需要合并 master 推到远端,远端 master 再合并 featB ,然后就出现了这么不符合知觉的事 |
18 rbaloatiw 2024 年 12 月 30 日按你的描述感觉不太可能, 你有最小可复现样例吗, 可以发出来看看 |
19 coolcoffee 2024 年 12 月 30 日git 的分支操作应该是像一颗树一样,开叉但是不会互相交叉。 如果平行的节点需要互相同步,那么应该一方往上推到相同的节点,另外一方再去拉,这样就遇到相同修改就必定会产生冲突。 |
20 BeautifulSoap 2024 年 12 月 30 日 via Android唔嗯?这情况你确定真没冲突吗? |
21 kivmi 2024 年 12 月 30 日太危险了,master -> branch , 相当于你对同一行的修改无效啊,各种冲突吧?可以从 master 同时 fork 几个分支?一个为开发分支,一个为上线分支?当需要上线时,合并到上线分支,然后合并到 master ,一直保持上线分支跟 master 保持一致,实现快速上线。貌似 git flow hotfix 也可以做到。 |
22 zthxxx 2024 年 12 月 30 日老生常谈话题之「不要把 master/dev 合到自己的分支」,开发时也始终应该像 GitHub / GitLab 那样的「把自己分支合到 master/dev (主干分支)」 |
23 leonshaw 2024 年 12 月 30 日@freesun165 #15 这样 base 应该是切出去时的 commit ,不然就是后面这个 commit 被重写掉了,最好画个图看看。 |
24 BeautifulSoap 2024 年 12 月 31 日我实际在本地测试了一下 最终结果是 master 合并入 feature b 后的确没报冲突,但被 feature b 删除的 line 也没再次出现 可能 lz 实际给个最小可复现例子比较好 |
25 nightwitch 2024 年 12 月 31 日git 只允许 fast-forward 就不容易出现这个问题。 |
26 FrankAdler 2024 年 12 月 31 日我也遇到过,目前没有头绪,我是 master 拉出来的分支,修改后合并到 dev 分支,cicd 到测试 k8s ,出现过几次代码没有提示冲突,但是丢了几行。 |
27 jqtmviyu 2024 年 12 月 31 日 |
28 jqtmviyu 2024 年 12 月 31 日 |
30 networm 2024 年 12 月 31 日@freesun165 #14 使用 Fork 的 Leaning Branch 功能进行同步,只需要一键就可以自动同步。 另外推荐看下: 合并分支只会通过合并提交引入最终的修改,而不是合并分支中的原始提交。 |
31 chenluo0429 2024 年 12 月 31 日 via Android我猜 featA 合并到 master 时,经过了 sqlash 之类的操作,导致 master 上 featA 的修改与 featB 所基于的 featA 并不是同一笔提交,而是修改内容相同的两笔不同提交 |
32 feelapi 2024 年 12 月 31 日merge, rebase 两种思路是冲突的。不建议混合使用。 |
33 wgbx 2024 年 12 月 31 日Git 不是万能药,要遵守 git flow |
35 freesun165 2024 年 12 月 31 日@jqtmviyu 就是( main ) git merge A 时加上 squash 就可以复现了,因为当时是 gitlab 上勾选了 squash commit 的选项 |
38 zhuisui 2024 年 12 月 31 日你要想充分利用 git merge 的自动冲突解决能力,就不要做 squash 、fixup 、amend 、cherry-pick 这类会修改 commit 的操作,你必须在 merge 时原样保留各路 branch 。 |
40 p1gd0g 2024 年 12 月 31 日之前遇到几次丢代码,几个主流的 git 软件都看不到哪一次提交丢了,只有 tortoisegit 可以。 |
41 wangtian2020 2024 年 12 月 31 日不使用 sourcetree 喜欢用命令行操作 git 导致的 |
42 leonshaw 2024 年 12 月 31 日很明显你 squash 把 A/B 分支点删除了,导致和 main 的分叉在 local/A 以前,这一行的添加删除都发生在分叉以后,互相抵消了。 |
43 blublu 2024 年 12 月 31 日 via iPhone因为你 feat A 和 master 的 base 点( b1 )并没有 line 70 ,当你把 feat A 向 master 进行 merge 并且用 squash 方式时,新的 merge 点有了 line 70 ,记为 m1 ,当在 feat B 删掉 line70 时,和 base 点(与前面 feat A 与 master 的 base 点一样( b1 ),因为用的是 squash ,所以这个 base 点并不是 feat A 中 co 到 feat B 的那个节点)的对比中,并不会出现 line70 的变更,因为和 feat A 增加的那一行已经抵消掉了,因此会把 m1 与 b1 对比中增加的 line70 加入到 featB 中新的 merge 点 m2 不知道我这样说你清楚了么?不清楚可以再多读几遍,应该解释了整个变更过程了 |
44 mark2025 2025 年 1 月 2 日@freesun165 |
45 mark2025 2025 年 1 月 2 日@freesun165 俺这规范就是上线前 featB 需要合并 master 推到远端,远端 master 再合并 featB ,然后就出现了这么不符合知觉的事 |
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。