git 分支管理

 


1.获取远程仓库的指定分支

当从远程仓库拉取代码的时候一般都是使用git clone 命令来获取,这样我们是将项目整个都克隆到我们本地仓库,并且分支还是主分支maser。当然有时候我们只需拉取远程仓库指定的某一个分支,下面三种方法可以使用。

git clone 命令获取

使用git管理代码版本的时候,本地分支默认与远程同名分支建立追踪关系。文章开始也提到git clone 命令默认将整个远程版本库克隆到本地,但是git clone -b <分支名称>命令可以将指定的某一个远程分支拉取到我们本地,而且拉取的本地分支自动和远程同名分支建立追踪关系,它不会将新创建的HEAD指向克隆仓库中HEAD指向的maser主分支,而是指向我们刚拉取下来的分支;示例如下: 

git clone -b dev开发分支 https://github.com/lanyy/repo_test.git

分支拉取结束以后,执行git branch -a 命令,结果如下:

$ git branch -a
* dev开发分支
remotes/origin/HEAD -> origin/master
remotes/origin/dev开发分支
remotes/origin/master
remotes/origin/test测试分支

从执行结果可以看出,当前分支为“dev开发分支” ,剩余的四个都是远程分支;

注意:用git clone -b <分支名称> 拉取指定的某一个分支时,我们本地是没有克隆url对应的远程仓库代码,也就是说进入某个路径的文件夹后直接使用该命令去拉取指定分支,而不是先执行git clone 将远程代码库克隆到本地以后进入项目目录再执行该命令去拉取指定分支。否则,拉取下来的还是master主分支。

git fetch 命令获取

git fetch命令从远程仓库拉取指定某一个分支时,和上面的git clone -b命令时不一样。使用git fetch命令时,需要先将远程的仓库克隆到本地,然后在执行git fetch命令。该命令执行完以后还是处在master主分支的,如果进去目录没有发现想要拉取的仓库文件。此时并不是git fetch命令没有执行,而是我们还没有切换到我们想要拉取的分支上,需要我们执行git checkout命令切换到我们想要拉取的分支上。示例如下:

1.拉取整个远程代码库

git clone https://github.com/lanyy/repo_test.git

2.进入项目目录,也就是进入master主分支

cd repo_test/

3.执行git fetch命令,将远程仓库的所有分支拷贝到本地仓库

git fetch

4.执行git checkout <分支名称>命令,切换到我们想要拉取的指定某一个分支的本地分支

git checkout dev开发分支

这是就会看到本地仓库的dev开发分支和远程仓库的dev开发分支一样的内容, 默认情况下,git fetch下载的分支和远程的分支名相同。

5.执行git branch -a命令查看所有分支情况

$ git branch -a
* dev开发分支
master
remotes/origin/HEAD -> origin/master
remotes/origin/dev开发分支
remotes/origin/master
remotes/origin/test测试分支

可以看到本地有两个分支,目前所在的分支为dev开发分支,还有三个远程分支。到此通过git fetch命令来获取远程仓库某一个指定分支的步骤就执行完毕了。

git checkout -b 命令获取

第三种获取远程仓库某一个指定分支的方法和第二种方法有点类似,都是将远程仓库克隆到本地仓库,然后执行git checkout -b <本地分支名称> origin/<远程分支名称>,具体步骤如下:

1.进入某个文件夹执行克隆远程仓库的git

git clone https://github.com/lanyy/repo_test.git

此时远程仓库就克隆到了本地仓库。

2.进入项目目录,也就是进入master主分支

$ cd repo_test/

3.执行git branch -a查看所有分支名称,* 号表示当前分支

$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/dev开发分支
remotes/origin/master
remotes/origin/test测试分支

4.执行git checkout -b <本地分支名称> origin/<远程分支名称>,拉取指定的某一个分支

$ git checkout -b dev开发分支 origin/dev开发分支

