查看、创建、切换、删除分支
查看分支
1 | git branch |
创建新分支
1 | git branch <newbranchname> |
在当前提交对象上创建一个新的分支 dev
,但并不会自动切换过去。
切换分支
1 | git checkout <branchname> |
此时,HEAD
指针已经从旧的分支指向了该分支 dev
。
创建并切换到新分支
1 | git checkout -b <newbranchname> |
删除分支
1 | git branch -d <branchname> |
强制删除。指定分支没有完全合并时,-d
参数会失效,此时需要强制删除:
1 | git branch -D <branchname> |
在不同的分支修改
此时,在新的分支 dev
上执行某些操作并提交并不影响原来的旧分支 master
:
1 | vim newFile.txt |
切换回旧分支 master
进行修改提交后,两个分支已经有了分叉。
1 | git checkout master |
此时可以通过 git log --oneline --graph
来查看。
合并
创建新功能分支
feature
进行开发,并提交1
2
3git checkout -b feature
some changes
git commit -a -m "New features"线上
master
分支有紧急 bug 需要修复。创建修复分支hotfix
进行修复1
2
3
4git checkout master
git checkout -b hotfix
fix bugs
git commit -a -m "Fix bugs"将修复代码部署到线上,即将
hotfix
合并到master
1
2git checkout master
git merge hotfix在合并时,会出现“快进(fast-forward)”这个词。 由于你想要合并的分支
hotfix
所指向的提交是当前所在的提交master
的直接后继, 因此 Git 会直接将指针向前移动。换句话说,当你试图合并两个分支时, 如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候, 只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧——这就叫做 “快进(fast-forward)”。bug 已经被修复,遂删除
hotfix
分支1
git branch -d hotfix
切换回
feature
分支进行开发1
2
3git checkout feature
some changes
git commit -a -m "New features"新功能开发完毕,需要合并到
master
分支现在的分支图看起来是这样的:
这和之前合并
hotfix
分支的时候有一点不一样。 在这种情况下,你的开发历史从一个更早的地方开始分叉开来(diverged)。 因为,master
分支所在提交并不是feature
分支所在提交的直接祖先,Git 不得不做一些额外的工作。 出现这种情况的时候,Git 会使用两个分支的末端所指的快照(C4
和C5
)以及这两个分支的公共祖先(C2
),做一个简单的三方合并。1
2git checkout master
git merge featureGit 将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它。 这个被称作一次合并提交,它的特别之处在于他有不止一个父提交。最终结果如图:
新功能开发完毕,删除
feature
分支1
git branch -d feature
解决冲突
如果在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,Git 就没法干净的合并它们。此时 Git 做了合并,但是没有自动地创建一个新的合并提交。Git 会暂停下来,等待你去解决合并产生的冲突。可以通过
git status
命令来查看那些因包含合并冲突而处于未合并(unmerged
)状态的文件。Git 会在有冲突的文件中加入标准的冲突解决标记:
1
2
3
4
5
6
7China
<<<<<<< HEAD
Tianjin
=======
Shanghai
Beijing
>>>>>>> dev上半部分表示
HEAD
所指分支master
的内容,下半部分为dev
分支内容,可以通过手动修改代码来解决冲突。解决之后手动将该文件添加到暂存区,确认无误后提交。
1
2git add <conflictFile>
git commit也有一些
merge
和diff
可视化工具来帮助更好的解决冲突,如p4merge
,bc
和opendiff
等。
远程分支
远程引用是对远程仓库的引用(指针),包括分支、标签等等。 可以通过 git ls-remote
来显式地获得远程引用的完整列表,一个更常见的做法是利用远程跟踪分支。远程跟踪分支是远程分支状态的引用,是无法移动的本地引用。在进行了网络通信之后,Git 会自动的更新远程跟踪分支。以 <remote>/<branch>
来命名,如 origin/master
。
推送
1 | git push <remote> <branch> |
这是一种简写形式,完整的形式为:
1 | git push origin refs/heads/dev:refs/heads/dev |
或者简写为:
1 | git push origin dev:dev |
此命令在推送到不同的分支名时比较有用。
拉取
1 | git fetch origin |
当抓取到新的远程跟踪分支 feature
时,本地不会自动生成一份可编辑的副本,只有一个不可修改的远程分支指针。要么将该分支合并到本地分支,要么基于该分支创建一个新的本地分支:
1 | git checkout -b feature origin/feature |
git pull
命令则将拉取和合并整合到一起。
跟踪
从一个远程跟踪分支检出一个本地分支会自动创建所谓的“跟踪分支”。
自动跟踪。
git clone
一个仓库时会自动创建一个跟踪到远程默认分支的本地分支。创建跟踪分支
1
git checkout -b <branch> <remote>/<branch>
创建同名跟踪分支
1
2
3git checkout --track <remote>/<branch>
简化版。当本地该分支名不存在,且刚好只有一个名字与之匹配的远程分支时有效
git checkout <branch>设置已有本地分支的跟踪分支
1
git branch -u <remote>/<branch>
查看分支跟踪信息
1
git branch -vv
该命令显示本地分支跟踪远程分支的信息,包括领先、落后、提交信息。
取消跟踪
1
git branch --unset-upstream <branch>
不输入
<branch>
时默认为当前分支。
删除
1 | git push <remote> -d <branch> |
变基
整合分叉分支常用的方法是进行 merge
合并,它会将两个分支与它们的公共祖先进行比较并生成一次合并提交。
还有一种方法即为:可以提取在当前分支中引入的补丁和修改,然后在另一分支的基础上应用一次。 在 Git 中,这种操作就叫做 变基(rebase)。你可以使用 rebase
命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。
例如,假设现在 topic
和 master
分支有分叉,执行:
1 | git checkout topic |
现在,将 topic
分支上的修改应用到了 master
分支上,新的 topic
分支好像从 master
分支直接改动过来的一样(可通过 git log
查看)。实际上,可以通过 git rebase <basebranch> <topicbranch>
来避免分支的切换。
现在可以执行快进合并来更新 master
分支:
1 | git checkout master |
一般使用 rebase
的目的是为了确保在向远程分支推送时能保持提交历史的整洁。
所生成的重放也可以指定另外的分支进行应用:
1 | git rebase --onto master server client |
取出 client
分支,找出它从 server
分支分歧之后的补丁,然后把这些补丁在 master
分支上重放一遍,让 client
看起来像直接基于 master
修改一样。此番操作之后可以将 client
快进合并到 master
。
注:只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作。因为变基操作改变了历史,如果他人使用历史进行了修改,将带来比较麻烦的后果。
压缩提交历史
在向远程仓库推送自己的某些修改之前,可以在本地通过 rebase
来压缩多次提交,使得历史记录看起来更整洁。
1 | 压缩后 3 次提交 |
此时 Git 会弹出文本编辑器,倒序显示最近三次的提交:
1 | pick 177b35c 66 |
我们把最后两次的提交压缩至倒数第三次提交,将第二第三行动作改为 squash
或者 s
:
1 | pick 177b35c 66 |
保存退出后,Git 开始压缩。中间若有冲突,我们需手动解决冲突并将文件添加至暂存区,并执行 git rebase --continue
命令。如果想放弃压缩,执行 git rebase --abort
。
当所有冲突都解决后,Git 会弹出文本编辑器要求输入新的提交的信息,保存退出后即为压缩成功。