Git 笔记
文章目录
- Git 笔记
- 前言
- 正文
- 一、基础篇(git主要命令)
- 1. git commit
- 2. git branch 分支名 | git checkout 分支名
- 3. git merge 分支名 | git rebasse 分支名
- 二、高级篇
- 1. 分离HEAD(git checkout 记录结点名)
- 2. 相对引用(git checkout 分支名^ | git checkout 分支名~num)
- 3. 撤销更改 (git reset 结点位置 | git revert 结点位置)
- 三、移动提交记录(自由修改树)
- 1. git cherry-pick 提交号
- 2. 交互式rebase(git rebase -i 分支名^ | git checkout 分支名~num)
- 四、杂项
- 1. 只取一个提交记录(git cherry-pick 和 git rebase -i 的特定场景应用)
- 2. 提交的技巧应用1(git rebase -i 结点名 | git commit --amend | git rebase 分支名 分支名)
- 3. 提交的技巧应用2(git rebase -i 结点名 | git commit --amend | git rebase 分支名 分支名)
- 3. git Tag(git tag 别名 节点名 | git tag 别名)
- 4. git Describe(git describe 结点名 | git describe )
- 五、高级话题
- 1. 多次rebase(git checkout (base的分支名) (需要移动的分知名) 的应用)
- 2. 两个父节点(HEAD的^~两种符号用法)
- 4. 纠缠不清的分支(git cherry-pick 多节点 | git branch -f 节点名 节点名 的应用)
- 六、远程 —— Push & Pull( Git 远程仓库)
- 1. git clone URL
- 2. 远程分支(origin/main)
- 3. git fetch
- 4. git pull
- 5. 模拟团队合作
- 6. git push
- 7. 偏离的提交历史(git pull、rebase/merge、push运用)
- 8. 锁定的main(git push origin 分支名)
- 七、远程 —— origin 和它的周边(Git 远程仓库高级操作)
- 1. 推送主分支(git rebase 节点名 的应用)
- 2. 推送主分支(git fetch | git rebase 分支名 分支名 | git pull --rebase 运用)
- 3. 合并远程分支(git fetch 和 git merge 综合应用)
- 4. 远程追踪(git rebase 节点名 的应用)
- 5. git push 的参数1(git push 远程名 指定分支名)
- 6. git push的参数2(git push 远程名 来源结点或分支:去向分支)
- 7. git fetch 参数(git fetch 远程名 来源结点或分支:去向分支)
- 8. 没有source的source(git fetch :分支名 | git push :分支名)
- 9. git pull 参数(git rebase 节点名 的应用)
- 总结
前言
本文是根据Learning Git Branching游戏中学习整理而来的。
本文整体结构就是按照游戏“目录设计”进行安排
同时本人也会加上命令解释、给出使用示例以及给出游戏的最终答案。
不想慢慢玩游戏学习的童鞋,可以看此文章速览全部游戏关于git介绍
虽然这个游戏并不会涵盖所有所有的命令,但是作为入门理解思想是非常到位的!因为这个是可视化git!
正文
开头的一到五章讲解的都是本地仓库的命令,即这些命令都是对本地仓库进行操作。第六章之后才是远程。
一、基础篇(git主要命令)
1. git commit
功能:将增量修改的内容进行提交
示例:(解释:C0、C1是分开的两次提交记录,其中C0 是C1 父分支,即C1是基于C0增量修改提交的,main意思是箭头指向的之处的分支线叫main分支,其标指向的就是该分支最新的提交处,其中*号意思是你目前正在操作的分支,是一个标记。)
git commit
之后
此时增加C2提交记录,且是基于C1的,仍然是main分支线上的延申。
游戏答案:
git commit
git commit
2. git branch 分支名 | git checkout 分支名
- git branch 分支名 -
功能 :即在现在的分支线上开辟另一个分支(有点像开一个分叉树枝的芽),在该节点之前的内容都是相同的,之后提交的内容就只能在一个分支上延申。
示例:
git branch newImage
(解释:我们可以看到现在多了一个newImage分支,但是因为我们只是新建分支,也就是多了一个芽而没有树干,所以两个分支都在C1处。
此时如果我们输入
git commit
main分支往前一步,当前分支还是main,newImage还是在C1处
- git checkout 分支名 -
功能 :切换当前操作的分支到特定分支名。
示例:(当前是main分支)
git checkout newImage
git commit
最后其实还有个快捷键:git checkout -b 分支名 实现创建分支的同时切换该分支为当前操作分支
游戏答案:
git checkout -b bugFix
3. git merge 分支名 | git rebasse 分支名
- git merge 分支名 -
功能:将当前分支和另一个指定分支合并,可能会产生新的结点,也可能不会,看下面示例。
示例:
git merge bugFix
git checkout bugFix
git merge main
git merge游戏答案:
git checkout -b bugFix
git commit
git checkout main
git commit
git merge bugFix
git rebase 分支名
作用:即将当前的分支合并到另一分支,但是合并的方式不是多一个结点,而是将当前分支的所有多出来的修改全部加到另一个分支,这时整体上看只有一条线性发展。而不是分开同步运行后合并的视角,而是将并行转化成前后的同步关系
示例:
git rebase main
git checkout main
git rebase bugFix
二、高级篇
1. 分离HEAD(git checkout 记录结点名)
作用:分离HEAD,就是我们可以操作的当前位置不再是对分支而是可以对某次记录也就是结点。
解释:HEAD默认就是指向分支名的,即我们看到的*指向的分支,当我们分支commit后,我们HEAD会往前走,分支便也会自动往前走,而如果我们指向具体历史记录commit后,HEAD往前走,分支原地不动,这就是分离HEAD脱离了分支。
即原本 HEAD->main分支->c1结点 变成 HEAD->c1 这就是分离
示例:
git checkout main
没有变化,因为HEAD->bugFix->c4,即使git commit两者同步向前
git checkout c4
HEAD->c4 分离开来
git commit
HEAD会往前走,但分支不会动
2. 相对引用(git checkout 分支名^ | git checkout 分支名~num)
作用:分离HEAD的时候可以通过当前分支相对的移动,这样我们可以不用记住某结点哈希值(可以通过git log查看)。这里说一说结点哈希值是什么,我们会发现我们之前分支名都是c1之类的,其实c1只是这个结点哈希值的头两个值,但因为具有区分唯一性,所以我们可以只打开头两个字符,全名可能是:c4d2da64c0efc5293610bdd892f82a58e8cbc5d8。所以相对引用就是HEAD的设置不根据哈希值来确定,可以通过相对位置确定。因为分支名字相对于结点名字更加的容易记住和使用。
示例:
git checkout main^
第二个例子:
git checkout c3
git checkout HEAD^
git checkout HEAD^
git checkout HEAD^
第三个示例:
git checkout HEAD~4
第四个示例:
git branch -f main HEAD~3
相对引用为我们提供了一种简洁的引用提交记录 C1 的方式, 而 -f 则容许我们将分支强制移动到那个位置。
第一个游戏答案:
gti checkout bugFix^
第二个游戏答案:
git checkout HEAD^
git branch -f main c6
git branch -f bugFix HEAD^
3. 撤销更改 (git reset 结点位置 | git revert 结点位置)
作用:撤销之前提交过的更改,这里要分为两种情况讨论,一个是对于本地而言的更改,一个是针对远程的更改。git reset是针对本地而言,这个撤回向上移动分支,原来指向的提交记录就跟从来没有提交过一样,这里没有提交过是针对远程的协作成员而言,他们不知道你曾经在你的本地撤销过,但其实撤销后记录还在,只是不在暂存区。而对于git revert则是针对远程的撤销这个更改所有人是可见的,怎么可见呢?就是会有个多出来的结点表示撤销了更改。可以看下面示例就清楚了。
示例:
示例1:git reset
git reset HEAD^
示例2:git revert
git revert HEAD~1
可以看到所谓的撤回还是增加了新的结点让所有人知道你撤回了。
游戏答案:
gti reset HEAD^
gti checkout pushed
gti revert HEAD~1
三、移动提交记录(自由修改树)
1. git cherry-pick 提交号
作用:将一些提交复制到当前所在的位置(HEAD)下面
示例:
git Cherry-pick c2 c4
可以看到,此时相对于rebase 来说,最大的特点就是原本的分支不会变,而是将这个“樱桃”给复制过来了。(这里只复制了c2 c4,没有c3)
第一个游戏答案:
gti cherry-pick c3 c4 c7
第二个游戏答案:
git checkout HEAD^
git branch -f main c6
git branch -f bugFix HEAD^
2. 交互式rebase(git rebase -i 分支名^ | git checkout 分支名~num)
作用:cherry-pick需要指定特定的记录,比如某个记录的哈希值,而如果清不清楚的话,这时候就可以使用rebase -interactive,这个命令的意思是将git可视化出现一个UI图,便于我们对UI图进行交互式的操作,(在实际使用时,所谓的 UI 窗口一般会在文本编辑器 —— 如 Vim —— 中打开一个文件。)它提供了三个操作:
- 调整提交记录的顺序(通过鼠标拖放来完成)
- 删除你不想要的提交(通过切换 pick 的状态来完成,关闭就意味着你不想要这个提交记录)
- 合并提交(允许你把多个提交记录合并成一个)
示例:
git rebase -i HEAD~4
(以下展示是游戏提供,真实情况并非如此!)
在这里我只选择c5和c4并且把他们跳到前面
结果便是另外的复制你想要的操作到当前HEAD
游戏答案:
git rebase -i HEAD~4^
四、杂项
1. 只取一个提交记录(git cherry-pick 和 git rebase -i 的特定场景应用)
作用:其实这次只是一个复习巩固,单独提出这个是为了表示某一特定场景的应用。比如只取一个记录进行提交。示例如下:
示例:(提示:debug和输出信息记录我们留了在历史记录,但是你想提交远程的时候不想让别人看到这些不堪的过去,所以可以用上面两个命令选择性的转移到main分支上。)
git checkout main
git cherry-pick c4
游戏答案:
git checkout main
git cherry-pick c4
2. 提交的技巧应用1(git rebase -i 结点名 | git commit --amend | git rebase 分支名 分支名)
作用:本次只是对于应用场景实践。场景如下:你之前在 newImage 分支上进行了一次提交,然后又基于它创建了 caption 分支,然后又提交了一次。此时你想对某个以前的提交记录进行一些小小的调整。比如设计师想修改一下 newImage 中图片的分辨率,尽管那个提交记录并不是最新的了。改完后还是原来顺序的分支,只是你想把特定的修改补上去。
本案例中使用的是rebase -i 它只能处理当前HEAD的分支之上!所以因为这个,你会看到我们通过调顺序的方式去达到我们的目的。(但其实里面是有可能出错的,另一种方式看下一个案例)
示例:
git rebase -i HEAD~2
这里利用rebase是想将c2和c3调整调换位置到最前面进行修改
git commit --amend
--amend参数的增加就是用来修改当前提交记录
git rebase -i HEAD~2
把顺序设置回来
git rebase caption main
将main分支调整到最前面,其中第一个参数表示rebase的基础结点,第二个参数用来表示移动哪个分支
游戏答案:
git rebase -i HEAD~2
git commit --amend
git rebase -i HEAD~2
git rebase caption main
3. 提交的技巧应用2(git rebase -i 结点名 | git commit --amend | git rebase 分支名 分支名)
作用:本次只是对于上面应用场景的优化。正如在上一关所见到的,我们可以使用 rebase -i 对提交记录进行重新排序。只要把我们想要的提交记录挪到最前端,我们就可以很轻松的用 --amend 修改它,然后把它们重新排成我们想要的顺序。但这样做就唯一的问题就是要进行两次排序,而这有可能造成由 rebase 而导致的冲突。下面是利用 git cherry-pick 完成的。
我们要记住! cherry-pick 可以将提交树上任何地方的提交记录取过来追加到 HEAD 上(只要不是 HEAD 上游的提交就没问题)。而之前的rebase -i 只能将当前分支进行操作,这也是导致我们只能通过排序实现修改的原因!
示例:
git checkout main
先将HEAD移至main处
git cherry-pick c2
只获取c2结点
git commit --amend
修改当前提交记录
git cherry-pick c3
拿回c3
游戏答案:
git checkout main
git cherry-pick c2
git commit --amend
git cherry-pick c3
3. git Tag(git tag 别名 节点名 | git tag 别名)
作用:相当于给某个结点打上标签,其实就是做了一个书签,这个书签不会像分支名一样,提交就改变,而是固定死的,但是我们又可以拿它当结点来使用。git tag 别名这种就是默认把HEAD取别名,如果想制定结点可以放结点哈希名。
示例:
git tag v1 c1
游戏答案:
git tag v0 c1^
git tag v1 c2
git checkout v1^
4. git Describe(git describe 结点名 | git describe )
作用:这个命令作用是查找离需要查找的结点的最近的tag,如:git describe c1,表示离c1结点最近的标签的寻找,git describe 表示离HEAD最近的标签的寻找。返回显示的格式是:TAG名_g和指定结点的距离_指定结点的哈希开头值 或者直接给出TAG名(这是因为指定结点就是tag,是同一个)如:v1_2_c1表示距离指定的c1往前退两次就是v1标签了。
示例:
git describe main
结果是v0_2_gc2
表示离c2这个哈希值结点最近的只需往上2步,标签名是v0
git describe c1
结果是v0_1_gc1
表示离c1这个哈希值结点最近的只需往上1步,标签名是v0
git describe
结果是v1_2_gc6
表示离c6这个哈希值结点最近的只需往上2步,标签名是v1
游戏答案:
gti commit
五、高级话题
1. 多次rebase(git checkout (base的分支名) (需要移动的分知名) 的应用)
作用:给定一个场景利用rebase去学习具体的用法,主要是需要大家弄明白rebse的后两个参数含义,以及rebase的理解,首先第一个参数是指“目的地”,是你想要移动到的地方!第二个参数是“操作对象”,是你想要移动的分支。其次就是怎么rebase呢?它会比较这两个目前几点往上最近分支处,把向移动的分支那一堆提交记录(当前分支的那个记录到两个分支的交点处的所有提交记录)整体移到另一边。看不懂就看例子吧!
示例: 项目中有许多分支,现在需要把这些分支 rebase 到 main 上,但你的领导给你提了点要求 —— 他们希望得到有序的提交历史,也就是我们最终的结果应该是 C6’ 在 C7’ 上面, C5’ 在 C6’ 上面,依此类推。
git rebase main bugFix
git rebase bugFix side
git rebase side another
git rebase another main
游戏答案:
git rebase main bugFix
git rebase bugFix side
git rebase side another
git rebase another main
2. 两个父节点(HEAD的^~两种符号用法)
作用:我们在前面学到的 ^ ~ 用法是,如果接 ^ 意味着HEAD的前一个结点,~ 加数字意味着HEAD的前几个节点。但其实^也可以加数字,它在拥有两个父节点的时候有用处,如果单是用 HEAD ^ 那么默认是往原本开始的第一个父亲的分支走,如果是HEAD ^2 那么就会往第二个父亲分支走。同时 ^ ~ 支持链式写法,如:HEAD ^ ~ 2 ~等等,可以看例子:
示例:
git checkout main^
(由图可以知道,main原本第一个“父亲”分支是直的那个!)
或者我们重新来另一个命令
git checkout main^2
再者我们可以看看综合的:
git checkout HEAD~
git checkout HEAD^2
git checkout HEAD~2
git checkout HEAD~^2~2
链式操作也能达到上面的效果!!
游戏答案:
git checkout -b bugWork HEAD~^2~
4. 纠缠不清的分支(git cherry-pick 多节点 | git branch -f 节点名 节点名 的应用)
作用:main上的分支去分配到其他分支上,具体看下面应用
示例:
起初模样:
最终目的:
大家可以先想想怎么实现!
git checkout one
git cherry-pick c4 c3 c2
git checkout two
git cherry-pick c5 c4 c3 c2
git branch -f three c2
游戏答案:
git checkout one
git cherry-pick c4 c3 c2
git checkout two
git cherry-pick c5 c4 c3 c2
git branch -f three c2
六、远程 —— Push & Pull( Git 远程仓库)
从这篇开始讲解的都是关于远程的命令,而远程操作才是git的核心,因为只有设置远程仓库(就是远程的设置一个仓库后,本地拷贝一个仓库,本地操作完同步到远程进行更新存储。)我们才可以不怕数据丢失,以及开始真正的协作开发。
1. git clone URL
作用:git clone命令是在本地创建一个远程仓库的拷贝,注意是先有远程才有可能clone一个项目到本地!,但是在游戏中,无法这样体现设置,所以游戏中的clone它会在远程创建一个你本地仓库的副本,注意区别!!!
示例:
这是远程仓库的模样:
git clone (此处该有url,但是游戏并没有设置)
右边虚线的是远程,左边实线就是新建的在本地仓库
游戏答案:
gti clone
2. 远程分支(origin/main)
作用:git clone后,细心概念的同学会发现我们本地分支除了main*以外,还有额外的o/main(实际是origin/main,游戏ui放不下这么长,就缩写了)。
这个标记是远程分支的标记,便于理解自己当前的分支和远程的分支区别,当你试图去checkout 的时候,其实你会将HEAD移向那位置,然后后续的commit也只是移动HEAD而远程的并不会变化。要想origin/main移动,必须是对远程分支进行操作,而不是对本地操作。
示例:
左边本地,右边远程
gti commit
此时main分支会向前移动
git checkout o/main
此时其实并不真正的选中远程分支,而是将HEAD意向那位置
gti commit
现在进行commit其实只是HEAD移动,远程分支并不会改变什么
游戏答案:
git commit
gti checkout o/main
git commit
3. git fetch
作用:git 远程操作分为两个操作,一个是向远程仓库传输数据以及从远程仓库获取数据。git fetch就是从远程仓库获取数据, 获取时本地的远程分支origin/main也会更新以反映最新的远程仓库。
这里最重要注意的点:git fetch 并不会改变你本地仓库的状态。它不会更新你的 main 分支,也不会修改你磁盘上的文件。即我们git fetch 只是仅仅把远程该更新的内容下载下来,并不会合并到我们本地,不会去修改,就好像没有发生过一样,就像你妈妈出去买菜把菜放到了桌子上,你的冰箱不会有任何变化,你所知道的是桌子多了菜可以放入你的冰箱进行修改。
示例:
git fetch
远程分支origin/main更新,但是本地并不会被修改
游戏答案:
gti fetch
4. git pull
作用:就是git fetch + git pull的两个操作的合并
我们知道在上面我们可以通过git fetch 去获取远程的新的数据到本地,但请注意!这里的代码并没有合并到本地代码,只是暂存,那么要想合并其实可以通过我们之前学过的一些命令去合并,如:
git cherry-pick o/main
git rebase o/main
git merge o/main
而在本篇中就是学习git pull它是两个操作的合并,也有很多参数,这就到后面再学习了。
示例:
首先我们先看一下分步骤的git fetch 和 git merge
git fetch
git fetch 获取了远程数据,main分支无变化,o/main向前移动
git merge o/main
合并main和 orign/main
git pull
效果和上面一摸一样
游戏答案:
git pull
5. 模拟团队合作
作用:本次就是模拟一个团队协作问题,一个小的综合场景
示例:
远程分支情况:(这里没有虚线,有点错误,别弄混了
最终的目的情况:
下面开始进行:
git clone
首先将远程分支克隆到本地
git fakeTeamwork 2
!!!实际中没有这个命令的,只是为了模仿其他队友在远程提交了两个分支
git commit
git pull
游戏答案:
git clone
git fakeTeamwork 2
git commit
git pull
6. git push
作用:git push 负责将你的变更上传到指定的远程仓库,并在远程仓库上合并你的新提交记录,这样你的变更所有人都可以看到
注意!:git push 其实有参数的,我们后面会学到,不带参数就是利用默认的方式push,具体什么方式和git的版本有关,则这里我们使用的是upstream
示例:
git push
提交后,本地的orign/main也会跟着更新
游戏答案:
git commit
git commit
git push
7. 偏离的提交历史(git pull、rebase/merge、push运用)
作用:这次依旧是场景综合应用,而本次场景是非常常见的场景,同时也会学习一个新的
git pull --rebase
,请仔细看示例理解运用。
示例: 什么是偏离的提交历史呢?就是你的伙伴一开始都是clone相同的远程情况,这时你们两边同时开发,他比你先提交,等你要提交的时候,你会发现无法提交到远程,因为远程不清楚你提交的内容是合并到你一开始接触的那个远程分支还是最新的远程分支情况。说白了就是你的本地的远程结点是旧的! 你只有把最新的远程分支情况给获取下来,远程才能够懂得你提交的内容怎么合并到远程,因为你获取了最新的远程分支情况。下面就是为了解决这个最常见的场景!历史偏离示例图:
本地的origin/main只到c1,而远程已经c2了,这时候git push上去是失效的
解决方式1:利用rebase这一个命令
git fetch
fetch获得最新远程分支到本地先
git rebase o/main
调整我们本地和最新分支进行整合
git push
推送远程成功!
解决方式2:利用merge这一个命令
git fetch
fetch获得最新远程分支到本地先
git merge o/main
合并成一个新的分支,也是基于新的远程分支的操作
>
git push
推到远程成功!
解决方式3:利用更简洁的指令:git pull --rebase,这个是fetch和rebase的合并,注意这里base的是最新远程分支
git pull --rebase
git push
解决方式4:利用更简洁的指令:git pull,这个是fetch和merge的合并
git pull
git push
综上就是:如果我们的本地的远程分支是旧的情况,就要去想办法获取远程分支到本地,然后基于最新的远程分支去和我们本地进行合并处理,再push上去。
游戏答案:
git clone
git fakeTeamwork 1
git commit
git pull --rebase
gti push
8. 锁定的main(git push origin 分支名)
作用:这次也是常见的场景应用之一,之所以称之为锁定main,是因为在我们大公司开发中,我们不会这么顺利的就push自己想要的东西上去,不然人人都推自己觉得ok的不久乱套了嘛,所以管理者会为此设置为远程直接push 到main分支,会拒绝,策略配置要求 pull requests 来提交更新,pull request就理解成一种提醒一种请求,告诉管理者我要更新。
所以解决方案:新建一个分支feature, 推送到远程服务器. 因为远程不会允许直接push到main,所以我们可以推一个其他分支到远程,再请求pull request即可,合并的事情交给远程。这里还有一个问题,我们之后需要reset main分支和远程服务器保持一致, 否则下次你pull 的同时呢,他人的提交和你有冲突,这就会有问题啦。具体看下面示例:
示例:
git checkout -b feature
创建feature分支
git push origin feature
提交feature这个分支到远程
git checkout main
git reset --hard o/main
如果我们不reset回原来,这时候如果有人在远程提交更新了main分支,这时我们选择git pull,有一定的几率是我们在main修改的内容和别人修改的内容有冲突的地方,这时候git无法知道以谁的为准进行修改就merge失败了。
游戏答案:
git reset --hard o/main
git checkout -b feature
git push origin feature
七、远程 —— origin 和它的周边(Git 远程仓库高级操作)
1. 推送主分支(git rebase 节点名 的应用)
作用:
示例:
git checkout one
git cherry-pick c4 c3 c2
git checkout two
git cherry-pick c5 c4 c3 c2
git branch -f three c2
游戏答案:
git checkout one
git cherry-pick c4 c3 c2
git checkout two
git cherry-pick c5 c4 c3 c2
gti branch -f three c2
第二个游戏答案:
git checkout HEAD^
git branch -f main c6
git branch -f bugFix HEAD^
2. 推送主分支(git fetch | git rebase 分支名 分支名 | git pull --rebase 运用)
作用:这次仍然是综合应用,针对的是远程分支更新快过我们本地的远程分支情况,而我们自己也有了许多全新的分支,这时候需要推送到远程main分支,我们第一个就是必须要更新本地的远程分支是最新的远程分支,之后再新远程分支的情况下去rebase我们的全新的内容,再push到远程。
示例:
比如现在需要把本地所有修改内容推到远程
git pull --rebase
这个指令意思是先fetch然后reabse
git push
再来一个新的案例:
这个案例是,现在本地有全新的三个side分支,同时我们本地的远程分支并不是最新的,现在需要把所有side分支push上去,但是要按照数字大小的顺序。
目标:
下面是答案:
git fetch
git rebase o/main side1
git rebase side1 side2
git rebase side2 side3
git rebase side3 main
git push
游戏答案:
git fetch
git rebase o/main side1
git rebase side1 side2
git rebase side2 side3
git rebase side3 main
git push
3. 合并远程分支(git fetch 和 git merge 综合应用)
作用:上题案例中,我们为了能够push到远程,我们首先必须做的事情就是,本地的远程分支必须是最新的,在这个最新的基础上去修改都可以push到远程。
那么在上述中,我们都是利用了rebase的方式,其实之前我们也学过merge也会有相近的效果,那为什么不使用merge呢?其实这个是仁者见仁智者见智的。两者有些许区别,看大家的习惯如何了?
rebase的优点是使你的提交树变得很干净, 所有的提交都在一条线上。缺点就是修改了提交树的历史,看上去像是顺序工作而不是并行工作。一些开发人员喜欢保留提交历史,因此更偏爱 merge。而其他人可能更喜欢干净的提交树,于是偏爱 rebase。
所以接下来就是使用merge完成之前的例子。
示例:
原本模样:
目标:
下面是答案:
git checkout main
git pull
git merge side1
git merge side2
git merge side3
git push
游戏答案:
git checkout main
git pull
git merge side1
git merge side2
git merge side3
git push
4. 远程追踪(git rebase 节点名 的应用)
作用:在前面,其实我们有以下体会:就是在我们pull或者push的时候,本地的main和从远程o/main有着莫名的联系,当我们pull将会在fetch完后默认的将本地的main一同改变到最新的情况,当我们push的时候,也是默认着将有关于main对于o/mian的各种修改push到远程。
main 和 o/main 的关联关系就是由分支的“remote tracking”属性决定的。main 被设定为跟踪 o/main —— 这意味着为 main 分支指定了推送的目的地以及拉取后合并的目标。当你克隆时, Git 会为远程仓库中的每个分支在本地仓库中创建一个远程分支(比如 o/main)。然后再创建一个跟踪远程仓库中活动分支的本地分支,默认情况下这个本地分支会被命名为 main。所以克隆的时候会看到下面的输出:local branch “main” set to track remote branch “o/main”。
我们也可以让任意分支跟踪 o/main, 然后该分支会像 main 分支一样得到隐含的 push 目的地以及 merge 的目标。有两种方式:
- git checkout -b 跟踪的分支名 o/main 这时会创建一个分支然后跟踪o/main
- git branch -u o/main 分支名 这时不是创建分支而是指定分支,如果当前分支就是我们要指定的,那么后面添加的分支名可以不填写
示例:
第一种:git checkout -b方式
git checkout -b foo o/main
git pull
这时跟踪的就是foo
git push也是如此:
git checkout -b foo o/main
git commit
git push
第二种:git branch -u方式
git branch -u o/main foo
git commit
git push
游戏答案:
git checkout -b side o/main
git commit
git pull
git push
5. git push 的参数1(git push 远程名 指定分支名)
作用:我们已经学到了 Git 是通过当前checkout分支的属性来确定远程仓库以及要 push 的目的地的。这是未指定参数时的行为。
当然我们也可以指定参数:git push 远程名 要同步的分支名,此时就会忽略我们目前checkout的任何分支情况
比如:git push origin main。 即切到本地仓库中的“main”分支,获取所有的提交,再到远程仓库“origin”中找到“main”分支,将远程仓库中没有的提交记录都添加上去,搞定之后告诉我。
示例:
此时我们先checkout 到 c0 再指定的push
git checkout c0
git push origin main
这时我们发现此时的push和我们的checkout指定的并没有关系
好的这时候我们可以试着不指定参数
git checkout c0
git push
失败并且报错。因为我们所检出的 HEAD 没有跟踪任何分支。
游戏答案:
git push origin main
git push origin foo
6. git push的参数2(git push 远程名 来源结点或分支:去向分支)
作用:本次的参数,是升级的用法,当我们的来源和去向分支的名称不同,比如你想把本地的 foo 分支推送到远程仓库中的 bar 分支。这时的名称不相同即源和去向不同。
git push 远程名 来源结点或分支:去向分支。但也要考虑两种情况,下面示例展示:
示例:
git push origin foo^:main
此时远程的main和本地跟踪origin/main也一同更新,但是并没有按照本地main分支的情况去更新,我们是指定了某一个确定位置:foo^
好的这时候如果我们指定了不存在的远程分支名呢?
git push origin main:newBranch
Git 会在远程仓库中根据你提供的名称帮你创建这个分支!
游戏答案:
git push c5:foo
git push foo:main
7. git fetch 参数(git fetch 远程名 来源结点或分支:去向分支)
作用:git fetch 参数其实就是和git push 参数一样的理解,他们的参数是相近的,只是方向相反罢了(因为现在你是下载,而非上传)。如下面例子:
示例:
git fetch orign
你将会更新远程的foo分支到本地,但是本地跟踪的foo分支并不会更新,更新的是origin/foo,上次fetch说过,这个命令只是暂存本地,但是并不会合并,合并需要我们去rebase或merge。
下一个:
git fetch origin foo~1:bar
第一个参数是源分支,这里的源指的是远程的,和git push相反,但又能理解,因为push是上传,fetch是下载,所以上述命令是将远程的foo~1下载到本地,让bar分支去跟踪,但是此时o/foo和foo都不会改变噢。
接下来情况是假设本地跟踪的分支不存在的情况:
git fetch foo~1:bar
跟 git push 一样,Git 会在 fetch 前自己创建立本地分支, 就像是 Git 在 push 时,如果远程仓库中不存在目标分支,会自己在建立一样。
接下来是没有参数的情况:
git fetch
那就是下载所有的分支到本地
游戏答案:
git fetch origin main^:foo
git fetch origin foo:main
git checkout foo
git merge main
8. 没有source的source(git fetch :分支名 | git push :分支名)
作用:在git fetch 和 git push 参数中都有种特殊的情况,就是我们不写关于源的东西即git fetch :分支名和git push :分知名,冒号前的参数不指定。他们的含义是挺特殊,接下来看示例:
示例:
git push origin :foo
结果是删除了远程的foo分支
对于fetch呢?
git fetch origin :bar
作用就是纯粹的创建本地分支bar
游戏答案:
git push origin :foo
git fetch origin :bar
9. git pull 参数(git rebase 节点名 的应用)
作用:git pull 我们都知道这个命令就是git fetch+git merge的合并。
git pull origin foo 相当于:git fetch origin foo; git merge o/foo
git pull origin bar~1:bugFix 相当于:git fetch origin bar ~1:bugFix; git merge bugFix
git pull 唯一关注的是提交最终合并到哪里(也就是为 git fetch 所提供的 destination 参数)
示例:
git pull origin main
合并的位置就和我们当前checkout的位置有关
接下来是指定两个参数:
git pull origin main:foo
其实只要理解拆分成两步就不难理解这个命令了,先建立本地的foo分支去跟踪main,之后再合并,注意还是合并到当前checkout的节点。
游戏答案:
git pull origin bar:foo
git pull origin main side
git checkout two
git cherry-pick c5 c4 c3 c2
gti branch -f three c2
总结
文章到此结束了,也就是这个游戏的结束啦!!
这篇文章我也每天通个一两关来写,写了好久好久/(ㄒoㄒ)/~~
不过总体下来,会对git的协作有了很大的理解,具体的实际情况还是要实战学习,但是这个游戏入门git能理解到里面很多的思想,比起单纯的命令解释好太多!
非常建议大家玩一轮!!!