git branch常用分支操作

前言

最近代码的版本控制工具由SVN换成了Git,只用管理个人项目常用的灵魂三步git addgit commitgit push看来是行不通了,之前虽然也一直在用 git,但是用法很有限,主要集中在前面提到的三步,所以为了更好的工作,我决定还是好好总结一下。

分支在Git的操作里有着很重要的地位,代表了不同的开发线路,创建一个分支,也就多了一个索引文件,相比于SVN分支拷贝全部文件来说来方便的多,所以Git使得按功能分支的开发模式变得非常简单,在开发过程中常常需要对分支进行操作。

远程仓库

本来就几个分支,操作上也没有太麻烦,但是加入了远程仓库以后,事情变得复杂起来。有了远程仓库一般意味着代码开发需要多人合作了,这时候常常会产生冲突,分支合并时也变得不那么容易了。

远程仓库其实也很好理解,就是放在远处用来保存代码资源的一个仓库,其实和本地的代码库没有什么区别,这个远程仓库主要是为了把大家修改的代码都合并到一起,给大家提供一个统一的目标点。

远程仓库究竟有多远,常见的代码托管平台:githubgitlab、码云都可以提供远程仓库,如果你在月球上放置一台可以联网的代码仓库服务器,那么距离就是38.4万千米,但是远程仓库也可以很近,你也可以把本机电脑的D盘里的代码仓库作为E盘的代码仓库的远程仓库,或许远程仓库可能只和你隔了一个文件夹。

由于网络的原因,githubgitlab 访问常常很慢,所以为了做练习测试推送,我在码云创建了一个仓库 gitstart,它的地址大概是这个样子:git@gitee.com:myname/gitstart.git,创建的方法一搜一大把,上面提到的几个托管平台,在哪创建都可以,一定要记住地址,因为后面还要用到。

建立联系

本地创建文件夹并进入

1
2
3
4
5
6
7
8
albert@homepc MINGW64 /d
$ mkdir gitstart

albert@homepc MINGW64 /d
$ cd gitstart/

albert@homepc MINGW64 /d/gitstart
$

这里的文件夹名字可以和远程仓库不同,但是为了看起来方便对应,还是取相同的名字好一点。

初始化仓库

1
2
3
4
5
6
albert@homepc MINGW64 /d/gitstart
$ git init
Initialized empty Git repository in D:/gitstart/.git/

albert@homepc MINGW64 /d/gitstart (master)
$

临时插播好奇心(不在流程中)

目前这个状态有点意思,初始化完之后,(master) 这个字符串表示当前是在 master分支,查一下日志看看:

1
2
3
4
5
6
albert@homepc MINGW64 /d/gitstart (master)
$ git log
fatal: your current branch 'master' does not have any commits yet

albert@homepc MINGW64 /d/gitstart (master)
$

提示也是正确的,说 master分支没有任何提交,但是我们查询一下分支看看:

1
2
3
4
5
albert@homepc MINGW64 /d/gitstart (master)
$ git branch -a

albert@homepc MINGW64 /d/gitstart (master)
$

居然是空的,没有分支,查询 .git\HEAD 文件发现里面有一行 ref: refs/heads/master,说明当前分支时 master,但是为什么查询分支没有结果呢?

打开 .git\refs\heads 目录,发现这个文件夹下根本没有 master文件,其实想想也对,Git 中的分支其实对应着 commit id,现在什么都没有提交,master 也就找不到 commit id,所以就是有 master 文件,里面也不知道写什么。

查询远程仓库

1
2
3
4
5
albert@homepc MINGW64 /d/gitstart (master)
$ git remote -v

albert@homepc MINGW64 /d/gitstart (master)
$

依旧什么内容都没有,说明还没有和远程仓库建立联系。

与远程仓库建立对应关系

1
2
3
4
5
6
7
8
9
10
albert@homepc MINGW64 /d/gitstart (master)
$ git remote add origin git@gitee.com:myname/gitstart.git

albert@homepc MINGW64 /d/gitstart (master)
$ git remote -v
origin git@gitee.com:myname/gitstart.git (fetch)
origin git@gitee.com:myname/gitstart.git (push)

albert@homepc MINGW64 /d/gitstart (master)
$

这一步需要注意,origin看起来就是一个远程仓库的别名,代表着 git@gitee.com:myname/gitstart.git 这个代码仓库,刚刚提到过,这个远程仓库也可以是本地的,所以你添加git remote add origin d:/test 也是可以的,就表明 gitstart 的远程仓库是本地的 test 仓库。

第一个分支

刚刚说过,现在本地库的状态有些特殊,实际上刚刚在码云上创建的 git@gitee.com:myname/gitstart.git 库也很特殊,他们都没有真正的分支,这时只要我们成功提交一次,创建一个commit id,就相当于初始化了master分支。

添加README文件

1
2
3
4
5
6
7
8
9
10
11
12
13
albert@homepc MINGW64 /d/gitstart (master)
$ echo "learn git branch command">README.md

