Git最难学习的就是Git的多分支问题,不同操作会对当前分支造成什么影响,比如相同初始状态,类似操作,rebase
和merge
的不同结果。
![de4c9e0a123ca75072855e667dca7e7c.png](https://i-blog.csdnimg.cn/blog_migrate/bcc692a0a048868a7497f9712593ba6b.jpeg)
教程简介
推荐一个非常通俗易懂的Git多分支教程:
Learn Git Branchinglearngitbranching.js.org![cf580038ea9951f9db09964dc8f59091.png](https://i-blog.csdnimg.cn/blog_migrate/94146a7d5a12c40b06bfa827aefbbeeb.jpeg)
学习时长:0.5-1天
教程特点:
- 将各个知识点划分成关卡,像打游戏一样学习。
- 所有操作均产生动态变化过程(可视化),十分容易理解。
- 每个知识点都带练习,看完讲解后亲手输命令看结果,加深印象。
![898b2c09f6b631d845b09f0d66fce746.png](https://i-blog.csdnimg.cn/blog_migrate/8b6f0e6ca5a2de69270936c275f767bb.jpeg)
教程平台自己的命令:
- 左边console输入
levels
命令,调出关卡页。 reset
:reset习题为初始状态。undo
:undo上一条git命令。
更多命令及设置:教程GitHub页
上手教程
初接触Git的朋友需要简单了解下Git的基础知识,即可轻松上手这个教程。
Git分为local和remote,一个典型的Git工作流:
- http://github.com上建一个repo(remote),
clone
到local。 - 修改后,
git add –-all
将所有修改加入staging area。 commit
到local repo。push
到remote repo。
![623a922561758ffd967bf12972567495.png](https://i-blog.csdnimg.cn/blog_migrate/47530869d2ac11f616c8bdc56f545fab.jpeg)
图片来源
教程要点
A 图例
如下图,一个节点(状态)对应一次commit
。节点的标识(i.e. c0)表示commit记录的hash值,可用git log
查看。
c1->c0表示c1是在c0基础上的commit。当你只有local或remote时,只有左边实线状态图;两者都有时,则用实线表示local状态(左),虚线表示remote状态(右)。
local的master, o/master,remote的master都是branch name,其中o/是origin/,教程中用o/简写。
默认local master跟踪o/master,o/master跟踪remote master。(跟踪track见教程)
local的HEAD表当前状态,若HEAD和某个branch(i.e. master)相同时,则省略HEAD,并在该branch上加*,表该branch是当前状态(i.e. master*)。
![701849f1f93048f7ea831b071fd80ead.png](https://i-blog.csdnimg.cn/blog_migrate/191876ea421e536b34b29b6460c07588.png)
B 主要命令汇总
- 创建、移动分支:branch, checkout
- 撤销变更:reset, revert
- 合并/整理记录:merge, rebase
- 远程相关:pull, push
- 其他:cherry-pick,PR问题
1 创建、移动分支
branch, checkout
创建:
git branch <branch>
git checkout -b <branch>
移动:
git checkout <branch> # 切换到<branch>
分离HEAD:
git log # 查看commit记录
git checkout <commit记录hash前几位> # 将HEAD指向一个状态
相对引用:^
和~
^
表上一节点,^<num>
表第<num>个父节点。~
也表上一节点,~<num>
表往上<num>个节点。- ^ ~支持链式操作,如
^2~3
:第二个父节点往上3个节点。
git checkout master^2 # 将HEAD移到master第2个父节点
![317cf917ec29edc509de3d229bf18225.png](https://i-blog.csdnimg.cn/blog_migrate/6a221e8c00e3a9f7f59b72681bfa41d2.png)
强制移动branch:
git branch -f master HEAD~3 # 强制移动master到当前节点往上三个节点的位置
![dd360b7e330ae9c1b90e18e884d73190.png](https://i-blog.csdnimg.cn/blog_migrate/e6d22d13e6fc3ba27508bc7d8703b40f.png)
2 撤销变更
reset, revert
- 这里是
git reset
,区别平台自己的reset
命令。 reset
:回滚到之前某一状态。revert
:增加新节点,复制之前某一状态。
git reset HEAD~1
![6cccd087e56b3fa4e2d5d3056501023e.png](https://i-blog.csdnimg.cn/blog_migrate/c218109f8372cbeffb3069287570d216.png)
reset后并不是直接删除,git log查到c2记录,还可以checkout或branch -f恢复c2。
git revert c0
![da0db3ee8630f03af5c09e8c3c6217ac.png](https://i-blog.csdnimg.cn/blog_migrate/70f89f2eb74005056963fbf1a25c5ed5.png)
3 合并/整理记录
merge, rebase
先来看下两个命令各自的效果:
初始(左)HEAD指向master,将master整理/合并到o/master上:
- git rebase o/master(中)
- git merge o/master(右)
![799364add1f532e50b86a961ea30e163.png](https://i-blog.csdnimg.cn/blog_migrate/d1faf4622fda3d5b09252d8ee9ca0bd2.jpeg)
可以看出,相比merge,rebase:
- 优点:rebase使状态图变得很干净,所有commit都在一条线上。
- 缺点:rebase修改了状态图历史。
rebase还支持交互式操作,只需加上-i (--interactive)参数。
![8824e487c2b27102c2f21aaf48f6df44.png](https://i-blog.csdnimg.cn/blog_migrate/326e1d9a0c5308ca48b1009b13813e2d.jpeg)
e.g.
git rebase -i HEAD~4
![82380155b8470b2cd023c20a6fdbbb19.png](https://i-blog.csdnimg.cn/blog_migrate/a19eccfa93a27858891936da829c1d82.jpeg)
4 远程相关
pull, push
pull和push对应。因为pull = fetch + merge,pull –rebase = fetch + rebase,故先解释下fetch:
fetch的使用场景是当clone后remote又有了非local的新的commit:
![c697d1e21c8a34425ac6a6bd522cb6b1.png](https://i-blog.csdnimg.cn/blog_migrate/48da0d9a3fbb5aff4888eaf8a923c5de.jpeg)
具体来说,fetch完成了两步操作:
- 从remote下载local缺失的状态。
- 更新local对应remote的指针(i.e. o/master)。
pull = fetch + merge:
git pull先fetch c3到local,并移动o/master指向local c3;然后将当前状态(master*)和o/master merge 。
git pull
![5ed15769a1febbeecd15e1203aa54989.png](https://i-blog.csdnimg.cn/blog_migrate/0445d5bebe2ab5cb35912003e6a0f93a.png)
pull –rebase = fetch + rebase:
上例用pull –rebase的话
![6199a444b73a08006bbab84ae03f02c2.png](https://i-blog.csdnimg.cn/blog_migrate/f494bdcc3f2c687fd9ca3087a993a75d.png)
push和pull对应,是将remote没有的local状态上传,并更新相关指针。
git push
![df955973a8952e8073ff615648e7b2f8.png](https://i-blog.csdnimg.cn/blog_migrate/bd83235bf7ac6ce3d3f326b021c8b863.png)
push和pull都有两种带参数的形式:
下面的<remote>就是remote repo,默认是origin。
push <remote> <local branch>
将<local branch>上remote没有的状态上传,并更新相关指针。
push <remote> <local状态>:<remote branch>
和第一条的区别:(1)只要是<local状态>就行,即使没branch指向。(2)上传到指定<remote branch>,若remote无<remote branch>,则会自动新建。
pull <remote> <remote branch>
pull <remote> <remote状态>:<local branch>
⭐其实无参数的push和pull就是同步所有变化。
e.g.
初始状态:
![8e27004aaaace192ce39a1e5a3eaca00.png](https://i-blog.csdnimg.cn/blog_migrate/c10fd05a4989efdd841e23884a2c688d.png)
git push origin foo
![a266a419294f53ce9114172abbf2537b.png](https://i-blog.csdnimg.cn/blog_migrate/c37cfec186e18a3b7a01cd556734ecc0.jpeg)
git push origin c5:foo
![184857867a13148469337b02b13525c9.png](https://i-blog.csdnimg.cn/blog_migrate/a74dc629cc60683266fce12485f4e024.jpeg)
5 其他
cherry-pick,PR问题
cherry-pick
也是用于整理记录的,可实现pick部分状态到当前branch上。
e.g.
git cherry-pick c2 c4
![882a65c268ac5395479192623f4b8f50.png](https://i-blog.csdnimg.cn/blog_migrate/6d596caee7521aaab3e14bb15927e5d9.jpeg)
PR问题:以remote master分支为例,若remote将master锁定,则git push时会返回
! [远程服务器拒绝] master -> master (TF402455: 不允许推送(push)这个分支; 你必须使用pull request来更新这个分支.)
即不允许直接push到master。
解决:新建一个分支,push这个分支,并提交pull request。