【git#4】分支管理 -- 知识补充

一、bug 分支

假如我们现在正在 dev2 分支上进行开发,开发到一半,突然发现 master 分支上面有 bug,需要解决。

  • 在Git中,每个 bug 都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。

可现在 dev2 的代码在工作区中开发了一半,还无法提交,怎么办?例如:

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ git branch
* dev2
  master

lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d
I am coding...

lighthouse@VM-8-10-ubuntu:gitcode$ git status
On branch dev2
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   book

no changes added to commit (use "git add" and/or "git commit -a")

Git 提供了 git stash 命令,可以将当前的工作区信息进行储藏,被储藏的内容可以在将来某个时间恢复出来。

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ git stash
Saved working directory and index state WIP on dev2: 2bd7b8b modify Readme
lighthouse@VM-8-10-ubuntu:gitcode$ git status
On branch dev2
nothing to commit, working tree clean

用 git status 查看工作区,就是干净的(除非有没有被 Git 管理的文件),因此可以放心地创建分支来修复bug。

储藏 dev2 工作区之后,由于我们要基于 master 分支修复 bug,所以需要切回 master 分支,再新建临时分支来修复 bug,示例如下:

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout -b fix_bg # 新建并切换
Switched to a new branch 'fix_bg'
lighthouse@VM-8-10-ubuntu:gitcode$ vim book
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d,e
lighthouse@VM-8-10-ubuntu:gitcode$ git add book
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "fix bug"
[fix_bg c0637e0] fix bug
 1 file changed, 1 insertion(+), 1 deletion(-)

修复完成后,切换到 master 分支,并完成合并,最后删除 fix_bg 分支

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout master
Switched to branch 'master'
lighthouse@VM-8-10-ubuntu:gitcode$ git merge --no-ff -m "merge fix_bug branch" fix_bg
Merge made by the 'ort' strategy.
 book | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

至此,bug的修复工作已经做完了,我们还要继续回到 dev2 分支进行开发。切换回 dev2 分支:

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout dev2
Switched to branch 'dev2'
lighthouse@VM-8-10-ubuntu:gitcode$ git status
On branch dev2
nothing to commit, working tree clean

工作区是干净的,刚才的工作现场存到哪去了?用 git stash list 命令看看:

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ git stash list
stash@{0}: WIP on dev2: 2bd7b8b modify Readme

工作现场还在,Git 把 stash 内容存在某个地方了,但是需要恢复一下,如何恢复现场呢?我们可以使用 git stash pop 命令,恢复的同时会把 stash 也删了,示例如下:

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ git stash pop
On branch dev2
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   book

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (e2dfd6d0312e2454d1a7a4a3eb65cf3e28f333af)

再次查看的时候,我们已经发现已经没有现场可以恢复了

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ git stash list
lighthouse@VM-8-10-ubuntu:gitcode$ 

另外,恢复现场也可以采用 git stash apply 恢复,但是恢复后,stash内容并不删除,你需要用 git stash drop 来删除;

  • 当然也可以多次 stash,恢复的时候,先用 git stash list 查看,然后恢复指定的 stash,用命令git stash apply stash@{o}

恢复完代码之后我们便可以继续完成开发,开发完成后便可以进行提交,例如:

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d
I am coding... Done
lighthouse@VM-8-10-ubuntu:gitcode$ git add .
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "modify book"
[dev2 ccb0f97] modify book
 1 file changed, 1 insertion(+)

但我们注意到了,修复 bug的内容,并没有在 dev2 上显示。此时的状态图为:

Master 分支目前最新的提交,是要领先于新建 dev2 时基于的 master 分支的提交的,所以我们在 dev2 中当然看不见修复 bug 的相关代码。

  • 我们的最终目的是要让 master 合并 dev2 分支的,那么正常情况下我们切回 master 分支直接合并即可,但这样其实是有一定风险的

原因:在合并分支时可能会有冲突,而代码冲突需要我们手动解决(在 master上解决)

  • 我们无法保证对于冲突问题可以正确地一次性解决掉,因为在实际的项目中,代码冲突不只一两行那么简单,有可能几十上百行,甚至更多,解决的过程中难免手误出错,导致错误的代码被合并到 master 上。

此时的状态为:

解决这个问题的一个好的建议就是:最好在自己的分支上合并下 master ,再让 master 去合并dev ,这样做的目的是有冲突可以在本地分支解决并进行测试,而不影响 master

此时的状态为:

对应的实操演示如下,要说明的是,以下演示的merge操作,没有使用 --no-ff ,但上述的图示是禁用 Fast forward 了模式后得出的,主要是为了方便解释问题。

bash 复制代码
# dev 合并 master
lighthouse@VM-8-10-ubuntu:gitcode$ git branch
* dev2
  master
