Git分支学习

本文主要记录Git分支的知识:

  • Git分支基本操作
    • 查看本地分支信息
    • 创建本地分支
    • 本地分支关联到远程分支
    • 取消远程分支关联并关联到新的远程分支
    • 取回远程仓库某个分支的更新再与本地的指定分支自动merge
    • 删除分支
  • 工作过程中切换分支
    • 现有未提交的工作移至Git中的新分支
    • 保存和恢复工作进度(stash)
  • 远程仓库有master和dev分支,使用dev分支进行开发的一个示例
  • 远程仓库只有mater分支,使用dev分支进行开发的一个示例
  • Git clone所有的远程分支的方法
  • Git里的origin理解

Git分支基本操作

查看本地分支信息

我们可以通过git branch查看本地分支信息,通过git branch -a查看所有分支(包括远程分支remote)。

1
2
$ git branch
* master
1
2
3
4
$ git branch -a
*master
remotes/origin/ -> origin/master
remotes/origin/master

​- *星号表示当前所在分支

  • remote表示远程分支

创建本地分支

git checkout -b branch_dev创建本地分支并切换到新建分支,等同于以下两行代码:

  • 创建本地分支git branch branch_dev
  • 切换到新创建的分支git checkout branch_dev

我们通过git branch可以看到现在已经切换到新建本地分支。

1
2
3
$ git branch
master
* branch_dev

本地分支关联到远程分支

我们可以将新建的本地分支关联到远程分支(push即可)。

1
git push origin branch_dev:branch_dev

第一个其实是本地分支的名,冒号后面是要创建的远程分支名,可以自己另起名称,如果直接使用git push origin branch_dev则默认和远程分支同名。

这样已经新建好本地与远程同步的分支,我们可以通过以下命令查看远程分支是否存在:

1
2
3
4
5
6
$ git branch -a
master
*branch_dev
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/origin/branch_dev

取消远程分支关联并关联到新的远程分支

首先解除关联:

1
git remote remove origin

重新关联新的远程分支:

1
git remote add origin https://github.com/tding/example.git

取回远程仓库某个分支的更新再与本地的指定分支自动merge

完整格式:

1
git pull <远程库名> <远程分支名>:<本地分支名>

比如,取回远程库中的develop分支,与本地的develop分支进行merge,要写成:

1
git pull origin develop:develop

如果是要与本地当前分支merge,则冒号后面的<本地分支名>可以不写。

1
git pull origin develop

通常,git会将本地库分支与远程分支之间建立一种追踪关系。比如,在git clone的时候,所有本地分支默认与远程库的同名分支建立追踪关系。也就是说,本地的master分支自动追踪origin/master分支。因此,如果当前处于本地develop分支上,并且本地develop分支与远程的develop分支有追踪关系,那么远程的分支名可以省略:

1
git pull origin

删除分支

删除远程分支

1
git push origin --delete 分支名

注意:在删除远程分支时,同名的本地分支并不会被删除,所以还需要单独删除本地同名分支。

删除本地分支

下面两条是删除本地分支:

1
2
git checkout master   # 切换到master分支
git branch -d dev # 删除本地dev分支

注意:删除dev分支时,当前所在的分支不能是dev分支。

工作过程中切换分支

现有未提交的工作移至Git中的新分支

当我们开始一项新功能的工作,经过一段时间的编码,最后决定该功能应该在其自己的分支上。那么如何将现有未提交的更改移至新分支并重置当前分支?

1
git checkout -b <new-branch>

注意:Git仓库分为本地仓库和远程仓库,如果远程新建的分支没有更新到本地,我们使用上面的命令会报错:fatal:‘XXX' is not a commit and a branch 'dev' cannot be created from it,我们可以通过fetch命令更新远程仓库数据到本地:

1
git fetch origin

这样当前的分支保持不变,创建并签出新分支,并保留所有更改。然后可以使用以下命令进行提交:

