文章目录
前言
本文从工作区,暂存区和版本库的概念引入, 介绍了Git中的一些基础命令, 同时结合实例来学习如何将文件提交到git仓库,以及如何进行撤销修改等操作.
一、工作区、暂存区和版本库的概念
1.介绍
工作区: 我们在电脑上修改的代码文件所在的目录,简单来说就是你对代码进行修改的地方;
暂存区(stage|index): 一般是位于.git目录下的index文件中,我们也称之为索引。需要先将待提交的文件添加到暂存区,然后再提交到版本库;
版本库(repository): 又名仓库,位于工作区的隐藏目录.git中,它不属于工作区,而是独立出来的Git的版本库。版本库中将每一次git提交作为一个Git对象进行管理,每个文件的修改、删除都会被跟踪,以便在后续开发中对历史记录进行查看或者“还原”。
2.它们之间的关系
工作区、暂存区、版本库之间的关系可以参考下图
- 当创建Git版本库时,Git会自动创建一个唯一的master分支,以及指向master分支的HEAD;
- 当对工作区修改的内容(增/删/改文件)执行git add命令时,暂存区目录树的文件索引会被更新;
- 当执行
git commit
提交命令时,master分支会进行对应的更新,即将暂存区的目录树真正写入到版本库中。
总结来说,我们在工作区进行增删改文件等操作不会同步更新到仓库中,只有使用git add
和git commit
命令后,才能将修改提交到仓库中进行管理。
二、命令介绍
1.git add
git add [file1] [file2] [file3] #添加一个或多个文件 到暂存区
git add [dir] #添加指定目录(及其子目录) 到暂存区
git add #添加当前目录下所有文件改动 到暂存区
2.git commit
git commit -m "commit message" #提交修改内容到版本库,-m后跟上本次提交的具体描述,方便后续回顾历史记录
注意: message绝对不能省略,要描述你的提交细节,方便后续维护。
举例:
创建文件code1,在文件中写入内容为"git add",通过git add
命令将code1文件添加到暂存区,再使用git commit
命令将暂存区的内容提交到版本库中。
可以看到git commit
命令的提示信息中说明:一个文件被修改(新增的文件code1),插入了一行内容(在code1中写入的"git add")。
也可以尝试add多个文件,然后一次commmit提交所有文件:
git commit是将暂存区中所有的修改提交到版本库中。
参考下面的例子,我们创建文件code5,然后使用命令git add code5
将它添加进暂存区,接着创建code6,最后执行git commit -m "msg"
将暂存区中的修改提交到版本库。可以看到,提交信息上显示的是1个文件被修改,即只提交了code5的修改,因为code6的修改没有被添加到暂存区中。
如果需要将code6的修改也提交到版本库,可以重复上面的过程,先执行git add
,再执行git commit
即可。
3.git log
git log #查看提交历史记录
git log --pretty=oneline #将日志信息精简为一行
可以看到我们先前进行的两次提交的日志信息,带上–pretty=oneline选项可以精简提交的日志信息为一行。
日志信息中commit后面跟着的一串乱码,实际上是每次提交的commit id(可以理解为版本号),是Git用于唯一标识某次提交的。commit id并非1,2,3,…依次递增的数字,而是通过计算得到的一个很大的数字,用十六进制表示。
commit id是由40位的SHA-1哈希值组成的,它是通过将提交内容和提交信息(比如作者、时间等)进行哈希函数处理后生成的。
4.git status
git status #查看最近一次提交后,当前对于文件的修改
提示信息告诉我们工作区的code2文件被修改过,但是还未完成添加到暂存区和提交到版本库等操作。
将修改添加到暂存区后,再执行git status
可以看到:
最后执行git commit
命令后,使用git status
命令就显示没有修改了:
5.git diff
通过git status
命令我们只能查看到修改了那些文件,但是无法获取到具体修改的内容。如果修改的代码量过大,不便于我们进行查看和修改,通过git diff
命令可以查询到当前修改的内容。
git diff [文件名] #查看暂存区和工作区文件的差异
git diff HEAD -- [file] #查看版本库和工作区文件的差异
显示信息的格式是Unix通用的diff格式:
a/code2
是修改前对应文件;
b/code2
是修改后对应文件;
---
是删除;
+++
是添加;
将修改添加到暂存区后,执行git diff [code2]
可以发现没有显示差异,再执行git diff -- [code2]
后可以看到版本库和工作区之间的差异:
最后执行git commit
命令后,使用git diff
命令就不会显示差异了:
6.git reset
在我们实际开发过程中,会出现需要从历史的某个版本重新开发的情况,这时就需要用到git的版本回退功能了.
git reset
命令可以指定回退到某次提交的版本.
git reset [--soft|--mixed|--hard] [HEAD] [file]#版本回退
举例:将代码回退到上一个版本
注意: 回退的本质是将版本库中的内容回退, 工作区或暂存区内容是否回退取决于配置的命令参数.
–soft 选项是将版本库回退到指定版本, 而暂存区和工作区内容保持不变.
–mixed 为默认选项, 即不带参数时相当于带这个选项. 该选项是将暂存区和版本库的内容回退到指定版本内容, 而工作区保持不变
–hard 选项是将工作区、暂存区和版本库都回退到指定版本. 注意: 当工作区有尚未提交的代码时谨慎使用这个命令, 因为一旦工作区回滚, 未提交的代码就再也找不回来了.
HEAD 选项用于指定回退的版本, 也可以写成指定版本的commit id.
HEAD表示当前版本(版本指的是版本库的版本);
HEAD^表示上一个版本;
HEAD^^表示上上一个版本;
以此类推.
也可以使用~数字
的形式指明版本:
HEAD~0表示当前版本;
HEAD~1表示上一个版本;
HEAD~2表示上上一个版本;
以此类推.
file 可以指定要回退的具体文件file,没有指定则默认回退所有修改的文件。
7.git reflog
当我们回退到历史版本version2后, 又想重新回到该历史版本之后的版本version3该怎么办? 同样是使用 git reset
命令, 但是必须要获取到对应版本的commit id。然而, 如果并非即时的进行版本回退,从上方的命令行中获取commit id,则此时无法获取到该版本的commit id。
下图可以看到再使用git log
是无法打印出version2之后的版本信息(commit id)。
可以看到日志中最新的是当前版本的信息,无法查询到change code2的版本信息了。
这时可以使用git reflog
命令:
git reflog #查看本地执行的所有git命令
通过这条命令可以找到本地所有的操作记录。
在实际操作中,我们会发现Git的版本回退非常快, 这是因为Git的版本回退本质是在Git里面有一个指向当前分支的HEAD指针(前文说过, HEAD指针是指向master的,而master是存储了最近一次提交的commit id). 当我们进行版本回退时,本质是将master中存储的commit id改成了指定版本的commit id,因此速度会很快。
8.git checkout
上文中的git reset
命令主要是对于版本库文件的回退版本来说的,如果我们在工作区进行了较长时间的修改, 但是目前不想要这些修改, 想恢复到上一个版本应该如何做?
当改动较小,则可以尝试用git diff
命令来查看当前工作区的修改,然后将修改重置回去。但是,当改动较多,此时手动一个个改回去就不太现实,耗时量大并且容易将代码改出bug,因此可以使用git checkout --
命令来将文件直接恢复到最近一次add/commit的状态。
git checkout -- [file] #将工作区指定文件恢复到最近一次add/commit的状态
注意:只有携带--
时, 该命令才是这个功能, 该命令的其他选项及其对应功能会在后续文章中进行介绍。
如果在工作区修改的内容还未add到暂存区,则可以使用命令
git checkout -- [file]
将指定文件恢复到最近一次add/commit的状态.
如果工作区修改的内容已经add到暂存区了或者已经commit到版本库了, 我们想要丢弃工作区当前的修改, 则可以参考前文的命令来进行撤销修改.
- add到暂存区的情况:
使用git reset [--mixed] HEAD [file]
命令, 可以将暂存区的内容回退到当前版本(当前版本库的版本)。然后,再使用git checkout -- [file]
将工作区的修改回退到当前版本
或者直接使用git reset --hard HEAD [file]
命令,将暂存区和工作区的修改都回退到当前版本。- commit到版本库的情况:
使用git reset --hard HEAD^
命令, 可以将工作区和暂存区的内容回退到上一个版本。
注意, 这种操作的前提是你还没有将自己的本地仓库的修改push到远程仓库,也就是commit之后还没有push。
我们进行撤销的目的,就是避免有问题的代码影响到远程仓库!!!只有被push到远程仓库之前的撤销才是有效的
9.git rm [file]
git rm [file] #将暂存区中的文件file删除
当我们需要从版本库中删除某个文件file时,可以执行以下步骤:
- 执行
rm file
命令将工作区的file文件删除,此时使用git status可以看到有一个修改待add和commit。
- 然后执行
git add file
命令,将工作区中删除file的这个修改添加到暂存区中,此时使用git status可以看到有一个修改待commit。 - 最后执行
git commit -m "rm file"
将暂存区中的修改提交到版本库中,至此版本库中的file文件就被删除了。
当然,git为我们提供了一种更简化步骤的命令 git rm
,步骤简化为:
- 执行
git rm [file]
命令,可以将工作区中的file命令删除,同时将这个修改添加到暂存区中,此时使用git status可以看到有一个修改待commit。 - 然后执行
git commit -m "git rm file"
将暂存区中的修改提交到版本库中,至此版本库中的file文件就被删除了。
三、.git目录
使用命令tree .git 查看.git目录的子目录
子目录的介绍:
- .git 目录下的index就是暂存区,执行git add后会将对应的Git对象索引添加到index中。
- HEAD 是默认指向master分支的指针:
我们再查看master中的内容:
可以看到master中保存的内容和最新一次的commit id是相同的,即master中保存的是当前最近一次的commit id。 - objects 是Git的对象库,其中存储了所创建的各个版本库对象及其内容。当我们执行git add命令时,工作区中对文件内容进行的修改会被创建出的Git对象记录,并写入objects目录下,同时暂存区内对应的目录树会被更新。
可以看到在我们进行了几次提交后,objects目录下多了几个子目录,子目录的名称实际上是我们每次commit得到的commit id的前两位数,而子目录下的文件的文件名则是commit id的后38位。
由于版本库对象对应的文件是经过sha(安全哈希算法)加密过的,所以我们无法直接查看该文件的具体内容,但是可以使用命令git cat-file
来查看版本库对象的内容:
可以看到版本库对象中记录了提交人信息,提交描述以及两个特殊的commit id。
其中,parent 对应的是当前版本库对象对应的提交的上一次提交的commit id:
tree 对应的是当前所有提交的记录:
总结
以上就是今天要讲的内容,本文介绍了 的相关概念。本文作者目前也是正在学习C++相关的知识,如果文章中的内容有错误或者不严谨的部分,欢迎大家在评论区指出,也欢迎大家在评论区提问、交流。
最后,如果本篇文章对你有所启发的话,希望可以多多支持作者,谢谢大家!