lighthouse@VM-8-10-ubuntu:gitcode$ git merge master
Auto-merging book
CONFLICT (content): Merge conflict in book
Automatic merge failed; fix conflicts and then commit the result.

# 发送冲突
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
<<<<<<< HEAD
a,b,c,d
I am coding... Done
=======
a,b,c,d,e
>>>>>>> master

# 解决冲突并重新提交
lighthouse@VM-8-10-ubuntu:gitcode$ vim book
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d,e
I am coding... Done
lighthouse@VM-8-10-ubuntu:gitcode$ git add .
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "merge master"
[dev2 9e77002] merge master
lighthouse@VM-8-10-ubuntu:gitcode$ git status
On branch dev2
nothing to commit, working tree clean

# 切回 master
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout master
Switched to branch 'master'

# master 合并 dev2  -- 无需解决冲突
lighthouse@VM-8-10-ubuntu:gitcode$ git merge dev2
Updating adbb267..9e77002
Fast-forward
 book | 1 +
 1 file changed, 1 insertion(+)
lighthouse@VM-8-10-ubuntu:gitcode$ git status
On branch master
nothing to commit, working tree clean

# 删除 dev2 分支
lighthouse@VM-8-10-ubuntu:gitcode$ git branch -d dev2
Deleted branch dev2 (was 9e77002).
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d,e
I am coding... Done

二、强制删除分支

软件开发中,总有无穷无尽的新的功能要不断添加进来

  • 添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个分支,我们可以将其称之为 feature 分支,在上面开发,完成后,合并,最后,删除该 feature 分支。
  • 可是,如果我们今天正在某个 feature 分支上开发了一半,被产品经理突然叫停,说是要停止新功能的开发。虽然白干了,但是这个 feature 分支还是必须就地销毁,留着无用了。
  • 这时使用传统的 git branch -d 命令删除分支的方法是不行的。

演示如下:

bash 复制代码
# 新增并切换到 dev3 分支
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout -b dev3
Switched to a new branch 'dev3'
lighthouse@VM-8-10-ubuntu:gitcode$ clear

# 开始开发新功能并提交
lighthouse@VM-8-10-ubuntu:gitcode$ vim book
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
write bbb for new branch
a,b,c,d,e
I am coding... Done
I am writing new features ...
lighthouse@VM-8-10-ubuntu:gitcode$ git add .
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "modify book for new features"
[dev3 fb6a737] modify book for new features
 1 file changed, 1 insertion(+)
 
 # 此时新功能叫停, 切回 master 准备删除 dev3
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout master
Switched to branch 'master'

对 dev3 进行删除,如下:

bash 复制代码
# 常规删除 dev3 分支时失败
lighthouse@VM-8-10-ubuntu:gitcode$ git branch -d dev3
error: The branch 'dev3' is not fully merged.
If you are sure you want to delete it, run 'git branch -D dev3'.
# 按照提示进行删除
lighthouse@VM-8-10-ubuntu:gitcode$ git branch -D dev3
Deleted branch dev3 (was fb6a737).

三、分支的作用

🌊 分支在实际中有什么用呢?

  • 假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。
  • 如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
  • 现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

而且 Git 无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件

四、细节补充

1. 未提交修改时(未commit)

当我们在 dev 分支下修改文件之后,master 还是可以看到的(没有 add 的情况下),如下:

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout dev
Switched to branch 'dev'
lighthouse@VM-8-10-ubuntu:gitcode$ vim file

lighthouse@VM-8-10-ubuntu:gitcode$ git checkout master
Switched to branch 'master'
lighthouse@VM-8-10-ubuntu:gitcode$ cat file
i miss you # master 分支
I Miss You # dev 分支

lighthouse@VM-8-10-ubuntu:gitcode$ git checkout dev
Switched to branch 'dev'
lighthouse@VM-8-10-ubuntu:gitcode$ git add file
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout master
A	file
Switched to branch 'master'
lighthouse@VM-8-10-ubuntu:gitcode$ cat file
i miss you # master 分支
I Miss You # dev 分支
  • 工作目录是共享的 :所有未提交的改动(包括未 add 的修改和已 add 但未 commit 的暂存)都存在于工作目录 中,不会被 Git 自动隔离到特定分支
  • 切换分支时的行为 :
    • 如果目标分支(如 master)和当前分支(如 dev)对同一文件的修改不冲突,Git 允许直接切换,并保留工作目录的改动。
    • 因此,在未提交的情况下,无论切换到哪个分支,看到的都是工作目录中的当前内容(即未提交的修改)

2. 已提交修改后

