Table of Contents
[原文链接: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 (会切换失败!)
-
-
解决方案:
-
-
切换前输入
$ git status
查看是否有文件未跟踪,未暂存,若有:临时 add 并 commit 到一个新 branch 中。
-
-
-
切换前输入
$ 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 stash 的 CURD 操作:
-
-
☠️关于 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 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)
-
-
此时,综合版 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” (配别名) 功能,十分方便
😄 望这篇笔记能对你也有所帮助,若是喜欢,也不妨点一下收藏,万分感谢。
如有错误,也尽请指出。