1. Git分支
分支在 GIT 中相对较难。
1.1 什么是分支
分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习 Git 的时候,另一个你正在另一个平行宇宙里努力学习 SVN。
如果两个平行宇宙互不干扰,那对现在的你也没啥影响。
不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了 Git 又学会了 SVN!
分支在实际中有什么用呢? 假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了 50% 的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。 现在有了分支,就不用怕了。 你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
Git 分支的速度非常快。
截止到目前,只有一条时间线,在 Git 里,这个分支叫主分支,即 master 分支。
HEAD 严格来说不是指向提交,而是指向 master,master 才是指向提交的,所以,HEAD 指向的就是当前分支。
1.2 git 分支中常用指令
代码语言:javascript复制 # 列出所有本地分支
$ git branch
# 列出所有远程分支
$ git branch -r
# 列出所有本地分支和远程分支
$ git branch -a
# 新建一个分支,但依然停留在当前分支
$ git branch [branch-name]
# 新建一个分支,并切换到该分支
$ git checkout -b [branch]
# 新建一个分支,指向指定commit
$ git branch [branch] [commit]
# 新建一个分支,与指定的远程分支建立追踪关系
$ git branch --track [branch] [remote-branch]
# 切换到指定分支,并更新工作区
$ git checkout [branch-name]
# 切换到上一个分支
$ git checkout -
# 建立追踪关系,在现有分支与指定的远程分支之间
$ git branch --set-upstream [branch] [remote-branch]
# 合并指定分支到当前分支
$ git merge [branch]
# 选择一个commit,合并进当前分支
$ git cherry-pick [commit]
# 删除分支
$ git branch -d [branch-name]
# 强制删除
$ git branch -D [branch-name]
# 删除远程分支
$ git push origin --delete [branch-name]
$ git branch -dr [remote/branch]
1.3 新建分支与切换分支
□ git branch git checkout
每次提交,Git 都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在 Git 里,这个分支叫主分支,即 master 分支。
HEAD 严格来说不是指向提交,而是指向 master,master 才是指向提交的,所以,HEAD 指向的就是当前分支。 一开始的时候,master 分支是一条线,Git 用 master 指向最新的提交,再用 HEAD 指向 master,就能确定当前分支,以及当前分支的提交点:
每次提交,master 分支都会向前移动一步,这样,随着你不断提交,master 分支的线也越来越长:
- 新建一个分支,但依然停留在当前分支,使用:
$ git branch [branch-name]
$ git branch dev1 $ git branch # 查看本地分支 dev1 * master 当我们创建新的分支,例如dev
时,Git 新建了一个指针叫dev
,指向master
相同的提交,再把HEAD
指向dev
,就表示当前分支在dev
上:
你看,Git 创建一个分支很快,因为除了增加一个dev
指针,改改HEAD
的指向,工作区的文件都没有任何变化!
不过,从现在开始,对工作区的修改和提交就是针对dev
分支了,比如新提交一次后,dev
指针往前移动一步,而master
指针不变:
假如我们在dev
上的工作完成了,就可以把dev
合并到master
上。Git 怎么合并呢?最简单的方法,就是直接把master
指向dev
的当前提交,就完成了合并:
所以 Git 合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除dev
分支。删除dev
分支就是把dev
指针给删掉,删掉后,我们就剩下了一条master
分支:
# 新建一个分支,但依然停留在当前分支 git checkout -b dev # 提交 git commit -m"D" # 切换到指定分支,并更新工作区 git checkout master # 合并分支 git merge dev # 删除dev分支 git branch -d dev
- 切换分支,
git checkout <name>
,如果name为-则为上一个分支 $ git checkout dev1 Switched to branch 'dev1' $ git checkout - Switched to branch 'master' - 新建一个分支,并切换到该分支,
git checkout -b [branch]
$ git checkout -b dev2 Switched to a new branch 'dev2' - 新建一个分支,指向指定commit使用命令:
git branch [branch] [commit]
# 在dev2分支 提交一个hyy05.txt $ git commit hyy05.txt -m"分支切换测试——dev2分支提交" warning: LF will be replaced by CRLF in hyy05.txt. The file will have its original line endings in your working directory [dev2 7e9d0b9] 分支切换测试——dev2分支提交 1 file changed, 1 insertion( ) create mode 100644 hyy05.txt # 查看已提交的文件(master主分支提交的文件,其他分支都可以看到) $ git ls-files hyy00.txt hyy02.txt hyy03.txt hyy04.txt hyy05.txt # 查看日志 $ git reflog 7e9d0b9 (HEAD -> dev2) HEAD@{0}: commit: 分支切换测试——dev2分支提交 # 切换到dev1分支 $ git checkout dev1 Switched to branch 'dev1' # 此时切换到dev1分支就看不到dev2分支提交的了 $ git ls-files hyy00.txt hyy02.txt hyy03.txt hyy04.txt # 创建dev3分支 并将HEAD指针指向dev3,dev3指针指向 7e9d0b9 这次提交的位置 $ git checkout dev1 7e9d0b9 # 这时候你发现在dev3中是可以访问到那次提交的文件的 $ git ls-files hyy00.txt hyy02.txt hyy03.txt hyy04.txt hyy05.txt - 新建一个分支,与指定的远程分支建立追踪关系使用命令:
git branch --track [branch] [remote-branch]
# 请求上游dev3,创建dev4 与远程分支dev3 进行追踪关系 $ git branch --track dev4 dev3 Branch 'dev4' set up to track local branch 'dev3'. $ git branch dev1 dev2 * dev3 dev4 master $ git checkout dev4 Switched to branch 'dev4' Your branch is up to date with 'dev3' # 您的分支会 使用“dev3”更新。 $ git checkout dev3 Switched to branch 'dev3' $ git add . warning: LF will be replaced by CRLF in hyy06.txt. The file will have its original line endings in your working directory # 在上游分支dev3 提交 $ git commit -m "git branch --track [branch] [remote-branch]测试,上游dev3提交" [dev3 5810a51] git branch --track [branch] [remote-branch]测试,上游dev3提交 1 file changed, 1 insertion( ) create mode 100644 hyy06.txt # 切换到分支dev4,会提醒你dev3 进行了一次提交,而当前dev4分支并没有,可以通过git pull根据dev3快速更新 $ git checkout dev4 Switched to branch 'dev4' # 您的分支在“dev3”之后1次提交,可以快速转发。 Your branch is behind 'dev3' by 1 commit, and can be fast-forwarded. # (使用“git pull”更新您的本地分支) (use "git pull" to update your local branch) $ git pull From . * branch dev3 -> FETCH_HEAD Updating 68963ae..5810a51 Fast-forward hyy06.txt | 1 1 file changed, 1 insertion( ) create mode 100644 hyy06.txt $ git status On branch dev4 Your branch is up to date with 'dev3'. nothing to commit, working tree clean # 可以看到hyy06.txt也同步到了当前分支dev4 $ git ls-files hyy00.txt hyy02.txt hyy03.txt hyy04.txt hyy06.txt
1.4 查看分支
□ git branch
列出所有本地分支使用 $ git branch
$ git branch
dev1
dev2
dev3
* dev4
master
□ git branch -r
列表所有远程分支使用 $ git branch -r
□ git branch -a
列出所有本地分支和远程分支使用 $ git branch -a
$ git branch -a
dev1
dev2
dev3
* dev4
master
1.5 分支合并
□ git merge [branch]
合并指定分支到当前分支使用指令 $ git merge [branch]
这里的合并分支就是对分支的指针操作,我们先创建一个分支再合并到主分支:
代码语言:javascript复制 $ git branch dev1
$ git checkout dev1
Switched to branch 'dev1'
# 在分支dev1 提交hyy07.txt 内容“1e”
$ git commit -m"提交hyy07.txt--dev1"
[dev1 d08ce1d] 提交hyy07.txt--dev1
1 file changed, 1 insertion( )
create mode 100644 hyy07.txt
# 创建并切换的到 dev2分支
$ git checkout -b dev2
Switched to a new branch 'dev2'
$ cat hyy07.txt
1e
$ echo "dev2 修改的内容"> hyy07.txt
$ 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: hyy07.txt
no changes added to commit (use "git add" and/or "git commit -a")
$ git add .
$ git commit -m"在分支dev2中提交对hyy07.txt的修改"
[dev2 894bff0] 在分支dev2中提交对hyy07.txt的修改
1 file changed, 1 insertion( ), 1 deletion(-)
# 查看hyy07.txt的内容,此时的俩分支的hyy07.txt的内容不同的(相当于两个平行宇宙)
$ cat hyy07.txt
dev2 修改的内容
# 回到分支dev1 去查看hyy07.txt 你可以看到是原本的内容,并不是dev2修改后的内容
$ git checkout dev1
Switched to branch 'dev1'
$ cat hyy07.txt
1e
# 而且你在分支dev1的时候是看不到dev2那次提交的
$ git log
commit d08ce1d6a6247b4ae73ce4d57563b1329e8dc046 (HEAD -> dev1)
Author: 胡宇洋 <2582952862@qq.com>
Date: Mon Nov 29 18:44:33 2021 0800
提交hyy07.txt--dev1
# 回到dev2后,是可以看到提交记录的
$ git checkout dev2
Switched to branch 'dev2'
$ git log
commit 894bff00c019ddca7390d6c790d1179489c2ff35 (HEAD -> dev2)
Author: 胡宇洋 <2582952862@qq.com>
Date: Mon Nov 29 18:50:36 2021 0800
在分支dev2中提交对hyy07.txt的修改
# 回到分支 dev1
$ git checkout dev1
Switched to branch 'dev1'
# 将分支dev2 合并当前分支(dev1)
$ git merge dev2
Updating d08ce1d..894bff0
Fast-forward
hyy07.txt | 2 -
1 file changed, 1 insertion( ), 1 deletion(-)
# 合并完之后你可以看到 分支dev2中的修改在分支dev1中也生效了
$ cat hyy07.txt
dev2 修改的内容
1.6 解决冲突
如果同一个文件在合并分支时都被修改了则会引起冲突,如下所示:
提交前两个分支的状态
代码语言:javascript复制 $ echo "dev1 修改了内容">hyy07.txt
$ git add .
warning: LF will be replaced by CRLF in hyy07.txt.
The file will have its original line endings in your working director
$ git commit -m "在分支dev1上提交hyy07.txt"
[dev1 9dcbd95] 在分支dev1上提交hyy07.txt
1 file changed, 1 insertion( ), 1 deletion(-)
$ git checkout dev2
Switched to branch 'dev2'
$ echo "在dev1之后,dev2修改了内容">hyy07.txt
$ git add .
warning: LF will be replaced by CRLF in hyy07.txt.
The file will have its original line endings in your working directory
$ git commit -m"在分支dev2上提交hyy07.txt"
[dev2 f9113e3] 在分支dev2上提交hyy07.txt
1 file changed, 1 insertion( ), 1 deletion(-)
$ git checkout dev1
Switched to branch 'dev1'
# 将dev2合并到当前分支dev1,会提示合并失败
$ git merge dev2
# 自动合并hyy07.txt
Auto-merging hyy07.txt
# hyy07.txt中的合并冲突
CONFLICT (content): Merge conflict in hyy07.txt
# 自动合并失败;修复冲突,然后提交结果。
Automatic merge failed; fix conflicts and then commit the result.
# 查看当前状态,可以看到
$ git status
On branch dev1
# 您有未合并的路径
You have unmerged paths.
# (修复冲突并运行“git提交”)
(fix conflicts and run "git commit")
# (使用“git merge--abort”中止合并)
(use "git merge --abort" to abort the merge)
# 未合并路径:
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: hyy07.txt
no changes added to commit (use "git add" and/or "git commit -a")
# 此时查看hyy.txt可以在 dev1 分支中的状态
$ cat hyy07.txt
<<<<<<< HEAD
dev1 修改了内容
=======
在dev1之后,dev2修改了内容
>>>>>>> dev2
代码语言:javascript复制Git 用
<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,其中<<<HEAD
是指主分支修改的内容,>>>>>dev2
是指 dev2 上修改的内容
# 解决的办法是我们可以修改冲突文件后重新提交,请注意当前的状态产生的,比如上面的:
<<<<<<< HEAD# 当前分支dev1
dev1 修改了内容 ------------->dev1分支修改的
=======
在dev1之后,dev2修改了内容 ------------->dev1分支修改的
>>>>>>> dev2
# 二者选一个你想要留下的,去手动修改,比如我这里是hyy07.txt 我想要dev1分钟的修改,我去手动把内容修改成了:
dev1 修改了内容
# 其他内容全部删除,只保留了dev1分支修改的部分,抛弃了dev2 分支的修改、
重新提交后冲突解决:
代码语言:javascript复制 $ git add .
$ git commit -m"解决分支冲突问题"
[dev1 8c8d593] 解决分支冲突问题
手动解决完冲突后就可以把此文件添 加git add
到暂存区中去,用 git commit
命令来提交,就像平时修改了一个文件 一样。
用 git log --graph 命令可以看到分支合并图。
□ 分支策略
master 主分支应该非常稳定,用来发布新版本,一般情况下不允许在上面工作,工作一般情况下在新建的 dev 分支上工作,工作完后,比如上要发布,或者说 dev 分支代码稳定后可以合并到主分支 master 上来。
1.7 删除分支
删除本地分支可以使用命令:
代码语言:javascript复制 # 删除分支。
# 分支必须完全合并到其上游分支中,或者 如果没有上游被设置为--track或--set upstream,则必须完全合并到其上游分支中。
git branch -d [branch-name]
# --delete--force的快捷方式。
# 强制删除
git branch -D [branch-name]
删除远程分支可以使用如下指令:
代码语言:javascript复制 $ git push origin --delete [branch-name]
$ git branch -dr [remote/branch]
-d 表示删除分支。分支必须完全合并在其上游分支,或者在 HEAD 上没有设置上游 -r 表示远程的意思 remotes,如果 - dr 则表示删除远程分支
我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表