而当我们在 切换到 dev 分支进行 commit 之后,然后再切换到 master 分支查看,然后 如下:

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout dev
A	file
Switched to branch 'dev'
lighthouse@VM-8-10-ubuntu:gitcode$ git commit file
Aborting commit due to empty commit message.
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "改变" file
[dev 1a1993f] 改变
 1 file changed, 2 insertions(+)
 create mode 100644 file
  • 提交 (commit) 的作用 :将暂存区的内容永久记录到当前分支的历史中,此时修改正式归属于 dev 分支。
  • 切换分支时的行为 :
    • Git 会严格根据目标分支(如 master)的最新提交重建工作目录。
    • 如果 master 分支从未包含 file 文件(即该文件只在 dev 分支提交过,下面等下会细说这个问题 ),切换到 master 时,Git 会删除工作目录中的 file 文件,因为 master 分支的历史中不存在它

总结

  • 提交后,数据已保存在 dev 分支的历史中,不会丢失。
  • master 分支的工作区被重建为它自己的最新提交状态,因此看不到 dev 分支的改动。

这里要说一下,由于我们在 master 分支下没有 commit 过文件,因此当我们在 dev下首次 commit,那么 master 分支下的 file 文件就会消失,如下:

bash 复制代码
lighthouse@VM-8-10-ubuntu:gitcode$ cat file
i miss you # master 分支
I Miss You # dev 分支

lighthouse@VM-8-10-ubuntu:gitcode$ git checkout master
Switched to branch 'master'
lighthouse@VM-8-10-ubuntu:gitcode$ cat file
cat: file: No such file or directory
lighthouse@VM-8-10-ubuntu:gitcode$ ll
total 20
drwxrwxr-x 4 lighthouse lighthouse 4096 Apr 18 19:52 ./
drwxrwxr-x 7 lighthouse lighthouse 4096 Apr 15 21:47 ../
-rw-rw-r-- 1 lighthouse lighthouse  129 Apr  8 23:05 book
drwxrwxr-x 8 lighthouse lighthouse 4096 Apr 18 19:52 .git/
drwxrwxr-x 3 lighthouse lighthouse 4096 Apr 10 22:29 git_learning/

初始状态:

  • master 分支未提交过 file 文件(或该文件未被跟踪)。
  • 你在 dev 分支修改并提交了 file,此时 file 成为 dev 分支的一部分。

切换回 master:

  • master 分支没有 file 的记录,Git 会清理工作目录,删除 file 文件以匹配 master 分支的状态

因此分支交换的逻辑,可以这样理解,如下:

  • 未提交时 :
    • 如果修改未提交,Git 在切换分支时会尽量保留工作区内容(除非目标分支和当前修改冲突)。
    • 保留的原因 :并非"怕数据丢失",而是为了用户能自由切换分支并继续工作。例如,你在 dev 修改了文件,想临时切到 master 修复问题,Git 允许携带未提交的修改切换(只要不冲突)。
  • 提交后 :
    • 提交的修改会写入 dev 分支的历史记录,此时 dev 分支的最新提交包含该文件,而 master 分支的历史记录中没有该文件。
    • 切换回 master 时,Git 会根据 master 的最新提交重建工作区,因此文件会消失(因为 master 从未记录过它)。

3. 如何避免问题

  • 提交前检查分支状态:确保在正确的分支提交改动。
  • 使用 git stash :临时保存未提交的修改,切换分支后再恢复
    • 核心功能:临时保存工作区和暂存区的未提交修改,清空工作区,使其"干净"(与当前分支的最新提交一致)
    • 效果:切换分支时,未提交的修改不会被带到其他分支(避免意外覆盖或冲突)
  • 理解文件跟踪 :新增文件需通过 git add 和 commit 明确添加到分支历史中。
  • 未提交的修改:属于工作目录,切换分支时可能保留(除非冲突)。
  • 已提交的修改:属于特定分支的历史,切换分支时 Git 会严格重建工作目录以匹配目标分支

这就是为什么在提交后切换到 master 时文件"消失"的原因------Git 严格遵循分支的历史记录管理文件

4. 重新理解 工作区、暂存区、版本库

  1. 工作区(Working Directory)

    • 所有分支共享同一个物理工作目录,未提交的修改(无论是否 add)都存在于工作区中,不直接绑定到任何分支
    • 工作区的内容会根据当前分支的最新提交动态变化
  2. 暂存区(Staging Area) :同样全局共享,git add 后的内容属于暂存区,与分支无关。

  3. 版本库(Repository)

    • 提交(commit)后,修改会绑定到当前分支的历史记录中,不同分支的提交历史是独立的
    • 提交后的内容属于分支的历史记录,与工作区无关

但是看到这里,也许大家也会有点问题,就是当 commit 之后,那么产生的文件在两个分支下不就内容不一样了吗,此时它两也能算得上全局共享嘛???

