【Git】--- 初识Git Git基本操作
Welcome to 9ilk's Code World
(๑•́ ₃ •̀๑) 个人主页: 9ilk
(๑•́ ₃ •̀๑) 文章专栏: Git
本篇我们来初步认识Git企业级应用是什么,有什么用以及Git基本操作。
🏠 初始Git
提出问题
在日常生活中,我们进行软件开发或日常文档维护,可能遇到以下问题:我们对文档进行多次修改,形成多个版本v1 v2 v3 v4... 长此以往我们的文档副本越来越多,每个版本都有各自内容,但最终只有一份会被我们采用,但我们想从不同版本汲取优点,面对这么多版本,我们是不清楚之前的每个版本的修改内容的,这并不方便我们进行维护,影响我们的开发效率。有什么解决方案吗?
解决方案
面对上面的问题,我们急需一个能记录每次修改以及版本迭代的管理系统,这就需要引出版本控制器的概念,我们的Git就是当前主流的版本控制器。版本控制器,通俗讲就是能让你了解到一个文件的历史,以及它的发展过程的系统,即一个可以记录工程的每一次改动和版本迭代的管理系统,同时也方便多人协同作业。
我们的主角Git是当前最主流的版本控制器,它可以控制电脑上所有格式的文件,例如doc execl dwg dgn等等。对于我们开发人员来说,Git最重要的就是可以帮助我们管理软件开发项目中的源代码文件!
🏠 Git 安装
Centos:
git --version
sudo yum install git -y
Ubuntu:
sudo apt-get remove git -y
git --version
sudo apt-get install git -y
🏠 Git基本操作
本地仓库创建
如果想使用Git管理文件,我们必须把这些文件放在Git仓库中,仓库是进⾏版本控制的⼀个⽂件⽬录。我们要想对⽂件进⾏版本控制,就必须先创建⼀个仓库出来
先创建一个目录做测试:
mkdir gitcode
创建Git本地仓库(注意命令要在⽂件⽬录下执行):
git init
当创建成功我们可以看到以下提示:
使用ls -a 命令我们发现,我们当前目录下多了个.git的隐藏目录,它是Git用来跟踪管理仓库的,不要手动修改这个目录里面的文件,不然乱改会把Git仓库给破坏了
本地仓库配置
将本地仓库创建好之后,我们最好对两个配置项email name进行配置。
git config [--global] user.name "Your Name"
git config [--global] user.email "email@example.com"
# 把 Your Name 改成你的昵称
# 把 email@example.com 改成邮箱的格式,只要格式正确即可
- --global是一个可选项,如果使用该选项,表示这台机器上所有的Git仓库都会使用这个配置。如果你希望在不同仓库中使用不同的name或e-mail,可以不要--global选项,但注意的是,执行命令时必须要在仓库里。
查看配置:
git config -l
重置某个配置:
git config [--global] --unset user.name
- 注意对于设置了--global选项的配置项,unset时需要带上--global
认识工作区,暂存区,版本库
zhuang@VM-8-14-ubuntu:~/gitcode$ touch ReadMe
zhuang@VM-8-14-ubuntu:~/gitcode$ ls
ReadMe
思考以下问题:当我们在gitcode下创建文件时,这个文件就会受到版本管理了吗?如果放在.git目录下呢?
答案是无论放在它们两哪个都不会受到版本管理,而且我们之前也说过不允许在.git下手动修改,误操作可能会导致整个本地仓库出错。
面对这个问题我们需要了解三个区域:
- 工作区:是在电脑上你要写代码或文件的目录。对应我们的gitcode目录。
- 暂存区:英文叫stage或index。一般存放在.git目录下的index文件(.git/index)中,我们
把暂存区有时也叫作索引(index)。 - 版本库:又名仓库,英文名repository。工作区有一个隐藏目录录.git,它不算工作区,而
是Git的版本库。这个版本库里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git
都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以"还原"。
工作区、暂存区、版本库三者的关系如下:
- 图中左侧为工作区,右侧为版本库。Git的版本库里存了很多东西,其中最重要的是暂存区。
- 在创建Git版本库事,Git会为我们自动创建一个唯一的master分支,以及指向master的一个指针叫HEAD。
- 当执行git add操作时,会将工作区修改的内容保存到版本库的暂存区中,暂存区目录树的文件索引会被更新。注意:这里工作区修改的内容不仅仅指的是新增和修改,还有删除!
- 版本库中还有一个模块,叫“对象库(objects)”,里面存储一堆git对象,维护git对象相当于维护了文件的所有版本,即进行了版本管理。
- 当执行git commit操作时,会把暂存区的index树写到master分支下,master分支会做相应的更新,注意:git对象都存在objects里,因此暂存区存的是一个个git对象的索引,它是轻量级的一个区域。
- master指向的是当前分支,即最新commit,即最近的一个版本。
总结:通过新建或粘贴进目录的文件,并不能称之为向仓库中新增文件,而只是在工作区新增文件。必须通过两板斧git add和git commit才能将文件添加到仓库中进行管理。
小细节:当我们刚创建完一个新目录,还没有git add时,是查看不了暂存区的,即.git目录下的index目录。
添加文件
(1)场景一:
先在gitcode目录下创建一个文件ReadMe,给ReadMe文件添加内容:
git add : 添加内容进暂存区
git add ReadMe
当然git add我们可以灵活使用:
git add [file1] [file2].. //添加一个或多个文件到暂存区
git add [dir] //添加指定目录到暂存区,包括子目录
git add . //添加当前目录下的所有文件
git commit命令将暂存区内容添加到本地仓库:
git commit -m "ReadMe" //提交暂存区全部内容
git commit [file1] [file2]... -m "message"//当然也可以提交暂存区的指定文件
- git commit 后面的 -m 选项,要跟上描述本次提交的message,由用户自己完成,这部分内容绝对不能省略,并要好好描述,它们用来记录你的提交细节,方便我们开放以及他人协作。
我们一次性add和commit多个文件:
zhuang@VM-8-14-ubuntu:~/gitcode$ touch file1 file2 file3
zhuang@VM-8-14-ubuntu:~/gitcode$ git add file1
zhuang@VM-8-14-ubuntu:~/gitcode$ git add file2
zhuang@VM-8-14-ubuntu:~/gitcode$ git add file3
zhuang@VM-8-14-ubuntu:~/gitcode$ git commit -m "add 3 file"
[master e42d583] add 3 file
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file1
create mode 100644 file2
create mode 100644 file3
完成之后,我们可以使用git log命令显示从最近到最远的提交日志,并且可以看到我们commit时的日志消息:
- commit后跟着的一串字符串是我们每次提交的commit id(版本号),Git的commit Id是一个SHA1计算出来的一个非常大的数字,用十六进制表示。
如果嫌git log一次性输出信息太多,可以加上--pretty=oneline:
经过上面两次提交,我们查看.git目录下发生什么变化:
- 我们发现新增了暂存区index,add后的内容就是添加到这里的。
- HEAD指针指向的就是默认master分支
- 我们查看master,里面保存的其实就是当前最新的一个commit ID,即一个git对象。
objects为Git的对象库,里面包含了创建的各种版本库对象以及内容,当执行git add命令时,暂存区的目录树被更新,同时工作区修改的文件内容被写入到对象库中的一个新对象中,就位于".git/objects"目录下,我们可以观察下:
- 查找objects时,要将commit id分成两部分,其中前两位是文件夹名称,后38位是文件名称
- 找到这个文件之后,一般不能直接看到里面是什么,该文件是经过SHA(安全哈希算法)加密过的文件,我们可以使用 git cat-file -p + commit id 来查看
- 其中还有一行tree,我们可以使用同样方法查看
- 在查看ReadMe对应的commit ID,我们发现我们第二次提交时对其修改的内容被git记录下来
总结:在本地的git仓库中,有几个文件或目录很特殊
1. index : 暂存区,git add后会更新该内容
2. HEAD:默认指向master分支的一个指针。
3. refs/heads/master:文件保存当前master分支的最新commit id
4. objects: 包含了创建的各种版本库对象及内容,可以简单理解为存放了git维护的所有修改。
(2)场景2
这里我们先创建file4,再创建file5,将file4进行add存放到暂存区,这里显示只有一个文件改变了,不应是新增了两个文件吗?
我们应该弄清楚,git add只是将文件添加到暂存区,git commit是将暂存区内容添加到本地仓库中。我们并没有git add file5导致其没有在暂存区中维护,因此我们commit时只将已经在暂存区中的file4提交了,要想提交file5,只需对其再进行两板斧add commit即可。
修改文件
Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件。
我们之前说过,修改不仅仅是修改内容,新增一行,删除一行也是修改,甚至在工作区新增文件也是一个修改。
我们在工作区对ReadMe文件内容进行修改:
此时仓库中的ReadMe和工作区中的ReadMe是不同的,我们可以使用git status 查看在你上次提交之后是否对文件有再次修改:
注:git status只能查看哪个文件变化/修改,但不知道具体修改内容(对于大文件我们cat无法准确得知修改内容)
我们可以使用git diff [file] 命令显示暂存区和工作区文件的差异,显示的格式正式Unix通用的diff格式
zhuang@VM-8-14-ubuntu:~/gitcode$ git diff ReadMe
diff --git a/ReadMe b/ReadMe //a是改动前 b是改动后
index 8d0e412..05fe86c 100644
--- a/ReadMe //改动前
+++ b/ReadMe //改动后
@@ -1 +1,2 @@ //-1代表改动前第一行内容 原文件在第1行开始,并且原文件只有1行内容。
hello git //+1,2表示改动后从第一行开始,连续两行的内容 新文件从第1行开始,并且新增了1行,使得现在有2行内容。
+hello world
也可以使用git diff HEAD -- [file]来查看版本库和工作区文件的区别
此时我们把修改的ReadMe再git add会提示在暂存区修改了:
此时再commit即可:
版本回退
我们知道Git能够管理文件的历史版本,这也是版本控制器重要的能力,如果有一天你发现之前工作的内容出现很大问题,需要在某个特定的历史版本重新开始,此时就需要版本回退。
Git中用于版本回退的命令是git reset,可以指定退回某一次提交的版本。
我们之前的操作使得ReadMe存在两个版本,第一个版本只有一行内容Hello git,第二个版本新增了一行内容Hello world,git reset本质是将版本库中的内容进行回退,而工作区和暂存区是否回退取决于它的三个选项:【--soft】【--mixed】【--hard】
- --soft : 参数对于⼯作区和暂存区的内容都不变,只是将版本库回退到某个指定版本。
- --mixed选项:为默认选项,使⽤时可以不⽤带该参数。该参数将暂存区的内容退回为指定提交版本内容,工作区文件保持不变
- --hard:参数将暂存区与⼯作区都退回到指定版本。切记⼯作区有未提交的代码时不要⽤这个命令,因为工作区会回滚,你没有提交的代码就再也找不回了,所以
使⽤该参数前⼀定要慎重
我们使用--hard选项演示一下:
我们发现我们的三个区域都回退了,如果我们想反悔,可以使用之前打印的commit ID复原出file1 file2 file3。但这样做的前提是commit ID没有被清除
如果commit id被清除了呢?此时我们还可以使用命令git reflog查看本地记录的每一次提交id进行reset
注:这个55604d7其实是commit ID的一部分,也可以用来进行回退
思考一个问题 : Git版本回退的速度是比较快的,为什么呢?
Git在内部有个指向当前分⽀(此处是master)的HEAD指针, refs/heads/master⽂件⾥保存当前 master 分⽀的最新 commit id 。当我们在回退版本的时候,Git仅仅是给refs/heads/master中存储⼀个特定的version 。
撤销修改
(1)情况一:对于工作区的代码还没add
在原来基础上我们给ReadMe新增上一行内容:
此时我们如果想撤销工作区的内容,可以使用git checkout -- 撤销的文件名:它其实就是帮我们将工作区文件回到最近一次add/commit的状态(注意加上两杠)
当工作区的代码没有add时,我们可以使用两种方式进行撤销:
1. 手动使用Vim工具撤销 --- 对于这种方式我们不推荐,如果代码写了几天但一直没有add,此时修改容易出错
2. 我们推荐使用git checkout -- [filename]
(2)情况二:已经add,但是没有commit
我们先对ReadMe文件修改,新增一行内容,add之后使用git status查看状态:
此时我们可以使用的git reset作用更详细来说是回退到版本库的当前版本,我们可以使用--mixed选项先将暂存区回退到版本库的当前版本,再使用git checkout对工作区进行撤销:
补充:
git reset --mixed HEAD ReadMe //回退到当前版本
git reset --mixed HEAD^ //回退到上个版本 ^^是回退到上上个版本
(3)情况3:已经add,也已经commit
此时版本库是最新版本,此时可以使用git rest的--hard选项将三个区域都回退,但是前提是commit之后,没有push,撤销才有效。(实际公司开放跑的代码都是围绕远程仓库的,所以撤销主要目的是不影响远程仓库),Push操作是将版本从版本库->远程仓库。
演示:
准备工作
撤销
删除文件
rm是删除工作区的文件,但对于本地仓库并没有删掉,实际应该怎么删除呢?
此时就完成一个文件在工作区 暂存区 版本库的修改,我们总结一下删除文件的步骤:
1. rm --- 删除工作区内容
2. git add --- 提交工作区的变动
3. git commit --- 更新到版本库
git rm + 要删除文件 : 该命令帮我们删除工作区文件同时帮我们add,我们只需要commit即可
总结一下:
1. Git是一个版本控制器,跟踪的是版本的修改。
2. git init 创建本地仓库
3. git三板斧 : git add -> 工作目录放到暂存区 git commit 暂存区->版本库master git push 本地仓库->远程仓库
4. 版本回退:git reset,存在三个选项--soft --mixed --hard
5. 查看相关命令:git log 查看commit id , git status 查看仓库状态