分支的意义与管理
创建分支可以避免提交代码后对主分支的影响,同时也使我们有了相对独立的开发环境,分支在日常开发中具有很重要的意义。
# 新建一个分支,但依然停留在当前分支
git branch [branch-name]
# 新建一个分支,指向指定 commit
git branch [branch] [commit]
# 切换到指定分支,并更新工作区
git checkout [branch-name]
# 切换到上一个分支
git checkout -
# 新建一个分支,与指定的远程分支建立追踪关系
git branch --track [branch] [remote-branch]
# 建立追踪关系,在现有分支与指定的远程分支之间
git branch --set-upstream [branch] [remote-branch]
# 合并指定分支到当前分支,如果有冲突需要手动合并冲突,然后 add、commit 再提交
git merge [branch]
# 选择一个 commit,合并到当前分支
git cherry-pick [commit]
# 删除分支
git branch -d [branch-name]
# 强制删除分支
git branch -D [branch-name]
# 删除远程分支
git push origin --delete [branch-name]
git branch -dr [remote/branch]
# 在需要删除的分支前面加一个冒号就可以了,push 上去之后,服务器上的分支自然就被删除了
git push origin :branch_name
创建并切换到新建的分支:
git checkout -b 分支名
查看本地分支,即查看本地创建了哪些分支:
git branch
# 列出所有远程分支
git branch -r
查看本地+远程分支
git branch -va
# 列出所有本地分支和远程分支
git branch -a
- 切换到远程分支
git checkout remotes/origin/branch_name
// 新建并切换到该分支
git checkout -b branch_name
# -b 的意思是 base,就是以当前分支为 base,新建一个分支
# 或者直接执行
git checkout -t origin/branch_name
变基-rebase
在 Git 中整合来自不同分支的修改主要有两种方法: merge 和 rebase
。步骤:
# 1. 假设当前在 dev 分支上,将 master 分支上的更新同步到当前分支
git rebase master
# 2. 切换回 master 分支
git checkout master
# 3. 最后把 dev 分支的最新代码 merge 到 master 分支上
git merge dev
第三步是最重要的,git 此时会自动 merge master 分支和当前分支 dev
。如果自动 merge 成功,就不需要再管了;如果自动 merge 失败,此时 git status
查看哪个文件 merge 失败,打开该文件,手动修改文件中冲突的地方,执行 git add .
命令去更新相应内容的索引,然后,不需要执行 git commit
命令,只要执行 git rebase --continue
,git 会继续应用(apply) 余下的补丁。
需要注意的是:可以在任何时候,使用
git rebase --abort
命令来终止 rebase 的行动,并且当前分支会回到 rebase 开始前的状态。
变基的基本操作
从上图可以看出,开发任务分叉到两个不同分支,又各自提交了更新。
我们知道,整合分支最容易的方法是 git merge
命令,该命令会把两个分支的最新快照(C3 和 C4) 以及两者最近的共同祖先(C2) 进行三方合并,合并的结果是生成一个新的快照(C5) 并提交。如上图所示:通过合并操作来整合分叉了的历史。
除了 git merge
之外,整合分支还有一种方法:我们可以提取在 C4
中引入的补丁和修改,然后在 C3 的基础上再应用一次。在 Git 中,这种操作就叫做变基。我们可以使用 rebase
命令将提交到某一分支上的所有修改都移至另一个分支上,就好像"重新播放"一样。
git checkout experiment
git rebase master
这一操作的原理是:首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master) 的最近共同祖先 C2,然后 对比当前分支 experiment
相对于该祖先的历次提交 ,提取相应的修改并存为临时文件,然后将当前分支指向目标基底 C3,最后将之前另存为临时文件的修改依序应用。如上图所示:将 C4 中的修改变基到 C3 上。
# 现在切换会 master 分支,进行一次快进合并
git checkout master
git merge experiment
这时候, C4'
指向的快照就和上面使用 git merge
命令的例子中 C5 指向的快照一模一样了。这两种整合方法的最终结果没有任何区别,但是变基使得提交历史更加整洁。我们在查看一个经过变基础的分支的历史记录时会发现,尽管实际的开发工作是并行的,但是它们看上去就像是先后串行的一样,提交历史是一条直线没有分叉。
特别注意: 无论是通过变基,还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。变基是将一系列提交按照 原有次序 依次应用到另一分支上,而合并是把最终结果合在一起。
rebase demo
在和远程分支同步后,对 demo.js
这个文件做了两次提交。用 git log
命令查看:
git log --graph --pretty=oneline --abbrev-commit
结果如下:
如上图所示:Git 用( HEAD -> master
) 和( origin/master
) 分别标识出当前分支的 HEAD
和远程 origin
的位置分别是 1e23035 test modify 2
和 3c696d0 test
,本地分支比远程分支快了两个提交。
现在我们尝试推送本地分支,很不幸,失败了,这说明有人先于我们推送了远程分支,我们需要先 git pull
一下。再用 git status
看看状态,加上刚才合并的提交,现在我们本地分支比远程分支超前 3 个提交。
用
git log
看看当前的提交历史:发现提交历史分叉了。
使用
git rebase
命令解决提交历史分叉问题:
➜ git_learn git:(master) git rebase
First, rewinding head to replay your work on top of it...
Applying: test modify 1
Applying: test modify 2
重新使用
git log
命令查看:
git log --graph --pretty=oneline --abbrev-commit
原本分叉的提交现在变成一条直线了!这种神奇的操作是怎么实现的?其实原理非常简单。我们注意观察,发现 Git 把我们本地的提交'挪动'了位置,放到了 fe1a412 (origin/master, origin/HEAD) Update README.md
之后,这样,整个提交历史就成了一条直线。rebase 操作前后,最终的提交内容是一致的,但是,我们本地的 commit 修改内容已经变化了,它们的修改不再基于 3c696d0 test
,而是基于 fe1a412 (origin/master, origin/HEAD) Update README.md
,但最后的提交 6ab73f9 (HEAD -> master) test modify 2
内容是一致的。
rebase 操作的特点:把分叉的提交历史'整理'成一条直线,看上去更直观。缺点是:本地的分叉提交已经被修改过了(之前本地提交的 commitId 发生了变化,但是内容不变)。
最后,通过 push 操作把本地分支推送到远程:
重新使用
git log
命令查看,远程分支的提交历史也是一条直线:
git pull 和 git pull --rebase 的区别使用
两者的区别可以用如下的等式来做解释:
git pull = git fetch + git merge
git pull --rebase = git fetch + git rebase
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论