Git基本用法中,我们介绍了工作区暂存区版本库等概念,并介绍了本地git仓库中文件的各种状态,以及添加修改、创建提交以及相关的撤回的命令。接下来我们将继续介绍git的基本用法

git branch

分支是Git中的一个重要概念,实际研发流程就是紧密依赖不同分支实现的。分支本质上是指向一系列提交的指针。它允许你从开发主线分离出来,在不影响主分支的情况下进行独立的开发工作。

分支改名

我们在本地git init创建了一个本地仓库后,默认的主分支名是master。而为了避免敏感词汇,如今我们更推荐将主分支命名为main,因此我们可以使用命令git branch -M对当前分支进行改名:

1
git branch -M main

创建分支

有两种创建分支的方式:

  • 使用git branch <branch-name>命令可以以当前分支为起点,创建一个分支
  • 使用git checkout -b <branch-name>可以以当前分支为起点,创建并跳转到新的分支

这里以创建分支feat/feat1为例:

1
git branch feat/feat1

跳转分支

使用git switch <branch>git checkout <branch>命令实现分支跳转

临时保存分支修改

如果目前在当前分支上已经有了一些未提交的修改,这时有一个紧急的 bug 需要在 main 分支上修复,就必须将当前修改进行保存

使用 git stash 命令将修改保存到 stash 栈:

1
git stash

这会将工作目录和暂存区的修改保存起来,并将工作目录和暂存区恢复到最近一次提交的状态。

使用 git stash list 命令查看 stash 栈中的内容:

1
git stash list

它会列出所有存储在 stash 栈中的修改,每个存储都有一个唯一的标识符,如 stash@{0}stash@{1} 等。

使用 git stash apply 命令将最近一次存储的修改应用到当前工作目录:

1
git stash apply

如果你想应用特定的 stash 项,可以使用 git stash apply stash@{n},其中 n 是 stash 项的索引。

应用 stash 时,修改会被应用到工作目录,但不会从 stash 栈中删除。如果要同时删除 stash 项,可以使用 git stash pop

1
git stash pop

它会将最近一次存储的修改应用到工作目录并从 stash 栈中删除。

可以使用 git stash save "message" 命令为 stash 保存添加描述信息,以便更好地识别 stash 中的内容:

1
git stash save "Working on new feature, not completed yet"

使用 git stash clear 命令可以清空 stash 栈中的所有存储:

1
git stash clear

合并分支

合并分支也有两种方式:

  • git merge 会创建一个新的合并提交,将两个分支的修改合并在一起
  • git rebase 会将一个分支上的提交移到另一个分支的末尾,让提交历史看起来是线性的。

比如我们在feat/feat1上有了新的提交之后,就可以尝试将该分支与主分支main合并:

git merge:

1
(main)$ git merge feat/feat1

或git rebase:

1
(feat/feat1)$ git rebase main

如果两个分支对同一文件有不同的修改,就会产生冲突,这时就需要手动解决冲突后git add .提交修复后的内容,再使用git merge --continuegit rebase --continue,或者使用--abort放弃合并

Git中合并分支的方式主要有两种:Fast-forward合并和Three Way Merge合并:

  1. Fast-forward:当试图将一个分支合并到另一个分支时,如果要合并的分支(源分支)是当前分支(目标分支)的直接后继,即要合并的分支是从当前分支直接分出去的,并且在源分支创建之后,当前分支没有新的提交,那么 Git 会使用 fast-forward 合并,即Git 会直接将源分支的指针向前移动(快进)到目标分支的最新提交
  2. Three Way Merge:当试图将一个分支合并到另一个分支时,要合并的分支(源分支)是从当前分支(目标分支)直接分出去的,并且在源分支创建之后,当前分支有新的提交,那么Git会使用three-way-merge合并:如果两个分支见存在冲突,需要先解决冲突并将修改加入暂存区,然后进行合并后git会提交一个**合并提交(merge commit)**,而这个合并提交有两个父提交,分别来自合并的两个分支,详情可见git之.git目录详解中object的介绍。最新版本中git使用Ort策略实现Three Way Merge。

git tag

Git 中的 tag 是一个指向某个特定提交的引用,通常用于标记项目中的重要版本或里程碑。它类似于一个分支,但不同的是,分支可以随着新的提交而移动,而 tag 是一个静态的指针,它会一直指向特定的提交,不会随着新的提交而改变。

git tag又分为轻量级tag附注tag,前者只是一个指向提交的指针,不包含额外的信息,后者包含更多信息,如创建者、创建日期、标签信息等。

1
2
3
4
5
6
7
8
# 轻量级
git tag <tag_name>

# 附注
git tag -a <tag_name> -m "tag message"

# 删除本地标签
git tag -d <tag_name>

附注标签还会对应一个tag object(轻量级标签没有),详情见git之.git目录详解中对object的介绍

git remote

绑定远程仓库

通过git remote add命令绑定远程仓库,如

1
git remote add origin https://github.com/DopamineNone/testGit.git

其中origin是指远程仓库的默认名称。

查看绑定的远程仓库

使用git remote -v可以查看:

1
2
3
$ git remote -v
origin http://github.com/DopamineNone/testGit.git (fetch)
origin http://github.com/DopamineNone/testGit.git (push)

这与.git/config文件中记录的一致:

1
2
3
[remote "origin"]
url = https://github.com/DopamineNone/testGit.git
fetch = +refs/heads/*:refs/remotes/origin/*

设置不同的push和fetch url

git remote set-url --push <name> <newurl>可以单独设置push url

1
2
3
4
$ git remote set-url --push origin https://DopamineNone/testGithubFlow.git
$ git remote -v
origin http://github.com/DopamineNone/testGit.git (fetch)
origin http://DopamineNone/testGithubFlow.git (push)

该设置常用于fork仓库中:即本地仓库与源开源仓库同步(fetch),推送时讲本地提交更新至远程fork仓库(push)

推送本地提交信息

前文中只标识了远程仓库的地址的默认别名origin,如将本地提交推送至远程空仓库时,还需要绑定分对应的upstream

1
git push -u origin main

这一步就是将本地main分支的upstream设置为orign/main(-u选项的作用),并执行推送。(但仍然不会设置其他分支的upstream)

也可以主动修改本地分支的upstream:

1
git branch --set-upstream-to=origin/feature feature

就是将feature分支的upstream设置为origin/feature

如果当前分支feat1没有设置upstream,但main分支设置了,可以直接使用git push origin feat1,这会将feat1推送至origin/feat1(但仍然不会设置feat1的upstream)

如果当前分支feat2的upstream已经设置为origin,那么就可以直接执行git push,等价于`git push origin feat2

获取远程仓库最新提交信息

前提是本地main分支设置了upstream

git fetch <repository> <branch>命令可以获取远程仓库相应分支的最新提交信息

不指明repository和branch时,等效于git fetch origin 与当前本地分支同名的远端分支

获取远程仓库最新提交信息后还需要git merge合并一下。

或者使用git pull <repository> <branch>命令,等价于git fetch <repository> <branch>+git merge

如果当前分支feat已经设置了upstream为orign/feat,那么git pull等价于git pull origin feat

分支管理工作流

有了上述的基础,我们就可以了解实际研发中的分支管理。常见的分支管理流有:Git Flow,Github Flow以及Gitlab Flow。推荐阮一峰大佬的博文:Git 工作流程,本文就不赘述相关内容。