该命令的作用是:checkout远程仓库origin的分支“dev开发分支”,在本地起名为“dev开发分支”分支,并切换到本地的“dev开发分支”分支。

5.拉取该分支的最新代码

$git pull origin dev开发分支

至此,通过三种方法从远程仓库拉取指定某一分支就总结完了。

git checkout拉取指定版本号

可以使用 `git checkout` 命令来拉取指定版本号,具体操作如下:

1. 首先,使用 `git log` 命令查看版本号,找到你需要拉取的版本号的哈希值(commit id)或者版本号(tag)。

2. 然后,使用 `git checkout` 命令加上相应的哈希值或者版本号即可:

git checkout <commit id>
git checkout c48c3b1e127eda6f1520891244933723815b4a43
git checkout <tag>

2.Git 分支管理

几乎每一种版本控制系统都以某种形式支持分支,一个分支代表一条独立的开发线。

使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。

Git 分支实际上是指向更改快照的指针。

有人把 Git 的分支模型称为必杀技特性,而正是因为它,将 Git 从版本控制系统家族里区分出来。

创建分支命令:

git branch (branchname)

切换分支命令:

git checkout (branchname)

当你切换分支的时候,Git 会用该分支的最后提交的快照替换你的工作目录的内容, 所以多个分支不需要多个目录。

合并分支命令:

git merge 

你可以多次合并到统一分支, 也可以选择在合并之后直接删除被并入的分支。

创建master分支并提交

开始前我们先创建一个测试目录和master分支,并进行第一次版本提交:

复制代码
$ mkdir gitdemo
$ cd gitdemo/
$ git init
Initialized empty Git repository...
$ touch README
$ git add README
$ git commit -m '第一次版本提交'
[master (root-commit) 3b58100] 第一次版本提交
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README
复制代码

列出分支

git branch 命令不只是可以创建与删除分支。 如果不加任何参数运行它,会得到当前所有分支的一个列表:

$ git branch
  iss53
* master
  testing

注意master分支前的*字符:带*号的分支表示该分支是当前分支(也就是说,当前HEAD指针所指向的分支)。 这意味着如果在这时候提交,master分支将会随着新的工作向前移动。当你执行 git init 的时候,默认情况下 Git 就会为你创建 master 分支。

如果需要查看每一个分支的最后一次提交,可以运行git branch -v命令:

$ git branch -v
  iss53   93b412c fix javascript issue
* master  7a98805 Merge branch 'iss53'
  testing 782fd34 add scott to the author list in the readmes

--merged 与 --no-merged这两个有用的选项可以过滤这个列表中已经合并或尚未合并到当前分支的分支。 如果要查看哪些分支已经合并到当前分支,可以运行git branch --merged :

$ git branch --merged
  iss53
* master

因为之前已经合并了iss53分支,所以现在看到它在列表中。 在这个列表中分支名字前没有*号的分支通常可以使用git branch -d删除掉; 你已经将它们的工作整合到了另一个分支,所以并不会失去任何东西。

查看所有包含未合并工作的分支,可以运行 :git branch --no-merged

$ git branch --no-merged
  testing

这里显示了其他分支。 因为它包含了还未合并的工作,尝试使用git branch -d命令删除它时会失败:

$ git branch -d testing
error: The branch 'testing' is not fully merged.
If you are sure you want to delete it, run 'git branch -D testing'.

如果真的想要删除分支并丢掉那些工作,如同帮助信息里所指出的,可以使用-D选项强制删除它。

Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是master 。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的分支master。 它会在每次的提交操作中自动向前移动。

Git 的 “master” 分支并不是一个特殊分支。 它就跟其它分支完全没有区别。 之所以几乎每一个仓库都有 master 分支,是因为git init命令默认创建它,并且大多数人都懒得去改动它。

创建新的分支

