以前看过一些git的语法,当时以为自己记住了基本用法,但是长时间不使用后忘得就差不多了。最近在加入了一个校园组织后提交代码需要使用git,在一段时间的摸索中对于git有了较为清晰的认知。在文章中我们可以通过图像来更清晰的理解它。
基础语法
level1
知道 git commit 表示提交命令就行。
level 2
Git 的分支非常轻量,即使创建再多分的支也不会造成储存或内存上的开销,并且按逻辑分解工作到不同的分支要比维护那些特别臃肿的分支简单多了。
当我们创建一个空项目的时候,项目内仅仅存在一个master分支,本地仓库中的分支也和远程分支相对应。如果说在一个团队中有多名成员,每个成员就需要自己的分支。
所以,为了创建这样的分支,我们可以使用:
git branch dev-lzz // 创建一个新成员分支
现在我就可以在自己的分支上进行内容的提交了!
git checkout dev-lzz // 切换到我的成员分支
git commit // 进行内容的提交
我们还可以使用下面这条更简单的语句创建并切换到新分支:
git checkout -b dev-lzz
level 3
接下来咱们看看如何将两个分支合并到一起。就是说我们新建一个分支,在其上开发某个新功能,开发完成后再合并回主线。
第一种方法 —— git merge
。在 Git 中合并两个分支时会产生一个特殊的提交记录,它有两个父节点。翻译成自然语言相当于:“我要把这两个父节点本身及它们所有的祖先都包含进来。”
如果想将bugFix分支中的内容,以及它以前的提交记录,全部都合并到master分支中,我们可以在master分支上使用:
git merge bugFix
这样就表示 master 能够合并 bugFix 分支。
此时master指向这两条分支的所有祖先分支,此时如果切换到bugFix,进行merge的话,最终结果将是简单的把 bugFix
移动到 master
所指向的那个提交记录。
level 4
这一关介绍第二种合并的方法—— git rebase。
rebase 实际上就是取出一系列的提交记录,“复制”它们,然后在另外一个地方逐个的放下去。
如果是希望bugFix分支合并到master分支后面,就站在该分支上,使用:
git rebase master
远程协作
远程仓库是一个强大的备份。本地仓库也有恢复文件到指定版本的能力, 但所有的信息都是保存在本地的。有了远程仓库以后,即使丢失了本地所有数据, 你仍可以通过远程仓库拿回你丢失的数据。
level1
使用 git clone 操作,可以将远程的仓库(这里用虚线表示)拷贝到本地
你可能注意到的第一个事就是在我们的本地仓库多了一个名为 o/master
的分支, 这种类型的分支就叫远程分支。远程分支反映了远程仓库(在你上次和它通信时)的状态。远程分支有一个特别的属性,你必须在别的地方完成你的工作, (更新了远程分支之后)再用远程分享你的工作成果。
你可能还会想问这些远程分支的前面的 o/
是什么意思呢?远程分支有一个命名规范 —— 它们的格式是:<remote name>/<branch name>。
因此,如果你看到一个名为 o/master
的分支,那么这个分支就叫 master
,远程仓库的名称就是 o
。大多数的开发人员会将它们主要的远程仓库命名为 origin
,并不是 o
。这是因为当你用 git clone
某个仓库时,Git 已经帮你把远程仓库的名称设置为 origin
了。
level2
Git 远程仓库相当的操作实际可以归纳为两点:向远程仓库传输数据以及从远程仓库获取数据。既然我们能与远程仓库同步,那么就可以分享任何能被 Git 管理的更新
git fetch
完成了仅有的但是很重要的两步:
- 从远程仓库下载本地仓库中缺失的提交记录
- 更新远程分支指针(如
o/master
)
git fetch
并不会改变你本地仓库的状态。它不会更新你的 master
分支,也不会修改你磁盘上的文件。所以, 你可以将 git fetch
的理解为单纯的下载操作。
level3
在知道如何将远程的代码下载到本地以后,我们可以进行rebase或者是merge操作进行数据的同步。这样来看,一共就执行了两个步骤。由于先抓取更新再合并到本地分支这个流程很常用,因此 Git 提供了一个专门的命令来完成这两个操作。它就是我们要讲的 git pull
。
首先说一下情景:假设你上一次克隆远程仓库时,克隆的是c1版本,然后你顺着这个版本写了自己的代码(c2),与此同时远程仓库被别人更新为了c3 版本。接下来你需要提交新的代码。
首先用 git fetch 和 git merge 的方法来实现这个情景。
先在本地通过 git fetch 拿到远程的最新数据:
然后通过 git merge 进行分支的合并:
此时再进行提交,就是最新版本的代码了。
接下来用 git pull 来实现这个需求,一步到位,这里就不贴图演示了。
level4
与 git pull 相反的是什么呢?git push!
git push
负责将你的变更上传到指定的远程仓库,并在远程仓库上合并你的新提交记录。一旦 git push
完成, 你的朋友们就可以从这个远程仓库下载你分享的成果了!
在简单的 push 后,远程仓库接收了你的提交,远程仓库中的 master
分支也会被更新,我们的远程分支 (o/master) 也同样被更新了。所有的分支都同步了。
level5
假设你周一克隆了一个仓库,然后开始研发某个新功能。到周五时,你新功能开发测试完毕,可以发布了。但是 —— 天啊!你的同事这周写了一堆代码,还改了许多你的功能中使用的 API,这些变动会导致你新开发的功能变得不可用。但是他们已经将那些提交推送到远程仓库了,因此你的工作就变成了基于项目旧版的代码,与远程仓库最新的代码不匹配了。
这种情况下, git push
就不知道该如何操作了。如果你执行 git push
,Git 应该让远程仓库回到星期一那天的状态吗?还是直接在新代码的基础上添加你的代码,异或由于你的提交已经过时而直接忽略你的提交?
因为这情况(历史偏离)有许多的不确定性,Git 是不会允许你 push
变更的。实际上它会强制你先合并远程最新的代码,然后才能分享你的工作。
这里针对多人协作进行整体的模拟介绍:
首先通过 git clone https:xxx 目标仓库中的代码,左边的表示自己克隆下来的本地仓库,右边表示远程仓库。
我们假设正在进行团队合作,你的队友neko在你克隆下来文件后,上传了新的commit。非常积极的他接连上传了三个commit,并且审核人员同意了master合并。
现在有几个需要注意的地方。在neko进行了提交后,远程仓库的master已经是c4版本了,但是我们的master仍然指向c1版本,如果我们想进行合并,首先要确保的是本地仓库的master与远程仓库的master的前沿版本相同,所以此时我们无法上传。
接下来我们也尝试做一些commit提交吧!
git add . // 提交到缓存区
git commit -m 'xxx' // 提交到本地仓库
通过commit提交到我们的本地仓库后,会遇到之前介绍过的问题,本地与远程master分支不一致导致无法合并的问题。那么我们就切换到master分支,将远程的代码pull下来试试。
git checkout master
git pull
成功将远程仓库中的内容都pull下来了,我们可以看到,在本地提交的commit c5、c6存在于dev分支中,同时master分支与远程的master分支一样,都指向了c4分支。同时,由于c2->c4这一条支线和commit的不一样,所以从上一个版本master存在的c1引出了新的支线。
我们在每次准备提交前都pull一下试试,确保master分支没有受到影响,并且拉下来的分支都是最新的代码。
提交两个支线肯定是不行的,我们需要进行支线的合并。现在需要考虑一个问题,我们是在dev分支中合并master分支,还是在master分支中进行总的合并呢?
需要记住的是我们是单个的打工人,master分支是所有打工人共同提交代码的地方,因此要在自己的dev分支中进行合并,然后提交PR等待审核。
git checkout dev
git merge master
现在我们的dev分支中已经拥有了所有前置版本的代码,并且master分支和远程master分支指向的版本相同,那么就可以通过 git push 进行上传了。
提交成功,接下来去github/gitee上提交PR,等待测试人员和审核人员同意合并即可。