Git简易指南

Intro

Git 是一个开源的分布式版本控制系统,而 Github 则是目前全球最大的开源社区,那么何谓“版本控制”
版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统,使用Git可以对任何类型的文件进行版本控制。

不同于本地版本控制系统集中式版本控制系统分布式版本控制系统的优点在于其对文件丢失风险的规避能力。简而言之,分布式版本控制系统中的每个客户端,都具有完整的文件,即原始仓库的镜像

Basic Conception

在开始直接使用 Git 之前,得先了解一下 Git 内的基本概念🧐,了解这些概念会更好的理解 Git 的工作方式和原理。

Snapshots, Not Differences

如标题所言,(记录)快照,而不是差异。不同于其他版本控制系统的差异比较,Git 会将文件视作“快照”,每次提交更新后,Git 会对之前的文件制作一个快照并保存这个快照的索引,也就是说,Git 会将更新后的文件替换掉之前文件,同时,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件(快照)。

Nearly Every Operation Is Local

在 Git 中的绝大多数操作都只需要访问本地文件和资源,一般不需要来自网络上其他计算机的信息。因为,在本地保存着这个项目文件的镜像,你可以离线进行提交,并在网络状态良好的时候,在推送到主服务器上。

The Three States

Git 有三种状态,本地仓库内的文件可能处于其中之一:已提交(committed)、已修改(modified)和已暂存(staged)。

数据已经安全的保存在本地数据库中。

修改了文件,但还没保存到数据库中。

对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。

由此引入 Git 项目的三个工作区域的概念:Git 仓库、工作目录及暂存区域。
Working Area

Git 用来保存项目的元数据和对象数据库的地方,从其他计算机克隆仓库时,拷贝的就是这里的数据。

对项目的某个版本独立提取出来的内容,这些从 Git 仓库的压缩数据中提取出来的文件,放在磁盘上供用户使用或修改。

暂存区域是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中,有时也被称作“索引”。

基本的 Git 工作流程如下:

  1. 在工作目录中修改文件
  2. 暂存文件,将文件的快照放入暂存区域
  3. 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库内

How to use

Git 有多种使用方式,可以使用原生的命令行模式(推荐),也可以使用 GUI 模式,但只有在命令行模式下,才可以执行 Git 的所有命令。

Installing Git

针对不同的操作系统,Git 的安装方法也不相同,对于现在比较成熟的 Git 而言,不同安装方式所带来的功能上的差异已经不是那么明显。对于Windows用户而言,在 Git 官网上下载后安装即可。
其他方式这里不再做过多介绍。

First-Time Git Setup

安装好了 Git 之后,需要对 Git 环境做定量的定制化操作,每台计算机上只用配置一次,程序升级时会保留配置信息,也可以在任何时候再次通过运行命令来修改它们。

User Identity

当安装完 Git 后应该做的第一件事就是设置你的用户名称与邮件地址,后面的每一次提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改。

1
2
$ git config --global user.name "Bachzart"
$ git config --global user.email "whistlesilp@gmail.com"

如果使用了--global选项,那么该命令只需要运行一次,因为之后无论做任何事情,Git 都会使用那些信息。若像针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有--global选项的命令来配置。

User Editor

用户信息设置完毕后,可以配置默认文本编辑器,当 Git 需要你输入信息时会调用它。如果未配置,Git 会使用操作系统默认的文本编辑器。

1
$ git config --gloabl core.editor emacs

Checking

如何检查 Git 配置信息呢?可以使用如下命令来列出在当前目录下 Git 能找到的所有配置信息。

1
$ git config --list

可以得到如下所示结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
core.symlinks=false
core.autocrlf=true
core.fscache=true
color.diff=auto
color.status=auto
color.branch=auto
color.interactive=true
help.format=html
rebase.autosquash=true
http.sslcainfo=D:/Git/Git/mingw64/ssl/certs/ca-bundle.crt
http.sslbackend=openssl
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
credential.helper=manager
user.name=Bachzart
user.email=whistlesilp@gmail.com

Getting Help

Git 自带有说明文档,可以直接使用以下三个命令查找指定命令的使用说明,或百度、google。

1
2
3
$ git help <verb>
$ git <verb> --help
$ man git-<verb>

若想获得config命令的手册,执行

1
$ git help config

Summary

上面的内容介绍了 Git 是什么,Git 和其他版本控制系统的区别和基本用法等,接下来就开始使用吧~

Basic Usage

在熟悉了 Git 的基本概念和用法后,就可以开始使用了。

