分支管理¶
我们往往是团队合作,但每个人的进度、节奏都不一样
- 所以如果代码都提交到一个同一个主干上,难免会出错
怎么解决这个问题呢?答案就是使用分支!
- 主干分支是对外的稳定版本
- 如果需要新功能时,就开一个支干分支来进行开发
- 支干分支与主干分支是相互独立的
- 等到开发完毕后,再将的代码支干分支合并到主干分支上
- 这样,既安全,又互不影响,每个人都能保持自己的节奏!
1.创建分支¶
1.使用git checkout命令,加上-b参数,即 创建并切换到分支
$ git checkout -b dev
Switched to a new branch 'dev'
# 或下面这种方式(新版Git使用,语义更清晰)【推荐】
$ git switch -c dev
Switched to a new branch 'dev'
- 相当于以下两条命令:
git branch dev # 创建dev分支
git checkout dev # 切换到dev分支
2.然后,我们就可以在dev分支上正常修改、暂存、提交了
2.查看所有分支¶
git branch命令会列出所有分支。当前所在的分支前面会标一个*号
$ git branch
* dev
master
3.切换分支¶
方式一:使用git checkout命令切换分支
(dev)
$ git checkout master
Switched to branch 'master'
D test.txt
(master) # 切换到了 master 分支
$
方式二:使用git switch命令来切换分支**【推荐】**
- 前面讲过的撤销修改
git checkout -- <file>,切换分支也是使用git checkout - 同一个命令,有两种作用,确实有点令人迷惑。
- 所以最新版本的 Git,就提供了
git switch命令,语义更清晰,比git checkout更容易理解
# 创建并切换到新的dev分支
$ git switch -c dev
Switched to a new branch 'dev'
# 切换到的master分支
$ git switch master
4.合并分支¶
git merge命令,用于合并指定分支到当前分支
(master) # 当前分支是master
$ git merge dev # 把dev分支的修改,合并到当前分支(即master)上
- 补充:
- 因为创建、合并和删除分支非常快,所以 Git 鼓励你使用分支完成某个任务,合并后再删掉分支
- 这和直接在
master分支上工作效果是一样的,但过程更安全 - 示例:
(dev) # 当前是dev分支
$ cat test.txt # 文件修改前
aaaa
aaaa
aaaaaaaaaa
(dev)
$ vim test.txt # 1.在dev分支修改文件
(dev)
$ cat test.txt # 文件修改后
aaaa
(dev)
$ git add test.txt # 2.暂存文件
(dev)
$ git commit -m 'delete somethings' # 3.提交修改
[dev 9c7b24e] delete somethings
1 file changed, 2 deletions(-)
$ git checkout master # 4.切回master分支
Switched to branch 'master'
# 示意图:
HEAD
│
▼
master
│
▼
┌───┐ ┌───┐ ┌───┐ ┌───┐
│ │───▶│ │───▶│ │───▶│ │
└───┘ └───┘ └───┘ └───┘
▲
│
dev
(master)# 当前是master分支
$ cat test.txt # 查看文件:此时master分支的文件,没有被dev分支的修改操作影响
aaaa
aaaa
aaaaaaaaaa
(master)
$ git merge dev # 5.把dev分支的工作成果,合并到当前的master分支上
Updating 65458a4..9c7b24e
Fast-forward # Fast-forward:这次合并是“快进模式”,也就是直接把master指向dev的当前提交
# 这种方式的合并不会创建新的合并提交(merge commit),而是直接将master分支的指针移动到要合并的分支的最新的提交
# 当然,也不是每次合并都能Fast-forward模式,后面会讲其他种合并方式
test.txt | 2 --
1 file changed, 2 deletions(-)
(master)
$ cat test.txt # 再查看文件:发现是dev分支修改后的内容了
aaaa
(master)
$ git branch -d dev # 6.合并成功后,就可以放心地删除分支了
Deleted branch dev (was 9c7b24e).
(master)
$ git branch # 7.查看分支,发现只剩下master分支了
* master
5.删除分支¶
1.使用git branch -d <name>,来删除 已经合并的分支
- 注意:不可以在分支中,删除分支本身
- 一般是切换到
master分支后,再删除其他分支
(master) # 在master分支
$ git branch -d dev # 删除dev分支
Deleted branch dev (was 9c7b24e).
2.使用git branch -D <name>,来**强行删除** 还没有合并的分支
- 使用
git branch -d <name>,来删除**还没有合并的分支**时,会报错 - 然而,有时候必须强行删除,防止信息泄露
- 有时候就是这样的,开发到一半功能不要啦!而为了防止代码泄露,所以就得强行删除分支!
(master) # 在master分支
$ git branch -D dev # 强行删除还没有合并的dev分支
Deleted branch dev (was 287773e).
6.解决分支合并冲突¶
(1)问题描述¶
如果两个分支都对同一个文件进行修改提交,就不能使用“快速合并”(Fast-forward)模式了,否则合并时会产生冲突
- 因为合并时,Git 不确定到底应该保留哪个分支的修改、以哪个分支的修改为主
- 所以就产生了冲突
demo 复现:
(feature1)
$ cat test.txt # 文件修改前的内容
aaaa
(feature1) # 1.在feature1分支进行修改
$ vim test.txt
(feature1)
$ cat test.txt # 修改后的内容
aaaa
a
# 2.然后在feature1分支进行暂存、提交
(feature1)
$ git add test.txt
(feature1)
$ git commit -m 'feature1 add somethings'
[feature1 87a87d7] feature1 add somethings
1 file changed, 1 insertion(+)
(master)
$ cat test.txt # master分支查看文件,未被修改
aaaa
(master) # 3.master分支修改文件
$ vim test.txt
(master)
$ cat test.txt # 修改后的内容
aaaa
a
a
# 4.然后在master分支进行暂存、提交
(master)
$ git add test.txt
(master)
$ git commit -m 'master add somethings'
[master 4f4afd9] master add somethings
1 file changed, 2 insertions(+)
# 5.在master分支,合并feature1分支
(master)
$ git merge feature1
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt # 合并冲突了
Automatic merge failed; fix conflicts and then commit the result.
# 6.也可以通过 查看git库状态,发现合并冲突
(master|MERGING) # 这里也发生变化了
$ 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: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
# 7.此时再查看文件
(master|MERGING)
$ cat test.txt
aaaa
a
# 标记之上的部分,都是共有的
<<<<<<< HEAD # 表示冲突的开始,且接下来的内容是属于 HEAD 分支
a # <<<<<<< HEAD 到 ======= 之间的 a ,是 HEAD 分支相对于共同祖先的修改
=======
>>>>>>> feature1
# ======= 到 >>>>>>> feature1 之间没有内容,表示在这个冲突区域,feature1 分支没有相对于共同祖先的额外添加,也即 它的修改止步于 aaaa a。
- 此时,分支树如下
HEAD
│
▼
master
│
▼
┌───┐
┌─▶│ │
┌───┐ ┌───┐ ┌───┐ │ └───┘
│ │───▶│ │───▶│ │──┤
└───┘ └───┘ └───┘ │ ┌───┐
└─▶│ │
└───┘
▲
│
feature1
(2)问题解决¶
如何解决?很简单:手动解决冲突(所以学车还是得学手动挡[dog])
-
也即 :
-
1.手动编辑冲突文件,保留你想要的版本
- 2.删除文件中的所有冲突标记
-
3.再重新提交即可
-
例如:
(master|MERGING)
$ cat test.txt
aaaa
a
<<<<<<< HEAD
a
=======
>>>>>>> feature1
# 1.解决冲突
(master|MERGING)
$ vim test.txt
## 1.1保留feature1版本,删除HEAD版本的内容;
## 1.2.删除所有冲突标记
(master|MERGING)
$ cat test.txt
aaaa
a
# 2.再进行提交
(master|MERGING)
$ git add test.txt
(master|MERGING)
$ git commit -m 'keep feature1'
[master a9de091] keep feature1 # 提交成功
(master) # 冲突解决了
$
# 现在,合并的示意图如下:
HEAD
│
▼
master
│
▼
┌───┐ ┌───┐
┌─▶│ │───▶│ │
┌───┐ ┌───┐ ┌───┐ │ └───┘ └───┘
│ │───▶│ │───▶│ │──┤ ▲
└───┘ └───┘ └───┘ │ ┌───┐ │
└─▶│ │──────┘
└───┘
▲
│
feature1
补充:查看冲突合并图¶
# 1.查看完整信息
$ git log --graph
* commit a9de0916b9167fe608a791acd4d3cb8c3d4b2ba3 (HEAD -> master)
|\ Merge: 4f4afd9 87a87d7
| | Author: wangshangjian <wsj15685374939@163.com>
| | Date: Sun Sep 15 12:22:08 2024 +0800
| |
| | keep feature1
| |
| * commit 87a87d74090e687abf73862df5acdd9c1bd3ac20 (feature1)
| | Author: wangshangjian <wsj15685374939@163.com>
| | Date: Sun Sep 15 11:52:02 2024 +0800
| |
| | feature1 add somethings
| |
* | commit 4f4afd9403a0298eaf715f688bf4af7a05fdccee
|/ Author: wangshangjian <wsj15685374939@163.com>
| Date: Sun Sep 15 11:55:17 2024 +0800
|
| master add somethings
# 2.查看简略信息
$ git log --graph --pretty=oneline --abbrev-commit
* a9de091 (HEAD -> master) keep feature1
|\
| * 87a87d7 (feature1) feature1 add somethings
* | 4f4afd9 master add somethings
|/
7.分支管理的整体策略¶
在实际开发中,我们应该按照几个基本原则进行分支管理
- 首先,
master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活 - 然后,干活都在
dev分支上 - 你和你的小伙伴们每个人都在
dev分支上干活,每个人都有自己的分支,时不时地往master分支上合并就可以 - 也就是说,
dev分支是不稳定的
所以,团队合作的分支看起来就像这样:
8.保存工作现场¶
当你临时接受到新任务时,自然要创建新分支;但当前分支上进行的工作还没有做完、没法提交,肿么办?
1.Git 提供了一个stash功能,可以把当前工作现场“储藏”起来,等待以后恢复现场、继续工作
- 冻结现场
git stash
# 作用:
# 1.1保存当前工作目录的所有更改
# 1.2重置工作目录,使其与最近一次提交的状态一致
$ git status
On branch master
nothing to commit, working tree clean # 很干净
2.可以查看储藏列表
$ git stash list
stash@{0}: WIP on master: 9cfd34c Merge branch 'feature1'
3.恢复工作现场
- 也即
应用储藏
git stash apply [stash-name]
# 注意:
# 3.1 如果不指定 `[stash-name]`,Git 默认使用最近的储藏(这对后面的几个命令也适用)
# 3.2 应用储藏不会将工作现场从储藏列表中删除,这意味着你可以多次应用同一个储藏。
# 示例:
$ git stash apply stash@{0}
On branch master
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: test.txt
no changes added to commit (use "git add" and/or "git commit -a")
4.删除储藏
- 这会从储藏列表中,删除指定的储藏。
git stash drop [stash-name]
# 示例
$ git stash drop stash@{0}
Dropped stash@{0} (6803dc11d0fffa6c1bf962e5358ecdb0de71c38f)
$ git stash list
5.恢复工作现场的同时,把储藏也删了
- 3、4 的简写
git stash pop [stash-name] # 弹出
9.多人协作开发¶
(1)查看远程库的信息¶
- 当你克隆远程仓库时,实际上 Git 自动把本地的
master分支,和远程的master分支关联起来了,并且,远程仓库的默认名称是origin。
1.要查看远程库的信息,用git remote:
$ git remote
origin
2.或者,用git remote -v显示更详细的信息:
$ git remote -v
origin https://gitee.com/xiaofuce233/test.git (fetch)
origin https://gitee.com/xiaofuce233/test.git (push)
上面显示了,可以**抓取(fetch)**和**推送(push)**的origin的地址。
- 如果没有推送权限,就看不到 push 的地址
(2)推送分支¶
- 推送分支,就是**把本地 git 库中目标分支上的提交,推送到远程库**。
1.推送时,要指定 远程库 和 本地分支
- 这样,Git 就会把该分支,推送到对应的远程库的相应分支上
# origin是远程库
# master是本地分支
$ git push origin master
Enumerating objects: 24, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 16 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (20/20), 1.71 KiB | 1.71 MiB/s, done.
Total 20 (delta 4), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Powered by GITEE.COM [1.1.5]
remote: Set trace flag d3438082
To https://gitee.com/xiaofuce233/test.git
b4def30..0f3985a master -> master
- 如果要推送其他分支,比如
dev,就改成:
$ git push origin dev
2.但并不是本地的所有分支都要往远程推,那么,哪些分支需要推送,哪些不需要呢?
-
master分支是主分支,因此要**时刻与远程同步**; -
dev分支是开发分支,团队所有成员都需要在上面工作,所以**也需要与远程同步**; -
*bug 分支只用于在本地修复 bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个 bug;
-
*feature 分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
-
总之,就是在 Git 中,分支完全可以在本地自己藏着玩,是否推送,视你的心情而定!
3.多人协作时,大家都会往master和dev分支上推送各自的修改。
(3)拉取分支¶
拉取分支有多种方式
**1.**当通过git clone克隆远程仓库时,默认只会拉取到master分支
$ git clone git@github.com:michaelliao/learngit.git
$ git branch
* master
**2.**当想要在dev分支上开发时,就必须本地创建dev分支,然后和远程origin的dev分支关联
- 主要目的:用于基于远程分支,创建新的本地分支
- 通常不涉及合并,因为它是基于一个远程分支,创建新的本地分支
git checkout -b [branch] [remote]/[branch]
# 命令格式允许你创建一个新的本地分支,并立即切换到这个分支,
# 同时这个新分支会设置为跟踪指定的远程分支
$ git checkout -b dev origin/dev
# 它执行了两个操作:
# 首先,它基于远程分支 origin/dev 创建并检出了一个新的本地分支 dev,并立即切换到这个分支
# 其次,它将这个新创建的本地分支, 设置为 跟踪远程分支 origin/dev。
# 或
$ git switch -c dev origin/dev
**3.**使用git pull命令,从远程仓库拉取数据,并尝试与当前检出的本地分支合并
- 主要目的:用于更新和合并(可能涉及合并操作)
git pull [remote-name] [branch-name]
[remote-name] 是远程仓库的名称,默认是 origin。
[branch-name] 是要拉取的远程分支的名称。如果不设置,会拉取和当前本地分支相同的远程库分支
(4)推送冲突¶
1.当 A**已经**向origin/dev分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送
- 会推送失败!因为 A 的最新提交,和你试图推送的提交有冲突
# 提交
$ git add test.txt
$ git commit -m "add new env"
$ git push origin dev # 推送
To github.com:michaelliao/learngit.git
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
2.解决办法也很简单,Git 已经提示了:
(1)先用git pull,把最新的提交从origin/dev拉取下来,在本地合并、解决冲突
1)即先更新你当前的分支信息
pull会拉取分支信息,并进行合并(前面说了)
$ git pull
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
git pull <remote> <branch>
If you wish to set tracking information for this branch you can do so with:
git branch --set-upstream-to=origin/<branch> dev
2)git pull失败:原因是没有把本地dev分支与远程origin/dev分支关联起来
- 根据提示,设置
dev和origin/dev的链接
$ git branch --set-upstream-to=origin/dev dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.
3)关联好两个仓库后,再 pull
- 这回
git pull成功,但是合并有冲突,需要手动解决
$ git pull
Auto-merging env.txt
CONFLICT (add/add): Merge conflict in env.txt # 有合并冲突
Automatic merge failed; fix conflicts and then commit the result.
- 解决的方法,和分支管理中的
解决分支合并冲突完全一样。
(2)然后,再提交和 push 推送
# 提交修改
$ git commit -m "fix env conflict"
[dev 57c53ab] fix env conflict
# push到远程仓库
$ git push origin dev
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 621 bytes | 621.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
7a5e5dd..57c53ab dev -> dev
(5)多人协作的工作模式¶
所以,多人协作的工作模式通常是这样:
- 首先,可以尝试用
git push origin <branch-name>推送自己的修改; - 如果推送失败,则因为远程分支比你的本地更加新,需要先用
git pull试图合并; - 如果
git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建 - 则用命令
git branch --set-upstream-to <branch-name> origin/<branch-name> - 如果合并有冲突,则解决冲突,并在本地提交;
- 没有冲突,或者解决掉冲突后,再用
git push origin <branch-name>推送,就能成功!
本站总访问量 次
