Git 学习(四)操作修改和版本穿梭
Git 学习(四)操作修改和版本穿梭
之前的章节,已介绍了本地Git库创建、暂存区增、删、改,以及提交版本库;可回顾下命令操作: git add 和 git commit。
光有之前章节的操作,Git 显然不能满足版本控制的需求。所谓的版本控制,可理解为文件夹的时间机,即从创建该文件夹伊始,所有文件提交操作都将被记录版本库,且可以随意穿梭版本(回退至昨日的版本,或甚至N年前)。
本文就此具体说明Git是如何管理修改、撤销修改以及在各个版本间穿梭的。
管理修改
为什么Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件。为达成这一目的,暂存区存在的意义就在于此。
此外,先依据 .git/index (暂存区文件)中记录的时间戳、长度等信息判断工作区文件是否改变。如果工作区的文件时间戳改变,说明文件的内容可能被改变了,需要要打开文件,读取文件内容,和更改前的原始文件相比较,判断文件内容是否被更改。如果文件内容没有改变,则将该文件新的时间戳记录到 .git/index 文件中。因为判断文件是否更改,使用时间戳、文件长度等信息进行比较要比通过文件内容比较要快的多,所以 Git 这样的实现方式可以让工作区状态扫描更快速的执行,这也是 Git 高效的因素之一。
git/index 实际上就是一个包含文件索引的目录树,像是一个虚拟的工作区。在这个虚拟工作区的目录树中,记录了文件名、文件的状态信息(时间戳、文件长度等),文件的内容并不存储其中,而是保存在 Git 对象库(.git/objects)中,文件索引建立了文件和对象库中对象实体之间的对应。下面这个图展示了工作区、版本库中的暂存区和版本库之间的关系。