Git 创建新分支只是为你创建了一个可以移动的新的指针。 如果我们要手动创建一个新的分支,执行 git branch (branchname) 即可。
$ git branch testing
$ git branch
* master
  testing

现在我们可以看到,有了一个新分支 testing,并且testing指针指向当前的master所指向的分支

在 Git 中,通过一个HEAD指针来知道当前在哪一个分支上的,有一个名为HEAD的特殊指针,指向当前所在的本地分支。 因为git branch命令仅仅创建 一个新分支,并不会自动切换到新分支中去,所以git branch testing后,仍然在master分支上

 

当在第一次提交更新之后创建了新分支testing,如果我们并没有切换到testing分支,而是继续在master分支工作,并且如果master分支后来又有更新提交, 当我们能切换到了 testing 分支,Git 将还原工作目录到创建testing分支时候的样子。

2.继续对master分支进行修改

复制代码
$ ls
README
$ echo 'runoob.com' > test.txt
$ git add .
$ git commit -m 'add test.txt'
[master 3e92c19] add test.txt
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt
$ ls
README        test.txt

复制代码

接下来我们将演示如何切换分支,我们用 git checkout (branch) 切换到我们要修改的分支。

分支切换

要切换到一个已存在的分支,你需要使用git checkout命令。 我们现在切换到新创建的testing分支去: 

$ git checkout testing

这样HEAD就指向testing分支了。

$ git checkout testing
Switched to branch 'testing'
$ ls
README

当我们切换到 testing 分支的时候,我们添加的新文件 test.txt 被移除了。切换回 master 分支的时候,它们又重新出现了。

$ git checkout master
Switched to branch 'master'
$ ls
README        test.txt

我们也可以使用 git checkout -b (branchname) 命令来创建新分支并立即切换到该分支下,从而在该分支中操作。

使用HEAD指针指向当前所在的分支,当我们切换到testing分支,并在testing分支上面做些修改提交后:

vim test.rb
$ git commit -a -m 'made a change'
HEAD 分支随着提交操作自动向前移动。
可以看到HEAD 分支随着提交操作自动向前移动。testing分支向前移动了,但是master分支却没有,它仍然指向运行git checkout时所指的对象。 这就有意思了,现在我们切换回masteer分支看看:
git checkout master
检出时 HEAD 随之移动。
检出时 HEAD 随之移动。git checkout命令做了两件事。 一是使 HEAD 指回master分支,二是将工作目录恢复成master分支所指向的快照内容。 也就是说,你现在做修改的话,项目将始于一个较旧的版本。 本质上来讲,这就是忽略testing分支所做的修改,以便于向另一个方向进行开发。
分支切换会改变你工作目录中的文件:
1.在切换分支时,一定要注意你工作目录里的文件会被改变。 如果是切换到一个较旧的分支,当前工作目录会恢复到切换到的分支最后一次提交时的样子。 如果 Git 不能干净利落地完成这个任务,它将禁止切换分支。
2.在切换分支时,要留意你的工作目录和暂存区里那些还没有被提交的修改,它可能会和你即将检出的分支产生冲突从而阻止 Git 切换到该分支。 最好的方法是,在你切换分支之前,保持好一个干净的状态。 有一些方法可以绕过这个问题(即,保存进度(stashing) 和 修补提交(commit amending)).
3.当切换分支的时候,Git 会重置你的工作目录,使其看起来像回到了检出分支上最后一次提交的样子。 Git 会自动添加、删除、修改文件以确保此时你的工作目录和检出分支最后一次提交时的样子一模一样。

删除分支

删除分支命令:

git branch -d (branchname)

例如我们要删除 testing 分支:

$ git branch
* master
  testing
$ git branch -d testing
Deleted branch testing (was 85fc7e7).
$ git branch
* master

分支合并

一旦某分支有了独立内容,你终究会希望将它合并回到你的主分支。 你可以使用以下命令将任何分支合并到当前分支中去:

复制代码
git merge
$ git branch
* master
  newtest
