git初入门(三):分支

2023-09-16 21:52:08 浏览数 (1)

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 分支的线也越来越长:

  1. 新建一个分支,但依然停留在当前分支,使用:$ 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

  1. 切换分支,git checkout <name>,如果name为-则为上一个分支 $ git checkout dev1 Switched to branch 'dev1' $ git checkout - Switched to branch 'master'
  2. 新建一个分支,并切换到该分支,git checkout -b [branch] $ git checkout -b dev2 Switched to a new branch 'dev2'
  3. 新建一个分支,指向指定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
  4. 新建一个分支,与指定的远程分支建立追踪关系使用命令: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

代码语言:javascript复制
 $ git branch
   dev1
   dev2
   dev3
 * dev4
   master

git branch -r

列表所有远程分支使用 $ git branch -r

git branch -a

列出所有本地分支和远程分支使用 $ git branch -a

代码语言:javascript复制
 $ 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

Git 用<<<<<<<=======>>>>>>> 标记出不同分支的内容,其中 <<<HEAD 是指主分支修改的内容,>>>>>dev2是指 dev2 上修改的内容

代码语言:javascript复制
 # 解决的办法是我们可以修改冲突文件后重新提交,请注意当前的状态产生的,比如上面的:
 <<<<<<< 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腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表

0 人点赞