1
2
git add <files>
git commit -m "<Brief description of this commit>"

工作区和缓存区内容是公共的,不从属于任何一个分支

工作区即为自身本地的相应文件夹,通过git add命令后,即可将文件放置缓存区;继而通过git commit即可将文件放置于相对应的Git分支。

工作区和缓存区内容是公共的,不从属于任何一个分支,所以切换到A分支时,仍然将修改的东西带过去了,当既想要在切换分支,又不想add时,可以使用git stash,当使用了git stash后,在其他分支仍然可以通过git stash pop找出来。

保存和恢复工作进度(stash)

前提:必须是处于Git下的文件,未add到Git的文件无法使用此命令

  1. 保存当前工作进度,将工作区和暂存区恢复到修改之前:
1
git stash

作用同上,message为此次进度保存的说明

1
git stash save message
  1. 显示保存的工作进度列表,编号越小代表保存进度的时间越近
1
git stash list
  1. 恢复工作进度到工作区,此命令的stash@{num}是可选项,在多个工作进度中可以选择恢复,不带此项则默认恢复最近的一次进度相当于git stash pop stash@{0}
1
git stash pop stash@{num}
  1. 恢复工作进度到工作区且该工作进度可重复恢复,此命令的stash@{num}是可选项,在多个工作进度中可以选择恢复,不带此项则默认恢复最近的一次进度相当于git stash apply stash@{0}
1
git stash apply stash@{num}
  1. 删除一条保存的工作进度,此命令的stash@{num}是可选项,在多个工作进度中可以选择删除,不带此项则默认删除最近的一次进度相当于git stash drop stash@{0}
1
git stash drop stash@{num}
  1. 误删内容找回:
    • 第一步:使用git fsck --unreachable命令查找所有unreachable的记录,这条命令会打印出所有不能从任何索引节点访问但是确存在的对象(大概有三种类型的内容,blob、tree和commit。我们这样看的话是看不出任何有用信息的,我们需要另外一条命令将其内容show出来)。
    • 第二步:使用git show命令显示记录内容,git show后面跟上要show的id,就可以展示这个id所对应的blob,tree,tag和commit。这些id所对应的记录并不是有序的,如果想要找到之前误删的内容,需要我们一条条的去show出这些内容,然后判断是否是要找回的
    • 第三步:根据第上一步找到我们所要恢复内容的id,使用git stash apply id进行恢复。git stash apply id只能恢复commit类型的记录,如果使用这条命令来恢复blob,tree或tag可能会报错。
  1. 删除所有保存的工作进度
1
git stash clear

分支无法切换的情况

  1. 没有add,也没commit,并且修改的内容在另一个分支上也有
  2. 已经add,但没有commit,并且修改的内容在另一个分支上也有

这时候,推荐使用stash保存工作进度再切换。

示例:远程仓库有master和dev分支开发方法

克隆代码

1
git clone https://github.com/master-dev.git

查看所有分支

1
git branch --a

默认有了dev和master分支,所以会看到如下三个分支:

1
2
3
master[本地主分支] 
origin/master[远程主分支]
origin/dev[远程开发分支]

新克隆下来的代码默认masterorigin/master是关联的,也就是他们的代码保持同步,但是origin/dev分支在本地没有任何的关联,所以我们无法在那里开发。

创建本地关联origin/dev的分支

创建本地分支dev,并且和远程origin/dev分支关联,本地dev分支的初始代码和远程的dev分支代码一样。

1
git checkout dev origin/dev

切换到dev分支进行开发

我们通过以下代码切换到dev分支,然后就是常规的开发:

1
git checkout dev

示例:假设远程仓库只有mater分支

克隆代码

1
git clone https://github.com/master-dev.git

查看所有分支

1
git branch --a

默认只有master分支,所以会看到如下两个分支:

1
2
master[本地主分支] 
origin/master[远程主分支]

