V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
git
Pro Git
Atlassian Git Tutorial
Pro Git 简体中文翻译
GitX
wiirhan
V2EX  ›  git

rebase 还是 merge?

  •  2
     
  •   wiirhan · 33 天前 · 6381 次点击
    这是一个创建于 33 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大家在项目里合并代码是用 rebase 还是 merge ? 两个远程分支合并,用 merge 会产生一个无意义的提交,次数多了分支线就很乱。

    80 条回复    2021-09-22 10:30:51 +08:00
    dcalsky
        1
    dcalsky   33 天前
    永远 rebase
    dcalsky
        2
    dcalsky   33 天前   ❤️ 21
    @dcalsky sub-branches rebase on master, master merges sub-branches. 差不多是这样。
    lingxi27
        3
    lingxi27   33 天前
    rebase +1
    wiirhan
        4
    wiirhan   33 天前
    @dcalsky 远程分支咋办?假如我有两个远程分支:master 、dev 。master 作为主分支,dev 作为开发分支。在项目迭代中,master 分支可能会存在 bug 修复,这个 bug 修复完成后需要同步到 dev 分支。一个迭代结束后,dev 的代码需要合并到 master 分支。我现在对个人分支合并到远程分支采用的 rebase,两个远程分支的合并采用的是 merge 。现在纠结的是两个远程分支的合并,每次合并都会产生不必要的提交,如果 bug 修复次数很多,那分支就会显得很乱😂😂😂。
    bjfane
        5
    bjfane   33 天前
    教程都是用 merge 的多,一般都写不能真实的反映“历史”,小项目随意。大项目的话 2 楼基本上是正解。


    “历史是什么” :
    <img src = 'https://i.bmp.ovh/imgs/2021/09/13b50db1bb1ef78f.png' />
    zjsxwc
        6
    zjsxwc   33 天前   ❤️ 1
    merge 稳一点,虽然会多一次提交记录
    zjsxwc
        7
    zjsxwc   33 天前
    同意 4 楼说的,自己有把握的两个分支用 rebase,对不熟悉的分支 merge
    konakona
        8
    konakona   33 天前
    merge,因为 no-ff 后只带一条记录。
    因为团队开发需要用一些 git 的 flow (任意),为了追述 MR 是 hotfix 还是 feature 、release 等,用 merge no-ff 。
    peterswan
        9
    peterswan   33 天前   ❤️ 1
    个人开发和本地分支喜欢 rebase,涉及到远程多人开发的分支只能用 merge,rebase 会弄的协同困难。
    Pipecraft
        10
    Pipecraft   33 天前   ❤️ 4
    一律采用 squash merge 。github PR 也只用 /允许 squash merge 。
    太多的小的提交,或反复的修改后提交,会使历史记录很乱。合并成一个 squash merge,既简洁又能看到一个 feature merge commit 里的多次提交的记录。
    尽可能在 Github 上面先创建 PR,再合并。
    monkeyWie
        11
    monkeyWie   33 天前
    同意 2L
    wellsc
        12
    wellsc   33 天前
    统一比选择难
    weiwenhao
        13
    weiwenhao   33 天前
    说一次去年的线上的故障。
    开发了 a 功能在 9 月 15 号(cimmit 在 9 月 15 号,测试了一周,9 月 22 号上线(合到 master)

    修复了 b bug 在 9 月 17 号,当天上线。(合到 master)

    9 月 22 号发版遇到 bug 需要回退。因此新的故障是 15 号提交的,所以此时需要回退到 15 号之前的 master 分支才能修复, 所以导致 17 号的修复分支没了( 15 号到 22 号其实不止 17 号一个功能没了,7,8 个 feature/或者 fix 都没了)。
    dilu
        14
    dilu   33 天前
    要 rebase 就全部 rebase,要 merge 就全部 merge

    有人 rebase 有人 merge 才最伤
    weiwenhao
        15
    weiwenhao   33 天前
    老大一开始就跟我说过要用 rebse 或者 git reset --soft,但是我没在乎,毕竟我看 廖雪峰阮一峰的教程都没说 rebase.. 出了故障才学会我可真是亏了。
    plko345
        16
    plko345   33 天前 via Android
    @weiwenhao rebase 能解决这个问题吗?只 reset 15 号的可行吗?
    karott7
        17
    karott7   33 天前 via iPhone
    @weiwenhao 你这种情况可以因检出一个分支,然后把主分支回退,再把 17 好发布的那些更改用 cherry-pick 命令放到主分支上,发布主分支
    weiwenhao
        18
    weiwenhao   33 天前
    如果 master 已经这样了就无解了,最后解决方法就是一直故障,然后立刻定位问题解决,足足持续了 2 个小时才解决。。。
    weiwenhao
        19
    weiwenhao   33 天前
    @karott7 我们当时发布工具比较垃圾,就是选择 master 上的 一个一个 commit 然后打包发布。 然后也没有打 tag 的习惯,如果有 tag 应该也是可以解决的,不确定。
    karott7
        20
    karott7   33 天前 via iPhone
    @weiwenhao #18 无解是因为乱用 merge 命令,应该所有的更改都从主分支检出新分支,每一个 commit 尽可能小,合并的时候照二楼说的先 rebase,再到主分支 merge(为什么要这样做?你可以在你的项目主分支和开源项目分别执行下 git log —oneline —graph 命令看看区别),最后发布完成给最新 commit 打版本 tag,更甚至建一个 changelog.md 文件记录每次版本号和更改内容
    karott7
        21
    karott7   33 天前 via iPhone   ❤️ 1
    楼里不知道 git flow 流程的赶紧去学习一下
    xlsepiphone
        22
    xlsepiphone   33 天前
    rebase,上一次 merge 应该是 2016 年了。
    daolanfler
        23
    daolanfler   33 天前
    rebase +1,rebase 的提交记录更好理解
    bingyiyu
        25
    bingyiyu   33 天前
    reabse+1
    Kobayashi
        26
    Kobayashi   33 天前 via Android   ❤️ 31
    Merge 多出来的提交不是无意义,它记录了一种合并关系,显式表明这个提交来自于一个分支。这也是 Git 分支的一大特性:Git 历史非一条直线,其中可以有岔路,或者说一个提交可以有多个父节点。Rebase 后再 fast forward 合并的话丢失了这种关系记录。

    一个好的分支名直接解释了这个分支在做什么,如修复某个 bug 、新增了某个功能。而分支内每个提交则记录了实现的步骤。从这个角度来看,分支也可以视作一个大的提交。

    Merge 而不是 rebase + fast forward 。更不要随意 merge --squash,而是根据情况使用。保留多个提交的实现步骤,如果这个功能出了问题,方便以后细分,定位问题。

    楼上很多人对 Git 的理解水平真的不大行,只是在把 Git 当 SVN 来用……
    建议了解了解 git-flow,理解一下分支。多翻翻 pro git book.

    https://nvie.com/posts/a-successful-git-branching-model/
    https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow
    https://git-scm.com/book/zh/v2
    yalin
        27
    yalin   33 天前
    merge
    vjnjc
        28
    vjnjc   33 天前   ❤️ 1
    #10 +1 “一律采用 squash merge 。 ”
    大型项目也要考虑 merge,为了追溯真实提交情况。

    假设一个场景,你想找 6 个月前有人做的 feature1 涉及到哪些文件改动。
    1. rebase,你需要翻很多 commit 。比如 03/14 ~ 03/18 之间 user1 的所有 commit
    2. merge 的话你只要看一个 commit 。或者是 gitlab/github 上的 mr
    bingyiyu
        29
    bingyiyu   33 天前
    我会先把本地分支 rebase 到远程 master 分支,然后再发起 merge request 合并到 master 分支。
    acidsweet
        30
    acidsweet   33 天前
    merge;
    1. 超大项目合码时 rebase 处理冲突的难度你不想体验
    2. rebase 本身破坏了真实 commit 之间的逻辑顺序,粗暴的采用时间序其实非常蛋疼不直观
    2i2Re2PLMaDnghL
        31
    2i2Re2PLMaDnghL   33 天前   ❤️ 1
    历史可以分叉是很恶的(双关:恶心且邪恶),但是因为爱因斯坦的关系不得不这么干。
    凡 git 的事想一想用邮件怎么玩。

    1. 什么时候 rebase ?
    你以别人的软件的 v1.0 为基础开始写一个 feature,还没写完的时候 v1.1 发布了,你把新代码 pull 下来并把你的修改全都 rebase 到 v1.1 上去。

    2. 什么时候 merge ?
    别人为你的软件写了一个 feature,然后 send-email 给了你。你拿到了他的 patch 并 merge 进你的代码。
    chaleaoch
        32
    chaleaoch   33 天前
    rebase 只在本地操作.

    要不然很容易出问题.
    OliveGlaze
        33
    OliveGlaze   33 天前   ❤️ 1
    2 楼的原则,加上 29 楼的具体实践说明,其实就是现在业界的标准玩法了。

    工作那么多年的老油条了,各种 git flow 用下来,你最后总会发现必须得有 MR/PR 这个环节。这一类的 flow 才是更适合实际工作的 flow,而且所谓的 rebase 和 merge 也没法完全割裂开来单独用的。
    kxuanobj
        34
    kxuanobj   33 天前 via Android
    @wiirhan master 比较稳定,更改较少的情况下,可以试试 cherry-pick 到 dev 分支。
    index90
        35
    index90   33 天前
    特性分支 rebase 主干分支,然后再 merge 主干
    2i2Re2PLMaDnghL
        36
    2i2Re2PLMaDnghL   33 天前
    @2i2Re2PLMaDnghL 话说起来顾名思义都行
    变基,是指『变更』提交的『基础』
    合并,是指将两个分支的提交进行『合并』(我知道,循环定义了)
    也就是说,当且仅当这些提交是那些提交的『基础』时才进行变基。

    @vjnjc 你可以 diff <merge 的主支>...<merge 的分支>
    据说 fossil 合并后分支会变成 tag 永久保留,你也可以轻易地看到这个 branch 的历史。
    squash 似乎不太适合在时域上进行 bisect,这对于大型项目还是挺重要的。
    maplerecall
        37
    maplerecall   33 天前 via Android
    微软这边的 git 项目合并 master 基本都 squash merge,保证 master 的记录是单线性的。至于合并前自己的分支爱怎么搞就怎么搞,PR 跑 build 和 test 能通过,不 conflict 就好了。

    不过我基本都只用 rebase,只有极少数情况出现多人同时开发具有互相依赖性的东西才会 merge 。很多 mono repo 每天 master 要进几十上百个不同 team 做的东西,用 merge 会很糟心。
    MrGoooo
        38
    MrGoooo   33 天前
    rebase 没有按时间排序,merge 按时间顺序
    oneisall8955
        39
    oneisall8955   33 天前   ❤️ 1
    @weiwenhao #13 有两点疑问
    1. 22 号的 bug,不能从 master 创建新分支修复吗?
    2. 22 号的 bug 是 15 号提交的,那在 15 号的分支上修复也可以吧?先 pull master 到 15 号分支,处理冲突,修复完 bug 再 merge 到 master
    Felldeadbird
        40
    Felldeadbird   33 天前
    我是个人和团队也用 merge 。分支线是会显得乱,但是不会出问题。
    charlie21
        41
    charlie21   33 天前
    为什么 ‘包含完整的提交历史记录’ 会是一个需要避免的问题? 你瞎搞之后丢记录了怎么办 行为艺术吗
    mdyy777
        42
    mdyy777   33 天前
    我选择 rebase
    MinonHeart
        43
    MinonHeart   33 天前
    一般原则 public branch 用 merge,private branch 用 rebase 。

    但是用 rebase 后要怎么 revert/reset 这次 rebase 呢?
    cco
        44
    cco   33 天前
    我用的 merge,因为场景并不复杂,merge 和 rebase 都差不太多。
    dyxLike
        45
    dyxLike   33 天前
    两个远程分支用 rebase 反而会乱吧
    libook
        46
    libook   33 天前   ❤️ 1
    我只知道当需要撤回合并操作的时候,特别是公司项目上线计划临时调整的时候,直接 revert merge 提交很方便,不知道 rebase 怎么处理,懂的可以分享一下。

    个人觉得版本控制系统的核心价值是体现整个版本变更历史,使用 rebase 仅会留下提交,无法区分是合并操作还是提交操作,所以“merge 产生无意义的提交”可能连 Linus 本人都不赞同。

    整理分支是另一码事,希望整理得多么“干净”取决于能接受丢失多少历史信息,就好比服务器每周五备份,周三的时候你想恢复周二的数据,对不起没有,只能恢复到上周五。

    你可以不在一个分支上体现任何 merge 记录,但也同时放弃了利用 merge 记录做审计或操作的能力,如果综合权衡是适合当前项目管理的方案的话,也是可以的。
    securityCoding
        47
    securityCoding   33 天前
    @libook 线上发版会基于 tag 来构建
    libook
        48
    libook   33 天前
    @securityCoding #47 不是每个 feature 一个 tag 吧,总会有合并操作的,打 tag 也是在合并完的分支上打 tag 。
    securityCoding
        49
    securityCoding   33 天前
    @libook 我的意思是用 tag 作为版本号,这样就隔离了版本与代码合并操作过程
    leafre
        50
    leafre   33 天前
    "merge 会产生一个无意义的提交" rebase 只是重播一遍,并不能解决无意义提交 的问题
    msg7086
        51
    msg7086   33 天前   ❤️ 1
    并入更改用 merge,散播更改用 rebase 。

    人人都懂 Git 的小公司 merge 的时候可以用普通的 merge commit,不是人人都懂 Git 的公司(特别是参差不齐的大公司)或者合并非常频繁的大公司,可以善用 squash merge 。(我司一般都是 squash merge,因为合并太频繁了,经常 Rebase 不现实。)



    ↑ 理想的 timeline 应该是类似这样的。



    ↑ 大多数公司代码的 timeline 是这样的。
    reactna1ve
        52
    reactna1ve   33 天前   ❤️ 1
    感觉 2#的说法是合理的
    本地分支同步 dev 用 rebase 保证本地的提交和顺序是清楚的
    dev 同步 hotfix 、合入 feature 用 merge,保证操作的节点顺序以及方便 revert

    我之前也比较喜欢用 squash merge,后来发现对于一个开发周期比较长的 feature,squash 到一起太容易丢 context 了。比如某几行修改是为了解决需求中的某个 bug,这时候提单个 commit,后续再看知道这个修改是干啥的;几千行的大修改,squash 到一个 commit 里,过几个月完全不知道这几行为啥要这么改……
    Biwood
        53
    Biwood   33 天前
    以前很少用 rebase,完全不知道有用 rebase 把提交历史记录整理一遍的说法,可能是每个人的习惯不同吧

    不用 rebase 的好处是,每一个操作细节都清清楚楚的留下记录,提交记录重要的不是“简洁”、“好看”,而是可追溯性
    wangbenjun5
        54
    wangbenjun5   33 天前
    merge 简单易懂,rebase 不是人人都会,另外 merge 包含完整的提交历史,这样出问题容易找人负责,谁改的谁写的一目了然,99%的公司都是 merge
    libook
        55
    libook   33 天前
    @securityCoding #49 这里讨论的问题是 merge 和 rebase,发生在打 tag 之前,似乎和 tag 关系不大。
    weiwenhao
        56
    weiwenhao   33 天前
    @oneisall8955 可以从 master 创建新的分支修复呀,也就是这么做的,但是定位问题然后修复上线用了 2 个小时。此时线上已经故障了两个小时了呀。 是比较严重的故障,需要立刻版本回退那种。
    Biwood
        57
    Biwood   33 天前
    由 2 楼的说法想到,这其实是一个思维模式问题,如果一直在主分支操作所有合并行为,包括解决冲突,那么可以一直用 merge 。如果操作主分支的人不希望承担解决冲突的责任,那么子分支用 rebase 的必要就来了。当然,直接把主分支往子分支合并也能解决一些问题,但这显然让分支流程变乱了,不管你坚持 merge 还是 rebase,都不推荐这么干。
    wingtao
        58
    wingtao   33 天前
    @weiwenhao 这种直接把 9.22 号的 pr revert 掉不好使么
    penghong
        59
    penghong   33 天前
    主干开发+小批量提交+squash merge
    weiwenhao
        60
    weiwenhao   33 天前
    @wingtao 应该是好使的,但是都没用过呀。。。当时 gitlab 的 revert 试了一下没成功就没试了,主要是不熟悉。
    zhw2590582
        61
    zhw2590582   33 天前
    看过一篇老外教程说:永远不要在公共分支 rebase
    oakland
        62
    oakland   33 天前
    @zhw2590582 此 rebase 非彼 rebase
    xiubin
        63
    xiubin   33 天前
    单人分支 rebase 公共分支;单人分支 merge into 公共分支
    Kobayashi
        64
    Kobayashi   33 天前
    @Kobayashi 仔细想了一想,之前的长回复应该补充一点。主要是楼主的问题应该从两个角度回答,我只回答了其中一部分。

    楼主问题提到“2 个远程分支合并”,是指原来两个分支都和主分支在一条线上,如果一个分支先合并,另一个与更新后的主分支分叉,合并时发生了 merge --no-ff. 按照楼主的理解,分支合并应该是

    1. rebase 到主分支,保证分之合并前没有分叉
    2. merge --ff,保证分支合并后没有额外 merge commit.

    其实这就是 非 Git 版本控制工具 的分支使用逻辑:分支历史必须是一条线,分支起点必须是主分支最新提交。如 SVN.

    这个问题实际要分为 2 个部分:

    1. 合并分支前是否要 rebase?
    2. merge 是否使用 --ff 快速推进,要不要不产生额外的“合并提价”?

    我之前的回复其实只针对了 2,介绍了 Git 分支非一条支线的特性,推荐了 --no-ff 合并。

    如果只针对 1,可以根据情况:

    - 如果向主分支合并时发生冲突,可以合并时解决冲突。或者 rebase 解决冲突,再合并。
    - 或者你想让提交历史图( timeline )更清晰一点,也可以先做 rebase 一下。如当前分支和合并前主分支时间隔的太久,直接合并后分支线头尾跨得太远,不好查看。或者是不想多个分支线合并后有交叉。(敲完才发现楼上 @msg7086 回复,参考其“理想的 timeline”一图,非常漂亮)
    - 或者分支合并前不做 rebase,降低工作流使用门槛。如 Github PR 合并方式:直接给你在网页上整一个按钮,点击后 merge --no-ff.

    不管哪种情况,推荐 merge --no-ff 优先。一些特殊情况,如分支上 只有 1 个新提交,可以 --ff 快速推进。
    ospider
        65
    ospider   33 天前   ❤️ 1
    都 2021 年了,竟然还有人在推荐 git flow
    supereasy
        66
    supereasy   33 天前
    从 16 年到现在 一直 merge --no-ff 不会转为 rebase
    celeron533
        67
    celeron533   33 天前
    我有时候先 interactive rebase,压掉不必要的 commit,最后 merge
    charlie21
        68
    charlie21   33 天前
    “次数多了分支线就很乱,怎么办”,如果关注的问题是这个,那么就你需要先列出你操作的分支名,然后会走向两种解决方式:
    1 增加分支,**增加一个分支作为 ‘缓存分支’ **,即改变分支策略
    2 分支不变,改变 merge 命令

    如果是办法 1,那么解决办法会非常简单,你会把 ‘造成分支错乱’ 归因为提交错了分支线。

    如果你需要前后三次提交(或无数次提交),将会导致分支错乱的原因是 你只有 2 个分支,自己的 branch -> main branch,这样 main branch 会很快被写入;将会导致分支清晰的原因是 你现在有 3 个分支,自己的 branch -> develop 分支 -> main branch 。这样因为多了一个分支,所以 develop 分支仍然会很乱( develop 分支是 ‘缓存分支’,等于为 main branch 作了缓存),故而 main branch 会保持清晰。

    https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow 图示
    https://www.atlassian.com/blog/git/written-unwritten-guide-pull-requests

    如果是办法 2,那么,哈哈 ... 这根本不是 merge 命令的问题 ... 你需要重新归因,而不是拿出某个命令来就用。实际上它是 pull request 策略的问题,而不是 merge 策略的问题。它是人员责任划分的问题,不是 git 的问题:是责任划分来指导 pull request 策略和具体 git 操作,而不是相反。相反只有颠覆,而且是盲从般的颠覆
    Kobayashi
        69
    Kobayashi   33 天前
    @ospider git flow 是严格了点,实践中未必要严格遵守使用,但其中的分支使用思想经久不衰。鉴于楼主目前遵循的分支使用逻辑是分支合并结果要保留单一直线,我觉的推荐 git flow 正合适。
    kaneg
        70
    kaneg   33 天前
    我看到过很多人把 git 的 commit 当成草稿箱,提交很多无意义的改动,每次 commit 基本在修改错别字或者反复 rollback 。针对这种情况,在 PR merge 到 master 之前,最好 squash 。否则如果日后做 trouble shooting 的时候,其中的每条 commit 就是对别人的折磨。
    xuanbg
        71
    xuanbg   33 天前
    项目比较复杂,多人同时维护。用 rebase 简直就是噩梦。
    wukongkong
        72
    wukongkong   33 天前 via Android
    @Pipecraft 我们用这个导致了半年的 commit 丢失,负责人不会用,瞎用,,,,
    beichenhpy
        73
    beichenhpy   33 天前
    永远 merge
    namelosw
        74
    namelosw   33 天前
    这其实本质和团队质量有关:

    其实最理想的情况就是努力培养团队,素质都不错,需求拆分合理,自动化测试和持续集成也做得很好,所有人在同一个分支疯狂 rebase 效果是最好的。

    如果有个总记不住拉代码,互相甩锅,功能拆分不完整,提代码就挂掉别人的功能,代码合进来也不知道对不对的团队,那只能先 merge…
    devfeng
        75
    devfeng   33 天前 via Android
    这个可以灵活应对吧,能用 rebase 的情况下尽量 rebase 了
    IvanLi127
        76
    IvanLi127   32 天前 via Android
    请求科代表做总结
    24bit
        77
    24bit   32 天前
    开发分支 rebase,合并 master fast forward merge
    Jsonz
        78
    Jsonz   32 天前
    @weiwenhao 我想了一下我们现在的流程
    各个 feature 会从 master 拉取分支,比如 featureA 、featureB 、featureC
    如果开发的过程中,master 上发现一个 bug,则会基于 master 拉取一个分支 hotfixA,改好合并到 master 自动发布
    发布完触发各个 feature 分支会自动 merge master 。
    假如这时候 featureA 测试完成,要发布的话,是 merge 到 master,发到线上发现有 bug,直接回滚上一个 merge 节点不就好了...
    git reset HEAD^ --soft 然后再修改代码提交先回滚?

    这样可以解决吗
    ychost
        79
    ychost   31 天前
    rebase 容易翻车,操作不熟
    SmiteChow
        80
    SmiteChow   29 天前
    rebase 是私有操作=你写了半天远程有更新且跟你改动有冲突你很不情愿需要及时解决并以此为基础继续干
    Merge 是公开操作=你写完了现在就是要合并推送到远程让其他人都瞧瞧你的改动有多么牛逼
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3049 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 01:09 · PVG 09:09 · LAX 18:09 · JFK 21:09
    ♥ Do have faith in what you're doing.