工作区、版本库、暂存区 操作原理图
在这个图中,我们可以看到部分 Git 命令是如何影响工作区和暂存区(stage/index)的:
图中左侧为工作区,右侧为版本库。在版本库中标记为 "index" 的区域是暂存区(stage/ndex),标记为 "master" 的是 master 分支所代表的目录树
图中我们可以看出此时 "HEAD" 实际是指向 master 分支的一个“游标”。所以图示的命令中出现 HEAD 的地方可以用 master 来替换
图中的 objects 标识的区域为 Git 的对象库,实际位于 ".git/objects" 目录下
当对工作区修改(或新增)的文件执行 "git add ..." 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID 被记录在暂存区的文件索引中。
当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树
当执行 "git reset HEAD" 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响
当执行 "git rm --cached <file>" 命令时,会直接从暂存区删除文件,工作区则不做出改变
当执行 "git checkout -- <file>" 命令时,会将文件在工作区的修改撤销
当执行 "git checkout HEAD ." 或者 "git checkout HEAD <file>" 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。
上文内容其实是第三章: Git 学习(三)本地仓库操作——git add & commit 工作区与版本库的补充说明,原理图中提及的部分命令还未介绍,可先大致浏览,完全看完下文后再理解上图(该图很重要)。
需要注意:工作区其实与Git库是分离的,我们在工作区进行的修改,如果不add到暂存区,commit提交并不会提交版本(再次重申,commit 提交修改仅针对暂存区)。
这边所说的修改,包括文件本身的修改(删行、加行、改内容等),而创建新文件或删除,也算一个修改。
修改撤销
这边,介绍下暂存区撤销修改的命令:
git checkout -- <file1> <file2> ... 将文件在工作区的修改全部撤销,可多个,空格分隔
git checkout -- file命令中的 "--" 很重要,没有"--",就变成了切换分支的命令,切换分支命令将在以后章节介绍。
举几个具体示例来说明以上命令的用法,初始化空git库,若你先创建了 1.txt 并将其 git add,你在工作区修改了 1.txt 文件,但发现修改错了,需要撤销修改至当时 git add 的情况
git status 可见如下提示
git checkout -- 1.txt 后,再次打开 1.txt,发现其中的内容被撤销修改了,即内容为 111;
若工作区删除了 1.txt,但现在又想撤销删除,也可操作 git checkout -- 1.txt ,此时查看工作区,可发现 1.txt 被恢复了。
版本穿梭
仅仅针对工作区的修改撤销是远远不够的,需要在所有版本库中任意切换;版本是针对 commit 操作而言的,每次 commit 成功后,都会自动生成版本号。
git log 显示当前分支提交版本库的日志
git log 该命令很常用,可显示提交日志信息(当前版本库,可加参数,help查询具体);上图可见茶色字体显示了一大串类似
每提交一个新版本,实际上Git就会把它们自动串成一条时间线。如果使用可视化工具查看Git历史,就可以更清楚地看到提交历史的时间线:
git reset --hard <revision> 重置至某一版本(强制,暂存区和工作区均重置)
必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交,上一个版本就是HEAD^,上上一个版本就是HEAD^^ ...
如上,我们要把当前版本回退到最新版本,就可以使用命令行 git reset --hard ,若使用命令行 git reset --hard HEAD^,则回滚为上一版本,此时 git log 仅显示了当前版本及其之前的信息
命令可输入版本号,前几位即可(通常前7位);显然,若回滚了昨天的版本后,又反悔了的这种情况还是时有发生的,这时,就需要输版本号了;然则,版本号忘了怎么办。。这时,需要另一个命令帮助:
git reflog 显示操作的日志
该命令可显示操作日志,且显示了对应的版本号及信息,可查询到之前的版本号并再次回滚, 如 git reset --hard 6de39b3 。
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD指针,当你回退版本的时候,Git仅仅是把HEAD指向改变
改为指向 2:
然后顺便把工作区、暂存区文件更新了。
Git 学习(四)操作修改和版本穿梭的更多相关文章
- git学习(四):理解git暂存区(stage)
与一般的版本管理不同的是,git在提交之前要将更改通过git add 添加到暂存区才能提交(git commit).即使是已经交给了git来管理的文件也是如此.这里继续学习git的暂存区. 通过git ...
- Git学习-->GitLab如何修改时区?
一.背景 今天有同事在GitLab上查看时间的时候,发现GitLab上显示的时间和提交的时间不一致. 本地时间现在为:2017-11-28 11:43 查看本地代码提交的时间为:2017-11-28 ...
- git 学习笔记 ---撤销修改
自然,你是不会犯错的.不过现在是凌晨两点,你正在赶一份工作报告,你在readme.txt中添加了一行: $ cat readme.txt Git is a distributed version co ...
- 三、git学习之——管理修改、撤销修改、删除文件
一.管理修改 现在,假定你已经完全掌握了暂存区的概念.下面,我们要讨论的就是,为什么Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件. 你会问,什么是修改?比如你新增了一行, ...
- Git学习(二)——创建版本库、查看与回退版本
一.创建版本库 版本库,又名仓库(Repository),可以简单理解为一个目录,这个目录里的所有文件可以被Git管理起来,每个文件的修改.删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者将来某 ...
- Git学习笔记(2)——版本的回退,和暂存区的理解
本文主要记录了版本的回退,以及工作区,暂存区概念的理解. //开始之前,先回顾上次的内容,修改文件如下,并提交到版本库. Git is a distributed version control sy ...
- git学习——<四>git版本管理
一.git版本管理的优势 都说git比svn强大,强大在哪呢? 首先,从部署上说:svn.cvs都是集中式的,一台服务器上部署服务,所有客户端编写的代码都要提交到该服务器上.git是分布式的,所有人都 ...
- git学习笔记 ---管理修改
现在,假定你已经完全掌握了暂存区的概念.下面,我们要讨论的就是,为什么Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件. 你会问,什么是修改?比如你新增了一行,这就是一个修改 ...
- git学习(四) git log操作
git log操作 log命令的作用:用于查看git的提交历史: git log命令显示的信息的具体含义: commit SHA-1 校验和 commit id Author 作者跟邮箱概要信息 D ...
随机推荐
- 【LOJ】#2674. 「NOI2012」美食节
题解 这道题的费用流如果朴素一点怎么建边呢 建出\(\sum_{i = 1}^{n} p^{i} M\)个点,第\(i\)个厨师的第\(j\)个点表示这个厨师倒数第\(j\)个做的是某道菜 这个点向汇 ...
- 【AtCoder】ARC062F - AtCoDeerくんとグラフ色塗り / Painting Graphs with AtCoDeer
题解 考虑一个点双(因为是简单环),如果没有环(两点一线),那么乘上K 如果有一个环,那么用polya定理,每个置换圈有gcd(i,n)个循环节 如果有两个及以上的环,任何一种置换都合法,那么只和每个 ...
- MemSQL Start[c]UP 2.0 - Round 1 E - Three strings 广义后缀自动机
E - Three strings 将三个串加进去,看每个节点在三个串中分别出现了多少次. #include<bits/stdc++.h> #define LL long long #de ...
- 分享实用的JavaScript代码库
1 var keyCodeMap = { 2 8: 'Backspace', 3 9: 'Tab', 4 13: 'Enter', 5 16: 'Shift', 6 17: 'Ctrl', 7 18: ...
- 接口调用 POST
/** * 接口调用 POST * @return [type] [description] */ public function portPhone(Request $request) { $pho ...
- 浅谈Comparable与Comparator的区别
平时进行自定义排序一直使用实现Comparable接口,一段时间后操作的时候居然发现有了个Comparator接口 上网差了些资料,总结笔记一下. 基本原理就是比较,底层是二叉树 比如是3,6,5,1 ...
- python学习笔记 - for循环: 遍历字典, 分别打印key, value, key:value
#遍历字典, 分别打印key, value, key:value emp = {'name':'Tom', 'age':20, 'salary' : 8800.00} for k in emp.key ...
- [Agc002E]Candy Piles
[Agc002E]Candy Piles 题目大意 有\(n\)个数,两人轮流操作,可以做以下操作之一: 删掉一个最大的数 将所有数-1 最后取没的人输,问先手是否必胜? 试题分析 直接决策不知道选哪 ...
- bzoj 1563
对于很多决策单调性DP问题,我们很难(但不是不可以)证明其决策满足单调性,所以感觉很像时,可以打表看是否满足. 这道题的精度(?范围)很难搞,开始生怕溢出,看了hzwer的代码,才发现用long do ...
- trigger、procedure和event如何同步
最近遇到一个需求涉及存储过程,被突然问题到如何同步问题问到了,赶紧补课学习一下. 首先,先看一下trigger.procedure和event的定义都是什么? trigger: 触发器是一个被指定关联 ...