如果第一次学习 Git ,请先阅读博主的上篇文章——Git 详细教程之一: Git 简介及其基本工作原理。本篇博客主要讲的是『Git 安装配置及其常用命令』。
一、Git 的下载安装
Git 的下载推荐进入官网下载,安装过程可无脑下一步。
初次安装好 Git,我们就可以打开『Git Bash』使用命令行的方式进行文件的版本控制了。如果需要将 Git 命令映射到『cmd』中,用『cmd』命令行的方式运行 Git ,具体的映射方法其实很简单,将『Git 安装路径下的 cmd 文件夹路径』加入到环境变量中的『path』中即可。
二、Git 的基本配置
Git 自带一个『git config』的工具来帮助设置控制 Git 外观和行为的配置变量。 这些变量存储在三个不同的位置:
/etc/gitconfig
文件: 包含系统上每一个用户及他们仓库的通用配置。 如果在执行 git config 时带上 --system 选项,那么它就会读写该文件中的配置变量。 (由于它是系统配置文件,因此你需要管理员或超级用户权限来修改它。)~/.gitconfig
或~/.config/git/config
文件:只针对当前用户。 你可以传递--global
选项让 Git 读写此文件,这会对你系统上 所有 的仓库生效。- 当前使用仓库的 Git 目录中的 config 文件(即
.git/config
):针对该仓库。 你可以传递--local
选项让 Git 强制读写此文件,虽然默认情况下用的就是它。
注意: 每一个级别会覆盖上一级别的配置,所以 .git/config
的配置变量会覆盖 /etc/gitconfig
中的配置变量。
2.1 查看所有配置及其所在的文件
git config --list --show-origin
2.2 配置用户签名
安装完 Git 之后,要做的第一件事就是设置你的用户名和邮件地址,即用户签名。签名的作用是区分不同操作者的身份。Git 首次安装必须设置一下用户签名,其会写入到每次提交代码中去,因此若提前没设置好会导致无法提交代码。
git config --global user.name 用户名
git config --global user.email 用户邮箱地址
注意: 如上所示,使用了 --global
选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 --global
选项的命令来配置。
2.3 检查已配置信息
如果想要检查你的配置,可以使用 git config --list
命令来列出所有 Git 当时能找到的配置。
$ git config --list
diff.astextplain.textconv=astextplain
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
http.sslbackend=openssl
http.sslcainfo=D:/Git/mingw64/ssl/certs/ca-bundle.crt
core.autocrlf=true
core.fscache=true
core.symlinks=false
pull.rebase=false
credential.helper=manager-core
credential.https://dev.azure.com.usehttppath=true
init.defaultbranch=master
注意: 你可能会看到重复的变量名,因为 Git 会从不同的文件中读取同一个配置(例如:/etc/gitconfig
与 ~/.gitconfig
)。这种情况下,Git 会使用它找到的每一个变量的最后一个配置。
另外,你可以通过输入 git config <key>
来检查 Git 的某一项配置:
$ git config user.name
PanyCG
三、Git 的常用命令
第三部分涵盖了在使用 Git 完成各种工作时将会用到的各种基本命令,包括配置并初始化一个仓库(repository)、开始或停止跟踪(track)文件、暂存(stage)或提交(commit)更改。
3.1 初始化本地库
进入到代码目录中,执行下面这条指令初始化本地仓库:
git init
该命令将创建一个名为 .git
的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件,这些文件是 Git 仓库的骨干。下面我们来粗略地讲解一下 .git
子目录下的文件内容,可能现在很难理解,后续讲到 Git 底层运行原理时会深入讲解。
- 新初始化的 .git 目录的典型结构如下:
config 文件
包含项目特有的配置选项;description 文件
仅供 GitWeb 程序使用,我们无需关心;HEAD 文件
指向目前被检出的分支;hooks 目录
包含客户端或服务端的钩子脚本(hook scripts);info 目录
包含一个全局性排除(global exclude)文件;objects 目录
存储所有数据内容;refs 目录
存储指向数据(分支、远程仓库和标签等)的提交对象的指针;
注意: 我们仅仅是做了一个初始化的操作,你的项目里的文件还没有被跟踪。
3.2 查看本地库状态
查看本地库状态的指令为:
git status
如果本地库为空库,即没有追踪任何文件也曾未提交过,并且文件夹内无任何文件,我们执行 git status
命令后,可以看到:
此时,Git 提示本地库的分支名称是“master”,这是默认的分支名, 分支 的知识后续会进行讲解。 并且该本地库未曾提交(commits)过任何东西,也没有任何东西可提交。
如果我们新建一个文件 test.cpp
,再执行 git status
,我们可以看到:
此时,Git 提示本地库未曾提交(commits)过,未追踪文件有 test.cpp
,同时没有任何东西可提交但存在为追中文件。此时,我们需要对文件夹中的文件进行追踪。
3.3 追踪新文件(添加到暂存区)
如果在一个已存在 文件 的文件夹(而非空文件夹)中进行版本控制,你应该开始追踪这些文件。 可以通过 git add
命令来指定所需的文件来进行追踪:
git add 文件名.后缀
注意: 工作目录下的每一个文件都不外乎这两种状态:已跟踪 或 未跟踪。
- 已跟踪文件 是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后, 它们的状态可能是未修改,已修改或已放入暂存区。简而言之,已跟踪的文件就是 Git 已经知道的文件。
- 未跟踪文件 是指工作目录中除已跟踪文件外的其它所有文件,它们既不存在于上次快照的记录中,也没有被放入暂存区。初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于 未修改 状态。
编辑过某些文件之后,由于自上次提交后你对它们做了修改,Git 将它们标记为 已修改 文件。 在工作时,你可以选择性地将这些修改过的文件放入暂存区,然后提交所有已暂存的修改,如此反复。
因此,现在已经得到了一个 存在被追踪文件但还未提交 的 Git 仓库。此时,执行 git status
可以看到,Git 提示我们未曾提交(commits)过,但存在未提交的更改项(changes)。
注意: git add
命令使用文件或目录的路径作为参数;如果参数是目录的路径,该命令将递归地跟踪该目录下的所有文件。
另外,Git 还提示可以使用 git rm --cached <file>
删除暂存区内的 <file>
文件,注意这里并不是指删除文件 <file>
,只是将它取消跟踪(unstage
)的意思。
3.4 忽略文件,不暂存
一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。 通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以创建一个名为 .gitignore
的文件,列出要忽略的文件的模式。 来看一个实际的 .gitignore
例子:
$ cat .gitignore
*.[oa]
*~
第一行告诉 Git 忽略所有以 .o
或 .a
结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的。 第二行告诉 Git 忽略所有名字以波浪符(~)结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存副本。 此外,你可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等。 要养成一开始就为你的新仓库设置好 .gitignore
文件的习惯,以免将来误提交这类无用的文件。
文件 .gitignore 的 格式规范 如下:
- 所有空行或者以
#
开头的行都会被 Git 忽略。 - 可以使用标准的
glob 模式
匹配,它会递归地应用在整个工作区中。 - 匹配模式可以以(/)开头防止递归。
- 匹配模式可以以(/)结尾指定目录。
- 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。
注意: 所谓的 glob 模式
是指 shell 所使用的简化了的正则表达式。
- 星号(*)匹配零个或多个任意字符;
- [abc] 匹配任何一个列在方括号中的字符 (这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);
- 问号(?)只匹配一个任意字符;
- 如果在方括号中使用短划线(-)分隔两个字符, 表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。
- 使用两个星号(**)表示匹配任意中间目录,比如 a/**/z 可以匹配 a/z 、 a/b/z 或 a/b/c/z 等。
我们再看一个 .gitignore 文件的例子:
# 忽略所有的 .a 文件
*.a
# 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a
# 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
/TODO
# 忽略任何目录下名为 build 的文件夹
build/
# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
doc/**/*.pdf
3.5 提交本地库,形成历史版本
在提交之前,请务必确认还有什么已修改或新建的文件还没有 git add
过, 否则提交的时候不会记录这些尚未暂存的变化,这些已修改但未暂存的文件只会保留在本地磁盘。 因此,每次准备提交前,先用 git status
看下,你所需要的文件是不是都已暂存起来了, 然后再运行提交命令 git commit
:
git commit
执行结果会自动启动你选择的文本编辑器来 输入提交说明,如果未输入退出将终止提交。
点击 i
进入插入模式,输入完毕后,点击 Esc
,并键盘输入 :wq
保存退出,即可提交成功。
此时已经创建了第一个提交! 可以看到,提交后 Git 会告诉我们,当前是在哪个分支(master)提交的,本次提交的完整 SHA-1 校验和(版本号)是什么(2dbd910 为前七位),以及在本次提交中,有多少文件修订过,多少行添加和删改过。
但是,上述的提交似乎有点繁琐,我们可以直接采用一下命令指定提交的版本信息(也成日志信息):
git commit -m "日志信息" 文件名
注意: 提交时记录的是放在暂存区域的快照,任何还未暂存文件的仍然保持已修改状态,可以在下次提交时纳入版本管理。 每一次运行提交操作,都是对你项目作一次快照,以后可以回到这个状态,或者进行比较。
此时,我们可以通过 git reflog
或者 git log
(详细查看用户签名)可以查看日志信息,可以看到有一次提交记录:
3.6 修改文件再次提交
为了模拟实战开发时文件内容发生改变后的 Git 用法,我们将原本的空文件 test.cpp
添加一些内容,执行 vim test.cpp
通过 vim 打开文件,输入以下内容保存退出。
此时,查看本地库状态如下:
可以看出,Git 提示我们 test.cpp
文件转变为 已修改
(modified)状态,且为未提交的更改,此时需要暂存这次更新,需要运行 git add
命令。 这是个多功能命令:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。将这个命令理解为“精确地将内容添加到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。
执行命令 git commit
提交到本地库,并查看提交日志如下:
3.7 撤销提交操作
在任何一个阶段,你都有可能想要撤消某些操作,并且有些撤消操作是不可逆的。 这是在使用 Git 的过程中,会因为操作失误而导致之前的工作丢失的少有的几个地方之一。
有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend
选项的提交命令来重新提交:
git commit --amend
这个命令会将暂存区中的文件提交。 如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执行了此命令), 那么快照会保持不变,而你所修改的只是提交信息。文本编辑器启动后,可以看到之前的提交信息。 编辑后保存会覆盖原来的提交信息。
例如,你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作:
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
最终你只会有一个提交——第二次提交将代替第一次提交的结果。
3.8 版本穿梭
版本穿梭用到的命令是:
git reset --hard 版本号
具体的实现方法是:
- Step 1:利用命令
git reflog
或者git log
查看版本日志; - Step 2:找到需要穿梭回去的版本号,比如想穿梭回第一次的本地库版本(2dbd910);
- Step 3:执行命令
git reset --hard 2dbd910
即可实现;
可以看到,穿梭成功后,日志会多加一条,且 HEAD
指针指向的版本号为第一次提交的本地库版本。此时,本地的 test.cpp
文件回到了空文件。
注意: Git 不仅仅可以往前面回溯版本,还可以实现往后穿梭,下面实现了从第一次提交的版本穿梭到第二次提交的版本上,此时本地的 test.cpp
文件又变回来了。