$ ls
README        test.txt
$ git merge newtest
Updating 3e92c19..c1501a2
Fast-forward
 runoob.php | 0
 test.txt   | 1 -
 2 files changed, 1 deletion(-)
 create mode 100644 runoob.php
 delete mode 100644 test.txt
$ ls
README        runoob.php
复制代码

以上实例中我们将 newtest 分支合并到主分支去,test.txt 文件被删除。

合并完后就可以删除分支:

$ git branch -d newtest
Deleted branch newtest (was c1501a2).

删除后, 就只剩下 master 分支了:

$ git branch
* master

分支开发工作流

长期分支

因为 Git 使用简单的三方合并,所以就算在一段较长的时间内,都可以反复把一个分支合并入另一个分支。 也就是说,在整个项目开发周期的不同阶段,均可以同时拥有多个开放的分支; 并且可以定期地把某些特性分支合并入其他分支中。

许多使用 Git 的开发者都喜欢使用这种方式来工作,比如只在master分支上保留完全稳定的代码——有可能仅仅是已经发布或即将发布的代码。 他们还有一些名为develop或者next的平行分支,被用来做后续开发或者测试稳定性——这些分支不必保持绝对稳定,但是一旦达到稳定状态,它们就可以被合并入master分支了。 这样,在确保这些已完成的特性分支(短期分支,比如之前的iss53分支)能够通过所有测试,并且不会引入更多 bug 之后,就可以合并入主干分支中,等待下一次的发布。

稳定分支的指针总是在提交历史中落后一大截,而前沿分支的指针往往比较靠前。

渐进稳定分支的线性图。
渐进稳定分支的线性图

通常把他们想象成流水线(work silos)可能更好理解一点,那些经过测试考验的提交会被遴选到更加稳定的流水线上去。

渐进稳定分支的工作流(“silo”)视图。
渐进稳定分支的流水线(“silo”)视图

你可以用这种方法维护不同层次的稳定性。 一些大型项目还有一个 proposed(建议) 或pu (proposed updates:建议更新)分支,它可能因包含一些不成熟的内容而不能进入 next或者master分支。 这么做的目的是使你的分支具有不同级别的稳定性; 当它们具有一定程度的稳定性后,再把它们合并入具有更高级别稳定性的分支中。 再次强调一下,使用多个长期分支的方法并非必要,但是这么做通常很有帮助,尤其是当你在一个非常庞大或者复杂的项目中工作时.

特性分支

特性分支对任何规模的项目都适用。 特性分支是一种短期分支,它被用来实现单一特性或其相关工作。 

例如在上一节用到的特性分支(iss53和hotfix分支)中提交了一些更新,并且在它们合并入主干分支之后,删除了它们。 这项技术可以使项目快速并且完整地进行上下文切换(context-switch)——因为工作被分散到不同的流水线中,在不同的流水线中每个分支都仅与其目标特性相关,因此,在做代码审查之类的工作的时候就能更加容易地看出做的改动。 你可以把做出的改动在特性分支中保留几分钟、几天甚至几个月,等它们成熟之后再合并,而不用在乎它们建立的顺序或工作进度。

考虑这样一个例子,在master分支上工作到C1,这时为了解决一个问题而新建issu91分支,在issu91分支上工作到 C4,然而对于那个问题你又有了新的想法,于是你再新建一个iss91v2分支试图用另一种方法解决那个问题,接着又回到master分支工作了一会儿,又冒出了一个不太确定的想法,你便在C10 的时候新建一个dumbidea分支,并在上面做些实验。 你的提交历史看起来像下面这个样子:

拥有多个特性分支的提交历史。
拥有多个特性分支的提交历史

现在,我们假设两件事情:你决定使用第二个方案来解决那个问题,即使用在iss91v2分支中方案; 另外,你将dumbidea分支拿给你的同事看过之后,结果发现这是个惊人之举。 这时你可以抛弃iss91分支(即丢弃C5和C6提交),然后把另外两个分支合并入主干分支。 最终你的提交历史看起来像下面这个样子:

