git
是开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。我们平时可能经常使用它,但是你真的了解 git 吗?先抛几个问题 git add
发生了什么?git 有哪些暂存区?git pull
与 git fetch
区别?git merge
与 git rebase
区别?git reset
与 get 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
添加文件。细分来说,应该是将工作区中的文件差异提交至暂存区。
相当于smartgit
的stage
-
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>
放弃更改。(不加 -- 也可以放弃更改)
相当于smartgit
的unstage
-
git reset HEAD <file>
取消添加暂存区 -
git switch <name>
切换分支,新版本提供的命令。git switch -c <name>
创建并切换
借一张图
工作区,暂存区,本地仓库,远程仓库
工作区就是我们 克隆 clone 一个项目,这个项目就是 工作区
;当执行 git add
时,会将改动添加到某个地方,这个地方就是暂存区
;本地仓库
,由 .git
目录管理;远程仓库
,就是拉取的地址。他们之间的关系如下面两张图所示:
HEAD
HEAD
是 git
内部的一个指针,指向当前版本
。这个当前版本包含两个概念 分支
和 提交
。 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 pull
与 git 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 merge
与 git 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 reset
与 get 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命令
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。