albert@homepc MINGW64 /d/gitstart (master)
$ git add README.md
warning: LF will be replaced by CRLF in README.md.
The file will have its original line endings in your working directory

albert@homepc MINGW64 /d/gitstart (master)
$ git commit -m"add readme file"
[master (root-commit) 3226b63] add readme file
1 file changed, 1 insertion(+)
create mode 100644 README.md

查询当前分支

1
2
3
albert@homepc MINGW64 /d/gitstart (master)
$ git branch -a
* master

这次可以是出现了,分支为 master,前面的 * 表示为当前分支。

将分支推送到远程仓库

1
2
3
4
5
6
7
8
9
10
albert@homepc MINGW64 /d/gitstart (master)
$ git push -u origin master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 248 bytes | 248.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: Powered by GITEE.COM [GNK-3.8]
To gitee.com:myname/gitstart.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.

至此,本地仓库和远程仓库就建立了联系,下面可以开始学习 Git 分支命令了。

分支操作

新建分支

新建分支可以使用 git branch branch_name 命令,以下就是一个创建名为 release 分支的命令:

1
2
albert@homepc MINGW64 /d/gitstart (master)
$ git branch release

也可以使用 git checkout -b branch_name 来创建一个新分支,创建完会自动切换到新分支:

1
2
3
4
5
6
albert@homepc MINGW64 /d/gitstart (master)
$ git checkout -b dev
Switched to a new branch 'dev'

albert@homepc MINGW64 /d/gitstart (dev)
$

切换分支

这是一个很奇怪的命令,命令格式为 git checkout branch_name,总感觉 checkout 子命令包揽了不属于自己的工作,如果在git branch的基础上加一个参数会更合理的一点,但这和切换分支的实际含义可能还有关系,切换分支其实就是修改HEAD文件中的 commit id,而没有真正的发生切换。

1
2
3
4
5
6
7
8
9
10
albert@homepc MINGW64 /d/gitstart (dev)
$ git checkout release
Switched to branch 'release'

albert@homepc MINGW64 /d/gitstart (release)
$ git checkout dev
Switched to branch 'dev'

albert@homepc MINGW64 /d/gitstart (dev)
$

查看本地分支

像刚才我们创建的 release 分支和 dev 分支都是在本地创建的,这样的分支通过 git branch 命令就可以查看

1
2
3
4
5
albert@homepc MINGW64 /d/gitstart (dev)
$ git branch
* dev
master
release

这样就列举了本地的所有分支,在当前分支名字 dev 前面哈还有一个 * 作为标记

查看远程分支

只要在上面的命令基础上加上 -r 参数就行了

1
2
3
albert@homepc MINGW64 /d/gitstart (dev)
$ git branch -r
origin/master

查询到的分支只有 origin/master 一个,这个分支是一开始我们进行第一次提交产生 master 分支之后,通过 git push -u origin master 推送到远程仓库的,所以现在只有一个。

查看所有分支

所有分支包括本地分支和远程分支,将 -r 参数换成 -a 参数就可以了

1
2
3
4
5
6
albert@homepc MINGW64 /d/gitstart (dev)
$ git branch -a
* dev
master
release
remotes/origin/master

将本地分支推送到远程仓库

其实之前已经操作过了,可以试着复习一下,git push -u origin branch_name,其实这是一个简写,-u 可以写成 --set-upstream 表示设置上游分支,其实就是和远程仓库的分支建立联系。

branch_name 也是 local_branch_name:remote_branch_name的一种简写,冒号前表示本地分支,冒号后面表示远程分支,如果只写一个就表示两个分支名相同,远程仓库中如果没有这个分支就会新建一个。

也就是说 git push -u origin devgit push--set-upstream origin dev:dev 是一样的,下面来试一下,然后查看一下分支:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
albert@homepc MINGW64 /d/gitstart (dev)
$ git push -u origin dev
Total 0 (delta 0), reused 0 (delta 0)
remote: Powered by GITEE.COM [GNK-3.8]
remote: Create a pull request for 'dev' on Gitee by visiting:
remote: https://gitee.com/myname/gitstart/pull/new/myname:dev...myname:master
To gitee.com:myname/gitstart.git
* [new branch] dev -> dev
Branch 'dev' set up to track remote branch 'dev' from 'origin'.

albert@homepc MINGW64 /d/gitstart (dev)
$ git branch -a
* dev
master
release
remotes/origin/dev
remotes/origin/master

冒号前后的米名字是不是一定相同呢?完全没有必要,我们可以让本地的 release 分支对应远程的 master 分支,只不过这样怪怪的,但是操作上完全可以的。

1
2
3
4
5
6
7
8
albert@homepc MINGW64 /d/gitstart (dev)
$ git checkout release
Switched to branch 'release'

albert@homepc MINGW64 /d/gitstart (release)
$ git push -u origin release:master
Everything up-to-date
Branch 'release' set up to track remote branch 'master' from 'origin'.

