Git - 在版本之间切换自如

栏目: 编程工具 · 发布时间: 5年前

内容简介:Git 的使用说难也不难,对很多人而言,git 无外乎那么几种命令。使用 git 开发就如同一条流水线式的作业:pull 下来、checkout 分支、add 一下、commit 一下、push 完事。Git 用起来非常舒适,因为靠着这么一顿操作,大多数情况下都能满足需要。但是一旦有一天中午,昏昏欲睡的你猛然发现自己好几次 commit 错了东西,或是一直工作在一个错误的分支上,那么 git 对于你来说,突然间就变成了洪水猛兽,平常使用的命令没有一个派的上用场。痛定思痛,除了满足日常开发,还是得掌握更多 g

Git 的使用说难也不难,对很多人而言,git 无外乎那么几种命令。使用 git 开发就如同一条流水线式的作业:pull 下来、checkout 分支、add 一下、commit 一下、push 完事。Git 用起来非常舒适,因为靠着这么一顿操作,大多数情况下都能满足需要。

但是一旦有一天中午,昏昏欲睡的你猛然发现自己好几次 commit 错了东西,或是一直工作在一个错误的分支上,那么 git 对于你来说,突然间就变成了洪水猛兽,平常使用的命令没有一个派的上用场。

痛定思痛,除了满足日常开发,还是得掌握更多 git 的使用,才能让在下一次犯错的时候吃上一瓶后悔药。

基础知识

学习 git 的一个重要的技巧就是结合类弹珠图的 git 提交历史来看,推荐使用一些图形化界面比如 Sourcetree 来观察每次执行命令之后 history 的变化。

提交对象

使用 git 作为版本控制系统,首先要理解什么是一个版本:每当进行一次 commit 操作时,Git 会保存一个提交对象(commit object),可以理解这个提交对象就包含了这次改动的内容快照,根据不同提交对象的 commit id ,可以随时访问不同版本的内容。

举例来讲:

1)添加 README 文件,add -> commit -> git 生成 commit 98c27 2)更新 README 为 v2、添加 app.js、package.json 文件,add -> commit -> git 生成 commit 2c9be 3)更新 README 为 v3、更新 app.js 为 v2,add -> commit -> git 生成 commit 1a35c

示意图如下:

Git - 在版本之间切换自如

时间轴是从左往右,但是 commit 的指向正好相反,因为每个新创建的 commit,都以前一个 commit 为父节点,所以指向前一个 commit。

每一个 commit 都包含了 当时版本的文件快照 ,也就是说,切换到某一个 commit,就能回到对应的版本上去。

分支

所以,我们如何知道自己在哪个 commit 上?一般来说,我们都是工作在分支上的,比如当一个项目初始化时,都默认有一个 master 分支, 分支本质上仅仅是指向提交对象的可变指针 。比如如下的 master 分支上,README 已经是 v3 版本了:

Git - 在版本之间切换自如

当在 master 分支上 checkout 一个分支出来时,仅仅是创建了一个新的指针,指向了当前的 commit。

Git - 在版本之间切换自如

所以此时 master 分支上和 feature 分支上的内容是一样的。

我们接着 commit,然后 master 的指针就会指向新的 commit:

Git - 在版本之间切换自如

为什么不是 feature 的指针改变?换句话说,git 怎么知道我们处在哪个分支?这是因为有一个特殊的指针 HEAD ,它指向当前所在的本地分支:

Git - 在版本之间切换自如

刚才创建分支使用的是 git branch 命令,它只是创建一个分支,并不会自动切换过去,使用 git checkout 命令使得 HEAD 指向特定的分支:

Git - 在版本之间切换自如

继续 commit,feature 将往前移动:

Git - 在版本之间切换自如

这时可以发现两个分支开始分叉了,也就是说这两个分支基于同一个版本分别做了不同的改动。

三个集合

要理解如何操纵 commit,还需要理解 git 中的三个集合。在 git 中,文件有三种状态:已修改(modified)、已暂存(staged)和已提交(committed),它们分别对应于三个区域: 工作区 (working directory)、 暂存区 (staging area) 和 版本库 (repository)。

Git - 在版本之间切换自如

git 通过比较三个区域的内容,来提示用户需要做的操作。比如工作区与暂存区不同,意味着你需要 add;暂存区与版本库不同,意味着你已经 add 但尚未 commit。

我们知道,基本的 Git 工作流程如下:

  1. 工作目录 中修改文件。
  2. 暂存文件(add),将文件的快照放入 暂存区域
  3. 提交更新(commit),找到暂存区域的文件,将快照永久性存储到 Git 仓库目录

