git分支命令(本地分支操作)

声明

本笔记总结的是learn git barnching内容。因此看完该笔记也可以尝试通关learn git barnching小游戏,链接如下:

新建分支

新建分支的git命令语法为,git branch <name><name>为新建分支的名字。

如,新建一个名为bugFix的分支命令为,git branch bugFix

切换分支

切换分支的命令语法为,git checkout <name><name>为切换进的分支名。

如,切换到我们刚刚新建的bugFix分支命令为,git checkout bugFix

新建并切换分支

新建并切换分支的命令语法为,git checkout -b <name>。即,在切换分支的命令基础上加上-b参数。

新建并切换分支这两个操作经常需要前后进行,在新建一个分支之后,如果直接提交修改,那么提交

修改是针对于原来的分支的。因为在提交修改之前,我们并没有切换到新分支上。

如果,我们想要新建一个名为bugFix的分支,并切换到该分支。该git命令为,git checkout -b bugFix

合并分支(merge)

合并分支的语法为,git merge <name>。将名为<name> 的分支合如当前所在的分支。

如下图所示,我们想将bugFix分支合并到main分支,运行git merge bugFix

注意下图的main分支上有一个星号*,这表示我们的当前分支为main分支。

如果当前不在main分支,则我们需要先切换到main分支 git chekcout main

合并结果如下图所示。

可以看到,main 现在指向了一个拥有两个父节点的提交记录。假如从 main 开始沿着箭头向上看,在到达起点的路上会经过所有的提交记录。这意味着 main 包含了对代码库的所有修改。

删除分支

删除分支的语法形式有两种:

git branch -d <name>

git branch -D <name>

其中 -d 和 -D都代表delete,不同之处在于-d参数用来删除已经合入到本分支的分支。既然已经合入进本分支,那就代表本分支拥有要删除分支的所有提交记录,所以删除分支毫无压力。

而-D参数表示强制删除,可以删除没有合入进本分支的分支。

查看分支

git branch 不加任何参数就能展示当前所有分支的清单。

要从该清单中筛选出已经(或尚未)与当前分支合并的分支,可以用 -merge-no-merged 选项。

衍合分支(rebase)

rebase其实和merge非常相似,可以称的上是另一种合并分支的方法,方便于merge命令区分,一般将rebase命令称为衍合。

rebase 实际上就是在本分支取出一系列的提交记录,“复制”它们,逐步放到另一分支

rebase 的优势就是可以创造更线性的提交历史,这听上去有些难以理解。如果只允许使用 rebase 的话,代码库的提交历史将会变得异常清晰。

如上图所示,我们有两个分支,bugFix和main分支,我们想要将bugFix中做的修改提交复制到main分支。首先切换到bugFix分支**,**git checkout bugFix,然后运行,git rebase main。我们会得到如下所示的结果。

将C3提交复制为C3’到main分支的顶端。现在 bugFix 分支上的工作在 main 的最顶端,同时我们也得到了一个更线性的提交序列。

注意,提交记录 C3 依然存在(树上那个半透明的节点),而 C3' 是我们 Rebase 到 main 分支上的 C3 的副本。

现在唯一的问题就是 main 还没有更新,现在切换到main上git checkout main,把它 rebase 到 bugFix 分支上,运行git rebase bugFix。结果如下所示:

在提交树上移动

可以看到上面笔记的图中的提交分支组成了提交树,以下笔记记录如何在复杂的提交树种移动。

首先了解下HEAD,HEAD 总是指向当前分支上最近一次提交记录。大多数修改提交树的 Git 命令都是从改变 HEAD 的指向开始的。

分离HEAD

HEAD 通常情况下是指向分支名的(如 bugFix)。在提交时,改变了 bugFix 的状态,这一变化通过HEAD 变得可见。

分离的 HEAD 就是让其指向了某个具体的提交记录而不是分支名。

在命令执行之前的状态如下所示:HEAD 指向 main, main 指向 C1。(可以看到这里的星号*在main右上角,表明HEAD指向main。)

运行git checkout c1。HEAD不再指向main而是指向C1。

使用相对引用

通过指定提交记录哈希值的方式在 git 提交树中移动不太方便。我们必须使用 git log 来查查看提交记录的哈希值,虽然git对哈希值的处理很智能。只需要提供能够唯一标识提交记录的前几个字符即可。

但是通过相对引用在git提交树种移动更方便,通过如HEAD、分支名bugFix进行移动。相对引用移动的两种形式:

  • 使用 ^ 向上移动 1 个提交记录
  • 使用 ~<num> 向上移动多个提交记录,如 ~3

首先看看操作符 (^)。把这个符号加在引用名称的后面,表示让 Git 寻找指定提交记录的父提交。

运行git checkout main^。得到以下结果。