新克隆下来的代码默认masterorigin/master是关联的,也就是他们的代码保持同步

创建本地新的dev分支

1
2
git branch dev  # 创建本地分支
git branch # 查看分支

这时会看到master和dev,而且master上会有一个星号。这个时候dev是一个本地分支,远程仓库不知道它的存在,本地分支可以不同步到远程仓库,我们可以在dev开发,然后merge到master,使用master同步代码,当然也可以同步。

发布dev分支

发布dev分支指的是同步dev分支的代码到远程服务器。

1
git push origin dev:dev  # 这样远程仓库也有一个dev分支了

在dev分支开发代码

1
git checkout dev      # 切换到dev分支进行开发

开发代码之后,我们有两个选择:

  1. 如果功能开发完成了,可以合并主分支
1
2
3
4
5
git checkout master   # 切换到主分支
git merge dev # 把dev分支的更改和master合并
git push # 提交主分支代码远程
git checkout dev # 切换到dev远程分支
git push # 提交dev分支到远程
  1. 如果功能没有完成,可以直接推送
1
git push  # 提交到dev远程分支

注意:在分支切换之前最好先commit全部的改变。

Git clone所有的远程分支的方法

Git clone只能clone远程库的master分支,无法clone所有分支,解决办法如下:

  • 1、找一个干净目录,假设是GitHub
  • 2、cd GitHub
  • 3、git clone git@github.com:dta0502/Data-Analysis-In-Action.git,这样在GitHub目录下得到一个Data-Analysis-In-Action子目录
  • 4、cd Data-Analysis-In-Action
  • 5、git branch -a,列出所有分支名称如下:
1
2
3
4
5
* master
remotes/origin/HEAD -> origin/master
remotes/origin/add-license-1
remotes/origin/dev
remotes/origin/master
  • 6、git checkout -b dev origin/dev,作用是checkout远程的dev分支,在本地起名为dev分支,并切换到本地的dev分支

Git里的origin理解

你的代码库(repository)可以存放在你的电脑里,同时你也可以把代码库托管到Github的服务器上。在默认情况下,origin指向的就是你本地的代码库托管在Github上的版本。

我们首先在GitHub上创建了一个叫repository的仓库,这时候指向我们的代码库链接是https://github.com/user1/repository,克隆:

1
git clone https://github.com/user1/repository

然后输入:

1
2
3
$ git remote -v
origin https://github.com/user1/repository.git (fetch)
origin https://github.com/user1/repository.git (push)

可见git为你默认创建了一个指向远端代码库的origin(因为你是从这个地址clone下来的)

现在有一个用户user2 fork了repository,那么他的代码库链接https://github.com/user2/repository,如果他也克隆后输入:

1
2
3
$ git remote -v
origin https://github.com/user2/repository.git (fetch)
origin https://github.com/user2/repository.git (push)

现在origin指向的位置是user2的的远程代码库。

这个时候,如果user2想加一个远程指向你的代码库,他可以在控制台输入

1
git remote add upstream https://github.com/user1/repository.git

然后再输入一遍 git remote -v,输出结果就会变为:

1
2
3
4
origin https://github.com/user2/repository.git (fetch)
origin https://github.com/user2/repository.git (push)
upstream https://github.com/user1/repository.git (fetch)
upstream https://github.com/user1/repository.git (push)

增加了指向user1代码库的upstream,也就是之前对指向位置的命名。

总结来讲,origin就是一个名字,它是在你clone一个托管在Github上代码库时,git为你默认创建的指向这个远程代码库的标签,origin指向的是repository,master只是这个repository中默认创建的第一个branch。当你git push的时候因为origin和master都是默认创建的,所以可以省略,但是这是bad practice,因为当你换一个branch再git push的时候,有时候就纠结了。

参考


----------- 本文结束啦感谢您阅读 -----------

赞赏一杯咖啡

欢迎关注我的其它发布渠道