Github入门3 - 分支基础(与merge冲突时的解决方案)

本文详细介绍了Git的分支操作,包括创建、查看、切换、删除和合并分支。强调了在执行`git checkout`和`git merge`时需要注意的事项,以及如何处理分支冲突。同时,探讨了实际工作中遇到的分支应用场景,如紧急修复分支的创建与合并。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[原文链接:Link] 转载请注明原作者

感谢guapi的指导与纠错


🌿Git 分支基础

区别于3种对象,分支(branch)逻辑上是一个版本队列(Queue)
只不过其本质只是一个 指针 (head)

这个指针可以被称为 **头指针(head)**其是活动的,永远指着它 ※最新※ 的commit对象 (的hash key)。

本地commit更新到第几个了,branch的head就指向它。

此外还有一个本地项目当前的 HEAD 指针,区别于各个 branches 的 head

其指向当前工作中的 branch
另一层含义: 每次 commit 时,HEAD 带着本地当前 branch 的 head 往前走

branch 被 ./.git/ 中的两块内容来管辖,分别是 HEAD 文件refs 目录

  • Git 系统层级:

    • branch > commitObj > TreeObj > BlobObj
  • .git 目录结构补充

    • hooks:
    • info:
    • logs: 存着 $ git log 所显示的内容,也就是commit和branch记录
    • objects: 存对象 (hash-object) 的数据库 (也就是版本库,本地Repo)
    • refs: 存着每个 branch 指向 commit 对象的指针(就是存着它最新commit对象的hash值)
    • COMMIT_EDITMSG:
    • config:
    • description:
    • FETCH_HEAD:
    • HEAD: 存着当前使用中的分支(就是存着上面👆 refs的路径,key=branchName,val=path)
    • index: 当前暂存区内容

🎐Git branch 初见

通过 $ git log --oneline 可查看commit和branch记录,大体为下:

08cb1a3 (HEAD -> newbranch) third commit
ad82e41 second commit
ab3b82f (master) first commit

上段表明当前 HEAD指针 指向了 newbranch 分支的最新 commit 上,

而 newbranch 领先了 master 主分支 2个 commits (主分支还停在 first commmit)

若现在进行更新,则默认把新 commit 分配给 HEAD 也就是 newbranch 分支中。

b93aaf9 (HEAD -> master, newbranch) second commit
ab3b82f first commit

上段表明当前 HEAD指针 指向了 master 分支的最新 commit 上,

而 newbranch 和 master 主分支目前版本相同

若现在进行更新,则默认把新 commit 分配给 HEAD 也就是 master 分支中。

b93aaf9 (HEAD -> newbranch, master) second commit
ab3b82f first commit

上段表明当前 HEAD指针 指向了 newbranch 分支的最新 commit 上,

而 newbranch 和 master 主分支目前版本相同

若现在进行更新,则默认把新 commit 分配给 HEAD 也就是 newbranch 分支中。

可以看出,HEAD 是个特别指针,指向当前工作中的 branch, 而branch 也是个指针,指向它的最新 commit


🎐Git branch 的 CURD 操作
✨创建分支 ($ git branch)
  • $ git branch <branchName> (于当前 commit 上创建分支,但不会变动 HEAD 所指的分支)

    (一般是先用上面这条,再用checkout切换)

  • $ git checkout -b <branchName> (于当前 commit 上创建分支,并将 HEAD 指针指向这个分支)

  • $ git branch <branchName> <commitObjHash> (新建分支并手动分配好自定义的 commit 指针)

✨查看分支 ($ git log / $ git status / $ git reflog )
  • $ git branch (查看所有 branches)
  • $ git branch -v (查看每个 branch 的最新 commit)
  • $ git branch --merged (查看有哪些 branches 已经合并到当前 branch)
  • $ git branch --no-merged (查看所有未合并的 branch)
  • $ git log (查看所有 branches 及主工作线上的所有 commits)
  • $ git log --pretty=oneline (上条的简洁版,每个commit描述只占一行)
  • $ git log --oneline (上条再简洁版,每个 hash 仅显示一部分)
  • $ git log --oneline --decorate (与上条相似)
  • $ git log --oneline --decorate --graph --all (与上条相似)
  • $ git reflog (查看项目分支历史,包含已删除的分支记录)