解释如下:

假设有一个文件 file.txt,初始状态如下:

步骤 1:在 master 分支创建文件并提交

bash 复制代码
git checkout master
echo "Hello from master" > file.txt
git add file.txt
git commit -m "Add file in master"

此时:

  • master 分支的提交历史包含 file.txt。
  • 工作区中的 file.txt 内容是 Hello from master。

步骤 2:创建 dev 分支并修改文件

bash 复制代码
git checkout -b dev
echo "Hello from dev" > file.txt
git add file.txt
git commit -m "Update file in dev"

此时:

  • dev 分支的提交历史包含修改后的 file.txt(内容是 Hello from dev)。
  • master 分支的提交历史仍为旧版本(内容是 Hello from master)。

步骤 3:切换回 master 分支查看文件

bash 复制代码
git checkout master
cat file.txt
Hello from master
关键现象解释
  1. 为什么切换分支后文件内容变了?
    • Git 会根据目标分支的最新提交重建工作区。
    • master 分支的最新提交是原始版本,而 dev 分支的最新提交是修改后的版本。
  2. 工作区是"共享"的吗?
    • 物理上共享:所有分支操作同一块磁盘区域。
    • 逻辑上隔离:切换分支时,Git 会覆盖工作区内容,使其匹配目标分支的提交。
    • 你可以理解为:工作区是"共享的舞台",但每次切换分支时,Git 会更换舞台上的"布景"。
  3. 提交后的文件到底属于谁?
    • 提交后的内容属于分支的历史记录,不直接绑定到工作区。
    • dev 分支的提交历史中有一个新版本的 file.txt,而 master 分支的提交历史中仍是旧版本。

全局共享 vs 分支独立
区域 是否全局共享? 是否受分支切换影响?
工作区 ✅ 是(所有分支共享同一物理目录) ✅ 是(切换分支时内容会被覆盖)
暂存区 ✅ 是 ✅ 是(切换分支时可能被覆盖)
版本库(提交) ❌ 否(每个分支有独立提交历史) ❌ 否(提交历史永久绑定到分支)

疑问解决
  • 你的问题:

    "commit 之后,产生的文件在两个分支下内容不一样了,此时它们还能算全局共享吗?"

  • 答案:

    • 工作区本身是共享的,但它的内容会根据当前分支的提交历史动态变化。
    • 提交后的差异是分支历史隔离的结果,而不是工作区本身的隔离。
    • 你可以想象工作区是一个"画布",而不同分支是"不同的画作版本"。每次切换分支时,Git 会擦掉当前画布上的内容,重新绘制目标分支对应的画作。

总结
  • 工作区共享:所有分支操作同一块磁盘区域,但内容由当前分支的提交历史决定。
  • 提交隔离:不同分支的提交历史独立,切换分支时 Git 会严格按目标分支的历史重建工作区。
  • 看似矛盾的现象 :工作区是共享的,但提交后的文件在不同分支下内容不同,这正是 Git 分支机制的核心设计------通过动态覆盖工作区内容,实现高效的多分支协作。
相关推荐
nvd117 小时前
Flink 批处理驱动的湖仓 AI 财务研报流水线:从双流广播汇聚到 Agent 智能决策与原生 Iceberg 落盘全景实战
大数据·人工智能·flink
计算机编程指导师9 小时前
【计算机毕设推荐】基于Hadoop+Spark的公共交通运营数据分析与可视化系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·计算机·数据分析·spark·交通
QYR_1110 小时前
机械制造用固体润滑涂层市场分析:2032年全球市场规模预计达8.78亿元,CAGR为6.2%
大数据·人工智能·物联网
数字化顾问10 小时前
(144页PPT)数字化转型汽车企业数智化战略规划(附下载方式)
大数据
zttbee10 小时前
git命令
git
智慧物业老杨12 小时前
数字底座,重构小区治理秩序
大数据
计算机编程指导师12 小时前
【计算机毕设选题推荐】基于Hadoop的宫颈癌变进程光谱数据分析系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·数据分析·spark·毕业设计·宫颈癌变
guhunyihan13 小时前
无代码系统搭建平台,探索恐象 AI 带来的开发新范式
大数据·人工智能
计算机编程指导师13 小时前
【计算机毕设选题推荐】基于Hadoop+Spark的化妆品销售大数据分析系统源码 毕业设计 选题推荐 毕设选题 数据分析 机器学习
大数据·hadoop·python·spark·毕业设计·课程设计·化妆品
benchmark_cc13 小时前
前复权数据每天可能变化,历史数据库应该覆盖还是保留原始价格?
大数据·python·pandas·量化交易·股票数据·quantdash