Git,分支 ~ 合并与变基

合并

       合并的流程如下:假定将other分支合并到master分支上。

  第一步,执行git merge other, Git会自动根据获取当前分支,并判断是否符合合并的条件。

  第二步,基于基点(base commit), 计算other分支与master分支上每个文件的差异,并尝试合并,若合并成功,无冲突,此时无需人工介入,Git自动创建一个合并提交(Merge commit),合并完成。

  第三步,若有冲突,把文件标志为”unmerged”状态,人工介入,解决冲突,手动创建一个提交,合并结束。

  第四步,第三步的另一种方案,当发现冲突之后,撤销合并操作,合并撤销。

1.1 前提条件

        A merge must occur within a single repository

        合并的分支处于同一个版本库。

        before you begin a merge, it’s best to tidy up your working directory. During a normal merge, Git creates new versions of files and place them in your working directory when it is finished. furthermore, Git also uses the index to store temporary and intermediate versions of files during the operation 

        在合并之前,工作目录必须是干净的。

1.2 有冲突

        若发生冲突,合并中断,需要人工介入,执行git status,可以查看冲突的文件列表。

On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)
 
Unmerged paths:
  (use "git add <file>..." to mark resolution)
    both modified:   Hello.txt
 
Untracked files:
  (use "git add <file>..." to include in what will be committed)
    result.txt
 
no changes added to commit (use "git add" and/or "git commit -a")

        显示Hello.txt文件存在冲突,点击查看冲突的内容。

<<<<<<< HEAD
Line under master
=======
Line under other
>>>>>>> other

        横线之上,master分支上的Hello.txt与基准点(base commit)的比较。横线之下,other分支上的Hello.txt与基准点(base commit)的比较。 

1.2.1 解决冲突

  逐个解决冲突的文件,只有三种策略。

  第一种,完全删除掉当前分支的内容。accept theirs。

  第二种,完全删除合并分支的内容。accept ours。

  第三种,前两种的mix。

  在实践中,需要遵循不覆盖别人代码的原则,所以accept ours很少使用。

1.2.2 回滚

        回滚,本质就是清空当前工作目录中的修改。若发生冲突,合并操作中断,不会自动创建合并提交(merge commit)。

  当执行合并时,

  当前分支的HEAD临时保存在ORGI_HEAD。

  被合并的分支HEAD临时保存在MERGE_HEAD。

  执行git merge –-quit,退出合并操作, abort的合并可以重新启动,退出之后只能重新开始。

  执行git reset –hard ORGI_HEAD, 回滚到最近的一次commit。

1.3  无冲突

  无冲突情况下,Git自动创建merge commit,日志信息为merge branch xx into XX,例如将other合并到master,显示为merge branch other into master。

  命令窗口会打印合并的策略,

1.3.1 already up-to-date

        when all the commits from the other branch (its HEAD) are already present in your target branch, even if it has advanced on its own, the target branch is said to be already up-to-date

        当master分支与other分支的差集为空时,或者表述为other分支中所有的提交都在master集合中。此时other分支合并到master分支,采用already up to date。

  它没有任何操作,因为它们已经合并过了。

1.3.2 fast-forward 

        A fast-forward merge happens when your branch HEAD is already fully present and represented in the other branch. This is the inverse of the Already up-to-date case 

        fast-forward是快进到最近一次提交, 当master分支合并到other分支时,other分支的HEAD会指向master分支的最近一次提交。

        例如将master合并到other分支上时,只是将other分支的HEAD指向master的最近一次提交。

1.3.3 resolve

        the resolve strategy operates on only two branches, locating the common ancestor as the merge basis and performing a direct three-way merge by applying the change from the merge base to the tip of the other branch HEAD onto the current branch

        默认的方式,比较两个分支的不同文件,尝试合并,若无冲突,会自动创建合并提交(merge commit)

1.3.4 recursive

        两个以上的分支进行合并时,采用的策略。假设A, B, C三个分支进行合并,根据merge命令中参数的顺序,先合并A, B,然后将二者的合并结果与C进行合并,类似于数据库中的join操作。 

1.3.5 octopus

        The octopus strategy is specifically designed to merge together more than two branches simultaneously. Conceptually, it is fairly simple, internally, it calls the recursive merge strategy multiple times, once for each branch you are merging, However, this strategy cannot handle a merge that requires any form of conflict resolution that would necessitate user interaction. In such a case, you are forced to do a series of normal merges, resolving the conflicts one step at a time.

        多线程,异步执行,例如A, B,C,D,异步执行A与B合并,C与D合并,然后再将二者的结果进行合并。

1.4 指令

 格式:

        git merge指令有两种格式。

        第一种格式,git merge (--continue, --abort, --quit)控制合并的流程,abort与continue是一对,quit退出后,只能重新进行合并。

        第二种格式