✨切换分支 ($ git checkout)
  • $ git checkout <branchName> (在当前commit上,把 HEAD 指向某个分支,也叫切换分支)
✨删除分支 ($ git branch -d)
  • $ git branch -d <branchName> (删除一个※已合并※ branch)
  • $ git branch -D <branchName> (强制删除一个※未合并※ branch)
✨合并分支 ($ git merge)
  • $ git merge <branchName> (将当前 branch 合并到目标 branch)

☠️关于 Git 的 checkout :切要小心操作
  • 每次 checkout (切换分支) 前,一定要确保:

  • 当前分支※必须※是干净的 (就是当前分支一定已被commit才行,且 commit 后没有任何修改!)

  • 不然会产生如下后果:

    • 切换失败,或切后的※分支被污染※,本地文件乱套,或被覆盖丢失!

      多次导致主分支污染,估计就要被开了…

  • 原因:

    • checkout (切换分支) 会动三个地方:

      • HEAD 指针当前的指向

      • 暂存区内容会滚到另一个 branch 保存的内容

      • 工作目录也会回滚!!

    • 但 checkout 管不上下列地方:

      • ⚠️未跟踪的新内容 untracked (会污染至切后分支!)
      • ⚠️未提交的 暂存区的新内容 unmodified (会切换失败!)
  • 解决方案:

      1. 切换前输入 $ git status 查看是否有文件未跟踪,未暂存,若有:

        临时 add 并 commit 到一个新 branch 中。

      1. 切换前输入 $ git status 查看是否有文件未跟踪,未暂存,若有:

        通过 $ git stash 临时将 unmodified 文件存入 git 的临时栈中,

        然后切换分支去进行其他工作,完成其他工作再切回来后,将临时栈中文件取回。

        • $ git stash 的 CURD 操作
          • $ git stash 将目前所有 unmodified 文件存入栈 【常用】
          • $ git stash list 查看栈内清单 【常用】
          • $ git stash pop 出栈,并恢复工作目录 【常用】
          • $ git stash apply 不出栈,但恢复工作目录
          • $ git stash drop 出栈,但不恢复工作目录

☠️关于 Git 的 merge:切要小心操作
  • ✔️正确的合并操作:
    • 1是大分支,2是小分支
    • $ git checkout <branchName1> 切到1
    • $ git merge <branchName2> 把2合到1 (把2的差异内容覆盖到1上)
    • $ git branch -d <branchName2> 删除2
  • ☠️错误的操作(顺序错误):
    • 1是大分支,2是小分支
    • 写完2分支内容,把1分支覆盖到2。
    • 刚写的全丢

🎐 Git branch 实际应用

【场景】:

  • 单位有个 ⛰️project 在 Github,

  • 其具有🏛️稳定发布分支(master),开发(dev)分支🏭production branch,与数千个🏗️function branches。

  • 你在其 🏗️function branch #2455 上进行工作。

    • 今天,你从 ⛰️project pull 下来 🏗️function branch #2455,
    • 并在本地 commit 了 3 个新版本在这分支,但还未 push 到线上分支中。
  • 此时,老板来电话:

    • “紧急情况!⚠️Github issue #1642 发现了🏭production branch 的一个严重问题,需要你来点对点地紧急修复!”