然后看看~<num>。当需要相对移动多步的话,用~<num>更为合适。

现在需要通过相对移动的方式让HEAD向上移动4步。只需要运行,git checkout ~4,得到如下结果。

如果让<ref>代表某个提交的引用的话,<ref>其实有三种表达形式。

  1. 直接利用哈希值
  2. 利用相对引用~<num>
  3. 利用相对引用^

强制修改分支位置

可以直接使用 -f 选项让分支指向另一个提交。例如:

git branch -f main HEAD~3

上面的命令会将 main 分支强制指向 HEAD 的第 3 级父提交。

在运行git branch -f main HEAD~3之后,会得到以下结果。

分离Head与强制修改分支位置小结

分离HEAD与强制修改分支位置的相同之处在于都是在分支树上移动,且都可以利用哈希值或者相对引用。

不同之处在于移动的对象不同,前者是移动HEAD,后者是移动分支名。

分离HEAD语法形式为:git checkout <ref>

强制修改分支位置语法形式为:git -f <branch> <ref>

回退分支

git reset(本地分支)

git reset 通过把分支记录回退几个提交记录来实现撤销改动。这里的回退既能通过哈希值引用又能通过相对引用。

命令语法形式为:

git reset <ref>

如我们相对以下分支进行回退一步,只需运行 git reset HEAD

得到以下结果:

git revert (远程分支)

虽然在本地分支中使用git reset很方便,但是这种“改写历史”的方法对大家一起使用的远程分支是无效。为了撤销更改并分享给别人,我们需要使用 git revert

git revert 的语法形式也和git reset 相似:

git revert <ref>

示例,对以下分支运行 git revert HEAD^

会得到以下结果:

要撤销的提交记录后面多了一个新提交,这是因为新提交记录 C2’ 引入了更改 ,这些更改刚好是用来撤销 C2 这个提交的。也就是说 C2’ 的状态与 C1是相同的。

revert 之后就可以把更改推送到远程仓库。

整理提交记录

git cherry-pick

命令形式为: git cherry-pick <ref>

将提交号指向的记录从其他分支复制到当前分支。

如下图所示,如果想要将side分支的C2,C4上的修改复制到main分支上。

我们在当前分支下,复制其他分支指定的提交记录到本分支,运行:

git rebase C2 C4

结果如下:

我们只需要提交记录 C2和 C4,所以 git 就将被它们抓过来放到当前分支下了。

rebase -i (交互式的rebase)

命令形式为:git rebase -i

交互式 rebase 指的是使用带参数 --interactive 的 rebase 命令, 简写为 -i

在命令后增加了这个选项, git 会打开一个 UI 界面并列出将要被复制到目标分支的备选提交记录,它还会显示每个提交记录的哈希值和提交说明,提交说明有助于你理解这个提交进行了哪些更改。

在实际使用时,所谓的 UI 窗口一般会在文本编辑器如 Vim中打开一个文件。

当 rebase UI界面打开时, 你能做3件事:

  • 调整提交记录的顺序(通过鼠标拖放来完成)。
  • 删除你不想要的提交(通过切换 pick 的状态来完成,关闭就意味着不想要这个提交记录)。
  • 合并提交。它允许你把多个提交记录合并成一个。

分支标签 (git tag)

因为分支容易发生变动,在分支上进行一次提交的话,分支就会向前移动一次。

有的时候,我们需要永远指向某个提交记录的标识,比如软件发布新的大版本,或者是修正一些重要的 Bug 或是增加了某些新特性。

此时分支的标签就能满足我们的需求,给某个提交记录打上标签之后,即使是经过多次提交,我们也能迅速找到该提交记录。

命令语法为:git tag <tag> <ref>。这里的<ref>可以是任何能被git识别成提交记录的引用,没有指定的话,git 会以你目前所检出的位置HEAD

描述标签 git describe

由于标签在代码库中起着“锚点”的作用,Git 还为此专门设计了一个命令用来描述离你最近的锚点(也就是标签),它就是 git describe

命令的语法为:git describe <ref><ref> 可以是任何能被 Git 识别成提交记录的引用,如果你没有指定的话,Git 会以你目前所检出的位置HEAD

它输出的结果是这样的:

<tag>_<numCommits>_g<hash>

  1. tag 表示的是离 ref 最近的标签
  2. numCommits 是表示这个 reftag 相差有多少个提交记录
  3. hash 表示的是你所给定的 ref 所表示的提交记录哈希值的前几位。

ref 提交记录上有某个标签时,则只输出标签名称。

git describe main 会输出:

v1_2_gC2 :v1距离main 2个提交记录距离 标签指向提交记录的哈希值为c2

git describe side 会输出:

v2_1_gC4 v2距离side 1个提交记录距离 标签指向提交记

编辑于 2022-07-10 23:20