Getting a Git Repository

获取 Git 项目仓库的方法有两种:

  1. 在现有项目或目录下导入所有文件到 Git 中
  2. 从一个服务器克隆现有的 Git 仓库

Initializing a Repository in an Existing Directory

如果只想在本地通过 Git 来进行版本控制,那么在bash内进入到想要建立仓库的目录,通过以下命令就可以建立一个仓库了。

1
$ git init

此时,在这个本地目录下会自动产生一个“.git”的目录,这个就是 Git 管理信息的目录,在 Windows 下默认隐藏。

Cloning an Existing Repository

如果只是想获取一份网络上(或局域网服务器)已存在的 Git 仓库的拷贝,那么可以使用以下命令来将仓库克隆到本地。

1
$ git clone https://github.com/example

上述命令的格式为git clone [url]https://github.com/example这个url并不是真正的存在,这里只做说明使用。

此时在当前目录下会创建一个“example”的目录,并在这个目录下初始化一个.git目录,从远程仓库拉取下所有数据放入.git目录,然后从中读取最新版本的文件拷贝。如果想重命名克隆下来的本地仓库的名字,可以使用如下命令:

1
$ git clone https://github.com/example myexample

Local Repository

前面已经提到了如何在本地创建 Git 仓库,现在来使用一下 Git 的部分功能。

Checking the Status of Local Reposity

要查看当前目录下哪些文件处于什么状态,可以使用git status。以在本地新建的仓库为例,当使用git status命令时,会出现如下结果:

1
2
3
4
$ git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)

根据显示的英文的含义,可以得知当前目录下,没有文件,也无法进行提交,可以使用git add命令来跟踪文件。

Tracking a new file

现在,在仓库内创建一个新的test.c文件,在使用git status命令来查看当前目录的状态。

1
2
3
4
5
6
7
8
9
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)

test.c

nothing added to commit but untracked files present (use "git add" to track)

此时,在Untracked files下面,出现了test.c文件,这意味着 Git 在之前的快照(提交)中没有这些文件(实际上,目前还没有一次提交)。Git不会自动将文件纳入跟踪范围,所以需要使用git add [file name]命令来跟踪指定文件,如下所示:

1
2
3
4
5
6
7
8
$ git add test.c
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)

new file: test.c

此时,可以看到Changes to be committed这行下,存在new file: test.c,就说明test.c文件是已暂存状态(staged)了。另外,git add命令使用文件或目录的路径作为参数;如果参数是目录的路径,该命令将递归地跟踪该目录下的所有文件。

Staging Modified Files

紧接上面的步骤,若此时,修改了已暂存的test.c文件,此时使用git status命令,会看到如下结果:

1
2
3
4
5
6
7
8
9
10
11
12
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)

new file: test.c

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: test.c

这实际上就是 Git 的版本控制机制的特点—保存文件的快照而不是差异。也即是说,现在 Git 暂存区域内存储的文件是仍未修改的test.c,要暂存这次更新,需要再次使用git add命令来完成暂存,如下所示:

1
2
3
4
5
6
7
8
$ git add test.c
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)

new file: test.c

git status命令的输出十分详细,使用git status -sgit status --short可以得到更加紧凑的信息:

1
2
3
4
$ git status -s
A change.c
AM test.c
?? test.exe

新添加的未跟踪文件前面有??标记,新添加到暂存区域的文件前面有A标记,修改过的文件前面有M标记;当然,M的有两个可能的出现位置,出现在右边的M表示该文件被修改了但是还没放入暂存区,出现在左边的M表示该文件被修改并放入了暂存区。例如,上面的状态显示test.c文件在工作区被修改了,还未放入暂存区。

Ignoring Files

一般总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表,通常这类文件都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。此时,可以创建一个名为.gitignore的文件,列出要忽略的文件模式。

1
2
3
4
5
$ vim .gitignore
*.[oa]
*~
*.exe
*.txt

.gitignore文件的格式规范如下:

  • 所有空行或者以#开头的行都会被 Git 忽略
  • 可以使用标准的 glob 模式匹配
  • 匹配模式可以以/开头防止递归
  • 匹配模式可以以/结尾指定目录
  • 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号!取反

所谓的 glob 模式是指 shell 所使用的简化了的正则表达式,比如*就可以匹配零个或多个任意字符。

TIPS:GitHub有一个十分详细的针对数十种项目及语言的.gitignore文件列表,可以访问 https://github.com/github/gitignore 获取更多帮助。