【你需要】:

  • 保存你本地分支内容在一个🗻新分支上,回 ⛰️project pull 下来存在问题的那个分支🏭production branch。

  • 再新建一个 🌋紧急修复分支 “#1642”, 点对点对 bug 进行修复,

  • 测试通过后,checkout 回 🏭production branch,将**🌋紧急修复分支 “#1642” **与其合并 -> 🌃。

  • push 新的合并后的 🌃function branch #1988(新) 到线上分支中。

    • 若你没有合并权限,则需要跳过合并那步,直接 commit & push 🌋紧急修复分支 "#1642"
    • 并发出 merge 请求,等待管理员或老板进行后续处理。
  • 最后回到你的刚存好的本地🗻新分支,继续你原先在 🏗️function branch #2455 的工作。


🎐分支过程中面临的问题:分叉 (分支冲突)

属于上述案例中的特殊情况,例如:

  • 项目的 🏭production branch 的工作目录中是 **a.java (version-137) **出错需要更改,
  • 你做完了 🌋紧急修复分支 “#1642” 并成功 merge 和 push 回去,此时 a.java (version-138-张三版) 已变动。
  • 但你回到自己原本基于 🏗️function branch #2455 的🗻新分支 时,发现它也变动了 **a.java (version-138-李四版) **。
  • 等你写完这个 🗻新分支, merge 回 🏗️function branch #2455 后,想进一步 merge 到 🏭production branch
  • 但你的 **a.java (version-138-李四版) ** 还是基于 v137-bug版 的老版本。
  • 此时你还能 merge 到 🏭production branch 吗?(对于a.java文件,过程类似下图↓)

git分叉git分叉

  • 能 ✔️ 。

  • 在你输入:

    • $ git checkout productionBranch
    • $ git merge functionBranch#2455
  • 会出现如下信息:

    • Administrator@x82t7420 user ~/Desktop/workspace (productionBranch)

    • 会变成 ↓

    • Administrator@x82t7420 user ~/Desktop/workspace (productionBranch|MERGING)

    • 若此时输入 $ git diff 会发现本地工作目录的被冲突文件被附加了下类信息:

      a line of a.java before v138

      <<<<<<< HEAD

      a line of a.java for v138-张三版

      **=======**

      a line of a.java for v138-李四版

      **>>>>>>> functionBranch#2455 **

      a line of a.java before v138

    • 你需要决定,对于

      • a line of a.java for v138-张三版
      • a line of a.java for v138-李四版
    • 这两行是全留下➕,还是需要继续修改🛠️,或是删掉其中一个✂️?。

  • 在你处理完这个 a.java 后,它就成为了 (version-138-综合版)

  • 此时你再 git add, commit, 就彻底 merge 完成!

    • Administrator@x82t7420 user ~/Desktop/workspace (productionBranch|MERGING)

    • 变回 ↓

    • Administrator@x82t7420 user ~/Desktop/workspace (productionBranch)
      git分叉

  • 此时,综合版 branch 一旦合并成功,其他分支就可以该删删了。


🎐分支模式 (branch mode)
  • —— 不同公司有不同模式,大体都一样,但面试时还是要问清楚

  • 通用分支模式:

    • master 分支,存稳定发布版代码
    • dev 分支,存开发版代码
    • topics 分支群,存开发中的各个功能 (新特性) 的代码,故又叫特性 (feature) 分支或功能 (function) 分支。
  • 分支层级:

    • master > dev > topics

      (master 分支总落后于 dev, dev分支总落后于 topics)

      最细的分支开发总是最靠前,而最稳定的总在后面


🌿题外话:客制化自己的(高层)封装命令

通过上一章了解了 $ git add$ git commit 其实是对多条底层命令的封装组合拳。

现在咱们自己也可以在一定程度上封装自己的 git 命令

如把 $ git log --oneline --decorate --graph --all 封装为 $ git loa

则仅需:

$ git config --global alias.loa "log --oneline --decorate --graph --all"

其实该功能更应该叫 “alias” (配别名) 功能,十分方便


😄 望这篇笔记能对你也有所帮助,若是喜欢,也不妨点一下收藏,万分感谢。

如有错误,也尽请指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值