简单清晰的 Git 版本控制(五)------ Git 分支(2)

之前已经学会了分支的创建,删除,转换和合并,那么如何对分支进行管理呢

分支的管理

查看分支:git branch

之前用到过 git branch 创建分支,删除分支,直接使用 git branch 就是查看有哪些分支。

其中,有 * 代表是当前工作分支。 

查看各个分支最后一次提交信息: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

从清单中筛选出你已经(或尚未)与当前分支合并的分支,加上 --merge 和 --no-merged 选项 

$ git branch --merged
iss53
* master

之前我们已经合并了 iss53,所以在这里会看到它。一般来说,列表中没有 * 的分支通常都可以用 git branch -d 来删掉。因为既然已经把它们所包含的工作整合到了其他分支,删掉也不会损失什么。 

而对于 --no-merged 的分支则不能 -d 直接删除,会报错(提示会丢失数据)。如果想要强制删除,使用 -D 选项。

远程分支

牢记这些分支全部都是本地分支,这一点很重要。当你在使用分支及合并的时候,一切都是在你自己的 Git 仓库中进行的 — 完全不涉及与服务器的交互。

远程分支(remote branch)是对远程仓库中的分支的索引。使用 (远程仓库名)/(分支名) 这样的形式表示远程分支,远程分支不能直接修改,只有与网络交互才能对他更新。

如果从远程仓库中克隆一个项目,Git 会自动将此远程仓库命名为 origin,并下载其中所有的数据,建立一个指向它的 master 分支的指针,在本地命名为 origin/master,但你无法在本地更改其数据。接着,Git 建立一个属于你自己的本地 master 分支,始于 origin 上 master 分支相同的位置,然后你可以就此开始工作。

如果团队成员在远程仓库推送了他们的更新, 服务器和本地 master 指针会向前移动,而本地的 origin/master 仍然不变

这时可以使用 git fetch origin 拉取服务器的最新数据并同步到本地仓库,origin/master 会移动到最新位置。

推送本地分支

要想和其他人分享某个本地分支,就需要把它推送到一个你拥有写权限的远程仓库。

将本地分支推送到远端服务器:git push (远程仓库名) (分支名)

$ git push origin serverfix
Counting objects: 20, done.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (15/15), 1.74 KiB, done.
Total 15 (delta 5), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
* [new branch] serverfix -> serverfix

这会将本地 serverfix 分支推送到远程服务器 serverfix 分支。若想把远程分支叫作 awesomebranch,可以用 git push origin serverfix:awesomebranch 来推送数据。

接下来,当协作者再次从服务器上获取数据时,他们将得到一个新的远程分支 origin/serverfix,并指向服务器上 serverfix 所指向的版本:

$ git fetch origin
remote: Counting objects: 20, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 15 (delta 5), reused 0 (delta 0)
Unpacking objects: 100% (15/15), done.
From git@github.com:schacon/simplegit
* [new branch] serverfix -> origin/serverfix

值得注意的是,在 fetch  操作下载好新的远程分支之后仍然无法在本地编辑该远程仓库中的分支。换句话说,在本例中,你不会有一个新的 serverfix 分支,有的只是一个你无法移动的 origin/serverfix 指针。

如果要把该远程分支的内容合并到当前分支,可以运行 git merge origin/serverfix。如果想要一份自己的 serverfix 来开发,可以在远程分支的基础上分化出一个新的分支来:

$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "serverfix"

这会切换到新建的 serverfix 本地分支,其内容同远程分支 origin/serverfix 一致,这样你就可以在里面继续开发了。

跟踪远程分支

从远程分支 checkout 出来的本地分支,称为 跟踪分支 (tracking branch)。跟踪分支是一种和某个远程分支有直接联系的本地分支。在跟踪分支里输入 git push,Git 会自行推断应该向哪个服务器的哪个分支推送数据。同样,在这些分支里运行 git pull 会获取所有远程索引,并合并到本地分支。

在克隆仓库时,Git 通常会自动创建一个名为 master 的分支来跟踪 origin/master。这正是 git push  git pull 一开始就能正常工作的原因。当然,你可以随心所欲地设定为其它跟踪分支,比如 origin 上除了 master 之外的其它分支。刚才我们已经使用:git checkout -b [分支名] [远程名]/[分支名]。如果是 1.6.2 以上版本的 Git,还可以用 --track 选项简化:

