1、Git所涉及的四大区域
先开宗明义的给大家看这个图,然后再依据这个图,用a.c, b.c这两个文件作为例子来一一详解git的工作流程。
- 1、工作区域:就是a.c,b.c文件所在的地方,用户可以任意对文件进行增删改除。通过git add可以将文件提交到暂存区。
- 2、暂存区:Staging Area,它有两个功能,其一是作为工作区连接git管理区域的第一站,其二是可以跟踪所有tracked files(后面再解释)的状态。使用git reset指令可以将工作区提交的文件退回给工作区。
- 3、本地仓库:Local Repository,git管理下的本地仓库通常会有很多个版本,每git commit一次就会产生的一个新的版本。本地仓库记录着文件的提交信息,也是连接远程仓库的桥梁。同时可以通过git reset来回溯以前的版本。
- 4、tracked files:在使用git的过程中,有一个很重要的概念就是tracked file。它是指一个文件被git标记,并且追踪起状态。比如“git add a.c”这条命令执行之后,a.c这个文件就会被标记为tracked file,此时如果再修改a.c的内容,或者删除a.c,暂存区都会记录下这一变化。当然你也可以用“git rm a.c --cache”这个指令,让a.c摆脱追踪,当然,如果这个文件还没有被提交到本地仓库,那么它就被提出git管理的区域。
最后,想真的理解git,还是得跳到第六小节。
2、语法说明
被”< >“和"[ ]“包含起来的内容表示用户自己选定的参数。但”< >“是要求用户必须输入的,而”[ ]"表示用户可以根据自己的需要选择输入。
比如git reset的语法是这样的:
git reset commit <commitid> --[option]
其中commitid指的是commit id,可以理解为每一提交到本地仓库之后该仓库状态的ID,利用这个ID我们可以快速定位到某个状态。
那么以下两个种方式都是合理的:
git reset commit 7b0dcac
git reset commit 7b0dcac --soft
3、本地仓库相关操作
建立一个git文件(git init)
用git Bash进入一个新的文件夹,输入以下命令可以建立一个git文件。
git init
查看一下是否有.git文件
把工作区的文件添加到暂存区(git add)
git add <object_file>
把暂存区的文件添加到本地仓库(git commit)
方法一:提交之后再进入vim编辑器写入这次提交的备注
git commit
方法一:提交的同时写入备注
git commit -m <"any information you wanna write.">
查看暂存区和本地仓库中的文件(git ls-files)
git ls-files
查看文件夹下所有文件的状态(git status)
git status
查看版本库中的提交记录(git log)
版本库即本地仓库。
方法一:直接查看提交记录的完整信息
git log
箭头所指的是每次提交更新之后本地仓库状态的哈希值,也可以理解该时间点本地仓库状态对应的ID,用的时候经常拿一部分来用即可。
方法二:查看部分重要信息
git log --oneline
红框内是哈希值的前N位,一般用这个来对应每一个的提交信息即可。
恢复的文件(git checkout)
- 在工作区中的文件被修改之后,却想要恢复到修改前的状态,但还未提交到暂存区和本地仓库。
git checkout <object_file>
注:git checkout默认只是恢复到上一次的状态,如果想要恢复到更久以前的状态,请继续往下看。再者,这一小节的修改,不仅指修改了文件,还可以指文件被删除了。
- 在工作区中的文件被修改之后,却想要恢复到修改前的状态,但已经提交到暂存区和本地仓库。
- 在工作区中的文件被修改之后,却想要恢复到以前的某个状态,但已经提交到暂存区和本地仓库。
git checkout commit <commitid> <object_file>
注:这里的ID即是第N次提交记录的哈希值。该指令可以把object_file文件恢复到第N次提交时候的状态。
版本退回(git reset)
版本退回有三种方式,分别是soft, hard, mixed。其中的mixed也是默认(default)的方式。
默认的方式下,本地仓库的记录会退回到之前的某个时间点。但工作区和暂存区保持不变。
git reset <commitid>
soft的方式下,本地仓库和暂存区的状态会退回到之前的某个时间点。但工作区保持不变。
git reset <commitid> --soft
soft的方式下,本地仓库、暂存区和工作区的状态都会退回到之前的某个时间点。
git reset <commitid> --hard
用git reset --hard,打个比方。比如你在早上8:00向本地仓库提交了一次更新,版本库记录这次更新后的状态ID为123456。接着你继续工作到中午12:00,但此时你发现你早上的工作方向全错了,想要恢复早上8:00时的文件状态,就可以使用git reset 123456 --hard。
查看本地仓库文件和暂存区文件中的内容(git show)
查看暂存区中文件的内容。
git show :<object_file>
查看本地仓库里某次状态下的文件内容。
git show <commitid>:<object_file>
文件差异对比(git diff)
1、对比工作区和暂存区文件的差异
git diff [object_file]
可以看到这里的object_file是被”[ ]“包含起来的,说明这个参数可写也可不写,不写的话表示对比所有文件的差异,写则表示只对比某个文件的差异。
2、对比工作区和本地仓库文件内容之间的差异
git diff <commitid> [oject_file]
3、对比本地仓库中两个版本的差异
git diff <commitid> <commitid> [object_file]
4、对比两个文件之间的差异
git diff <object_file_1> <object_file_2>
忽略文件(.gitignore)
在一个项目中,经常会生成一些中间文件,比如C++在Windows编译之后有一个.exe文件,而这些文件我们并不希望它被上传到本地仓库中。那么,我们就可以利用.gitignore文件去隐藏那些我们不希望上传的文件。
第一步:创建一个.gitignore文件
vim .gitignore
第二步:在.gitignore文件里写入我们希望被忽略的文件名。(比如所有的.exe文件)
echo *.exe -> .gitignore
4、SSH简介(密钥,GitHub)
在传统的网络通信当中,访问一个网站存在被第三方截取数据的风险,更甚至当你以自己的用户名和密码登录该网站的时候,这些信息也有可能被窃取。于是为了规避这种风险,人们提出了ssh。
SSH(Secure Shell): 一种网络安全协议,让信息以加密的形式进行传输。具体体现为ssh通信依赖公钥和私钥这两把钥匙来加密和解析数据。
无论是公钥还是私钥都由本地计算机生成,然后本地计算机会把公钥发给目标服务器。目标服务器所发送的信息都会用公钥进行加密,当收到信息之后,本地计算机再用私钥进行数据解析。由于公钥加密的信息只能用私钥进行解析,而私钥一直存在于本地PC之中,所以不可能被第三方通过网络窃取。通过这种设置,即便第三方通信数据,也因为只有一把钥匙而无法解析。
以上只是一些关于SSH的粗略理解,事实上公钥私钥只用于SSH握手过程的相互确认身份,具体的信息传递还是其他一些加密方法。
在本地生成公钥和私钥
进入git bash
第一步,切换到根目录且进入.ssh文件夹。
cd ~
cd .ssh
第二步,生成密钥。
sshtest-keygen -t rsa -b 4096
第三步,输入密钥的名称(例如test)。
第四步,输入密码。
通过这个这两部操作,会生成test和test.pub两个文件,前者是私钥文件,后者是公钥文件。
第五步,创建config文件,指定使用该密钥文件来认证GitHub。
tial -5 config
最后一步,进入test.pub文件,复制公钥添加在GitHub中。
在GitHub中添加公钥
通过上一个步骤,我们获取了本地计算机生成的公钥。接下来进入GitHub添加公钥。
如图,先进入GitHub页面,点击自己的头像,再点击Settings…
通过以上的操作,我们就为建立本地仓库和远程仓库的连接打下了基础。
5、远程仓库(GitHub)相关操作
5.1、本地仓库和GitHub建立连接
举个例子,我配置好公私钥之后,再和GitHub的某个仓库建立连接。
git remote add origin git@github.com:hyq123-cmd/single-reactor.git
- origin:给GitHub对应的项目仓库起一个origin的别名。当然你也可以起其它别名。
- git@github.com:hyq123-cmd/single-reactor.git:按下面图示操作复制即可。
操作完之后可以通过下面指令查看有没有成功连接。
git remote -v
5.2、下载GitHub上的代码(git clone/git pull)
5.2.1、下载别人的代码
下载GitHub上的代码可以通过命令行的方式,也可以通过网页点击的方式。网页点击则相对简单,如图,直接点击Download ZIP即可以下载相应的压缩包。
命令行的方式则有三种,HTTPS, SSH, GitHub CLI。这三种方式只是复制对应的链接,然后在git bash输入命令行即可。
git clone <link>
在我们克隆(clone)别人的仓库之后,也可以用git log去查看作者的修改记录。
5.2.2、下载自己仓库的代码
如果你和某个GitHub项目的仓库建立连接,其实可以直接用git pull下载下来。同时git pull也可以用于拉取被更新的代码(别人和自己的都可以)。
5.3、上传修改的代码(git push)
我们在本地修改代码并添加到本地仓库之后可以用git push命令来将代码上传到GitHub上。但这不意味着你可以随随便便的将自己的代码push到别人的仓库中,一般而言需要得到作者的许可。而对于自己的仓库,GitHub会通过用户名或ssh的密钥来自动匹配你的权限。
git push origin master:main
- origin:前面提到的仓库别名
- master:main:我的Linux上git的版本比较老,所以得用master来指代本地的分支,如果版本高的话,可以直接输入 git push origin main。
6、git更内核的东西(真正的理解git)
其实暂存区和本地仓库都是人为创造的区域,只是便于用户理解罢了。但由于git的运行内核并不真的是这么划分的,所以经常会遇到很多无法理解的问题。如果理解git的内核,那这些问题就迎刃而解了。
进入.git文件下的object目录
cd ./git/objects
会看到许多文件,如图。
这些文件的名称都其实都是哈希值,而这些文件分为三类,分别是blob, tree, commit。关系图如下。
红色箭头表示指针指向,黑色箭头则表示依赖关系。比如tree指向blob的箭头,意味着tree文件存放指向blob的指指针。也blob指向commit(3.0)则意味着commit(3.0)是依据blob生成的。
- blob:存放数据的文件,一般而言,一个文件对应一个blob。比如我用命令git add a.c b.c之后,就会在objects目录下生成两个blob,分别用于存放a.c和b.c的数据。
- tree:存放指向blob的指针。
- commit:存放用户的信息以及用户的提交信息,并且指向tree的文件的指针。
工作流程(以a.c为例):
git add a.c
执行完上面语句之后,.git/objects目录下会生成一个装门用于存放a.c数据的blob。
git commit -m "add a.c file"
执行完上面语句之后,.git/objects目录下会生成一个tree和一个commit文件,tree文件存放执行blob的指针,commit文件记录者提交者的信息和提交信息——“add a.c file”,同时存放着指向tree文件的指针。因此我们可以根据commit文件查看到blob的内容。即看到a.c里面写啥。
git add b.c
执行完上面语句之后,.git/objects目录下会生成一个装门存放用户b.c数据的blob。
rm b.c
执行完上面语句之后,b.c文件会从工作区域消失。但.git/objects目录下会那个一个装门用于存放b.c数据的blob还是存在。所以此时,你可以通过git checkout b.c将b.c文件从工作区域恢复。
git rm a.c
执行上面语句之后,a.c文件会从工作区域消失,并且也不会被追踪。但是.git/objects目录下会那个一个装门用于存放a.c数据的blob还是存在。所以可以通过git reser+版本后id,将a.c文件找回。