4.分支管理

本文最后更新于:2021年9月8日 晚上

分支管理

创建与合并分支

  • HEAD指针:指向你正在工作中的本地分支的指针

  • 默认本地仓库只有一条分支main

    • HEAD指向main,main指向要提交的时间线
  • git switch <分支名>:切换分支

    • -c 创建并切换分支,分支指向main相同的提交

    • 此时HEAD指向新分支。之后的提交都是在新分支下

      img

      • HEAD指向正在工作的本地分支,随该分支一起移动
  • git branch:查看本地所有分支

    • 当前分支名前会有一个*号
    • -a:查看本地和远程仓库所有分支
    • -r:查看远程仓库分支
    • -v:查看各分支最后一个提交对象的信息
    • --merged:查看哪些分支是当前分支的直接上游
      • 一般来说,列表中没有 * 的分支通常都可以用 git branch -d 来删掉。原因很简单,既然已经把它们所包含的工作整合到了其他分支,删掉也不会损失什么
    • --no-merged:查看尚未合并的工作
      • 由于这些分支中还包含着尚未合并进来的工作成果,所以简单地用 git branch -d 删除该分支会提示错误,因为那样做会丢失数据
      • -D:强制删除
  • git merge <分支名>:合并指定分支的工作到当前分支下

  • git branch -d <分支名>:删除分支

    • -D:删除一个没有被合并过得分支

实际操作总结

  • 如果分支切换时,该分支的暂存区或者工作目录里,存在还没有提交的修改,会和你即将检出的分支产生冲突从而阻止 Git 为你切换分支
    • 要么提交修改,要么使用git stash暂存
  • 分支切换后,Git 会把工作目录的内容恢复为检出某分支时它所指向的那个提交对象的快照

分支冲突

  • 单线的历史分支不存在任何需要解决的分歧

  • 合并冲突:

    • 当创建多分支时,如果修改不同文件,则合并不会提示冲突

      • 任何包含未解决冲突的文件都会以未合并(unmerged)的状态列出
    • 如果在不同分支中修改相同文件,合并时会提示冲突,需要手动修改冲突,确定文件的最终版本

      • 删除标记

      img

  • Git用<<<<<<<=======>>>>>>>标记出不同分支的内容

    • ======= 隔开的上半部分,是 HEAD中的内容,下半部分是在合并分支中的内容
  • 合并策略:

    • 默认使用Fast forward,会直接将Master分支指向Develop分支。在这种模式下,删除分支后,会丢掉分支信息

      img
    • git merge --no-ff -m "merge with no-ff" dev

      • 使用--no-ff参数后,会执行正常合并,在Master分支上生成一个新节点

        img
      • 当合并的分支,没有祖先关系(即两个不同线分支),Git会用两个分支以及它们的共同祖先进行一次简单的三方合并计算,然后创建一个分支存放合并结果

  • 合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并

分支管理策略

img

  • 主分支main(master):代码库应该有一个、且仅有一个主分支。仅用来发布新版本,平时不能在上面干活.

  • 工作分支dev:日常开发。如果想正式对外发布,就在分支上,对Develop分支进行"合并"

  • 临时分支

    • 功能分支feature-xxx:为了开发某种特定功能,从dev分支上面分出来的。开发完成后,要再并入dev

      img
    • 预发布分支release-xxx:指发布正式版本之前(即合并到main分支之前),我们可能需要有一个预发布的版本进行测试。预发布分支是从dev分支上面分出来的,预发布结束以后,必须合并进dev和main分支.

    • 修补bug分支fixbug-xxx:修补bug分支是从main分支上面分出来的。修补结束以后,再合并进main和dev分支

      • bug突然出现,如何保存当前的工作?恢复工作?

        1
        2
        3
        4
        git stash	//把当前工作现场“储藏”起来,等以后恢复现场后继续工作
        git stash list //查看该分支保存的状态
        git stash pop //在该分支下,恢复之前保存的状态,并删除该记录(如果状态属于该分支会删除,如果不属于相当于一个合并操作)
        git stash apply <名字> //恢复指定的状态
      • 修补main分支后,如何在dev分支上进行同样的修改操作?

        1
        git chery-pick <commit编号>	//复制一个特定的提交到当前分支

多人协作

  • 当从远程仓库克隆时,实际上Git自动把本地的main分支和远程的main分支对应起来了,并且,远程仓库的默认名称是origin

    • (远程仓库名)/(分支名) 这样的形式表示远程分支

    • 它们是一些无法移动的本地分支,只有在 Git 进行网络交互时才会更新

      img
  • 分支推送策略:

    • main分支是主分支,因此要时刻与远程同步;
    • dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
    • bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
    • feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
  • 工作模式:

    1. 首先,可以试图用git push origin <branch-name>推送自己的修改;

    2. 如果推送失败,则因为远程分支比你的本地新,需要先用git pull试图合并来保证本地和远程同步;

      img
      • 如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
    3. 如果合并有冲突,则解决冲突,并在本地提交;

    4. git status查看当前状态、寻找冲突的文件,手动修改

    5. 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!

rebase

  • 作用:rebase操作可以把本地未push的分叉提交历史整理成直线;

  • 目的:使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比。

  • 示例:

    img

    • 通过merge合并这两个分支,会产生一个新的提交对象(C5)

    • $ git checkout experiment
      $ git rebase master
          First, rewinding head to replay your work on top of it...
          Applying: added staged command
      

      会在在 C3 里产生的变化补丁在 C4 的基础上重新打一遍

  • 原理:回到两个分支最近的共同祖先,根据当前分支(也就是要进行衍合的分支 experiment)后续的历次提交对象(这里只有一个 C3),生成一系列文件补丁,然后以基底分支(也就是主干分支 master)最后一个提交对象(C4)为新的出发点,逐个应用之前准备好的补丁文件,最后会生成一个新的合并提交对象(C3’),从而改写 experiment 的提交历史,使它成为 master 分支的直接下游

    img

  • 命令:git rebase [主分支] [特性分支] 命令会先取出特性分支 ,然后在主分支上重演

    • 特性分支必须是从主分支直接分出来的,一步一步走
    • git rebase --onto <主分支> <特性分支1> <特性分支2>
      • 特性分支1从主分支分出,特性分支2从特性分支1分出
      • 取出 主分支 分支,找出 特性分支2 分支和 特性分支1 分支的共同祖先之后的变化,然后把它们在 主分支 上重演一遍
  • 注意:一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。

相关命令

  • git remote:查看远程库的信息
    • -v:显示更详细的信息,显示可以抓取和推送的地址
  • git push origin --delete <远程分支名>:删除远程分支
    • git clone -b <指定分支名> <远程仓库地址>:克隆远程库指定分支到本地库

扩展阅读


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!