一. Git基本命令
工欲善其事,必先利其器,拓展一下知识,总结一下OSI(open system interconnection)七层网络协议模型,TCP/IP模型
1.1 网络协议
网络协议拓展
七层模型
应用层:应用层是与用户的最终一个接口,其中应用层的协议有:HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP
表示层:表示层是指数据的表示、安全、压缩。(在五层模型里面已经合并到了应用层)格式有,JPEG、ASCll、EBCDIC、加密格式等
会话层:建立、管理、终止会话。(在五层模型里面已经合并到了应用层)对应主机进程,指本地主机与远程主机正在进行的会话
传输层:定义传输数据的协议端口号,以及流控和差错校验。协议有:TCP UDP,数据包一旦离开网卡即进入网络传输层
网络层:主要进行网络寻址,进行逻辑地址寻址,实现不同网络之间的路径选择。协议有:ICMP IGMP IP(IPV4 IPV6)
数据链路层:组帧,建立逻辑连接、进行硬件地址寻址、差错校验 [3] 等功能。(由底层网络定义协议)将比特组合成字节进而组合成帧,用MAC地址访问介质,错误发现但不能纠正
物理层:建立、维护、断开物理连接。(由底层网络定义协议)
TCP/IP 层级模型结构,应用层之间的协议通过逐级调用传输层(Transport layer)、网络层(Network Layer)和物理数据链路层(Physical Data Link)而可以实现应用层的应用程序通信互联。
应用层需要关心应用程序的逻辑细节,而不是数据在网络中的传输活动。应用层其下三层则处理真正的通信细节。在 Internet 整个发展过程中的所有思想和着重点都以一种称为 RFC(Request For Comments)的文档格式存在。针对每一种特定的 TCP/IP 应用,有相应的 RFC [4] 文档。
一些典型的 TCP/IP 应用有 FTP、Telnet、SMTP、SNTP、REXEC、TFTP、LPD、SNMP、NFS、INETD 等。RFC 使一些基本相同的 TCP/IP 应用程序实现了标准化,从而使得不同厂家开发的应用程序可以互相通信
1.2 git基本操作
Git版本管理中分为三个区:工作区,暂存区,本地/远程仓库
git clone
git clone 远程分支地址(http://xxxx.git)
git clone克隆代码可以通过ssh和http协议
git status
可以通过git status 查看分支代码及文件状态
git log
查看版本记录
git branch
git branch 不带参数:列出本地已经存在的分支,并且在当前分支的前面加“*”号标记
git branch -r 列出远程分支
git branch -a 列出本地分支和远程分支
git branch 分支名,创建一个新的本地分支,需要注意,此处只是创建分支,不进行分支切换,例如:
#git branch develop
注意git branch +分支名只是单纯的创建一个分支并不会切换到创建的分支
git checkout 分支名
切换到对应的分支上
git branch -m | -M oldbranch newbranch 重命名分支,如果newbranch名字分支已经存在,则需要使用-M强制重命名,否则,使用-m进行重命名。
git branch -d | -D branchname 删除branchname分支
git branch -d -r branchname 删除远程branchname分支
git checkout
git checkout 分支名切换到对应的分支名上
git checkout -b 分支名
git checkout -b 分支名是创建一个分支名并切换到对应的分支上
git checkout -b 分支名等于执行git checkout 分支名 和 git branch 分支名
git add filename
git add filename将执行修改的文件从工作区添加到暂存区
git diff
git diff develop master查看本地develop和master分支差异
git diff是查看本地工作区和暂存区文件差异
git commit
git commit -m “push code by someone” 是将暂存区的修改提交到本地仓库
git diff --cached
git diff --cached是指查看暂存区和本地仓库文件差异
git pull origin master
git pull origin master 拉取远程master分支上的代码到本地当前分支上,有冲突手动修改并合入
git push origin master
git push origin master 将本地代码提交到远程的master分支上
git push origin --delete [branch_name]
git push origin --delete develop 删除远程仓库develop分支
git branch -m | -M oldbranch newbranch 重命名分支,如果newbranch名字分支已经存在,则需要使用-M强制重命名,否则,使用-m进行重命名。
git branch -d | -D branchname 删除branchname分支
git branch -d -r branchname 删除远程branchname分支
关于git add和git commit的反向操作解释
本质上要分两个维度看,一个是数据,一个是记录。
基于磁盘来看,数据就是我们要管理的代码本身。
基于Git的管理来看,三个区本质上是管理的修改、暂存和提交的差异记录。不能说“提交后暂存区就没了”,这个是大家引起理解偏差的位置。工作区>>>>暂存区>>>>仓库
初始化完成后,三个区域都是空的,这个时候记录就算是初始化了,开始记录这三者差异。
在工作区创建一个新的文件test.txt,先add到暂存区,这时可以使用git diff来查看工作区和暂存区的差异(操作1),当然,这里肯定是没有差异的!记住,这里是比较差异,不存在哪个区的数据没有了或空了,因为数据只有一份。
然后,你在工作区对test.txt进行修改(并没有将暂存区提交到仓库),修改保存后,同样可以使用git diff来查看工作区和暂存区的差异(操作2),当然,这里肯定是有差异的!
在你并没有再次进行git add test.txt操作前,使用git commit将暂存区(第一次add的test.txt版本)提交到仓库,这时仓库就有了第一个版本的test.txt文件。
这时你同样可以使用git diff来查看工作区和暂存区的差异,和操作2的结果是不是一样的?对,是一样的。因为你并没有git add,工作区和暂存区数据存在差异。
这时你使用git diff --cached来查看暂存区和仓库的差异(操作3),当然,这里肯定是没有差异的!同样是因为你并没有再一次git add。
好了,你开始执行第二次git add,执行完后,再试试git diff操作,是不是发现没有差异了?可以证明这里确实比较的是工作区和暂存区的数据差异了吧!
好,再试试git diff --cached操作,是不是发现有差异了?也证明了这里确实比较的是暂存区和仓库的数据差异。
另外,我还想说一下git add的反向命令git checkout,就是将工作区提交到暂存区的数据撤销掉。以及git commit的反向命令git reset HEAD,就是将提交到暂存区的数据以仓库数据为基准撤销暂存
git再合入代时如果又冲突,如果希望保留生产服务器上所做的改动,仅仅并入新配置项, 处理方法如下
git stash
git pull
git stash pop
然后
git add .即可以看到合入的代码
如果合入代码的过程中一直提示有冲突文件,由一些非法命名引起的,执行如下命令
git reset --hard HEAD
git clean -f -d
git pull 即可
git rebase 和 git merge 有啥区别
rebase
会把你当前分支的 commit 放到公共分支的最后面,所以叫变基。就好像你从公共分支又重新拉出来这个分支一样。
举例:如果你从 master 拉了个feature分支出来,然后你提交了几个 commit,这个时候刚好有人把他开发的东西合并到 master 了,这个时候 master 就比你拉分支的时候多了几个 commit,如果这个时候你 rebase master 的话,就会把你当前的几个 commit,放到那个人 commit 的后面,如下图:
merge
会把公共分支和你当前的commit 合并在一起,形成一个新的 commit 提交
注意:
不要在公共分支使用rebase
本地和远端对应同一条分支,优先使用rebase,而不是merge
抛出问题:
为什么不要再公共分支使用rebase?
因为往后放的这些 commit 都是新的,这样其他从这个公共分支拉出去的人,都需要再 rebase,相当于你 rebase 东西进来,就都是新的 commit 了
1-2-3 是现在的分支状态
这个时候从原来的master ,checkout出来一个prod分支
然后master提交了4.5,prod提交了6.7
这个时候master分支状态就是1-2-3-4-5,prod状态变成1-2-3-6-7
如果在prod上用rebase master ,prod分支状态就成了1-2-3-4-5-6-7
如果是merge
1-2-3-6-7-8
… |4-5|
会出来一个8,这个8的提交就是把4-5合进来的提交
merge和rebase实际上只是用的场景不一样
更通俗的解释一波.
比如rebase,你自己开发分支一直在做,然后某一天,你想把主线的修改合到你的分支上,做一次集成,这种情况就用rebase比较好.把你的提交都放在主线修改的头上
如果用merge,脑袋上顶着一笔merge的8,你如果想回退你分支上的某个提交就很麻烦,还有一个重要的问题,rebase的话,本来我的分支是从3拉出来的,rebase完了之后,就不知道我当时是从哪儿拉出来的我的开发分支
同样的,如果你在主分支上用rebase, rebase其他分支的修改,是不是要是别人想看主分支上有什么历史,他看到的就不是完整的历史课,这个历史已经被你篡改了
常用指令
git rebase -I dev 可以将dev分支合并到当前分支
这里的”-i“是指交互模式。就是说你可以干预rebase这个事务的过程,包括设置commit message,暂停commit等等。
git rebase –abort 放弃一次合并
合并多次commit操作:
1 git rebase -i dev
2 修改最后几次commit记录中的pick 为squash
3 保存退出,弹出修改文件,修改commit记录再次保存退出(删除多余的change-id 只保留一个)
4 git add .
5 git rebase --continue
git pull 与git fetch + git merge区别
(这部分介绍引用源于:https://www.cnblogs.com/ruiyang-/p/10764711.html 这篇博客)
- 相同点
首先在作用上他们的功能是大致相同的,都是起到了更新代码的作用。 - 不同点
先补充一些git里面相关的一些知识:
首先我们要说简单说git的运行机制。git分为本地仓库和远程仓库,我们一般情况都是写完代码,commit到本地仓库(生成本地仓的commit ID,代表当前提交代码的版本号),然后push到远程仓库(记录这个版本号),这个流程大家都熟悉。
我们本地的git文件夹里面对应也存储了git本地仓库master分支的commit ID 和 跟踪的远程分支orign/master的commit ID(可以有多个远程仓库)。那什么是跟踪的远程分支呢,打开git文件夹可以看到如下文件:
.git/refs/head/[本地分支]
.git/refs/remotes/[正在跟踪的分支]
其中head就是本地分支,remotes是跟踪的远程分支,这个类型的分支在某种类型上是十分相似的,他们都是表示提交的SHA1校验和(就是commitID)。
但是,不管他们是如何的相似,他们还是有一个重大的区别:
更改远端跟踪分支只能用git fetch,或者是git push后作为副产品(side-effect)来改变。我们无法直接对远程跟踪分支操作,我们必须先切回本地分支然后创建一个新的commit提交。
首先假设我们本地仓库的 master 分支上 commit ID =1 ,orign/mastter中的commit ID =1 ;这时候远程仓库有人更新了github ogirn库中master分支上的代码,新的代码版本号commit ID =2 ,那么在github上 orign/master的commitID=2,然后我们要更新代码。
git fetch
使用git fetch更新代码,本地的库中master的commitID不变,还是等于1。但是与git上面关联的那个orign/master的commit ID变成了2。这时候我们本地相当于存储了两个代码的版本号,我们还要通过merge去合并这两个不同的代码版本,如果这两个版本都修改了同一处的代码,这时候merge就会出现冲突,然后我们解决冲突之后就生成了一个新的代码版本。
这时候本地的代码版本可能就变成了commit ID=3,即生成了一个新的代码版本。
相当于fetch的时候本地的master没有变化,但是与远程仓关联的那个版本号被更新了,我们接下来就是在本地合并这两个版本号的代码。
2. git pull
是用git pull更新代码的话就比较简单暴力了,看下图
使用git pull的会将本地的代码更新至远程仓库里面最新的代码版本
3. 总结
由此可见,git pull看起来像git fetch+git merge,但是根据commit ID来看的话,他们实际的实现原理是不一样的。
这里借用之前文献看到的一句话:
不要用git pull,用git fetch和git merge代替它。
git pull的问题是它把过程的细节都隐藏了起来,以至于你不用去了解git中各种类型分支的区别和使用方法。当然,多数时候这是没问题的,但一旦代码有问题,你很难找到出错的地方。看起来git pull的用法会使你吃惊,简单看一下git的使用文档应该就能说服你。
将下载(fetch)和合并(merge)放到一个命令里的另外一个弊端是,你的本地工作目录在未经确认的情况下就会被远程分支更新。当然,除非你关闭所有的安全选项,否则git pull在你本地工作目录还不至于造成不可挽回的损失,但很多时候我们宁愿做的慢一些,也不愿意返工重来。