git 的 分支特点,轻量级
什么是分支
什么是commit?
首先我们了解:当commit时,我们commit了什么?
其实我们保存了一个 commit 对象:
- 一个指针:指向暂存内容快照
- 包含了这次提交的 作者,时间 等相关信息
- 包含了0+个指向其 父对象 的指针 (第一个commit是没有父对象的)(指针可以连成链)
比如:当我们 add 3个文件 file-0,file-1,file-2的之后,commit了,我们执行了哪些操作呢?
add
- 对 其中 每一个文件进行校验和计算
- 然后 将当前的文件快照(文件快照的对象类型是 blob) 加入git仓库
- 校验和加入暂存区
commit
- 计算每一个子目录的校验和
- 在Git仓库中将这些目录保存为 tree 对象,然后创建一个commit对象,如下图(重要):
多次提交之后就会形成一个commit链(出现分支的意思了),如下图:
什么是分支?
只要理解分支是链式结构,那么多分支就很明显了,如下:
这是只有主分支的时候:
这是添加了一个分支的时候,git branch testing
:
其中 HEAD 是指向当前工作的本地分支,可以使用
git checkout xxx
来切换分支
同时git checkout -b xxx
就是创建并切换到某一个分支
分支可以应对 实际开发过程中的一些常见问题:比如紧急修复bug,或者要发开一个新的功能,怎么办?
新开个分支啦~
如何合并
实例1,fast forword 合并:
git checkout master // 切换到主分支
git merge hotfix // 合并hotfix分支
合并的时候会出现 Fast Forword 提示,如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,因为这种单线的历史分支不存在任何需要解决的分歧,所以这种合并过程可以称为快进(Fast forward)。
另外:
git branch -d hotfix // 合并后可以删掉这个 <hotfix> 分支了
实例2,合并双线分支
找相同的祖先节点,创建新的commit对象,当然也有新的快照,新的 commit对象就有 两个不同的父对象了。
关键的问题是:合并时发生冲突该怎么办?
git status // 查看并解决冲突
解决冲突后:执行 git add .
标记为已经解决的状态
然后 git commit
大功告成!
罗列一些分支管理的命令:
git branch // 给出当前所有分支的清单
git branch -v // 可以查看每个分支对应的 <最后一个commit对象>
git branch --merged // 查看已经并入 **当前分支的** 分支
git branch --no-merged // 查看没有并入当前分支的分支
远程仓库
远程分支是对远程仓库的分支的索引
是一些无法移动的本地分支,只有当git网络交互的时候才会更新
表示形式:(远程仓库)/(分支名)
很可能是来自不同的远程仓库的
用一个实际的例子来解释一下,远程仓库的交互:
- 首先,你clone了一个远程仓库
- Git服务器会自动的将此远程仓库命名为origin
- 下载其中所有的数据
- 建立一个指向远程仓库的 master 分支的指针 在本地命名为 origin/master (此时这条分支是无法更改数据的)
然后
- Git又建立了一个属于你自己的本地master分支
- 始于origin上的master分支的相同位置,开始工作
只要不和服务器交互,那么origin/master就不会移动
使用
git fetch origin
来从服务器抓取新的更新,此时origin/master 更新(移动)了
git remote add xxx xxx.com.... // 这是添加一个多个远程仓库的命令
推送分支
git push (远程仓库名) (本地分支名) // 上传分支
git push (远程仓库名) (本地分支名):(上传之后的远程分支名) // 上传并改名
此时如果你的小伙伴,抓取了你上传的分支
git fetch origin
那么他的远程分支会更新,但是仍然还是不可操作的,怎么才能使我们可以操作这个分支呢?
- 创造一条和这个一样的本地新分支
- 合并到一个分支
git merge <远程仓库名>/<某个分支名> // 合并法
git checkout -b <新分支名字> <远程仓库名>/<某个分支名> // 新建分支法
跟踪分支
从远程分支中 checkout
出来的本地分支,也叫做 跟踪分支
跟踪分支有很大的意义:表示这条本地分支是和 某条远程仓库的分支 是绑定的
也就意味着
push
可以自动推送相应的分支,pull
意味着从这些分支中拉取合并到本地来
现在再看clone操作,就是自动创建了一个 master 分支来 跟踪 origin/master分支
git checkout -b <新分支名字> <远程仓库名>/<某个分支名> //建立了联系
或者
git checkout --track <远程仓库名>/<某个分支名> //以默认名字建立新的分支
删除分支
git push <远程仓库名>/<某个分支名> //相当于将 null push 给了某个远程分支,也就是执行了 删除
分支的rebase
什么是rebase?
merge**(三方:两个最新分支,和它们的最初祖先合并)只是合并的一种方式,还有 另外的一种方式叫做rebase**
rebase的操作大概就是:在一条分支上 执行 另一条分支commits,可以想象为 打补丁
rebase的好处在于,可以产生一个更为整洁的 提交记录