查看本地分支与远程分支对应关系

这个也是刚刚知道的,可以使用 git branch -vv 命令,注意是两个 v:

1
2
3
4
5
albert@homepc MINGW64 /d/gitstart (release)
$ git branch -vv
dev 3226b63 [origin/dev] add readme file
master 3226b63 [origin/master] add readme file
* release 3226b63 [origin/master] add readme file

执行这个命令之后可以看出,本地的 masterrelease 分支都对应着远程的 master 分支

删除本地分支

我们先复习一下新建分支,然后把它推送到远程仓库,再使用 git branch -d branch_name 命令进行删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
albert@homepc MINGW64 /d/gitstart (release)
$ git checkout -b feature_test
Switched to a new branch 'feature_test'

albert@homepc MINGW64 /d/gitstart (feature_test)
$ git push origin feature_test
Total 0 (delta 0), reused 0 (delta 0)
remote: Powered by GITEE.COM [GNK-3.8]
remote: Create a pull request for 'feature_test' on Gitee by visiting:
remote: https://gitee.com/myname/gitstart/pull/new/myname:feature_test...myname:master
To gitee.com:myname/gitstart.git
* [new branch] feature_test -> feature_test

albert@homepc MINGW64 /d/gitstart (feature_test)
$ git branch -a
dev
* feature_test
master
release
remotes/origin/dev
remotes/origin/feature_test
remotes/origin/master

开始删除分支,删除之前记得切换到别的分支,否则删除不成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
albert@homepc MINGW64 /d/gitstart (feature_test)
$ git checkout dev
Switched to branch 'dev'
Your branch is up to date with 'origin/dev'.

albert@homepc MINGW64 /d/gitstart (dev)
$ git branch -d feature_test
Deleted branch feature_test (was 3226b63).

albert@homepc MINGW64 /d/gitstart (dev)
$ git branch -a
* dev
master
release
remotes/origin/dev
remotes/origin/feature_test
remotes/origin/master

删除远程分支

通过上面的操作我们发现只删除了本地的分支,远程的分支还在,要想删除远程分支,需要使用 git push origin --delete branch_name 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
albert@homepc MINGW64 /d/gitstart (dev)
$ git push origin --delete feature_test
remote: Powered by GITEE.COM [GNK-3.8]
To gitee.com:myname/gitstart.git
- [deleted] feature_test

albert@homepc MINGW64 /d/gitstart (dev)
$ git branch -a
* dev
master
release
remotes/origin/dev
remotes/origin/master

这次再查看时发现远程分支也被删掉了。

获取远程主分支到本地

其实 Git 的克隆命令默认就是把远程仓库的主分支下载到本地,我们可以使用 git clone 远程地址 本地文件夹 命令来克隆一个仓库,如果本地文件夹省略,则默认新建一个与仓库名相同的文件夹:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
albert@homepc MINGW64 /d
$ git clone https://gitee.com/myname/gitstart.git gitstartcopy
Cloning into 'gitstartcopy'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.

albert@homepc MINGW64 /d
$ cd gitstartcopy/

albert@homepc MINGW64 /d/gitstartcopy (master)
$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/dev
remotes/origin/master

获取远程其他分支到本地

从上面命令执行后的结果来看,当前本地仓库中只有 master 分支,其他的分支都是在远程仓库上,这时可以用 git checkout branch_name 命令来下载远程分支:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
albert@homepc MINGW64 /d/gitstartcopy (master)
$ git checkout dev
Switched to a new branch 'dev'
Branch 'dev' set up to track remote branch 'dev' from 'origin'.

albert@homepc MINGW64 /d/gitstartcopy (dev)
$ git branch -a
* dev
master
remotes/origin/HEAD -> origin/master
remotes/origin/dev
remotes/origin/master

albert@homepc MINGW64 /d/gitstartcopy (dev)
$ git branch -vv
* dev 3226b63 [origin/dev] add readme file
master 3226b63 [origin/master] add readme file

看到这里可能会疑惑了,git checkout branch_name 不是切换分支的命令吗?实际上当 branch_name 分支在本地不存在而远程仓库存在时,这个命令与 git checkout -b <branch> --track <remote>/<branch> 含义相同,会在本地新建一个分支,并与远程分支建立联系。

常用集合

  • 新建分支:git checkout -b branch_name
  • 切换分支:git checkout branch_name
  • 查看分支:git branch -a
  • 删除分支:git branch -d branch_name
  • 推送分支到远程:git push origin branch_name
  • 删除远程的分支:git push origin --delete branch_name
  • 拉取远程分支到本地:git checkout branch_name
  • 查询分支的对应关系:git branch -vv

总结

  • 以上这些命令都是在本地测试过的,可能考虑的不太全面,不过没关系,以后的分支操作还会补充到这里。
  • 这些命令在有些特殊的情况下使用可能会遇到问题,如果大家发现了问题请及时指出,我会尽快修改的。
Albert Shi wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客