git merge [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
          [--no-verify]
          [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
          [--[no-]allow-unrelated-histories]
          [--[no-]rerere-autoupdate] [-m <msg>] [-F <file>] [<commit>…]

选项:

        n,stat:显示合并的统计信息。

        no-commit:合并时不自动创建提交对象。

        squash:压缩合并提交和当前提交为一个提交。不会这么干,会混乱提交历史。

        m,F,edit:提交的日志信息,m从控制台输入,F从文件中获取,edit开启编辑器。

        s :指定合并的策略。默认的策略即可。

        no-verify:不校验合并提交的对象。

        S :指定提交的签名。

        allow-unrelated-histories:多个分支合并时,必须至少存在一个基准点。它的作用就是比较彼此的不同之处。这个选项慎用,因为除补丁之外,添加这个选项说明大概率是错误的合并

示例:

        git merge other(当前分支为master)

变基

        变基(rebase),改变分支的基准点,流程如下:

        第一步,计算变基分支与当前分支的提交差集。

        第二步,重新创建差集中的每一个提交对象。

        第三步,变更变基分支与当前分支的基准点为HEAD(默认值,可以提供commit标识指定基准点)。

        个人理解,rebase会修改有向无环图,实际中不使用。但是它的优点也非常明显,可以使有向无环图变的非常清晰。

        例如dev, master分支,互相merge多次之后,有向无环图会存在很多交叉点,非常乱。

2.1 场景

        存在三种情形。

        第一种情形,假设master,dev分支存在直接的基准点

 

        此时变基的过程如下:

        创建新的提交对象D’, E’

        将dev分支与master分支的基准点由A变为C。

        第二种情形,假设master,dev分支存在间接的基准点。

        此时的变基过程如下:

        计算dev分支与master分支的差集,上图中为D,E,F,G

        创建新的提交对象D’,E’,F’,G’。

        master, dev分支的基准点变为C, some,dev分支的基准点消失。

        具体的影响有:F,G提交消失,取而代之的是F’,G’。 D, E提交没有变,但是新创建了D’,E’提交,它们的变更集与D,E 是一样的。提交的历史结构图也发生了改变。

        第三种情形,假设master,dev分支存在直接基准点,但是dev分支上存在子分支

        此时的变基过程如下:

        创建新的提交对象D’,E’

        dev,master分支的基准点由A变为C。

        dev,some分支的基准点消失,some,master分支基准点为A。

        可以看到整个过程也是多出了两个提交,D’, E’,而且是重复的。

2.2 指令

格式:

        git rebase有三种指令格式:

        第一种, git rebase (--continue | --skip | --abort | --quit | --edit-todo | --show-current-patch),控制rebase流程的,略。

        第二种格式:

git rebase [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase> | --keep-base] [<upstream> [<branch>]]

        第三种格式与第二种格式是类似的。

选项: 

        -i,interactive为交互模式,它会打开编辑器,允许修改整个DRG。压缩,排序,修改单个提交对象等等。

        --exec :执行1到N组shell脚本指令。略。

        --onto :指定基准点。若指定的是分支,则为分支的最近一次提交。

        upstream, branch:远程分支名称或本地分支名称。

### Git 分支合并后的存在状态 当使用 `git merge` 或 `git rebase` 处理分支时,分支的存在否取决于用户的操作以及后续的行为。以下是关于这两种情况的具体分析: #### 1. **Git Merge 后的分支状态** 在执行 `git merge` 将某个分支(如 `feature`)合并到另一个分支(如 `master`)之后,原分支并不会自动删除[^1]。这意味着即使已经完成了合并,`feature` 分支仍然会存在于仓库中,直到显式调用命令将其移除。通常可以通过以下方式清理不再需要的分支: ```bash git branch -d feature ``` 如果尝试删除尚未完全合并分支,则需要强制删除: ```bash git branch -D feature ``` 因此,在默认情况下,被合并分支依然保留其历史记录上下文信息。 #### 2. **Git Rebase 后的分支状态** 对于 `git rebase` 操作而言,它是将一系列提交应用到新的础之上,而不是简单地创建一个新的合并点。一旦完成动作后,原始分支上的提交实际上已经被重新定位到了目标分支上[^2]。然而需要注意的是,尽管这些更改已成功移植至新位置,但源分支本身依旧保持不——除非特别指示去更新它的指针指向最新版本的位置。 例如,在下面的例子中: ```bash $ git rebase --onto master server client ``` 这里实际上是把 `client` 分支相对于 `server` 的差异部分转移到了 `master` 上面。此时虽然实现了功能性的迁移,但是如果没有进一步的动作比如切换当前工作目录到该分支并推进远程服务器(`push`)的话, 那么原来的 `client` 分支还是维持现状并未消失. 同样地,要彻底消除旧版的历史痕迹,也需要明确发出指令来丢弃那些已被替代掉的部分: ```bash git branch -d old_branch_name ``` 综上所述,无论是采用 `merge` 方法还是采取 `rebase` 方案来进行项目开发流程管理的时候,默认都不会让涉及其中任一分支自行消亡;只有当我们主动决定清除它们之时才会真正意义上结束他们的生命周期。 ```python # 示例代码展示如何安全地删除无用分支 def delete_safe(branch_name): try: # 检查分支是否存在且未被合并 check_output(f'git branch --contains {branch_name}') print(f"{branch_name} 已经被合并,可以安全删除") system_call(f'git branch -d {branch_name}') # 安全删除 except CalledProcessError as e: print(f"{branch_name} 还有未合并的内容,无法直接删除") delete_safe('example_feature') ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜗牛旅行1899

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值