假设我们处在 feature 分支,当我们进行以上操作后,commit 与三个区域的内容变化分别如下:

Git - 在版本之间切换自如

从左到右分别是工作区、暂存区和版本库,版本库上面标注了 HEAD,这表示我们展示的是 HEAD 指针指向的内容,也就是当前分支所在的 commit。

接下来对工作区内的文件进行修改,换句话说就是修改磁盘上的文件:

Git - 在版本之间切换自如

修改磁盘上的文件只是改变了工作区的内容,接下来使用 git add 命令将修改提交到暂存区:

Git - 在版本之间切换自如

将修改提交到暂存区并不会新增一个 commit,接下来通过 git commit 来提交:

Git - 在版本之间切换自如

此时新的 commit 被创建,HEAD 指向的 commit 相应发生改变。

有了上面这些 git 操作的印象后,解释如何切换版本就容易多了。

Git 中的撤销

撤销可能是使用过程中最需要的操作,你可能在任何时候都需要撤销。根据情况不同,撤销的命令也是不同的。

撤销最近几次 commit

要撤销最近几次的提交,可以使用 git reset ,下面介绍它的三种模式: softmixedhard

假设目前分支情况如下,我们需要撤销到 98c27 commit 上去。

Git - 在版本之间切换自如

1)soft 模式

执行 git reset --soft 98c27 ,git 会首先修改 HEAD 的指向,它会连带修改 HEAD 所在分支的指向:

Git - 在版本之间切换自如

如上图所示,现在的暂存区和 HEAD 是不同的,这个操作本质上撤销了 2c9be 这个 commit,如同回到了上次准备 commit 的时候。(git 中的时光机!)

此时你可以进行后悔操作,继续修改文件再 add,然后重新 commit,这时会提交一个新的 commit。

2)mixed 模式

回到一开始的时候,假如我们执行的是 git reset --mixed 98c27 ,它也会首先修改 HEAD 的指向,使得 HEAD 上的 commit 为 98c27

但还不够,git 还会接着更新你的暂存区,如同回到了你准备 add 的时候。(时光机再向前!)

Git - 在版本之间切换自如

对你来说可能更方便了,继续改就行,然后重新 add、commit。这实际上是 reset 的默认模式,等同于 git reset 98c27

3)hard 模式

不用我多说你可能已经意识到 hard 是干什么用的了。这一次 git 摧枯拉朽,把你的 HEAD、暂存区、工作区全给干掉了:

Git - 在版本之间切换自如

一下子回到了你开始写需求的时候。所以这个命令是 危险 的,除非你真的打算不要这些修改了,否则最好不要用。

不过即使你真的用了又后悔,那也是有办法的,在 git 里面,既然能回到过去,也能在过去穿越到未来。使用 git reflog 可以查看你最近的修改,找到最前面的 commit id,可以继续使用 reset 穿回去。

合并 commit

有时候你可能发现自己刚才提交的好几个 commit 其实都是中间状态,还不如把它们合并成一个。根据上面的 reset,实际上就能完成这件事情。

比如下面的场景,我们多提交了一个 File V1.1 的中间版本,希望将其从 commit 历史中去掉:

Git - 在版本之间切换自如

那其实可以直接 reset 到 v1 版本:

Git - 在版本之间切换自如

然后重新进行 commit,这样就会将 v1 之后的修改都提交到了新的版本,如同移除了中间的版本。

Git - 在版本之间切换自如

当然,这个场景也能用 rebase 解决,之后会提到。

挪动 commit

在多个分支上切换开发的时候,有时候会忘记切换分支就开始开发。当发现自己提交的 commit 放错分支怎么办呢?在 git 中,这也不算个事,通过 git cherry-pick 就能解决。

cherry-pick 可以将指定的 commit “摘到”当前的分支上面,git 会为你重新生成一个 commit,但内容与 pick 的 commit 一致。

Git - 在版本之间切换自如

如果你要 pick 好几个 commit,它们之间有依赖关系,那需要根据先后顺序依次进行 cherry pick。

当发生冲突时,此时需要修改文件解决冲突,可以使用 git cherry-pick --abort 放弃此次 pick,或者解决完 add 进暂存区,然后使用 git cherry-pick --continue 。注意这里并不是使用 git commit ,如果你需要改变 commit 的信息,可以使用 commit,否则 git 会默认使用 pick 的 commit 的信息。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Bad Blood

Bad Blood

John Carreyrou / Knopf / 2018-5-21 / USD 27.95

The full inside story of the breathtaking rise and shocking collapse of Theranos, the multibillion-dollar biotech startup, by the prize-winning journalist who first broke the story and pursued it to t......一起来看看 《Bad Blood》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具