创建版本库

  1. 选择一个合适的地方,创建一个空目录:
bash
$ mkdir learngit
$ cd learngit
$ pwd
/Users/michael/learngit
  1. 通过git init命令把这个目录变成Git可以管理的仓库:
bash
$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/

在文件夹目录下面会出现一个 .git 的目录,这个目录的作用是Git来跟踪版本管理库的,对于该文件夹下面的文件修改要慎重,盲目修改可能会导致版本库出现问题。
如果你没有看到.git目录,那是因为这个目录默认是隐藏的,用ls -ah命令就可以看见。
也不一定必须在空目录下创建Git仓库,选择一个已经有东西的目录也是可以的。

将文件提交到仓库的步骤

  1. 用命令git add告诉Git,把文件添加到仓库:
bash
$ git add readme.txt

执行上面的命令,没有任何显示,这就对了,Unix的哲学是“没有消息就是好消息”,说明添加成功。

  1. 用命令git commit告诉Git,把文件提交到仓库
bash
$ git commit -m "wrote a readme file"
[master (root-commit) eaadf4e] wrote a readme file
1 file changed, 2 in
sertions(+)
create mode 100644 readme.txt

git commit命令,-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。
git commit命令执行成功后会告诉你,1 file changed:1个文件被改动(我们新添加的readme.txt文件);2 insertions:插入了两行内容(readme.txt有两行内容)。

为什么Git添加文件需要add,commit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:

bash
$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."

版本回退

git status
git status 命令可以让我们时刻掌握仓库当前的状态

bash
$ git status
On branch master
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: readme.txt

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

上面的命令输出告诉我们,readme.txt被修改过了,但还没有准备提交的修改。

git diff
git diff顾名思义就是查看difference,显示的格式正是Unix通用的diff格式.

bash
$ git diff readme.txt
diff --git a/readme.txt b/readme.txt
index 013b5bc..2ec0ed2 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
-Git is a distributed version control system.
+Git is a perfect distributed version control system.
Git is free software.
\ No newline at end of file

从上面的命令可以看出。我们在第一行中添加了一个单词 perfect
当知道了对readme.txt作了什么修改后,再把它提交到仓库就放心多了。

提交修改和提交新文件是一样的两步:
第一步是git add:

bash
$ git add readme.txt

命令在执行之后同样没有任何提示。不过我们可以通过 git status 命令来了解到当前仓库的存在。

$ git status  
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

modified: readme.txt

提交后,我们再用git status命令看看仓库的当前状态:

bash
$ git status
On branch master
nothing to commit, working tree clean

Git告诉我们当前没有需要提交的修改,而且,工作目录是干净(working tree clean)的。

git log
git log命令显示从最近到最远的提交日志,我们可以看到3次提交,最近的一次是append GPL,上一次是add distributed,最早的一次是wrote a readme file
加上–pretty=oneline参数: 可以减少输出信息。

bash
$ git log --pretty=oneline
d304540b814243a41ce9ce1c2ad802326dde7b7b (HEAD -> master) append GPL
ba4ce482d04b936b123b31e0152174241f53f2d5 succeed in deleting lhg.txt and t
lhg.top.txt
9a4d1e5895a6f8485c54bf9010f097bf7742989f add perfect distributed and delet
e tlhg.top.txt
94d7ce607d4e75423ab46b49ef25f495c733e898 wrote a tlhg.top file
98cfd639681054d4a790a28b758f7c125f423a3a wrote a readme file

git log 的退出方法: 输入字母Q即可退出.

git reset
git reset命令:把当前版本回退到上一个版本add distributed.

bash
$ git reset --hard ba4ce482d04b
HEAD is now at ba4ce48 succeed in deleting lhg.txt and tlhg.top.txt

git reflog
Git提供了一个命令git reflog用来记录你的每一次命令: 想恢复到新版本,可以通过git reflog 找到新版本的commit id

bash
$  git reflog
ba4ce48 (HEAD -> master) HEAD@{0}: reset: moving to ba4ce482d04b
d304540 HEAD@{1}: commit: append GPL
ba4ce48 (HEAD -> master) HEAD@{2}: commit: succeed in deleting lhg.txt and tlhg.top.t
xt
9a4d1e5 HEAD@{3}: commit: add perfect distributed and delete tlhg.top.txt
94d7ce6 HEAD@{4}: commit: wrote a tlhg.top file
98cfd63 HEAD@{5}: commit (initial): wrote a readme file

总结:

HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id。

穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。

要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

工作区和暂存区

工作区(Working Directory)
就是你在电脑里能看到的目录,比如我的learngit文件夹就是一个工作区:

版本库(Repository)
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。

把文件往Git版本库里添加的时候,是分两步执行的:

第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当 前分支。

因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。

现在测试一下:

  1. 先对readme.txt做个修改,比如加上一行内容:
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
  1. 然后,在工作区新增一个LICENSE文本文件(内容随便写)。
    先用git status查看一下状态:
$ 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

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

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

Git非常清楚地告诉我们,readme.txt被修改了,而LICENSE还从来没有被添加过,所以它的状态是Untracked。

现在,使用两次命令git add,把readme.txt和LICENSE都添加后,用git status再查看一下:

$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: LICENSE
modified: readme.txt

现在,暂存区的状态就变成这样了:

所以,git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit就可以一次性把暂存区的所有修改提交到分支。

$ git commit -m "understand how stage works"
[master acc5181] understand how stage works
2 files changed, 3 insertions(+), 1 deletion(-)
create mode 100644 LICENSE

一旦提交后,如果你又没有对工作区做任何修改,那么工作区就是“干净”的:

$ git status
On branch master
nothing to commit, working tree clean

现在版本库变成了这样,暂存区就没有任何内容了:

撤销修改

git checkout = git switch + git restore

git checkout -- file 可以撤销修改,丢弃在工作区的修存在两种情况。

  1. 一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;

  2. 一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。

总之,就是让这个文件回到最近一次git commit或git add时的状态。

现在举例说明上述两种情况:

第一种情况:文件修改后还没有被放到暂存区

修改过的文件(添加了最后一行):

$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
My stupid boss still prefers SVN.

git status 观察一下情况 (修改后)

$ 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 checkout -- readme.txt

git status 观察一下情况(撤销后)

$ git status
On branch master
nothing to commit, working tree clean
````

撤销后文件内容(添加的最后一行被删除):

$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.



第一种情况:文件修改后还已经被放到暂存区

修改过的文件(添加了最后一行):

$ cat readme.txt
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
My stupid boss still prefers SVN.


将修改的文件提交到暂存区:

git add readme.txt


`git status` 查看(在 `commit` 之前)

$ git status
On branch master
Changes to be committed:
(use “git restore --staged …” to unstage)
modified: readme.txt

可以看到,修改只是提交到了暂存区,还没有提交。  

现在让我们测试一下撤销修改的命令

$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt

`git reset`命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。  

`git status` 观察一下情况(撤销后)

$ git status
On branch master
Changes not staged for commit:
(use “git add …” to update what will be committed)
(use “git restore …” to discard changes in working directory)
modified: readme.txt

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

现在暂存区是干净的,工作区有修改:  

之后撤销工作区的修改:

$ git checkout – readme.txt

$ git status
On branch master
nothing to commit, working tree clean

使用`git status`查看,发现工作目录是干净的。  

总结:
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。

场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD <file>,就回到了场景1,第二步按场景1操作。

场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。


## 删除文件

在Git中,删除也是一个修改操作,我们实战一下,先添加一个新文件test.txt到Git并且提交:

$ git commit -m “add test.txt”
[master 4b29612] add test.txt
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test.txt


这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了:

$ git status
On branch master
Changes not staged for commit:
(use “git add/rm …” to update what will be committed)
(use “git restore …” to discard changes in working directory)
deleted: test.txt

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

2020-09-27

⬆︎TOP