git.jpg

git 是开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。我们平时可能经常使用它,但是你真的了解 git 吗?先抛几个问题 git add 发生了什么?git 有哪些暂存区?git pullgit fetch 区别?git mergegit rebase 区别?git resetget restore 区别?

虽然,我一直在用 git ,像上面这些问题,我就不知道,所以将它们总结下。原文在个人博客

什么是版本控制系统

开篇说了 git 是一个分布式的版本控制系统,那么什么是版本控制系统呢?可以参考 廖雪峰举的例子 Word 文档操作

Word 文档操作举例,当你想要 删除 某一段落的时候,又怕将来想要 恢复 找不到怎么办?你可能,会保存一个 副本。接着再修改,再保存一个 副本,这样一直持续,将会有好几个 副本

过了一周,你想找到某一段,可能需要从这些 副本 中,一个一个查找,是不是很麻烦。

这还是你一个人写 Word 的情况,假如,你的同事和你一起编辑这个 Word,为了保证文档同步,你们之间可能需要不停的相互发送传递(通过 U盘,或者 qq 微信 等方式)。总之,很繁琐。

那假如说有这样一个软件,可以记录每次修改,而且还可以和多人共同编辑,是不是很方便。git 就是解决类似上面的问题,方便我们查看每次修改内容,以及同步别人的修改等。

基本操作

  • git clone
    一般来说,通过 git 来进行远程操作的第一步,是通过此命令从远程主机上克隆一个版本库
  • git fecth
    将某个远程主机的更新,全部取回本地
  • git pull
    取回远程主机某个分支的更新,再与本地的指定分支合并
    smartgit pull 按钮有个下拉选项,可以选择:
    Merge fetched remote changes
    Rebase local branch onto fetched changes
  • git add
    添加文件。细分来说,应该是将工作区中的文件差异提交至暂存区。
    相当于 smartgitstage
  • git commit
    提交文件。将暂存区中的修改,提交到本地分支。每次提交会产生一个 commit-id,并且会带上你的 username email 等信息。
  • git push
    将本地分支的更新,推送到远程主机
  • git marge
    合并分之,多条线
  • git rebase <name>
    合并某分支到当前分之,变基 衍合,一条线
  • git branch <name>
    创建分支
    git branch -d <name> 删除分支
  • git checkout
    git checkout <name> 切换分支
    git checkout -b <name> 创建 并 切换 分支。
    git checkout -- <file> 放弃更改。(不加 -- 也可以放弃更改)
    相当于 smartgitunstage
  • git reset HEAD <file>
    取消添加暂存区
  • git switch <name>
    切换分支,新版本提供的命令。
    git switch -c <name> 创建并切换

借一张图

工作区,暂存区,本地仓库,远程仓库

工作区就是我们 克隆 clone 一个项目,这个项目就是 工作区;当执行 git add 时,会将改动添加到某个地方,这个地方就是暂存区本地仓库,由 .git 目录管理;远程仓库,就是拉取的地址。他们之间的关系如下面两张图所示:

HEAD

HEADgit 内部的一个指针,指向当前版本。这个当前版本包含两个概念 分支提交HEAD 负责指向哪条 分支,而 分支 指向某次具体 提交

默认情况

创建新分支。Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化。从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变。

合并分支。首先切到 master ,然后 将 dev 合并到当前分支。就是直接把 master 指向 dev 的当前提交。git 很懒,这个提交方式 是因为 git 尝试采用 fast-forward (—ff) 这类合并不会创建新的提交。

如果 master 上没有修改,这个时候情况就是这样的。如果 master 上修改,将会采用 No-fast-foward (—no-ff),会创建一个 merge 提交。

删除分支。开发完分之后,可以视情况将其删除。删除dev分支就是把dev指针给删掉

动画演示 如下:

git pull 与 git fetch

git pullgit fetch 都可以从远程仓库中拉取最新代码。不同之处在于更新的方式不同。

git fetch

git fetch 方式,是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中。最新的更新记录会保存在 .git/FETCH_HEAD 文件中。

git pull

git pull 则是将远程主机的最新内容拉下来后直接合并,这样可能会产生冲突,需要手动解决。git pull = git fetch + git merge

注意,不一定是 git merge 也可以选择 git rebase,比如,我用的 smartgit:

git merge 与 git rebase

git mergegit rebase 都是用来合并分之的。不同之处,在于生成的 log 分叉线不同。

git merge 会把公共分支和你当前的commit 合并在一起,形成一个新的 commit 提交。

git rebase 会把你当前分支的 commit 放到公共分支的最后面,所以叫变基。就好像你从公共分支又重新拉出来这个分支一样。

假设,你有如下分支记录,

假设在 master 分支上的新提交与你正在开发的 feature 相关。需要将新提交合并到你的 feature 分支中,你可以有两个选择:merge 或者 rebase

git merge 方式

git checkout feature
git merge master

# 或者一条命令。前提是你得在 feature 分支上
git merge feature master 

如上图所示,这会在 feature 分支中创建一个新的 merge commit,它将两个分支的历史联系在一起。

使用 merge 是很好的方式,因为它是一种 非破坏性的 操作。现有分支不会以任何方式被更改。这避免了 rebase 操作所产生的潜在缺陷。

缺点是会产生一个额外的提交。

git rebase 方式

git checkout feature
git rebase master

如上图所示,这会将整个 feature 分支移动到 master 分支的顶端,从而有效地整合了所有 master 分支上的提交。但是,与 merge 提交方式不同,rebase 通过为原始分支中的每个提交创建全新的 commits重写 项目历史记录。

rebase 的主要好处是可以获得更清晰的项目历史。

git rebase 黄金法则

git rebase 的黄金法则是 永远不要在公共分支上使用它

什么是 公共分支呢。我的理解是想 master dev test 这样的分之,或者说是有两个人以上使用的分支,就叫公共分支。

你 rebase master 分支到 feature 分支之上会发生什么:

git reset 与 get revert

git resetget revert 都可用于版本回退,区别在于,一个可以硬重置,不保留记录;一个是覆盖式提交,保留记录。

先假设我们有这样的分支:

git reset

git reset 分为 软重置 (git reset --soft <commit id>) 和 硬重置(git reset --head <commit id>)。默认为 软重置,一般在回滚代码的时候,我们用的是 硬重置

git reset --hard <commit id>
git push -f

git revert

git revert 还原,通过对特定的提交执行还原操作,我们会创建一个包含已还原修改的新提交

git 练习

发现一个很好的了解Git 基本概念和操作的工具,Git Online 。这个网站通过一个个任务让你了解 git,如果不想做题,可以直接加参数 NODEMO Git Online 沙盒模式,来在线验证。

如果,还想通过动图的方式,直观的了解 git 命令是如何工作了,可参考我转载的这篇文章 CS可视化:有用的Git命令

参考链接

Git 教程

一个小时学会Git

git rebase VS git merge? 更优雅的 git 合并方式值得拥有

Git恢复之前版本的两种方法reset、revert(图文详解)


zhangjinpei
103 声望6 粉丝

做一枚精致的前端er