版本库也叫仓库,英文名 repository。
创建版本库
之前我们说了版本库的概念:
存储版本的地方(存放各个版本之间差异的地方),通常称为版本库。通常版本库是以文件(夹)的形式存放在磁盘上:
- Git 是用一个目录来存储各个版本和差异的文件,目录名字为
.git
;- SVN 同理,用
.svn
目录来存储的- CVS 同理,用
.csv
目录来存储的一般情况下这几个目录是隐藏的(防止被随意的删除和修改等),在 Windows 上可以通过显示隐藏文件夹来查看,Linux 下可以用
ls -ah
命令查看
有了版本库,我们就可以跟踪里面所有的文件的改动,包括添加,修改和删除,并且可以追踪历史(什么时候被添加,修改了多少次,每次修改了什么),还可以还原到某个历史。
接下来我们来实践,也建议读者一起动手。
在 Git 中,创建一个版本库非常简单,新建一个文件夹(名字最好不要带有中文和空格),打开 cmd 或者 Git Bash,输入以下命令即可:
$ git init
或者同时创建文件夹并初始化:
$ git init demo
示例:
> mkdir LearnGit
> cd LearnGit
> git init
Initialized empty Git repository in D:/Projects/LearnGit/LearnGit/.git/
可以看到 Git 告诉我们已经创建好了版本库,并且是该仓库目前是空的(还没有管理任何文件)。
此时我们可以看到有一个.git 文件夹被创建了,这就是版本库,默认是隐藏的。
如果是 Linux 环境下,读者也可以使用 ls -ah
命令查看当前目录下有什么文件。
特别注意:如果你使用 Windows 系统,为了避免遇到各种莫名其妙的问题,请确保目录名(包括父目录)不包含中文和空格。
也不一定必须在空目录下创建 Git 仓库,选择一个已经有东西的目录也是可以的,但推荐用空目录开始练习,避免在学习过程中对那些文件有什么影响。
添加文件到版本库
将文件用版本库管理起来只需两步:
- 将文件添加到版本库
- 提交到版本库
实践:将刚刚我们演示 diff 和 patch 命令的文件添加到版本库里。我们创建 1-diffAndPath 文件夹,然后将文件挪到该文件夹里。此时的目录结构为:
LearnGit
└── 1-diffAndPath├── diff.txt├── hello.txt└── world.txt
那么开始第一步,使用 git add 文件名
来告诉 Git,添加文件到版本库
git add 1-diffAndPath/hello.txt
执行上面的命令,没有任何显示,这就对了,Unix 的哲学是“没有消息就是好消息”。
如果是在 Windows 下,可能会有如下警告(warning):
warning: LF will be replaced by CRLF in 1-diffAndPath/hello.txt.
The file will have its original line endings in your working directory这是说在版本库里,换行符会被替换为 CRLF;但我们自己的原始文件不会有影响,我们后续展开来说。如果你实在感兴趣并有一定的基础,可以参考这个回答:newline - LF will be replaced by CRLF in git - What is that and is it important? - Stack Overflow
第二步,我们就可以用 git commit
命令,告诉 Git,将文件提交到版本库:
> git commit -m "add diff and patch hello.txt"
[master (root-commit) abf2051] add diff and patch hello.txt1 file changed, 2 insertions(+)create mode 100644 1-diffAndPath/hello.txt
我们提交后,这次 Git 有好消息显示了:
1 file changed
:有一个文件被改动(添加也是一种改动)2 insertions(+)
:插入了 2 行内容(hello.txt 有 2 行)
其他消息我们暂且不表。
-m
参数后面是对本次提交的说明,这里我简单写了下添加一个文件。说明应该是有意义的,方便自己或其他人知道这次提交了什么内容,不建议随便输入说明,甚至不输入说明。
事实上,如果不使用-m 参数,是有报错的:Aborting commit due to empty commit message.
强烈建议使用 -m 参数,如果实在不想输入,请自行 Google,这里不演示这种不好的用法
为什么 Git 添加文件需要 add
,commit
一共两步呢?因为 commit
可以一次提交很多文件,所以你可以多次 add
不同的文件,比如:
> git add 1-diffAndPath/world.txt 1-diffAndPath/diff.txt
> git commit -m "add world.txt and diff.txt"
[master 0b3cfef] add world.txt and diff.txt2 files changed, 11 insertions(+)create mode 100644 1-diffAndPath/diff.txtcreate mode 100644 1-diffAndPath/world.txt
需要注意的是,版本库里的子文件夹下,也可以执行 git add 等命令。但如果不是在版本库里执行 git add 和 git commit 等命令,是没有意义的,因为都还没创建版本库。比如我们随便在一个没有创建版本库的地方执行:
> git add .
fatal: not a git repository (or any of the parent directories): .git
这个报错(fatal)是告诉我们,目前的文件夹并没有版本库,并且其所有父目录也没有版本库。
小技巧:
如果文件比较多,一个一个添加比较麻烦,可以使用 git add .
表示添加所有,然后再 commit;
或者直接一条命令解决:git commit -am
,注意该方式只适用于已被 git 追踪的文件(即文件至少提交过一次)。
版本库的状态:git status
我们在一个新的目录来演示。
$ mkdir 2-versionControl
$ cd 2-versionControl
我们新建一个文件,readme.txt,并准备以下内容:
$ touch readme.txt
$ echo "Git is a version control system" >> readme.txt
$ echo "Git is free software" >> readme.txt
$ cat readme.txt
Git is a version control system
Git is free software
我们介绍下 git status 命令,该命令可以让我们时刻掌握仓库当前的状态:
$ git status
On branch master
Untracked files:(use "git add <file>..." to include in what will be committed)./
结果显示,当前目录 ./
没有纳入 Git 来管理跟踪(Untracked )。
我们可以用 git add
命令来添加当前目录:
$ git add ./
然后我们再次查看仓库状态:
$ git status
On branch master
Changes to be committed:(use "git restore --staged <file>..." to unstage)new file: readme.txt
此时 Git 告诉我们添加了一个新文件(new file: readme.txt),并且可以被提交(Changes to be committed)。
我们来提交下:
$ git commit -m "wrote a readme file"
[master 0282c44] wrote a readme file1 file changed, 2 insertions(+)create mode 100644 2-versionControl/readme.txt
然后再次查看 Git 仓库状态:
$ git status
On branch master
nothing to commit, working tree clean
此时 Git 告诉我们,目前没有什么需要被提交的,工作目录是干净的(working tree clean,其他信息我们晚点再讲)
如果我们修改文件呢?例如修改 readme.txt 文件,改成如下内容:
Git is a distributed version control system.
Git is free software.
我们来看看仓库状态:
$ vim readme.txt$ cat readme.txt
Git is a distributed version control system
Git is free software$ git status
On branch master
Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git restore <file>..." to discard changes in working directory)modified: readme.txt
Git 告诉我们,readme.txt 被修改了( modified: readme.txt),但还没准备提交(Changes not staged for commit)。
比较差异:git diff
有时候,我们需要比较下当前版本和上一个版本的差异(比如你度蜜月回来,已经记不清上次改了什么),此时我们就可以用 git diff 命令了:
$ git diff readme.txt
diff --git a/2-versionControl/readme.txt b/2-versionControl/readme.txt
index f7249b8..2fdf0c4 100644
--- a/2-versionControl/readme.txt
+++ b/2-versionControl/readme.txt
@@ -1,2 +1,2 @@
-Git is a version control system
+Git is a distributed version control systemGit is free software
可以看到,git diff 命令的输出,和我们之前讲的 diff 命令的输出很像,这里就不再一一说明了。通过输出我们可以看到,第一行被修改了,添加了一个 distributed
单词。
此时我们可以继续提交:
$ git add readme.txt$ git status
On branch master
Changes to be committed:(use "git restore --staged <file>..." to unstage)modified: readme.txt$ git commit -m "add distributed word"
[master 750360e] add distributed word1 file changed, 1 insertion(+), 1 deletion(-)
深入 Git diff
-
git diff
比较的是工作区和暂存区的所有差别git diff -- 文件名
:查看具体某个文件 在工作区和暂存区之间的差异git diff -- 文件名1 文件名2 文件名3
:查看多个文件在工作区和暂存区之间的差异
-
git diff --cached
比较的是暂存区和版本库的差别 -
git diff HEAD
可以查看工作区和版本库的差别 -
git diff --name-status
:仅查看被修改的文件名和状态。有时候我们只想知道哪些文件被修改了,不想知道修改了什么,可以使用这个命令。
我们来演示下。首先创建一个 txt,并添加和提交到版本库
$ echo "test diff" > 4-diff/testDiff.txt
$ git add .
$ git commit -m "add testDiff.txt"
我们修改下该文件:
$ echo "test diff" >> 4-diff/testDiff.txt
然后使用 git diff
查看
$ git diff 4-diff/testDiff.txt
diff --git a/4-diff/testDiff.txt b/4-diff/testDiff.txt
index b69a2df..47bb840 100644
--- a/4-diff/testDiff.txt
+++ b/4-diff/testDiff.txt
@@ -1 +1,2 @@test diff
+test diff
此时我们使用 git diff HEAD
,和上面的输出一样。
此时由于我们还没添加到暂存区,使用 git diff --cached 是没有输出的。我们添加到暂存区后再次查看:
$ git diff --cached 4-diff/testDiff.txt$ git add .$ git diff --cached 4-diff/testDiff.txt
diff --git a/4-diff/testDiff.txt b/4-diff/testDiff.txt
index b69a2df..47bb840 100644
--- a/4-diff/testDiff.txt
+++ b/4-diff/testDiff.txt
@@ -1 +1,2 @@test diff
+test diff
此时再使用 git diff HEAD
,就没有输出了,说明版本一致。
我们来看看–name-status 参数:
$ echo "fuck" >> fuck
$ git add fuck
$ echo "echo" >> ./3-branch/branch.txt
$ git diff head --name-status
M 3-branch/branch.txt
A fuck
可以看到输出了文件名,并且前面有个字母:M 指修改,A 指添加,D 指删除
查看某个文件的修改记录
使用 git blame 文件名
,可以看到某个文件的修改记录,包括修改用户,修改时间等;:
$ git blame 3-branch\branch.txt
dd140df7 (peterjxl 2023-01-14 16:27:11 +0800 1) Creating a new branch is quick and simple
8f876055 (peterjxl 2023-01-14 16:55:07 +0800 2) test no fast forward
17942124 (peterjxl 2023-01-14 20:06:01 +0800 3) test cherry-pick
00000000 (Not Committed Yet 2023-01-15 10:05:59 +0800 4) test
练习
将 readme.txt 文件修改如下,并提交:
Git is a distributed version control system.
Git is free software distributed under the GPL.
答案(仅供参考):
$ vim readme.txt$ cat readme.txt
Git is a distributed version control system
Git is free software distributed under the GPL.$ git add readme.txt$ git commit -m "append GPL word"
[master efc9138] append GPL word1 file changed, 1 insertion(+), 1 deletion(-)
小结
本文我们介绍了以下几个概念
- 创建版本库:
git init
- 将文件添加到版本库:
git add
,可添加多个文件git add 文件名1,文件名2
,添加所有文件git add .
- 提交:
git commit -m 提交说明
- 查看版本库的状态:
git status
- 比较文件的差异:
git diff