`

progit学习笔记-分支

    博客分类:
  • git
 
阅读更多

Git鼓励在工作中频繁使用分支与合并。

3.1 何为分支

GIT每次提交会创建一个提交commit对象,这个对象包含指向快照的指针,还有作者及其它附属信息。还包含一个指向直接祖先的指针,直接祖先是上次提交的对象,如果本地提交是由多个分支合并而成,那就有多个直接祖先。

GIT在通过git add添加文件到暂存区时,会创建一个记录目录结构的tree对象。下图描述三个文件在第一次提交后及多次提交后的对象及指针指向关系。

 

GIT的分支仅仅是指向commit对象的可变指针。默认的分支名是master。若干次提交后,分支指向最后一次提交。说它可变是每次提交它都向前移动指向最新一次的提交。

 

创建一个新的分支

$ git branch testing #这会在当前commit对象上创建一个分支指针,与原来master分支的指针指向同一个commit对象。

HEAD:特别指针,指向当前工作的分支。

$ git checkout testing   #这样会将HEAD指针指向testing分支。

在新分支testing上提交后,再回到master分支提交一次。生成的版本图如下:

 

创建一个分支,其实就是新创建一个文件记录提交对象的校验后(41个字节,40位SHA-1串,及一个换行)。

 

3.2 基本的分支与合并

多使用分支与合并的原理场景如下:发一个版本V8.0,拉一个分支V8.0-branch-one,在它上在开发新功能。如果主版本有问题,需要修改。那在 V8.0上拉一个分支V8.0-bug-fix,修改然后打补丁给生产环境。然后把这个修复bug的分支合并到主干上,并删除掉。

3.2.1 基本分支

$ git checkout -b new-branch #新创建分支并切换到这个分支上。

合并分支

$ git merge branch-new

下图是merge一个分支后的图:

注意:由于master分支这时还在要合并的分支的上游,所以当合并的时候,只需要快进到那个分支就OK了。就是master指针指向那个commit对象。

 

合并后删除无用的分支

$ git branch -d branch-name

 

两分支合并

修改问题的分支与新功能的分支进行合并。如下图:

GIT负责找到两分支的共同祖先,并决定哪个做为合并基础,它可以自动合并,合并后产生一个新的commit.合并后的分支图:

 

3.2.3 冲突的合并

两个分支都修改了同一个文件的同一个部分。如果这时尝试去合并,GIT会提示

$ git merge iss53

Auto-merging index.html

CONFLICT (content): Merge conflict in index.html

Automatic merge failed; fix conflicts and then commit the result.

这时可以通过 git status 查看冲突.

unmerged 文件是合并冲突的文件状态,需要我们手工修改。GIT会在文件中加入标准的冲突标记

<<<<<<< HEAD:index.html

<div id="footer">contact : email.support@github.com</div>

=======

<div id="footer">

please contact us at support@github.com

</div>

>>>>>>> iss53:index.html

用=======隔开的上下两部分 分别是不同的分支。

手工合并后,使用 git add命令把它们标记为已解决(resolved)。合并也可以使用

git mergetool 来图形工具合并。

 

3.3 分支管理

$ git branch #查看当前所有分支

$ git branch -v # 查看各分支最后一次提交

$ git branch --merged或--no-merged #查看与当前分支已经合并或者未合并的分支。

$ git branch --merged

iss53

* master

没有星号的表示已经合并过来,即可以删除 $ git branch -d iss53

 

3.4 分支式工作流程

 master保留稳定的代码(已发布或即将发布)。再有一个名为develop的开发版,用于合并新功能,并进行测试。测试完成后,合并到master主干上来。

 

3.5 远程分支

远程分支-remote branch是对远程仓库状态的索引,它们是一些无法移动的本地分支。远程分支就是远程库的一个本地快照。

远程分支命名:远程仓库名/分支名。

clone一个远程分支到本地。GIT会在本地创建一个origin名称来对应远程库,并且使用master分支名来对应远程库的最新版本。然后它还会自动创建一个本地master分支,来对应这个远程分支。

当远程库有修改后,我们通过git fetch origin,该命令查看origin对应的远程库地址,然后更新本地没有的内容,再然后origin/master远程分支将向前移动,而本地分支在合并前不会对应移动。

添加多个远程分支:

多个远程分支是根据同一个主版本库拉出的多个分支。下面的截图演示通过 git remote add tempone xxxx

后,再通过git fetch tempone命令来拉取这个分支的内容。GIT会同时创建一个远程分支用来标识这个远程库。

 

3.5.1 推送

$ 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

这会在远程库中创建一个新的同名分支。

过程中GIT将上例中的serverfix串扩展为 refs/heads/serverfix:refs/heads/serverfix

意为“取出我的 serverfix 本地分支,推送它来更新远程仓库的 serverfix 分支”。也可以使用

git push origin serverfix:othername 来自定义远程分支的名称。

推送后,远程库中就多了个分支。

 

另外用记通过fetch远程库时,就会下到推送的分支,但是同样这只是远程分支。如果希望将它合并到当前分支:git merge origin/serverfix。

如希望在这个分支基础上拉一个新的分支出来:git checkout -b serverfix origin/serverfix。

 

3.5.2 跟踪分支

从远程分支检出的本地分支称为 跟踪分支。它与远程分支直接关联,在这个分支下执行 git push,会直接将当修改推送到对应的远程分支上支。同样 git pull会拉取所有更新,并自动合并到当前分支。

在clone一个远程库时,GIT基于origin/master远程分支,分化出一个本地分支master。所以,在master分支下,我们可以直接push 或 pull。同样,我们可以不只是基于origin/master分支分化,可以通过这个远程库上的其它远程分支分化:git checkout -b 分支名 远程库名/远程分支名。git 1.6.2后简化命令为:

git checkout -b --track origin/serverfix。如果想自定义本地分支名,代上就是了。

 

3.5.3 删除远程分支

$ git push 远程名 :远程分支名。这个对应 git push 远程名 本地分支名:远程分支名。

意思就是提取空白然后把它变化为远程分支名。

 

3.6 衍合

整合分支两人种方式:merge-合并与rebase-衍合

3.6.1 基础

如c2分出c3与c4两分支。通过merge是,提交一个c5,并把c3与c4合并进来。

其实还可以:在c4分支上把c3的变化在c4上再发生一次(重放)。

$ git checkout experiment

$ git rebase master

切换到experiment分支,把当前分支的补丁打到master分支上去。

它的工作原理是GIT回到两人个分支的共同祖先,然后把当前版本发生过的提交再在rebase对象上发生一次。

衍合后,在目标分支上进行一次快进合并,将目标分支的指针指向最新衍合的提交。

衍合产生的提交历史比合并更清晰,能区分哪些是A分支的修改,哪些是B分支的修改。

一种合适的工作方式:开发者基础A库拉一个分支进行修改,完了将分支rebase到origin/master库。然后,A库的维护者只需要一个快进合并就可以把开发者的修改合并进来,而且历史清晰。

衍合将每行改变发生的次序重演,而合并是将最终结果合在一起。

 

3.6.2 更多有趣的衍合

 

图3.31表示:基于主分支,先拉一个server分支,又基于server分支拉了client分支,master,server,client三者都有提交。

现在,如果希望只把client提交那部分合并到master分支上来,又不希望把server的合并进来。可以通过:

$ git checkout client

$ git rebase --onto master server client

它的意思是找出client相对server与client共同祖先以后提交的变化内容,并在master分支上衍合进来。

$ git checkout master

$ git merge client   #快进

如果要再把server合并进来,

$ git rebase master server  #不需要checkout到server分支,使用git rebase [主分支] [特性分支]就自动检出特性分支,然后在主分支上重演。

 

3.6.3 衍合的风险

永远不要衍合那些已经推送到公共库中的更新。不要在公共库上使用衍合,只在本地分支使用。如果分支已经push到远程库,就不要再将其衍合到其它分支。

 

 

 

 

 

 

  • 大小: 80.2 KB
  • 大小: 76.8 KB
  • 大小: 34.4 KB
  • 大小: 34.7 KB
  • 大小: 77.3 KB
  • 大小: 36.6 KB
  • 大小: 21.3 KB
  • 大小: 22 KB
  • 大小: 51.6 KB
  • 大小: 58.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics