文章目录
名人榜上天下第一辩
众生芸芸难貌相,海水滔滔难斗量,平凡不是平凡客,世情百态掌握中。
天下第三人时期造型。
概述
分支是所有版本控制系统都支持的的功能。可以从主线分离开任务,以进行独立的开发而不形象主线。
一、Git分支简介
1.1 基本概念
Git的分支采用的是指针记录每个文件的快照以及相应的结构信息,而不是直接复制文件,这样的特性决定了Git的分支非常的轻量,几乎可以瞬间创建分支。
Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 master 分支会在每次提交时自动向前移动。
Git 的 master 分支并不是一个特殊分支。 它就跟其它分支完全没有区别。 之所以几乎每一个仓库都有 master 分支,是因为 git init 命令默认创建它,并且大多数人都懒得去改动它。
1.2 创建分支
git branch branchname # 创建分支,但是不会切换到新的分支
git checkout -b <newbranchname> # 创建分支,同时切换到新建的分支
(1) 先查看当前的版本信息
先查看下当前分支信息:
D:\Desktops\Test>git log --oneline --decorate # 查看日志信息
917573c (HEAD -> master) 添加readme # HEAD缓存指针指向master
(2)创建分支
创建的是分支的指针,不会自动切换到新的分支。
新建的分支会在当前对象的基础上创建一个新指针,并指向当前对象。
此时标识位置的指针HEAD依然指向当前版本,而不是新的分支上。
D:\Desktops\Test>git log --oneline --decorate
917573c (HEAD -> master, testbranch) 添加readme # 有两个分支,HEAD依然指向master
1.3 分支切换
使用checkout可以切换当前分支,每次提交指挥提交到HEAD所在的分支,而不会分支之间是独立的。
通过间的的切换分支和提交动作,可以快速的在不同分支之间切换,然后时机成熟时将分支合并起来。
git checkout <branchname> # 切换分支
(1) 使用指令直接切换分支:
D:\Desktops\Test>git checkout testbranch
Switched to branch 'testbranch'
A Test1.txt
A Test2.txt
D:\Desktops\Test>git log --oneline --decorate
917573c (HEAD -> testbranch, master) 添加readme
(2) 提交修改
提交只会提交到当前分支里,其他分支不会变化。
D:\Desktops\Test>git log --oneline --decorate # 查看当前分支
917573c (HEAD -> testbranch, master) 添加readme
D:\Desktops\Test>git commit # 提交资料
[testbranch f60127a] 添加新文件
2 files changed, 1 insertion(+)
create mode 100644 Test1.txt
create mode 100644 Test2.txt
D:\Desktops\Test>git log --oneline --decorate
f60127a (HEAD -> testbranch) 添加新文件 # 新提交分分支
917573c (master) 添加readme # 旧的分支一人保持旧的快照版本
(3) 切换到master分支,重新提交
切换master分支,重新提交,将会在master当前分支快照的基础上,延伸出先得的一个版本。
D:\Desktops\Test>git checkout master # 切换到master分支
Switched to branch 'master'
D:\Desktops\Test>git log --oneline --decorate --all # 查看所有分支
f60127a (testbranch) 添加新文件
917573c (HEAD -> master) 添加readme
D:\Desktops\Test>git add TestAdd.txt TestFile.txt # 添加文件
D:\Desktops\Test>git commit -a -m "另一个提交版本" # 提交修改
[master ea99183] 另一个提交版本
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 TestAdd.txt
create mode 100644 TestFile.txt
D:\Desktops\Test>git log --oneline --decorate --all # 重新查看日志
ea99183 (HEAD -> master) 另一个提交版本 # 当前分支新版本
f60127a (testbranch) 添加新文件 # 另一个分支没有变化
917573c 添加readme
1.4 删除分支
使用-d参数删除分支。
git branch -d <branchname> # 删除分支
二、新建和合并分支
2.1 工作流程示意图
- 开发软件时有一个新需求1,那就在原来的基础上新建一个“新分支1”进行修改;
- 新需求1还没有改完的时候,来个个新需求2,要求先改新需求2;
- 这个时候就可以根据新需求2先新建一个分支“新分支2”进行修改,修改完之后合并到主分支上;
- 然后可以切换到新分支1上继续完成修改;
- 修改完成后再合并到主分支上;
- 这样就可以再各个分支上进行切换,而不会影响到各自的操作;
2.2 新建分支
使用-b参数可以新建分支的时候直接切换到新分支。
git checkout -b <branchname> # 新建分支,同时切换到新的分支
2.3 合并分支
合并分支是以当前分支未主分支,然后把要合并的分支合并到当前分支中,也就是合并时将其他分支合并到HEAD执行的分支中。
$ git checkout master
$ git merge <branchname>
2.4 分支示例
2.4.1 当前除了主分支,再次创建了两个分支
D:\Desktops\Test>git log --oneline --decorate --all
7582919 (HEAD -> test1) add test1.txt
ea99183 (master) 另一个提交版本
f60127a (testbranch) 添加新文件
917573c 添加readme
- 提交后再master的基础上,创建了2个分支test1和testbranch;
- 然后2个分支各自有重新提交了一个版本;
- 限制的HEAD执行test1分支;
2.4.2 先合并test1分支
这个分支是在master基础上修改的分支,操作就是快进(Fast-forward)master分支到最新版本。
注:
- 被合并的分支来源于主分支时,会将主分支的指针往前移。
- 没有创建新的快照版本。
D:\Desktops\Test>git checkout master # 切换到主分支
Switched to branch 'master'
D:\Desktops\Test>git merge test1 # 合并test1分支
Updating ea99183..7582919
Fast-forward
test1.txt | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test1.txt
D:\Desktops\Test>git log --oneline --decorate --all # 查看分支
7582919 (HEAD -> master, test1) add test1.txt # 合并了分支,两个分支都还存在
ea99183 另一个提交版本
f60127a (testbranch) 添加新文件
917573c 添加readme
删除被合并的分支。
注意,如果分支未合并将无法删除。
D:\Desktops\Test>git branch -d test1 # 删除被合并的分支
Deleted branch test1 (was 7582919).
D:\Desktops\Test>git log --oneline --decorate --all
7582919 (HEAD -> master) add test1.txt
ea99183 另一个提交版本
f60127a (testbranch) 添加新文件
917573c 添加readme
2.4.3 合并testbranch分支
合并testbranch分支,由于两个分支不是延续的,所有会创建一个新的版本在主分支。
新的版本分支只在master分支上。
D:\Desktops\Test>git merge testbranch
Merge made by the 'ort' strategy.
Test1.txt | 1 +
Test2.txt | 0
2 files changed, 1 insertion(+)
create mode 100644 Test1.txt
create mode 100644 Test2.txt
D:\Desktops\Test>git log --oneline --decorate --graph --all
* bc352f3 (HEAD -> master) Merge branch 'testbranch'
|\
| * f60127a (testbranch) 添加新文件
* | 7582919 add test1.txt
* | ea99183 另一个提交版本
|/
* 917573c 添加readme
2.5 解决合并时的冲突
合并时有文件冲突是会停止合并,然后将文件标记为冲突。
- 可以通过手动修改冲突文件,然后用add指令将文件修改为已解决冲突。
- 也可以通过git mergetool指令调用默认的冲突解决工具修改差异解决冲突。
(1) test1分支修改test1.txt文件
D:\Desktops\Test>git branch test1 # 创建到test1分支
D:\Desktops\Test>git checkout test1 # 切换到test1分支
Switched to branch 'test1'
M test1.txt
D:\Desktops\Test>git commit -a -m "修改test1文件" # 修改test1文件,然后提交
[test1 01b290b] 修改test1文件
1 file changed, 1 insertion(+)
D:\Desktops\Test>git log --oneline --decorate --graph --all # 查看分支
* 01b290b (HEAD -> test1) 修改test1文件
* bc352f3 (master) Merge branch 'testbranch'
|\
| * f60127a (testbranch) 添加新文件
* | 7582919 add test1.txt
* | ea99183 另一个提交版本
|/
* 917573c 添加readme
(2) master分支修改test1.txt文件
D:\Desktops\Test>git checkout master
Switched to branch 'master'
M Test1.txt
D:\Desktops\Test>git commit -a -m "修改test1文件"
[master f2c82e1] 修改test1文件
1 file changed, 1 insertion(+)
D:\Desktops\Test>git log --oneline --decorate --graph --all
* f2c82e1 (HEAD -> master) 修改test1文件
| * 01b290b (test1) 修改test1文件
|/
* bc352f3 Merge branch 'testbranch'
|\
| * f60127a (testbranch) 添加新文件
* | 7582919 add test1.txt
* | ea99183 另一个提交版本
|/
* 917573c 添加readme
(3) 合并有分歧的两个分支
D:\Desktops\Test>git merge test1
Auto-merging test1.txt
CONFLICT (content): Merge conflict in test1.txt
Automatic merge failed; fix conflicts and then commit the result.
此时提示了合并冲突的文件名字。
(4) 使用“git mergetool”指令解决冲突
D:\Desktops\Test>git mergetool # 使用默认工具解决冲突
This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
tortoisemerge emerge vimdiff nvimdiff
Merging:
test1.txt
Normal merge conflict for 'test1.txt':
{local}: modified file
{remote}: modified file
Hit return to start merge resolution tool (tortoisemerge): local # 选择解决方式
一下是弹出的对比工具的界面,下方是解决冲突后的文件内容。
保存退出后,重新提交(git commit)就可以完成合并了。
D:\Desktops\Test>git merge test1
fatal: You have not concluded your merge (MERGE_HEAD exists).
Please, commit your changes before you merge.
D:\Desktops\Test>git commit
[master a71a2a7] Merge branch 'test1'
D:\Desktops\Test>git merge test1 # 再次执行合并指令会提示已经全部更新。
Already up to date.
D:\Desktops\Test>git log --oneline --decorate --graph --all # 查看分支装填显示已合并。
* a71a2a7 (HEAD -> master) Merge branch 'test1'
|\
| * 01b290b (test1) 修改test1文件
* | f2c82e1 修改test1文件
|/
* bc352f3 Merge branch 'testbranch'
|\
| * f60127a (testbranch) 添加新文件
* | 7582919 add test1.txt
* | ea99183 另一个提交版本
|/
* 917573c 添加readme
三、分支管理
注: 下文示例分支状态见2.5
3.1 查看所有分支列表
git branch # 不添加任何参数表示查看说有分支列表
示例:
D:\Desktops\Test>git branch
* master
test1
testbranch
“*” 字符:它代表现在检出的那一个分支(也就是说,当前 HEAD 指针所指向的分支)
3.2 查看每一个分支的最后一次提交
git branch -v
示例:
D:\Desktops\Test>git branch -v
* master a71a2a7 Merge branch 'test1'
test1 01b290b 修改test1文件
testbranch f60127a 添加新文件
3.3 查看已经合并或尚未合并到当前分支的分支
git branch --merged # 已合并到当前分支的分支
git branch --no-merged # 未合并到当前分支的分支
示例:
D:\Desktops\Test>git branch --merge
* master
test1
testbranch
D:\Desktops\Test>git branch --no-merge
D:\Desktops\Test>
四、远程分支
远程引用是对远程仓库的引用(指针),包括分支、标签等等。
4.1 获取远程分支
git ls-remote <remote> # 显式地获得远程引用的完整列表
git remote show <remote> # 获得远程分支的更多信息
使用远程跟踪分支来看远程分支。
远程跟踪分支以<remote>/<branch> 的形式命名。
注: 所有的操作均在本地,只要不推送到远程分支或者拉取远程分支,那远程跟踪分支将不会更新。
4.2 推送
git push # 直接推动当前分支
git push <remote> <branch> # 将本地分支推送到远程同名分支上
git push <remote> <branch>:<remotebranch> # 将本地分支推送到远程指定分支上
D:\Desktops\TestClone\Clone2>git push
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 4 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 579 bytes | 579.00 KiB/s, done.
Total 5 (delta 3), reused 0 (delta 0), pack-reused 0
To D:/Desktops/Test/.git/
57a41ad..4ecf733 master -> master
4.3 跟踪远程分支
git checkout --track origin/branch # 跟踪远程分支
git checkout <branchname> # 当本地分支和远程分支有唯一一个匹配的分支时,会自动跟踪
git checkout -b <branch> <remote>/<branch> # 指定本地分支和远程分支,两个分支名可以不一样
git branch -u <remote>/<branch> # 设置本地分支跟踪刚刚拉取下来的远程分支
git branch -vv # 查看所有的跟踪分支
4.4 拉取
git fetch # 从服务器上抓取本地没有的数据时,它并不会修改工作目录中的内容
git pull # 大多数情况下它的含义是一个 git fetch 紧接着一个 git merge 命令
注: git pull 的自动合并经常令人困惑,所以通常单独显式地使用 fetch 与 merge 命令会更好一些。
4.5 删除远程分支
使用–delete配合push可以删除远程分支(移除指针)。
git push <remote> --delete <branch>
五、变基(rebase)
用 rebase 命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。
git checkout <branch> # 检出分支
git rebase <newbranch> # 将当前分支变基到另一个分支上
git rebase --onto master server client # 选中在 client 分支里但不在 server 分支里的修改(即 C8 和 C9),将它们在 master 分支上重放
git rebase <basebranch> <topicbranch> # 直接将topicbranch分支 变基到basebranch分支上。 这样做能省去你先切换到 server 分支,再对其执行变基命令的多个步骤。
合并和变基两种整合方法的最终结果没有任何区别,但是变基使得提交历史更加整洁。
注:
- 如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基;
- 变基操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。
如果你已经将提交推送至某个仓库,而其他人也已经从该仓库拉取提交并进行了后续工作,此时,如果你用 git rebase 命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行整合,如果接下来你还要拉取并整合他们修改过的提交,事情就会变得一团糟。