V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
unco020511
V2EX  ›  程序员

关于 git 工作流我有个小疑问(冲突在本地还是远端解决)

  •  
  •   unco020511 · 2022-03-27 13:56:22 +08:00 · 5783 次点击
    这是一个创建于 1001 天前的主题,其中的信息可能已经有所发展或是发生改变。

    正常开发中,我们会从 main->new branch feature 分支,当我的 feature 开发完毕后,origin/main 可能已经更新了很多个 commit(从其他 feature 合并而来),很可能存在冲突,此时我有两种操作方式,哪种方式更好?

    1. 先在本地将 main pull 之后,将 local/main 合并到 local/feature,在本地解决冲突,然后 push origin feature,然后在 gitlab(或 github)提交 merge request(或者 pull request),将 origin/feature 合并到 origin/main
    2. 直接 push origin feature,然后在远程提交 merge request(或者 pull request),在远程仓库(可视化工具)解决冲突,然后将 origin/feature 合并到 origin/main

    这两种方式各有什么优缺点?哪种更适合企业项目的团队合作?

    42 条回复    2022-03-28 17:33:31 +08:00
    imkerberos
        1
    imkerberos  
       2022-03-27 13:58:08 +08:00
    远端不用重新 approve .
    unco020511
        2
    unco020511  
    OP
       2022-03-27 14:02:45 +08:00
    @imkerberos approve 肯定都需要,我们是两个同事 review 后 approve,才能进行 mr
    momocraft
        3
    momocraft  
       2022-03-27 14:03:09 +08:00
    1 才有机会解决冲突后运行和测试

    除非你们有足够好的自动测试 不需要手工保证
    unco020511
        4
    unco020511  
    OP
       2022-03-27 14:07:10 +08:00
    @momocraft 你的意思是 1 可以在 mr 之前基于 feature 进行测试是吗?我这里简化了,实际上肯定不是直接 mr 到 main 上,一般会有个 dev,2 的话也可以 mr 之后基于 dev 测试
    imkerberos
        5
    imkerberos  
       2022-03-27 14:09:12 +08:00
    我的意思是 重新 approve.
    unco020511
        6
    unco020511  
    OP
       2022-03-27 14:10:33 +08:00
    @imkerberos 推荐 1 是吧
    EastLord
        7
    EastLord  
       2022-03-27 14:37:20 +08:00
    1
    lidlesseye11
        8
    lidlesseye11  
       2022-03-27 14:37:40 +08:00
    1
    cowcomic
        9
    cowcomic  
       2022-03-27 14:53:12 +08:00
    1 提交代码要保证合并的正确性和正常运行
    janus77
        10
    janus77  
       2022-03-27 14:59:19 +08:00
    对于比较大的团队和比较严格的规范,应该是远程合并,因为普通开发不应该有 write main 分支的权限。
    而对于简单项目和小团队,以及实际操作上来讲,本地合并的话,解决冲突更容易,因为远程合并一般都是命令行或者 web 界面,本地可以用一些 gui ,鼠标点点就能正确合并,操作更简单。
    sue0917
        11
    sue0917  
       2022-03-27 15:00:42 +08:00 via Android
    楼上在说啥😂
    Macolor21
        12
    Macolor21  
       2022-03-27 15:10:32 +08:00
    @janus77 #10

    让 feat 分支 rebase main ,然后解决冲突后 push feat 再 开启 mr 就可以了,不用 merge 到 main 再 push main 。
    GeruzoniAnsasu
        13
    GeruzoniAnsasu  
       2022-03-27 15:20:21 +08:00   ❤️ 6
    其实没有「远端解决冲突」一说,所有的合并和冲突解决都是在叶子节点上或者说都在 git 的「客户端」进行的。

    web 界面只是自动做了一些额外的事情而已,跟你在本地用一个 GUI git 工具是一回事。




    > 当我的 feature 开发完毕后,origin/main 可能已经更新了很多个 commit(从其他 feature 合并而来),很可能存在冲突

    此时你 **不应该进行任何 MERGE 尝试**。

    1. 首先应该在本地切换到主分支( dev/main/master ),拉取远程的状态。由于你不可能直接在这些分支上修改,所以这一步不会产生任何冲突,仅仅是快进
    2. 切回到你的开发分支,把它 rebase 到主分支上,此时产生冲突,resolve ,重新 commit 。
    3. 由于到目前为止你还是只修改过你的独占分支(就算有远程也是可以随便 push -f 的那个),所以不会对其他人产生任何影响。
    4. push 你 rebase 过后的分支,开启或刷新 MR





    之所以采用不断 rebase 分岔点的方式是因为,如果你不进行 rebase ,merge 操作时是一个三路合并,而三路合并是一个**既复杂又存在危险性** 的操作


    (!!) 其实我本来想简单解释一下为什么三路合并会出问题,但在我搜索看了近一个小时文章后,我选择放弃解释:
    https://www.waynerv.com/posts/git-merge-intro/
    https://git-repo.info/zh_cn/2020/03/something-about-git-merge/
    https://actake.github.io/2021/03/21/git%E5%BF%85%E7%9F%A5%E5%BF%85%E4%BC%9A-%E5%88%86%E6%94%AF%E5%90%88%E5%B9%B6%E9%82%A3%E4%BA%9B%E4%BA%8B/





    (!!) 因为这已经是我至少第 4 次搜索这个问题然后仍然没有完全搞懂了


    如果采用 rebase - merge FF 的方式,合并操作等同于在对方分支上把你做过的操作重放一次,心智负担和风险要小得多。只有一个麻烦,因为是重放,当你的 commit 序列一开始就与对方冲突时,这个冲突会有传递性(对方是 A ,你第一个提交把 A 改成了 B ,后面的提交全部在用 B ;发现冲突后你决定改成 C ,那么当你 rebase 重放的时候所有后面的提交都会不断发生 B 和 C 的冲突)。但这都可以通过减少 commit 修改量和 squash 改善,相比起三路合并能由(虽然存在疏忽的)正常操作产生 **无感知的** 丢修改相比,成本显然要低得多
    rickll
        14
    rickll  
       2022-03-27 15:24:13 +08:00
    如果在本地已经有冲突的代码,为什么还要提交到远端去? 别人把这个冲突代码拉下来不是骂娘。 所有冲突都应该在本地解决。
    maninfog
        15
    maninfog  
       2022-03-27 15:27:20 +08:00
    一般这种情况是 1.git fetch 2.git rebase origin/master 3. git push -f (rebase 之后 feature 分叉了所以需要 force push)
    rbe
        16
    rbe  
       2022-03-27 15:30:06 +08:00
    这两个方式没有什么本质区别呀,核心都是自己 feature 分支随便玩,自己单独开发的话 rebase 都可以,保证合入不冲突,最后 mr 到 main 都只有一个 commit 。
    区别就是你在本地 editor 解决冲突还是网页端可视化工具解决冲突。大概率复杂情况下你都需要在本地解决的,网页端都不好搜索代码
    Chism
        17
    Chism  
       2022-03-27 15:40:20 +08:00 via Android
    我倾向于本地解决冲突,还能顺便测试一下是否运行正常
    cyang812
        18
    cyang812  
       2022-03-27 16:53:24 +08:00
    @GeruzoniAnsasu rebase 到 main 和 merge main 有什么区别呢?
    ClericPy
        19
    ClericPy  
       2022-03-27 16:54:58 +08:00
    不太复杂的小项目 git flow 感觉有点复杂, Github flow 就够用了

    rebase 吧, 你的基被人往前推了, 那就变基到跟线上一致提个 PR, 主线分支光溜溜一根挺好的.
    jessun1990
        20
    jessun1990  
       2022-03-27 17:01:37 +08:00
    git rebase ,本地解决冲突,再 push 上去。
    GeruzoniAnsasu
        21
    GeruzoniAnsasu  
       2022-03-27 17:07:09 +08:00   ❤️ 1
    @cyang812 rebase 后分岔点在基分支的最前端,merge 的分岔点是基分支上历史中的某个点。rebase 的历史永远是线性的,merge 会织出复杂的演化网。

    rebase 目标分支和本分支不对等,你基本不可能搞错(不可能试图把 main 拼到 feature 上,只会把 feature 拼到 main )
    而 merge 就可 tm 难说了,feature merge main 和 main merge feature 观感上根本没什么区别,看起来也都很合法,但形成的历史网是不同的,出问题的时候根本没人有能力搞清楚发生了啥
    FrankHB
        22
    FrankHB  
       2022-03-27 17:10:12 +08:00
    正常都是开发者自己解决冲突,不限制解决冲突使用的工具,测过了再提交,而不是滥用 Web 编辑器让公共分支变成不可维护的临时 patch 火葬场。
    Reviewer 只需要对 diff 和 merge 结果负责,不需要对具体操作负责。
    即便要用统一的 flow ,Gerrit 之类也有事后诸葛亮。
    实际上 merge 不见得应该是首选项。要 merge 还是 ff-only 还是 squash ,你作为分支的 owner 应该清楚。或者你就不管,活干完了找清楚怎么处理这些问题的专人负责。
    msg7086
        23
    msg7086  
       2022-03-27 18:49:04 +08:00
    你说的两点都是错的。
    2 不行因为 WebUI 功能太弱,建议本地合并完做好测试再推。
    1 的话做法错了,主线往分支合并用 rebase 更好。以前 git 那个坑爹的命令行默认 pull 执行 merge ,然后不懂的小白就跟着 pull 了瞎 merge 。现在新版本的 git 命令行总算是去掉了默认 merge 的行为。
    jsq2627
        24
    jsq2627  
       2022-03-27 19:57:12 +08:00
    尝试在团队推行过 "Require branches to be up to date before merging"
    最后发现 PR 合并效率太低,一次只能合并 1 个人 PR ,合并后其他人又要 rebase master ,然后重新等 CI 。。
    unco020511
        25
    unco020511  
    OP
       2022-03-27 20:53:03 +08:00
    @GeruzoniAnsasu #13,我明白了,谢谢
    alanhe421
        26
    alanhe421  
       2022-03-27 22:19:22 +08:00
    根本上还是在于是在 feat 分之还是 main 分支上处理冲突,肯定都会是在非 main 分支处理的。

    比如我所在的团队,均是 feat owner 拉取 main 分支的,解决冲突后,再 MR 到 main.且为了 Review 体验方便,一般是在本地,当然特别小的 diff 的话,上游 WEB 也 OK
    codeMore
        27
    codeMore  
       2022-03-27 23:11:46 +08:00
    1 、feat 要合并前,先 rebase master 分支,本地解决完冲突后,推送到 feat
    levelworm
        28
    levelworm  
       2022-03-27 23:34:26 +08:00 via Android
    我之前恰好看过几篇文章,似乎是推荐先 rebase
    levelworm
        29
    levelworm  
       2022-03-27 23:45:54 +08:00
    @jsq2627 求问一下这样是否可行?

    假如某 feature 需要多人共同开发,于是事先约定大家新建、改动什么文件,保证不会互相干扰,于是从 main 分出 feature_branch ,并又分成多个个人的 feature_individual_branch ,最后开发完成之后合并进 feature_branch ,如何?

    如果互相之间有干扰,比如说有个配置文件多人需要共同编辑,那看来只能指认其中一人为 feature reviewer ,把这些共同的文件承担下来了。
    levelworm
        30
    levelworm  
       2022-03-27 23:47:34 +08:00
    @Macolor21 #12
    新手求问,如果能够让每个 feature branch 在合并之前都自动进行 rebase ,是好是坏?
    Macolor21
        31
    Macolor21  
       2022-03-28 00:16:54 +08:00
    @levelworm 有冲突的时候 rebase 不成功的,没冲突的情况下,rebase 没问题
    815979670
        32
    815979670  
       2022-03-28 00:44:28 +08:00
    看公司,如果这个项目是你单独维护,甚至可以直接 push main 分支,能解决冲突就好。
    如果是多人协作 且你不是分支管理员 的情况下 通常使用 1.
    但需要注意的是,无论哪种方案,冲突都是在本地解决的,不允许在线上( web )处理。
    levelworm
        33
    levelworm  
       2022-03-28 01:33:07 +08:00
    @Macolor21 也是,看来还是冲突最麻烦。那么是否应该尽量从项目架构上去避免冲突?比如说尽量避免多人修改同一个文件的情况出现?虽然未必现实。。。
    darknoll
        34
    darknoll  
       2022-03-28 06:43:14 +08:00 via Android
    把 main 分支更新下,然后重新 checkout 一个新分支,把修改加进去,然后用这个新分支发送 pr
    wu67
        35
    wu67  
       2022-03-28 09:29:05 +08:00
    当然是本地处理, 远程当成存档点来用. 我个人是倾向自己处理冲突合并的, 基本没 rebase 过.
    nothingistrue
        36
    nothingistrue  
       2022-03-28 09:58:02 +08:00
    你说的 2 ,其实就是 1 ,只不过是把解决冲突的操作从本地搬到远程而已。2 发生冲突的时候,你并不是必须用远程仓库的工具,还可以本地在 feture 解决冲突并推送之后,再重新执行 MR/PR 的合并。MR/PR 开启之后,是可以继续提交的。

    如果你执行的是全 merge ,并没有 rebase 的话,2 会更省事点。

    如果是用 rebase 来搞准线性历史的话,要用 1 的方式。
    zhaol
        37
    zhaol  
       2022-03-28 10:20:17 +08:00
    @GeruzoniAnsasu 想问下,如果 rebase 的话,这个时候我的分支会有别人的 feature 或者 bugfix 的代码了,但是如果别人的 feature 这个版本不上,我的分支要上,怎么把别人的那部分拆出来?
    libotony
        38
    libotony  
       2022-03-28 10:25:50 +08:00   ❤️ 1
    @zhaol cherry-pick
    stimw
        39
    stimw  
       2022-03-28 11:43:08 +08:00 via iPhone
    冲突要在 rebase 解决,不要在 merge 时候再去解决冲突。。我一直记得这句话
    cgdddd
        40
    cgdddd  
       2022-03-28 11:53:15 +08:00
    我们公司要求,所有冲突必须要求本地解决,一律 request 的冲突全部打回
    GeruzoniAnsasu
        41
    GeruzoniAnsasu  
       2022-03-28 12:08:36 +08:00   ❤️ 1
    @zhaol 在他的 feture 合并前,应该准备好 4 个分支:1 你的 feature ,2 他的 feature ,4 有他 feature 的版本分支,4 没有他 feature 的版本分支

    我们之前的实践是,有一个接受所有 feature 的分支,比如 master ,然后给每个要发布的版本建 release 分支,他先写完后合并到 master ,你写完,rebase master ,合并。此时 master 上有两个 feature ( 0-2-1 ),而 release 上还什么都没有。 像 gitlab 有 自动 cherry-pick 的功能,web 界面上点一下可以把整个 MR (比如你合并 master 那个 MR )里的所有 commit 都 cherry-pick 到另一个分支上( release )。pick 完 release 看起来像是( 0-1 ),但 1 的那些 commit 不是原始 commit ,是 cherry-pick 重新生成的。

    如果 web 界面没有这个功能,就只能在本地手动 pick 一堆 commit 。不过鉴于 release 分支一般也不需要保留修改历史( master 已经有了),所以可以把 feature 的所有 commit 都 squash 成一个 pick 给 release ,这样手动也不会很麻烦
    hanleisky
        42
    hanleisky  
       2022-03-28 17:33:31 +08:00
    理论上是 1,但是小公司菜逼多,都是让他们推上来发 PR ,我来解决冲突然后合并
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2896 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 12:39 · PVG 20:39 · LAX 04:39 · JFK 07:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.