$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "serverfix"

要为本地分支设定不同于远程分支的名字,只需在第一个版本的命令里换个名字:

$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch refs/remotes/origin/serverfix.
Switched to a new branch "sf"

现在你的本地分支 sf 会自动将推送和抓取数据的位置定位到 origin/serverfix 了。

删除远程分支

如果不再需要某个远程分支了,比如搞定了某个特性并把它合并进了远程的 master 分支(或任何其他存放稳定代码的分支),可以这样来删除它:git push [远程名] :[分支名]。如果想在服务器上删除 serverfix 分支,运行下面的命令:

$ git push origin :serverfix
    To git@github.com:schacon/simplegit.git
    - [deleted] serverfix

有种方便记忆这条命令的方法:不久前见过 git push [远程名] [本地分支]:[远程分支] 语法,如果省略 [本地分支],那就等于是在说“在这里提取空白然后把它变成 [远程分支]”。

分支的衍合

把一个分支中的修改整合到另一个分支的办法有两种:merge 和 rebase(衍合)

衍合的基本操作

假如两个分支进行到如下阶段

使用 merge 操作整合分支,就会把两个分支的最新快照(C3和C4)以及他们的共同祖先(C2)进行三方合并,产生新的提交对象C5。

还有另外一个选择:就是把在 C3 里产生的变化补丁在 C4 的基础上重新打一遍。在 Git 里,这种操作叫做衍合(rebase)。有了 rebase 命令,就可以把在一个分支里提交的改变移到另一个分支里重放一遍。

$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command

用当前分支给分支名标识的分支打补丁:git rebase 分支名 

它的原理是回到两个分支最近的共同祖先,根据当前分支(也就是要进行衍合的分支 experiment)后续的历次提交对象(这里只有一个 C3),生成一系列文件补丁,然后以基底分支(也就是主干分支 master)最后一个提交对象(C4)为新的出发点,逐个应用之前准备好的补丁文件,最后生成一个新的合并提交对象(C3'),从而改写 experiment 的提交历史,使它成为 master 分支的直接下游。

然后回到 master 分支,进行一次快速合并

接下来看一个复杂一点的衍合,但是看过之后你会对衍合有更深的理解。

假如 master 操作后又添加了新的分支 server ,提交到 C4,这时又添加 client 分支修改客户端代码,提交到 C9 又回到 server 并提交到 C10。

接下来在一次发布中要把 client 合并到 master 中。这个时候,我们就可以把 client 分支的改变即 C8 和 C9,跳过 server 直接放到 master 分支中重演一遍,但这需要用 git rebase 的 --onto 选项指定新的基底分支 master

$ git rebase --onto master server client

这个命令的意思是:“取出 client 分支,找出 client 分支和 server 分支的共同祖先之后的变化,然后把它们在 master 上重演一遍”。结果如图。

现在可以快进 master

$ git checkout master
$ git merge client

现在决定把 server 分支的变化也包含进来。我们可以直接把 server 分支衍合到 master,而不用手工切换到 server 分支后再执行衍合操作 — git rebase [主分支] [特性分支] 命令(注意:特性分支也就是要使用的改变所在的分支是在命令的最后面,就可以理解 --onto 中最后是 client 了)会先取出特性分支 server,然后在主分支 master 上重演:

$ git rebase master server

然后就可以快进主干分支 master 了:

$ git checkout master
$ git merge server

现在 client 和 server 分支的变化都已经集成到主干分支来了,可以删掉它们了。

$ git branch -d client
$ git branch -d server

 

衍合的风险

使用衍合也是有风险的,但是请记住:

一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。

也就是说,如果把衍合当成一种在推送之前清理提交历史的手段,而且仅仅衍合那些尚未公开的提交对象,就没问题。如果衍合那些已经公开的提交对象,并且已经有人基于这些提交对象开展了后续开发工作的话,就会出现叫人沮丧的麻烦。 因此,最好在分享之前进行衍合。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值