Viewing Changes

git status命令输出的信息只对文件所处的状态进行了展示,可能觉得模糊,如果想知道具体改了什么地方,可以使用git diff命令。git diff命令会回答两个问题:

  1. 当前做的那些更新还没有暂存?
  2. 有哪些更新已经暂存起来准备好了下次提交?

git diff会通过文件补丁的格式在相应栏下显示具体哪些行发生了改变。
现在修改test.c文件,在文件中加入如下一行:

test.c
1
2
3
4
5
6
7
8
#include <stdio.h>

int main(int argc, char const *argv[]) {
printf("Hello Git!\n");
printf("I want to change this file.\n");
+ printf("Test git diff!\n");
return 0;
}

接下来,使用git diff命令查看修改的部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git diff
diff --git a/test.c b/test.c
index e0e5171..8642431 100644
--- a/test.c
+++ b/test.c
@@ -3,5 +3,6 @@
int main(int argc, char const *argv[]) {
printf("Hello Git!\n");
printf("I want to change this file.\n");
+ printf("Test git diff!\n");
return 0;
}
\ No newline at end of file

可以看到,Git 回显了文件更新区域的信息以及对应的更新内容,而此时,git diff比较的是工作目录中当前文件(未暂存)和暂存区域快照(已暂存)之间的差异,也就是修改之后还没暂存起来的变化内容。

使用git diff --cached/git diff --staged可以查看已暂存的将要添加到下次提交里的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ git diff --cached
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..e0e5171
--- /dev/null
+++ b/test.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char const *argv[]) {
+ printf("Hello Git!\n");
+ printf("I want to change this file.\n");
+ return 0;
+}
\ No newline at end of file

注意到上面并没有printf("Test git diff!\n");,那是因为,更新后的test.c文件并没有暂存。另外,git diff只能显示尚未暂存的改动,而不是自上次提交(commit)以来所作的所有改动。

Committing Changes

现在的暂存区与已经摸熟了,可以来愉快的提交了😊,不过正式使用仓库的时候,提交之前最好看看有没有什么记录没有暂存起来,可以先用git status命令看下,是不是都已暂存起来了,然后运行提交命令:

1
$ git commit

提交后,会跳入到 vi/vim 编辑器界面(不同系统可能不一致),基本上都是默认的提交消息,保存在.git目录下的COMMIT_EDITMSG文件内,开头的空行用来键入提交说明,其他#开头的都是注释,去掉与否取决于个人,也可以使用如下命令来简化提交:

1
2
3
4
5
6
$ git commit -m "Test Commit"
[master (root-commit) 88ba107] Test Commit
3 files changed, 18 insertions(+)
create mode 100644 .gitignore
create mode 100644 change.c
create mode 100644 test.c

注意,master表示当前提交是在master分支进行的提交,88ba107就是本次提交的完整 SHA-1 校验和,下面的信息表示本次提交中,有多少文件修订过,多少行添加和修改过。

使用git commit -a可以跳过提交之前先使用git add暂存文件(这些文件必须已经被暂存过)的步骤而直接提交。

Removing Files

要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域),然后提交。可以使用git rm命令完成此项工作,并连带的从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。

如果只是简单地从工作目录中手工删除文件,运行git status时就会在“Changes not staged for commit”部分(也就是未暂存清单)看到该文件的删除记录了。例如,在Test目录下,删除change.c文件,使用git status命令可以看到:

1
2
3
4
5
6
7
8
9
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

deleted: change.c

no changes added to commit (use "git add" and/or "git commit -a")

然后还需在运行git rm记录此次移除文件的操作:

1
2
3
4
5
6
7
8
$ git rm change.c
rm 'change.c'
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

deleted: change.c

这样下一次提交时,该文件就不再纳入版本管理了。

如果将文件保留在磁盘内,但是并不想让 Git 继续跟踪,可以使用--cached选项,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git rm --cached update.c
rm 'update.c'
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

deleted: update.c

Untracked files:
(use "git add <file>..." to include in what will be committed)

update.c

接着使用git commit命令提交后update.c文件就不在仓库内,但仍在磁盘上了。

Moving Files

Git 很聪明,一条移动文件的命令就能重命名文件并保留相同异名文件的状态,如下:

1
$ git mv file_from file_to

上述命令与下面三条命令类似:

1
2
3
$ mv file_from file_to
$ git rm file_from
$ git add file_from

使用一条命令干三件事,很棒吧~


Buy me a coffee ? :)
0%