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到远程库,就不要再将其衍合到其它分支。
相关推荐
提炼了各种Git 应用场景的命令和基础说明与分类,基本满足大型软件开发要求,我主要基于Android 系统开发,几百个git 仓库各种分支,合并。
辛星笔记之ProGit涵盖了版本控制、git基础、git分支管理、服务器上git的使用、分布式git概念、git工具使用、自定义git、以及git内部原理等关键知识点。下面将详细介绍这些知识领域。 版本控制是一种记录文件内容...
6. **版本控制**:使用Git进行版本管理和协同开发,理解Git的基本命令和分支管理。 7. **调试技巧**:因为涉及到内核模式的代码,调试会相当复杂,需要熟悉WinDbg等工具。 8. **文档和API理解**:可能需要阅读和...
尤其是后者的命名可能意味着这是一个开源项目(master是Git版本控制中主分支的常见命名),使用者可以在遵循一定的协议下自由地查看、修改和分享代码。 这项技术的应用场景非常广泛,不仅限于学术领域,还包括了...
12. **版本控制**: 介绍Git的基本用法,理解分支、合并和提交的概念,用于团队协作和代码管理。 在"100-Days-of-Code-Python-main"这个文件夹中,可能包含了课程的代码示例、项目文件、笔记、挑战任务等资源,学员...
【readhubtron】是一个基于Electron框架开发的跨平台...对于开发者而言,readhubtron的源代码是一个学习Electron应用开发和Web技术跨平台应用的好实例,同时也展示了如何通过持续集成和版本控制来维持项目的高效开发。
"libpythonpro:Treinamento do Curso Python Pro" 是一个针对Python编程的高级培训课程,旨在帮助学习者提升他们的Python专业技能。这个课程可能涵盖了Python的基础语法、面向对象编程、数据结构、函数式编程、异常...
"master"分支在Git版本控制系统中通常代表主分支,包含了项目的主要代码和更新。对于想要学习如何在苹果电脑上进行软件开发,特别是使用Java编程的人来说,这个压缩包可能包含了一系列的指导文件、示例代码和配置...