合并了 `dumbidea` 和 `iss91v2` 分支之后的提交历史。
合并了dumbidea和iss91v2分支之后的提交历史

请牢记,当你做这么多操作的时候,这些分支全部都存于本地。 当你新建和合并分支的时候,所有这一切都只发生在你本地的 Git 版本库中 —— 没有与服务器发生交互。

远程分支

远程引用是对远程仓库的引用(指针),包括分支、标签等等。 你可以通过git ls-remote (remote)来显式地获得远程引用的完整列表,或者通过git remote show (remote)获得远程分支的更多信息。 然而,一个更常见的做法是利用远程跟踪分支。

远程跟踪分支是远程分支状态的引用。 它们是你不能移动的本地引用,当你做任何网络通信操作时,它们会自动移动。 远程跟踪分支像是你上次连接到远程仓库时,那些分支所处状态的书签。

它们以(remote)/(branch)形式命名。 例如,如果你想要看你最后一次与远程仓库origin通信时master分支的状态,你可以查看origin/master分支。 你与同事合作解决一个问题并且他们推送了一个iss53分支,你可能有自己的本地iss53分支; 但是在服务器上的分支会指向origin/iss53的提交。

这可能有一点儿难以理解,让我们来看一个例子。 假设你的网络里有一个在git.ourcompany.com的 Git 服务器。 如果你从这里克隆,Git 的clone命令会为你自动将其命名为origin,拉取它的所有数据,创建一个指向它的master分支的指针,并且在本地将其命名为origin/master。 Git 也会给你一个与 origin 的master分支在指向同一个地方的本地master分支,这样你就有工作的基础。

“origin” 并无特殊含义

远程仓库名字 “origin” 与分支名字 “master” 一样,在 Git 中并没有任何特别的含义一样。 同时 “master” 是当你运行git init时默认的起始分支名字,原因仅仅是它的广泛使用,“origin” 是当你运行git clone时默认的远程仓库名字。 如果你运行git clone -o booyah,那么你默认的远程分支名字将会是 booyah/master

克隆之后的服务器与本地仓库。
克隆之后的服务器与本地仓库

如果你在本地的master分支做了一些工作,然而在同一时间,其他人推送提交到git.ourcompany.com并更新了它的的master分支,那么你的提交历史将向不同的方向前进。 也许,只要你不与 origin 服务器连接,你的origin/master指针就不会移动。

本地与远程的工作可以分叉。
本地与远程的工作可以分叉

如果要同步你的工作,运行git fetch origin 命令。 这个命令查找 “origin” 是哪一个服务器(在本例中,它是git.ourcompany.com),从中抓取本地没有的数据,并且更新本地数据库,移动origin/master指针指向新的、更新后的位置。

`git fetch` 更新你的远程仓库引用。
git fetch更新你的远程仓库分支

为了演示有多个远程仓库与远程分支的情况,我们假定你有另一个内部 Git 服务器,仅用于你的 sprint 小组的开发工作。 这个服务器位于git.team1.ourcompany.com。 你可以运行git remote add 命令添加一个新的远程仓库引用到当前的项目,这个命令我们会在 Git 基础 中详细说明。 将这个远程仓库命名为teamone,将其作为整个 URL 的缩写。添加另一个远程仓库。

添加另一个远程仓库

现在,可以运行git fetch teamone来抓取远程仓库teamone有而本地没有的数据。 因为那台服务器上现有的数据是origin服务器上的一个子集,所以 Git 并不会抓取数据而是会设置远程跟踪分支teamone/master指向teamone的master分支。 

远程跟踪分支 `teamone/master`。
远程跟踪分支 teamone/master
posted @   luckylan  阅读(763)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示

目录导航