Git & GitHub ——2:Git 基础命令

文章目录

Git 本地操作通过命令行来完成,比如执行git --version命令查看 Git 版本:

dang@DFLubuntu:~$ git --version
git version 2.27.0
dang@DFLubuntu:~$ 

尽管 Git 中有许多命令,但有三种等价的方法可以找到 Git 命令手册(manpage):

  • git help <verb>
  • git <verb> --help
  • man git-<verb>

比如执行git config --help获得 git config 命令详细手册。当然,命令详情内容是相当详细的,太长的可以重定向到一个文件中集中查看:

dang@DFLubuntu:~$ git config --help > man-config.txt
dang@DFLubuntu:~$ cat man-config.txt

当然也能执行git config -h获得 git config 命令可用选项的快速参考:

dang@DFLubuntu:~$ git config -h
用法:git config [<选项>]

配置文件位置
    --global              使用全局配置文件
    --system              使用系统级配置文件
    --local               使用仓库级配置文件
    --worktree            使用工作区级别的配置文件
    -f, --file <文件>     使用指定的配置文件
    --blob <数据对象 ID>  从给定的数据对象读取配置

操作
    --get                 获取值:name [value-regex]
    --get-all             获得所有的值:key [value-regex]
    --get-regexp          根据正则表达式获得值:name-regex [value-regex]
    --get-urlmatch        获得 URL 取值:section[.var] URL
    --replace-all         替换所有匹配的变量:name value [value_regex]
    --add                 添加一个新的变量:name value
    --unset               删除一个变量:name [value-regex]
    --unset-all           删除所有匹配项:name [value-regex]
    --rename-section      重命名小节:old-name new-name
    --remove-section      删除一个小节:name
    -l, --list            列出所有
    -e, --edit            打开一个编辑器
    --get-color           获得配置的颜色:配置 [默认]
    --get-colorbool       获得颜色设置:配置 [stdout-is-tty]

类型
    -t, --type <>         取值为该类型
    --bool                值是 "true""false"
    --int                 值是十进制数
    --bool-or-int         值是 --bool or --int
    --path                值是一个路径(文件或目录名)
    --expiry-date         值是一个到期日期

其它
    -z, --null            终止值是 NUL 字节
    --name-only           只显示变量名
    --includes            查询时参照 include 指令递归查找
    --show-origin         显示配置的来源(文件、标准输入、数据对象,或命令行)
    --show-scope          显示配置的作用域(工作区、本地、全局、系统、命令)
    --default <取值>      使用 --get 参数,当缺少设置时使用默认值

dang@DFLubuntu:~$ 

你还可以通过访问 Git Documentation页面来获取命令的详细内容。

通过上面的方法获取命令信息后就能自由使用了,比如执行git config --get user.name获取用户名

dang@DFLubuntu:~$ git config --get user.name
xiaolu2333
dang@DFLubuntu:~$ 

一,获取 Git 仓库

想要使用 Git 在本地完成项目开发,需要获取 Git 仓库,然后才能在 Git 本地仓库所在的工作目录中编辑项目。

通常有两种获取 Git 项目仓库的方式:

  • 将尚未进行版本控制的本地目录转换为 Git 本地仓库。
  • 从其它服务器克隆 一个已存在的 Git 远程仓库作为 Git 本地仓库。

(一)在已存的项目目录中初始化 Git 本地仓库:init

执行git init命令在已存的项目目录中初始化 Git 本地仓库:

dang@DFLubuntu:~$ mkdir git-tutorial
dang@DFLubuntu:~$ ls -l
总用量 44
drwxr-xr-x 2 dang dang 4096 116 00:40 公共的
drwxr-xr-x 2 dang dang 4096 116 00:40 模板
drwxr-xr-x 2 dang dang 4096 116 00:40 视频
drwxr-xr-x 2 dang dang 4096 116 00:40 图片
drwxr-xr-x 2 dang dang 4096 116 00:40 文档
drwxr-xr-x 3 dang dang 4096 116 01:27 下载
drwxr-xr-x 2 dang dang 4096 116 00:40 音乐
drwxr-xr-x 2 dang dang 4096 116 00:40 桌面
drwxrwxr-x 2 dang dang 4096 1114 13:59 git-tutorial
drwxrwxr-x 4 dang dang 4096 1114 01:14 projects
drwx------ 4 dang dang 4096 116 01:18 snap
dang@DFLubuntu:~$ cd  git-tutorial
dang@DFLubuntu:~/git-tutorial$ ls -l
总用量 0
dang@DFLubuntu:~/git-tutorial$ git init
已初始化空的 Git 仓库于 /home/dang/git-tutorial/.git/
dang@DFLubuntu:~/git-tutorial$ ls -la
总用量 12
drwxrwxr-x  3 dang dang 4096 1114 14:26 .
drwxr-xr-x 20 dang dang 4096 1114 13:59 ..
drwxrwxr-x  7 dang dang 4096 1114 14:26 .git
dang@DFLubuntu:~/git-tutorial$ tree .git
.git
├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

9 directories, 16 files
dang@DFLubuntu:~/git-tutorial$ 

可以看到,git-tutorial 项目中什么都还没有时,.git/的结构就是这样的,其中有一些目录和文件,这里简单介绍一下:

  • config配置文件:该文件主要记录针对该项目的一些配置信息,而且通过git remote add命令增加的远程分支的信息就保存在这里;实际上,Git 拥有三种级别的配置
dang@DFLubuntu:~/git-tutorial$ cd .git
dang@DFLubuntu:~/git-tutorial/.git$ cat config
[core]
	repositoryformatversion = 0
	filemode = true
	bare = false
	logallrefupdates = true
  • objects目录:主要包含 Git对象。1,Git中的文件和一些操作都会以 Git对象来保存,它分为 BLOB、tree 和 commit 三种对象。Git 通过 tree 对象(版本树)来组织各个 commit 对象(包含前面说的快照及一些与操作人员相关的记录,共同组成当前版本),具体就是让 HEAD 指向某个commit对象,而该commit对象又会指向几个 BLOB 对象(二进制格式的单个文件内容)或者tree 对象,从而达到通过版本树来组织各个版本的目的;2,objects文件夹中会包含很多的子目录,其中 Git对象保存在以其 SHA-1值的前两位为子目录、后38位为文件名的文件中;3,Git为了节省存储对象所占用的磁盘空间,会定期对Git对象进行压缩和打包,其中 pack 目录用于存储打包压缩的对象,而 info 目录用于从打包的文件中查找 Git对象。
  • refs目录:存储指向数据(分支)的提交对象的指针,用于实现 Git 引用。1, heads 目录存储本地每一个分支最近一次 commit 的 sha-1值(也就是 commit 对象的sha-1值);2,remotes 目录则记录你最后一次和每一个远程仓库的通信,Git 会把你最后一次推送到这个 remote 的每个分支的值都记录在这个文件夹中;3,tag 目录则是分支的别名。
  • HEAD文件:该文件指明了git branch(即当前分支)的结果,比如当前分支是 master,则该文件就会指向 master,但是并不是存储一个 master字符串,而是分支在 refs 中的表示,例如 ref: refs/heads/master。
  • hooks:定义了客户端或服务端的 hook 脚本,这些脚本用于在特定命令和操作之前、之后进行特殊处理。
  • description:仅供 GitWeb 程序使用。
  • logs:记录了本地仓库和远程仓库的每一个分支的提交信息,即所有 commit 对象都会被记录在此,这个文件夹内容应该是我们查看最频繁的。
  • info:其中保存了一份不希望在 .gitignore 文件中管理的忽略的全局可执行文件。
  • COMMIT_EDITMSG:记录了最后一次提交时的注释信息

因为每次提交时都要生成各种对象或文件内容,所以 .git/ 中的文件会因为几次提交就成倍的增长。

在这个时候,我们仅仅是在工作目录中做了一个初始化的操作,项目里啥都还没有。

另一种情况是,我们需要在一个已经拥有文件的项目中初始化 Git 本地仓库,命令都是一样的:

dang@DFLubuntu:~$ mkdir testproject
dang@DFLubuntu:~$ cd  testproject
dang@DFLubuntu:~/testproject$ ls -l
总用量 0
dang@DFLubuntu:~/testproject$ vim test.py
dang@DFLubuntu:~/testproject$ python -V
Command 'python' not found, did you mean:
  command 'python3' from deb python3
  command 'python' from deb python-is-python3
dang@DFLubuntu:~/testproject$ python3 -V
Python 3.8.10
dang@DFLubuntu:~/testproject$ python3 test.py
hello world
2021-11-14 17:01:32.700909
dang@DFLubuntu:~/testproject$ ls -l
总用量 4
-rw-rw-r-- 1 dang dang 76 1114 17:00 test.py

dang@DFLubuntu:~/testproject$ git init
已初始化空的 Git 仓库于 /home/dang/testproject/.git/
dang@DFLubuntu:~/testproject$ ls -la
总用量 16
drwxrwxr-x  3 dang dang 4096 1114 17:04 .
drwxr-xr-x 21 dang dang 4096 1114 17:03 ..
drwxrwxr-x  7 dang dang 4096 1114 17:04 .git
-rw-rw-r--  1 dang dang   76 1114 17:00 test.py
dang@DFLubuntu:~/testproject$ tree .git
.git
├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

9 directories, 16 files

一文讲透 Git 底层数据结构和原理
git底层原理,从常见操作解释git的底层原理,再也不怯

(二)克隆现有的仓库:clone

当你是在团队中开发时或者需要为开源项目作贡献时,大多数情况下我们都是直接把一个现有的远程仓库克隆克隆为 Git 本地仓库。比如执行git clone https://github.com/libgit2/libgit2克隆 Git 的链接库 libgit2 :

dang@DFLubuntu:~$ ls -l
总用量 48
drwxr-xr-x 2 dang dang 4096 116 00:40 公共的
drwxr-xr-x 2 dang dang 4096 116 00:40 模板
drwxr-xr-x 2 dang dang 4096 116 00:40 视频
drwxr-xr-x 2 dang dang 4096 116 00:40 图片
drwxr-xr-x 2 dang dang 4096 116 00:40 文档
drwxr-xr-x 3 dang dang 4096 116 01:27 下载
drwxr-xr-x 2 dang dang 4096 116 00:40 音乐
drwxr-xr-x 2 dang dang 4096 116 00:40 桌面
drwxrwxr-x 3 dang dang 4096 1114 14:26 git-tutorial
drwxrwxr-x 4 dang dang 4096 1114 01:14 projects
drwx------ 4 dang dang 4096 116 01:18 snap
drwxrwxr-x 3 dang dang 4096 1114 17:04 testproject
dang@DFLubuntu:~$ git clone https://github.com/libgit2/libgit2
正克隆到 'libgit2'...
remote: Enumerating objects: 113092, done.
remote: Counting objects: 100% (113092/113092), done.
remote: Compressing objects: 100% (32114/32114), done.
remote: Total 113092 (delta 80557), reused 111462 (delta 79011), pack-reused 0
接收对象中: 100% (113092/113092), 55.81 MiB | 17.85 MiB/s, 完成.
处理 delta 中: 100% (80557/80557), 完成.
正在更新文件: 100% (11419/11419), 完成.
dang@DFLubuntu:~$ ls -l
总用量 52
drwxr-xr-x  2 dang dang 4096 116 00:40 公共的
drwxr-xr-x  2 dang dang 4096 116 00:40 模板
drwxr-xr-x  2 dang dang 4096 116 00:40 视频
drwxr-xr-x  2 dang dang 4096 116 00:40 图片
drwxr-xr-x  2 dang dang 4096 116 00:40 文档
drwxr-xr-x  3 dang dang 4096 116 01:27 下载
drwxr-xr-x  2 dang dang 4096 116 00:40 音乐
drwxr-xr-x  2 dang dang 4096 116 00:40 桌面
drwxrwxr-x  3 dang dang 4096 1114 14:26 git-tutorial
drwxrwxr-x 16 dang dang 4096 1114 17:13 libgit2
drwxrwxr-x  4 dang dang 4096 1114 01:14 projects
drwx------  4 dang dang 4096 116 01:18 snap
drwxrwxr-x  3 dang dang 4096 1114 17:04 testproject
dang@DFLubuntu:~$ cd libgit2
dang@DFLubuntu:~/libgit2$ ls -la
总用量 200
drwxrwxr-x 16 dang dang  4096 1114 17:13 .
drwxr-xr-x 22 dang dang  4096 1114 17:13 ..
-rw-rw-r--  1 dang dang   267 1114 17:13 api.docurium
-rw-rw-r--  1 dang dang  1286 1114 17:13 AUTHORS
drwxrwxr-x  3 dang dang  4096 1114 17:13 ci
drwxrwxr-x  2 dang dang  4096 1114 17:13 cmake
-rw-rw-r--  1 dang dang  5021 1114 17:13 CMakeLists.txt
-rw-rw-r--  1 dang dang 57605 1114 17:13 COPYING
drwxrwxr-x  8 dang dang  4096 1114 17:13 deps
drwxrwxr-x  2 dang dang  4096 1114 17:13 .devcontainer
drwxrwxr-x  2 dang dang  4096 1114 17:13 docs
-rw-rw-r--  1 dang dang   334 1114 17:13 .editorconfig
drwxrwxr-x  2 dang dang  4096 1114 17:13 examples
drwxrwxr-x  3 dang dang  4096 1114 17:13 fuzzers
drwxrwxr-x  8 dang dang  4096 1114 17:13 .git
-rw-rw-r--  1 dang dang    49 1114 17:13 .gitattributes
-rw-rw-r--  1 dang dang  3101 1114 17:13 git.git-authors
drwxrwxr-x  3 dang dang  4096 1114 17:13 .github
-rw-rw-r--  1 dang dang    63 1114 17:13 .gitignore
-rw-rw-r--  1 dang dang  1169 1114 17:13 .HEADER
drwxrwxr-x  3 dang dang  4096 1114 17:13 include
-rw-rw-r--  1 dang dang  1312 1114 17:13 .mailmap
-rw-rw-r--  1 dang dang   281 1114 17:13 package.json
-rw-rw-r--  1 dang dang 16881 1114 17:13 README.md
drwxrwxr-x  2 dang dang  4096 1114 17:13 script
-rw-rw-r--  1 dang dang   601 1114 17:13 SECURITY.md
drwxrwxr-x  9 dang dang 12288 1114 17:13 src
drwxrwxr-x 55 dang dang  4096 1114 17:13 tests
drwxrwxr-x  2 dang dang  4096 1114 17:13 .vscode
dang@DFLubuntu:~/libgit2$ tree .git
.git
├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│       ├── heads
│       │   └── main
│       └── remotes
│           └── origin
│               └── HEAD
├── objects
│   ├── info
│   └── pack
│       ├── pack-179bbb01f6b14b240cfc776af96f0fdb6a5f3453.idx
│       └── pack-179bbb01f6b14b240cfc776af96f0fdb6a5f3453.pack
├── packed-refs
└── refs
    ├── heads
    │   └── main
    ├── remotes
    │   └── origin
    │       └── HEAD
    └── tags

16 directories, 25 files
dang@DFLubuntu:~/libgit2$ 

这会在当前目录下创建一个名为 libgit2 的目录,同时Git 会从这个远程仓库拉取下所有数据放入.git/,然后从中读取最新版本的文件的拷贝。发现没有,.git/本地仓库中的内容更多了,而且所有的项目文件已经在工作目录里面了。

当然你也能在克隆远程仓库的时候通过额外的参数自定义本地仓库的名字,比如执行git clone git@github.com:libgit2/libgit2.git mylibgit命令:

dang@DFLubuntu:~$ ls -l
总用量 52
drwxr-xr-x  2 dang dang 4096 116 00:40 公共的
drwxr-xr-x  2 dang dang 4096 116 00:40 模板
drwxr-xr-x  2 dang dang 4096 116 00:40 视频
drwxr-xr-x  2 dang dang 4096 116 00:40 图片
drwxr-xr-x  2 dang dang 4096 116 00:40 文档
drwxr-xr-x  3 dang dang 4096 116 01:27 下载
drwxr-xr-x  2 dang dang 4096 116 00:40 音乐
drwxr-xr-x  2 dang dang 4096 116 00:40 桌面
drwxrwxr-x  3 dang dang 4096 1114 14:26 git-tutorial
drwxrwxr-x 16 dang dang 4096 1114 17:13 libgit2
drwxrwxr-x  4 dang dang 4096 1114 01:14 projects
drwx------  4 dang dang 4096 116 01:18 snap
drwxrwxr-x  3 dang dang 4096 1114 17:04 testproject
dang@DFLubuntu:~$ git clone git@github.com:libgit2/libgit2.git mylibgit
正克隆到 'mylibgit'...
remote: Enumerating objects: 113092, done.
remote: Counting objects: 100% (113092/113092), done.
remote: Compressing objects: 100% (32114/32114), done.
remote: Total 113092 (delta 80557), reused 111462 (delta 79011), pack-reused 0
接收对象中: 100% (113092/113092), 55.81 MiB | 5.53 MiB/s, 完成.
处理 delta 中: 100% (80557/80557), 完成.
dang@DFLubuntu:~$ ls -l
总用量 56
drwxr-xr-x  2 dang dang 4096 116 00:40 公共的
drwxr-xr-x  2 dang dang 4096 116 00:40 模板
drwxr-xr-x  2 dang dang 4096 116 00:40 视频
drwxr-xr-x  2 dang dang 4096 116 00:40 图片
drwxr-xr-x  2 dang dang 4096 116 00:40 文档
drwxr-xr-x  3 dang dang 4096 116 01:27 下载
drwxr-xr-x  2 dang dang 4096 116 00:40 音乐
drwxr-xr-x  2 dang dang 4096 116 00:40 桌面
drwxrwxr-x  3 dang dang 4096 1114 14:26 git-tutorial
drwxrwxr-x 16 dang dang 4096 1114 17:13 libgit2
drwxrwxr-x 16 dang dang 4096 1114 17:27 mylibgit
drwxrwxr-x  4 dang dang 4096 1114 01:14 projects
drwx------  4 dang dang 4096 116 01:18 snap
drwxrwxr-x  3 dang dang 4096 1114 17:04 testproject
dang@DFLubuntu:~$ cd  mylibgit
dang@DFLubuntu:~/mylibgit$ ls -la
总用量 200
drwxrwxr-x 16 dang dang  4096 1114 17:27 .
drwxr-xr-x 23 dang dang  4096 1114 17:27 ..
-rw-rw-r--  1 dang dang   267 1114 17:27 api.docurium
-rw-rw-r--  1 dang dang  1286 1114 17:27 AUTHORS
drwxrwxr-x  3 dang dang  4096 1114 17:27 ci
drwxrwxr-x  2 dang dang  4096 1114 17:27 cmake
-rw-rw-r--  1 dang dang  5021 1114 17:27 CMakeLists.txt
-rw-rw-r--  1 dang dang 57605 1114 17:27 COPYING
drwxrwxr-x  8 dang dang  4096 1114 17:27 deps
drwxrwxr-x  2 dang dang  4096 1114 17:27 .devcontainer
drwxrwxr-x  2 dang dang  4096 1114 17:27 docs
-rw-rw-r--  1 dang dang   334 1114 17:27 .editorconfig
drwxrwxr-x  2 dang dang  4096 1114 17:27 examples
drwxrwxr-x  3 dang dang  4096 1114 17:27 fuzzers
drwxrwxr-x  8 dang dang  4096 1114 17:27 .git
-rw-rw-r--  1 dang dang    49 1114 17:27 .gitattributes
-rw-rw-r--  1 dang dang  3101 1114 17:27 git.git-authors
drwxrwxr-x  3 dang dang  4096 1114 17:27 .github
-rw-rw-r--  1 dang dang    63 1114 17:27 .gitignore
-rw-rw-r--  1 dang dang  1169 1114 17:27 .HEADER
drwxrwxr-x  3 dang dang  4096 1114 17:27 include
-rw-rw-r--  1 dang dang  1312 1114 17:27 .mailmap
-rw-rw-r--  1 dang dang   281 1114 17:27 package.json
-rw-rw-r--  1 dang dang 16881 1114 17:27 README.md
drwxrwxr-x  2 dang dang  4096 1114 17:27 script
-rw-rw-r--  1 dang dang   601 1114 17:27 SECURITY.md
drwxrwxr-x  9 dang dang 12288 1114 17:27 src
drwxrwxr-x 55 dang dang  4096 1114 17:27 tests
drwxrwxr-x  2 dang dang  4096 1114 17:27 .vscode
dang@DFLubuntu:~/mylibgit$ tree .git
.git
├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│       ├── heads
│       │   └── main
│       └── remotes
│           └── origin
│               └── HEAD
├── objects
│   ├── info
│   └── pack
│       ├── pack-179bbb01f6b14b240cfc776af96f0fdb6a5f3453.idx
│       └── pack-179bbb01f6b14b240cfc776af96f0fdb6a5f3453.pack
├── packed-refs
└── refs
    ├── heads
    │   └── main
    ├── remotes
    │   └── origin
    │       └── HEAD
    └── tags

16 directories, 25 files
dang@DFLubuntu:~/mylibgit$ ls -l
总用量 156
-rw-rw-r--  1 dang dang   267 1114 17:27 api.docurium
-rw-rw-r--  1 dang dang  1286 1114 17:27 AUTHORS
drwxrwxr-x  3 dang dang  4096 1114 17:27 ci
drwxrwxr-x  2 dang dang  4096 1114 17:27 cmake
-rw-rw-r--  1 dang dang  5021 1114 17:27 CMakeLists.txt
-rw-rw-r--  1 dang dang 57605 1114 17:27 COPYING
drwxrwxr-x  8 dang dang  4096 1114 17:27 deps
drwxrwxr-x  2 dang dang  4096 1114 17:27 docs
drwxrwxr-x  2 dang dang  4096 1114 17:27 examples
drwxrwxr-x  3 dang dang  4096 1114 17:27 fuzzers
-rw-rw-r--  1 dang dang  3101 1114 17:27 git.git-authors
drwxrwxr-x  3 dang dang  4096 1114 17:27 include
-rw-rw-r--  1 dang dang   281 1114 17:27 package.json
-rw-rw-r--  1 dang dang 16881 1114 17:27 README.md
drwxrwxr-x  2 dang dang  4096 1114 17:27 script
-rw-rw-r--  1 dang dang   601 1114 17:27 SECURITY.md
drwxrwxr-x  9 dang dang 12288 1114 17:27 src
drwxrwxr-x 55 dang dang  4096 1114 17:27 tests
dang@DFLubuntu:~/mylibgit$ cd ..
dang@DFLubuntu:~$ 

libgit2 目录和 mylibgit 目录中的内容是一样的,只不过从远程仓库进行克隆时使用的链接格式不一样,前者用https://github.com/libgit2/libgit2,后者用git@github.com:libgit2/libgit2.git,是因为 GitHub 支持三种数据传输协议以供克隆:

二,查看工作目录和暂存区的状态:status

先来回顾一下我们的三个项目:

  • git-tutorial 本地创建的,里啥都没有。
  • testproject 本地创建的,里就一个 test.py 文件。
  • libgit2 从远程仓库克隆的。

后面我们会基于这三个项目进行迭代操作。

(一)“三态三地”回顾

之前不是说过吗,我们可以在工作目录中编辑项目文件,编辑完成后需要将变更添加到暂存区——相当于是给当前的项目拍了一张快照,变更就会被跟踪);确认所有需要提交的变更都添加后就能创建一次提交了——把暂存区中的快照存储到 Git本地仓库.git/中。

这其中就伴随着文件状态的三态变化:已修改——已暂存——已提交。有这三态表明变更进入 VCS 已被跟踪,否则就是未被跟踪

在这里插入图片描述

已修改的文件可能在工作目录和暂存区都有,已暂存的文件只存在于暂存区,已提交的文件只存在于 Git 本地仓库。

(二)第一次查看文件状态

那么,这里我们就使用 git status 命令来看看各个阶段的状态信息吧。
git-tutorial 中:
在这里插入图片描述

  • 啥都没有,干干净净,显示”尚无提交“,并给出了建议。关于分支的东西后面再说。

testproject 中:
在这里插入图片描述

  • 也提示”尚无提交“,但有一个用红色文件名的”未跟踪的文件“,也是给出了建议。

libgit2 中:
在这里插入图片描述

  • 啥都没做时的正常提示。表明所有已跟踪文件在上次提交后都未被更改过。

(三)产生变更

现在,在 git-tutorial 中创建一个文件,再看看状态:
在这里插入图片描述
此情此景,跟 libgit2 的状态一毛一样:未跟踪的文件意味着 Git 在之前的快照(提交)中没有这些文件。

Git 不会自动将未跟踪的文件纳入跟踪范围,除非你明明白白地告诉它“我需要跟踪该文件”。

三,向暂存区中添加文件:add

(一)暂存文件

一旦编辑了文件产生了变更之后,需要做的就是执行 git add <files> 命令将它们添加到暂存区中去,这样才能实现 VCS 对它们的跟踪。

testproject 中:
在这里插入图片描述

  • 显示一个绿色文件名的”新添加到暂存区的文件“,这个文件就是”要提交的变更“了。

只要在”要提交的变更“这行下面的,就说明是已暂存状态。

git add 命令使用文件或目录的路径作为参数:

  • 如果参数是目录的路径,比如执行 git add testproject/ ,该命令将递归地跟踪该 testproject/ 目录下的所有文件和目录。
  • 当然能同时跟多个参数,中间用空格隔开。
  • 还有一个特殊的参数 . ,它会将当前所有发生变更的文件都添加到暂存区。

(二)编辑已被跟踪的文件

testproject 中我们来修改一下已经被跟踪的这个文件,再来看看状态:
在这里插入图片描述

  • 显示多了一个红色文件名的”尚未暂存以备提交的文件“。

为什么同一个文件又是红的又是绿的?那是因为它们其实是不同的:它们是同一文件在不同时间下的不同状态,时间不同,状态已经发生变化。绿的是在暂存区中已暂存的状态,是上一次 add 时该文件的快照,而红的是编辑它后在工作目录中已修改的状态,是这次编辑后该文件的快照,这就是VCS 跟踪的效果。

正是跟踪,使得同一文件在不同时期可以拥有不同状态的快照这一现象,而这就是 VCS 要记录的东西。

所以,运行了 git add 之后又作了修订的文件,需要重新运行 git add 把最新版本重新暂存起来:
在这里插入图片描述

  • 产生变更文件的状态已经为已暂存状态了。

(三)更简便地查看状态:status -s

说实话,前面同一文件因不同时间状态不同而导致查看状态时出现的详细\繁琐的默认显示会让人看起来不太方便,所以可以执行git status -s命令以简洁的方式查看状态。

在 testproject 中我们再来修改一下已经被跟踪的这个文件,再来看看状态:
在这里插入图片描述
发现没,输出更简洁了,文件名前面出现了两个并列字母:绿A 红M。联系前面的内容,猜得出来:

  • 左栏指明了暂存区的状态。新添加到暂存区中的文件有 绿A 标记。
  • 右栏指明了工作目录的状态。修改过的文件前面有 红M 标记。

再在 testproject 中创建一个新文件看看状态:
在这里插入图片描述

  • 新添加的未跟踪文件前面有 ?? 标记。

通过这条命令,甚至能看到下面的状态:

$ git status -s
 M README				# 在工作区已修改但尚未暂存
MM Rakefile				# 已修改,暂存后又作了修改
A  lib/git.rb			# 新添加到暂存区中的文件
M  lib/simplegit.rb		# 已修改且已暂存
?? LICENSE.txt			# 在工作区新添加的未跟踪文件
 D 						# 已删除
 R 						# 己重命名
 c						# 已复制

总之,git status命令显示所有状态变更

(四)忽略文件: .gitignore

实际上,在开发中,有些文件是不需要提交到远程仓库中去的,比如日志文件、缓存文件、数据库文件等,不需要提交,自然也就不需要添加到暂存区。

我们既不希望手动通过添加来过滤要被忽略的文件,又不希望状态信息区中大片大片的红色文字,这可以通过将要忽略的文件路径放入项目主目录下的 .gitignore 文件中来实现,它自动地帮你在 git add 操作中忽略你指定的文件。

在 testproject 中创建一个 .gitignore 文件,并在其中指定要忽略的 README.md 文件:

dang@DFLubuntu:~/testproject$ git add test.py
dang@DFLubuntu:~/testproject$ git status -s
A  test.py
?? README.md
dang@DFLubuntu:~/testproject$ vim .gitignore
dang@DFLubuntu:~/testproject$ cat .gitignore
README.md
dang@DFLubuntu:~/testproject$ git status -s
A  test.py
?? .gitignore
dang@DFLubuntu:~/testproject$ git add .
dang@DFLubuntu:~/testproject$ git status -s
A  .gitignore
A  test.py

看见没,?? 的 README.md 在文件名被加入后,就从状态跟踪中忽略了。当然,一旦我们的**.gitignore 文件**初次编辑完成后,最终是需要提交的,该项目下的所有开发者共享一套它定义好的忽略规则。

GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表, 你可以在 https://github.com/github/gitignore 找到它。

.gitignore 文件是永久性的忽略,如果只是忽略临时性的本地修改,可这样做:

  1. 忽略一些已被跟踪的文件:git update-index --assume-unchanged <filename>;
  2. 停止忽略:用--no-assume-unchanged选项来取消--assume-unchanged选项对各单一文件的忽略。

四,查看已修改的内容:diff

相对 git status 命令来说,git diff 命令能通过文件补丁的格式更加具体地显示发生了什么变更,功能更强,作用范围更广。

(一)git diff 的本质:无参数

注意,git diff 命令只显示尚未暂存的变更。所以,如果你一下子暂存了所有变更过的文件,运行 git diff 后却什么也没有,就是这个原因,
在 testproject 中,我们之前已经将所有变更都添加到了暂存区,此时执行 git diff 就不会有任何输出:
在这里插入图片描述
我们还是在 testproject 中做一些编辑:

dang@DFLubuntu:~/testproject$ cat .gitignore
README.md
dang@DFLubuntu:~/testproject$ vim .gitignore	# 清空 .gitignore 文件
dang@DFLubuntu:~/testproject$ cat .gitignore

dang@DFLubuntu:~/testproject$ git status -s
AM .gitignore
A  test.py
?? README.md
  • 修改了暂存区中的 .gitignore 文件,将 README.md 文件名从中去除,状态就是这样。

此时在 testproject 中执行 git diff 命令:
在这里插入图片描述

  • 结果显示 .gitignore 文件出现变更:-README.md 表明删除了”README.md“,+ 表明此行现在为空,这跟 catstatus结合起来表示的结果一致。
  • How to read the output from git diff?

再次强调,git diff命令比较的是工作目录中当前文件和暂存区快照之间的差异。 也就是修改之后还没有暂存起来的变化的内容。实际上就是在 git status 的基础上更加详细地相识了不同快照之间文件的变更之处。

(二)扩展 git diff:有参数

执行 git diff --staged 命令将能够比对已暂存文件与最后一次提交的文件的差异
在 libgit2 中的 AUTHORS 末尾添加了一行”xiaolu2333“并暂存,然后执行git diff --staged 命令来查看暂存文件与最后一次提交的文件的差异:
在这里插入图片描述

  • git diff --staged 等价于 git diff -cached

执行 git diff HEAD 命令将能够比对工作目录与本地仓库内容的差异

这样一来,本地环境中的三个取域之间的差异都能够进行两两间的比较了。
总结一下 diff 命令:

  • git diff 比对工作目录与暂存区的差异。
  • git diff -staged 比对暂存区与 Git 本地仓库的差异。
  • git diff HEAD 比对工作目录与 Git 本地仓库的差异。

我们会在后面的讲解中中多次执行 diff 命令来分析文件差异。

五,提交更新:commit

什么是”提交更新“

  • 从接近 Git 底层工作原理的角度来说,就是创建一次提交或者说是创建一个 commit 对象。
  • 从高层命令的角度来说,就是将暂存区的项目快照加上一些信息后存储到 Git 本地仓库 .git/中去。

所以,”提交“既是一个名词( commit 对象),又是一个动词(存储快照),但要表达的意思都是相同的。

(一)为提交做准备

实际上,在 libgit2 中我们做的就是下面的工作(除了 commit 这一步):
在这里插入图片描述
这其实是在执行新的提交前,需要做一些准备:
1,查看变更内容以确定变更是否正确;
2,确保将所有已变更且待提交的文件都被添加到暂存区;
3,查看暂存区中本次的待提交与最近一次提交中的差异。

(二)简单的提交

执行git commit 命令就可以将暂存区中的变更存储到 Git 本地仓库中。

不加参数的情况下,git commit 命令会启动一个文本编辑器来输入提交说明(提交说明是必须的)。
在 git-tutorial 中暂存所有变更后提交:

dang@DFLubuntu:~/git-tutorial$ git status -s
?? README.md
dang@DFLubuntu:~/git-tutorial$ git add README.md
dang@DFLubuntu:~/git-tutorial$ git status -s
A  README.md
dang@DFLubuntu:~/git-tutorial$ git commit

出现:
在这里插入图片描述

  • 或通过执行git config --global core.editor vim将编辑器更改为 vim。
  • 详细的内容修改提示可以用 -v 选项查看,这会将你所作的更改的 diff 输出到启动的编辑器中,以便让你知道本次提交具体作出哪些修改。

如果没在编辑器中进行编辑就退出的的话,会显示:

dang@DFLubuntu:~/git-tutorial$ git commit
终止提交因为提交说明为空。

也可以使用 -m 选项将提交信息与命令放在同一行:

dang@DFLubuntu:~/git-tutorial$ git commit -m "第一次提交"
[master (根提交) 10ae697] 第一次提交
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
dang@DFLubuntu:~/git-tutorial$ 

让我们来看看命令结束后显示的信息的意义:

  • master :表明本次是在 master 分支中进行的。
  • 10ae697:是本次提交的 SHA-1 校验和,对本次提交进行标识。
  • 第一次提交:是提交说明,对本次提交进行描述。
  • 1 file changed:表示本次提交中有一个文件发生变化。
  • 1 insertion(+):表示本次提交中添加了一行。x deletion(-)表示删改了 x 行。

为了养成良好的确认习惯,我们在 testproject 中再简单地完成一遍提交前的准备工作并最后完成提交:

# 重新创建 git-tutorial 并初始化 Git 本地仓库
dang@DFLubuntu:~$ mkdir git-tutorial
dang@DFLubuntu:~$ cd git-tutorial
dang@DFLubuntu:~/git-tutorial$ git init
已初始化空的 Git 仓库于 /home/dang/git-tutorial/.git/
dang@DFLubuntu:~/git-tutorial$ ls -l
总用量 0
dang@DFLubuntu:~/git-tutorial$ git status
位于分支 master

尚无提交

无文件要提交(创建/拷贝文件并使用 "git add" 建立跟踪)
dang@DFLubuntu:~/git-tutorial$ git status -s
dang@DFLubuntu:~/git-tutorial$ git diff
dang@DFLubuntu:~/git-tutorial$ git diff --staged

# 编辑a.md并第一次提交
dang@DFLubuntu:~/git-tutorial$ vim a.md
dang@DFLubuntu:~/git-tutorial$ git status		# 查看工作目录与暂存区的变更,由于刚创建并编辑a.md文件且暂未暂存,所以显示工作目录有未跟踪的新文件
位于分支 master

尚无提交

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	a.md

提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于刚创建并编辑a.md文件且暂未暂存,所以显红色??
?? a.md
dang@DFLubuntu:~/git-tutorial$ git diff			# 查看工作目录相对于暂存区的变更,由于刚创建并编辑a.md文件且暂未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于刚创建并编辑a.md文件且暂未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git add a.md		# 暂存a.md
dang@DFLubuntu:~/git-tutorial$ git status		# 查看工作目录与暂存区的变更,由于a.md文件已暂存且暂未提交,所以显示暂存区要提交的变更
位于分支 master

尚无提交

要提交的变更:
  (使用 "git rm --cached <文件>..." 以取消暂存)
	新文件:   a.md

dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于a.md文件已暂存且暂未提交,所以显示绿色A
A  a.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件已暂未暂存且未变更,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于a.md文件已暂存且暂未提交,所以显示暂存区中的变更
diff --git a/a.md b/a.md
new file mode 100644
index 0000000..987e615
--- /dev/null
+++ b/a.md
@@ -0,0 +1 @@
+第一次输入的内容
dang@DFLubuntu:~/git-tutorial$ git commit -m "第一次提交"	# 第一次提交a.md
[master (根提交) e85b9a5] 第一次提交
 1 file changed, 1 insertion(+)
 create mode 100644 a.md
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md文件提交后暂未变更,所以显示工作目录干净
位于分支 master
无文件要提交,干净的工作区
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后暂未变更,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后暂未变更,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后暂未变更,所以无显示
dang@DFLubuntu:~/git-tutorial$ vim a.md		# 变更a.md
dang@DFLubuntu:~/git-tutorial$ touch b.md	# 新增b.md
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且尚未暂存,还新增了新文件b.md,所以显示所以显示工作目录有文件变更且有未跟踪的文件
位于分支 master
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
	修改:     a.md

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	b.md

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且尚未暂存,还新增了新文件b.md,所以显示 红M 和 红??
 M a.md
?? b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后已变更且尚未暂存,所以显示工作目录中的变更:在a.md中新增一行内容
diff --git a/a.md b/a.md
index 987e615..aba5dbd 100644
--- a/a.md
+++ b/a.md
@@ -1 +1,2 @@
 第一次输入的内容
+第二次输入的内容
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后已变更但暂未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git add a.md		# 暂存a.md
dang@DFLubuntu:~/git-tutorial$ git status		# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,新文件b.md还是暂未暂存,所以显示暂存区有文件变更且有未跟踪的文件
位于分支 master
要提交的变更:
  (使用 "git restore --staged <文件>..." 以取消暂存)
	修改:     a.md

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	b.md

dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,新文件b.md还是暂未暂存,所以显示 绿M 和 红??
M  a.md
?? b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,所以显示工作目录中的变更:在a.md中新增一行内容
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后已变更且暂存,所以显示暂存区中的变更:在a.md中新增一行内容
diff --git a/a.md b/a.md
index 987e615..aba5dbd 100644
--- a/a.md
+++ b/a.md
@@ -1 +1,2 @@
 第一次输入的内容
+第二次输入的内容
dang@DFLubuntu:~/git-tutorial$ git commit -m "第二次提交"	# 第一次提交a.md
[master eda8fb0] 第二次提交
 1 file changed, 1 insertion(+)
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md文件提交后暂未变更且尚未暂存,新文件b.md还是暂未暂存,所以显示有未跟踪的文件
位于分支 master
未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	b.md

提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件提交后暂未变更且尚未暂存,新文件b.md还是暂未暂存,所以显示 红??
?? b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后暂未变更且尚未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后暂未变更且尚未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ vim a.md		# 变更a.md
dang@DFLubuntu:~/git-tutorial$ vim b.md		# 变更b.md
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md文件提交后已变更且尚未暂存,新文件b.md还是暂未暂存,所以显示暂存区变更且有未跟踪的文件
位于分支 master
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
	修改:     a.md

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	b.md

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件提交后已变更且尚未暂存,文件b.md还是暂未暂存,所以显示 红M 和 红??
 M a.md
?? b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后已变更且尚未暂存,文件b.md还是暂未暂存,所以显示工作目录有文件变更
diff --git a/a.md b/a.md
index aba5dbd..e0c0d0f 100644
--- a/a.md
+++ b/a.md
@@ -1,2 +1,3 @@
 第一次输入的内容
 第二次输入的内容
+第三次输入的内容
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后已变更但暂未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git add a.md b.md	#暂存所有
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,新文件b.md也已暂存,所以显示暂存区有文件变更且有新文件暂存
位于分支 master
要提交的变更:
  (使用 "git restore --staged <文件>..." 以取消暂存)
	修改:     a.md
	新文件:   b.md

dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,文件b.md也已暂存,所以显示 绿M 和 绿A
M  a.md
A  b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,b.md自暂存后未变更,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后已变更且暂存,文件b.md也已暂存,所以显示暂存区中的变更:在a.md中新增一行内容,在新暂存的b.md中有一行内容
diff --git a/a.md b/a.md
index aba5dbd..e0c0d0f 100644
--- a/a.md
+++ b/a.md
@@ -1,2 +1,3 @@
 第一次输入的内容
 第二次输入的内容
+第三次输入的内容
diff --git a/b.md b/b.md
new file mode 100644
index 0000000..cd74efb
--- /dev/null
+++ b/b.md
@@ -0,0 +1 @@
+第一次插入内容
dang@DFLubuntu:~/git-tutorial$ git commit -m "第三次提交"	# 第三次提交
[master 6dfd1d9] 第三次提交
 2 files changed, 2 insertions(+)
 create mode 100644 b.md
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md和b.md自上次提交后暂未变更且尚未暂存,所以显示工作目录干净
位于分支 master
无文件要提交,干净的工作区
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md和b.md自上次提交后暂未变更且尚未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md和b.md自上次提交后暂未变更且尚未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md和b.md自上次提交后暂未变更且尚未暂存,所以无显示

# 查看提交历史及其变更
dang@DFLubuntu:~/git-tutorial$ git log -p	
commit 6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Wed Nov 17 01:05:55 2021 +0800

    第三次提交

diff --git a/a.md b/a.md
index aba5dbd..e0c0d0f 100644
--- a/a.md
+++ b/a.md
@@ -1,2 +1,3 @@
 第一次输入的内容
 第二次输入的内容
+第三次输入的内容
diff --git a/b.md b/b.md
new file mode 100644
index 0000000..cd74efb
--- /dev/null
+++ b/b.md
@@ -0,0 +1 @@
+第一次插入内容

commit eda8fb01f0f0adc1d7355cb5a2cc0b20b33a22bf
Author: xiaolu2333 <2694977226@qq.com>
Date:   Wed Nov 17 01:02:45 2021 +0800

    第二次提交

diff --git a/a.md b/a.md
index 987e615..aba5dbd 100644
--- a/a.md
+++ b/a.md
@@ -1 +1,2 @@
 第一次输入的内容
+第二次输入的内容

commit e85b9a559a84b3a5ff8719463755a3ab5791c67d
Author: xiaolu2333 <2694977226@qq.com>
Date:   Wed Nov 17 00:59:56 2021 +0800

    第一次提交

diff --git a/a.md b/a.md
new file mode 100644
index 0000000..987e615
--- /dev/null
+++ b/a.md
@@ -0,0 +1 @@
+第一次输入的内容

(三)暂存区的意义

想象一下,如果我们有许多文件发生了变更,且需要将它们提交到本地仓库中,要是能直接从工作目录中提交到本地仓库就会很方便,就不用再执行许多中间命令,这样该多好呀。
但实际上这种想法要不得。因为提交操作是如此重要,它直接关系着 VCS 对的版本控制能力。如果跳过对暂存区的使用,就会丢掉暂存区带给用户的最大好处:强大的对提交内容进行控制的能力。

  • 然而 Git 还是允许你执行 git commit -a <filename>命令跳过暂存区直接提交变更,但有时这个选项会将不需要的文件添加到提交中。

下面再来看看暂存区存在的另一个意义。
在 testproject 中完成上次的提交后,查看一下 .git/index 文件的时间戳:

dang@DFLubuntu:~/testproject$ ls -l .git/index
-rw-rw-r-- 1 dang dang 289 1115 02:18 .git/index
dang@DFLubuntu:~/testproject$ git status -s	
dang@DFLubuntu:~/testproject$
  • 于工作目录里的文件自上次提交后未发生变更且暂存区是空的,所以status -s不输出状态变化。

然后在工作目录中重新编辑 README.md 和 test.py 这两个文件,再来看看.git/index 文件的时间戳:

dang@DFLubuntu:~/testproject$ vim README.md
dang@DFLubuntu:~/testproject$ vim test.py
dang@DFLubuntu:~/testproject$ ls -l .git/index
-rw-rw-r-- 1 dang dang 289 1115 02:18 .git/index
dang@DFLubuntu:~/testproject$ git status -s
 M README.md
 M test.py
dang@DFLubuntu:~/testproject$ git diff
diff --git a/README.md b/README.md
index 7bcfe7c..acd3ef0 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-TESTPROJECT
+WELCOME TO TESTPROJECT
diff --git a/test.py b/test.py
index 3b0b1ed..509056f 100644
--- a/test.py
+++ b/test.py
@@ -1,4 +1,4 @@
 from datetime import datetime
 
-print("What's the time?")
+print("Now: ")
 print(datetime.today())
  • 时间戳已变化
  • 状态变化

不进行任何操作,再来看看.git/index 文件的时间戳:

dang@DFLubuntu:~/testproject$ ls -l .git/index
-rw-rw-r-- 1 dang dang 289 1115 02:18 .git/index
dang@DFLubuntu:~/testproject$ git status -s
 M README.md
 M test.py
  • 时间戳未变化
  • 状态未变化

然后暂存所有工作目录中的变更,再来看看.git/index 文件的时间戳:

dang@DFLubuntu:~/testproject$ git add .
dang@DFLubuntu:~/testproject$ ls -l .git/index
-rw-rw-r-- 1 dang dang 270 1115 14:35 .git/index
dang@DFLubuntu:~/testproject$ git status -s
A  README.md
A  test.py
  • 时间戳已变化
  • 状态已变化

不进行任何操作,再来看看.git/index 文件的时间戳:

dang@DFLubuntu:~/testproject$ ls -l .git/index
-rw-rw-r-- 1 dang dang 270 1115 14:35 .git/index
dang@DFLubuntu:~/testproject$ git status -s
A  README.md
A  test.py
  • 时间戳未变化
  • 状态未变化

最后创建一次提交,再来看看.git/index 文件的时间戳:

dang@DFLubuntu:~/testproject$ git commit -m "再次修改问候语"
[master 5a4052c] 再次修改问候语
 2 files changed, 2 insertions(+), 2 deletions(-)
dang@DFLubuntu:~/testproject$ ls -l .git/index
-rw-rw-r-- 1 dang dang 289 1115 14:45 .git/index
dang@DFLubuntu:~/testproject$ git status -s
dang@DFLubuntu:~/testproject$ 
  • 时间戳已变化
  • 状态已变化

实际上,git statusgit diff 查看是否有变更时,都会先对 .git/index 文件的时间戳和长度等信息进行检查,如果有变化,再去查看到底发生了什么变更。可以通过观察这几次时间戳的变化以及状态变化进行印证。
这种通过比较简单信息比直接比较内容变更来确定是否有变更的做法,快得多。

这才是真正的Git——Git内部原理揭秘!

六,查看提交历史与差异

目前,凭借记忆,我们:

  • 在 git-tutorial 中创建了一次提交。
  • 在 testproject 中创建了三次提交。
  • 在 libgit2 中还没有创建提交。

但是,还记得提交说明吗?还记得标识提交的 SHA-1 值吗?显然不会全部都记得,不然的话,只能说你是真的强!

Git 提供了 logdiff 来允许我们查看提交历史以及版本之间的差异。

(一)重新认识 SHA-1 值

在我们之前的成功的提交的结果显示中,有一个短的 SHA-1 值,比如10ae697,一般情况下,这个 SHA-1 值会呈现为一个40位的十六进制串,比如10ae697f1c9e85f02003f630ba83b18d10be1115,它被用来标识本次提交。

我们不需要了解 SHA-1 算法是如何工作的,但我们应该知道的是:

  • 校验和算法将数据转换为一个简单的数字(称为校验和)。
  • 相同的数据总是得到相同的校验和,改变数据会改变校验和。
  • Git 使用 SHA-1 哈希校验和算法来为每个变更生成校验和(哈希值)。

Git 使用 SHA-1 来识别提交对吧?雀食,它使用 SHA-1 来识别它跟踪的所有 Git 对象,当然包括 Git 对中的 commit 对象。然而,用户一般情况下只在提交上下文中看到 SHA-1 的短码。

Git storage – SHA1
Git Transitioning Away from the Aging SHA-1 Hash

(二)查看所有提交的历史与差异:log

在提交了若干更新或者克隆了某个项目之后,你也许想回顾下提交历史,可执行 git log 命令。

在 testproject 中查看提交历史:
在这里插入图片描述

  • git log 会按时间先后顺序列出所有的提交,最近的更新排在最上面。
  • 结果中包含每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。

git log 有许多选项可以帮助你搜寻你所要找的提交。

1,显示每次提交所引入的差异:-p--patch选项

在这里插入图片描述

dang@DFLubuntu:~/testproject$ git log -p
commit 5a4052cf13aef78e15d3ae0fb71057e0996b3bad (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 14:45:05 2021 +0800

    再次修改问候语

diff --git a/README.md b/README.md
index 7bcfe7c..acd3ef0 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-TESTPROJECT
+WELCOME TO TESTPROJECT
diff --git a/test.py b/test.py
index 3b0b1ed..509056f 100644
--- a/test.py
+++ b/test.py
@@ -1,4 +1,4 @@
 from datetime import datetime
 
-print("What's the time?")
+print("Now: ")
 print(datetime.today())

commit c56e23dc020651f88c959c7f0242c49632779772
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 02:18:08 2021 +0800

    修改问候语

diff --git a/test.py b/test.py
index 1bac997..3b0b1ed 100644
--- a/test.py
+++ b/test.py
@@ -1,4 +1,4 @@
 from datetime import datetime
 
-print("Hello!")
+print("What's the time?")
 print(datetime.today())

commit 60ba7bc17fa192c73da07c5c78505f41557f9581
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 02:09:15 2021 +0800

    第一次提交

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7bcfe7c
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+TESTPROJECT
diff --git a/test.py b/test.py
new file mode 100644
index 0000000..1bac997
--- /dev/null
+++ b/test.py
@@ -0,0 +1,4 @@
+from datetime import datetime
+
+print("Hello!")
+print(datetime.today())
  • 当进行代码审查,或者快速浏览某个搭档的提交所带来的变化的时候,这个参数就非常有用了。

2,显示每次提交的简略统计信息:--stat--shortstat选项

在这里插入图片描述

dang@DFLubuntu:~/testproject$ git log --stat
commit 5a4052cf13aef78e15d3ae0fb71057e0996b3bad (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 14:45:05 2021 +0800

    再次修改问候语

 README.md | 2 +-
 test.py   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

commit c56e23dc020651f88c959c7f0242c49632779772
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 02:18:08 2021 +0800

    修改问候语

 test.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

commit 60ba7bc17fa192c73da07c5c78505f41557f9581
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 02:09:15 2021 +0800

    第一次提交

 .gitignore | 1 +
 README.md  | 1 +
 test.py    | 4 ++++
 3 files changed, 6 insertions(+)
  • 列出所有被修改过的文件、有多少文件被修改了以及被修改过的文件的哪些行被移除或是添加了。

3,通过指定的格式以不同于默认格式的方式显示提交历史:--pretty选项

在这里插入图片描述

dang@DFLubuntu:~/testproject$ git log --pretty=oneline
5a4052cf13aef78e15d3ae0fb71057e0996b3bad (HEAD -> master) 再次修改问候语
c56e23dc020651f88c959c7f0242c49632779772 修改问候语
60ba7bc17fa192c73da07c5c78505f41557f9581 第一次提交
dang@DFLubuntu:~/testproject$ git log --pretty=format:"%h - %an, %ar : %s"
5a4052c - xiaolu2333, 2 小时前 : 再次修改问候语
c56e23d - xiaolu2333, 15 小时前 : 修改问候语
60ba7bc - xiaolu2333, 15 小时前 : 第一次提交
dang@DFLubuntu:~/testproject$ 

git log --pretty=format 常用的选项:更多

4,只显示指定文件的提交历史与差异:指定文件名

在这里插入图片描述

dang@DFLubuntu:~/testproject$ git log README.md
commit 5a4052cf13aef78e15d3ae0fb71057e0996b3bad (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 14:45:05 2021 +0800

    再次修改问候语

commit 60ba7bc17fa192c73da07c5c78505f41557f9581
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 02:09:15 2021 +0800

    第一次提交
dang@DFLubuntu:~/testproject$ git log -p README.md
commit 5a4052cf13aef78e15d3ae0fb71057e0996b3bad (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 14:45:05 2021 +0800

    再次修改问候语

diff --git a/README.md b/README.md
index 7bcfe7c..acd3ef0 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-TESTPROJECT
+WELCOME TO TESTPROJECT

commit 60ba7bc17fa192c73da07c5c78505f41557f9581
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 02:09:15 2021 +0800

    第一次提交

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7bcfe7c
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+TESTPROJECT
dang@DFLubuntu:~/testproject$

5,限制输出长度

dang@DFLubuntu:~/testproject$ git log --pretty="%h - %s" --author='xiaolu2333' --since="2021-10-01"   --before="2021--11-15"
5a4052c - 再次修改问候语
c56e23d - 修改问候语
60ba7bc - 第一次提交
  • 限制输出长度的选项:List item

6,显示各个提交集(分支)的关系:--graph选项

在这里插入图片描述

dang@DFLubuntu:~/libgit2$ git log --graph
 *   commit 7687948ac129fb097d822a3b6a8787fa037cb240 (HEAD -> main)
|\  Merge: 42205e72d 4e84ddd5b
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Thu Nov 11 16:13:38 2021 -0500
| | 
| |     Merge pull request #6112 from libgit2/ethomson/cmake3
| |     
| |     cmake refactorings
| | 
| * commit 4e84ddd5b091b6e6e85ff6484e72d9f90da1c4b0
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:59:46 2021 -0500
| | 
| |     cmake: refactor zlib selection
| |     
| |     Move zlib selection into its own cmake module.
| | 
| * commit 83fa548078b0b35030ba028676d6b5674d86ba18
:...skipping...
 *   commit 7687948ac129fb097d822a3b6a8787fa037cb240 (HEAD -> main)
|\  Merge: 42205e72d 4e84ddd5b
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Thu Nov 11 16:13:38 2021 -0500
| | 
| |     Merge pull request #6112 from libgit2/ethomson/cmake3
| |     
| |     cmake refactorings
| | 
| * commit 4e84ddd5b091b6e6e85ff6484e72d9f90da1c4b0
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:59:46 2021 -0500
| | 
| |     cmake: refactor zlib selection
| |     
| |     Move zlib selection into its own cmake module.
| | 
| * commit 83fa548078b0b35030ba028676d6b5674d86ba18
| | Author: Edward Thomson <ethomson@edwardthomson.com>
:...skipping...
 *   commit 7687948ac129fb097d822a3b6a8787fa037cb240 (HEAD -> main)
|\  Merge: 42205e72d 4e84ddd5b
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Thu Nov 11 16:13:38 2021 -0500
| | 
| |     Merge pull request #6112 from libgit2/ethomson/cmake3
| |     
| |     cmake refactorings
| | 
| * commit 4e84ddd5b091b6e6e85ff6484e72d9f90da1c4b0
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:59:46 2021 -0500
| | 
| |     cmake: refactor zlib selection
| |     
| |     Move zlib selection into its own cmake module.
| | 
| * commit 83fa548078b0b35030ba028676d6b5674d86ba18
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:58:12 2021 -0500
:...skipping...
 *   commit 7687948ac129fb097d822a3b6a8787fa037cb240 (HEAD -> main)
|\  Merge: 42205e72d 4e84ddd5b
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Thu Nov 11 16:13:38 2021 -0500
| | 
| |     Merge pull request #6112 from libgit2/ethomson/cmake3
| |     
| |     cmake refactorings
| | 
| * commit 4e84ddd5b091b6e6e85ff6484e72d9f90da1c4b0
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:59:46 2021 -0500
| | 
| |     cmake: refactor zlib selection
| |     
| |     Move zlib selection into its own cmake module.
| | 
| * commit 83fa548078b0b35030ba028676d6b5674d86ba18
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:58:12 2021 -0500
| | 
:...skipping...
 *   commit 7687948ac129fb097d822a3b6a8787fa037cb240 (HEAD -> main)
|\  Merge: 42205e72d 4e84ddd5b
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Thu Nov 11 16:13:38 2021 -0500
| | 
| |     Merge pull request #6112 from libgit2/ethomson/cmake3
| |     
| |     cmake refactorings
| | 
| * commit 4e84ddd5b091b6e6e85ff6484e72d9f90da1c4b0
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:59:46 2021 -0500
| | 
| |     cmake: refactor zlib selection
| |     
| |     Move zlib selection into its own cmake module.
| | 
| * commit 83fa548078b0b35030ba028676d6b5674d86ba18
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:58:12 2021 -0500
| | 
| |     cmake: refactor WinHTTP selection
:...skipping...
 *   commit 7687948ac129fb097d822a3b6a8787fa037cb240 (HEAD -> main)
|\  Merge: 42205e72d 4e84ddd5b
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Thu Nov 11 16:13:38 2021 -0500
| | 
| |     Merge pull request #6112 from libgit2/ethomson/cmake3
| |     
| |     cmake refactorings
| | 
| * commit 4e84ddd5b091b6e6e85ff6484e72d9f90da1c4b0
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:59:46 2021 -0500
| | 
| |     cmake: refactor zlib selection
| |     
| |     Move zlib selection into its own cmake module.
| | 
| * commit 83fa548078b0b35030ba028676d6b5674d86ba18
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:58:12 2021 -0500
| | 
| |     cmake: refactor WinHTTP selection
| |     
:...skipping...
 *   commit 7687948ac129fb097d822a3b6a8787fa037cb240 (HEAD -> main)
|\  Merge: 42205e72d 4e84ddd5b
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Thu Nov 11 16:13:38 2021 -0500
| | 
| |     Merge pull request #6112 from libgit2/ethomson/cmake3
| |     
| |     cmake refactorings
| | 
| * commit 4e84ddd5b091b6e6e85ff6484e72d9f90da1c4b0
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:59:46 2021 -0500
| | 
| |     cmake: refactor zlib selection
| |     
| |     Move zlib selection into its own cmake module.
| | 
| * commit 83fa548078b0b35030ba028676d6b5674d86ba18
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:58:12 2021 -0500
| | 
| |     cmake: refactor WinHTTP selection
| |     
| |     Move WinHTTP selection into its own cmake module.
:...skipping...
 *   commit 7687948ac129fb097d822a3b6a8787fa037cb240 (HEAD -> main)
|\  Merge: 42205e72d 4e84ddd5b
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Thu Nov 11 16:13:38 2021 -0500
| | 
| |     Merge pull request #6112 from libgit2/ethomson/cmake3
| |     
| |     cmake refactorings
| | 
| * commit 4e84ddd5b091b6e6e85ff6484e72d9f90da1c4b0
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:59:46 2021 -0500
| | 
| |     cmake: refactor zlib selection
| |     
| |     Move zlib selection into its own cmake module.
| | 
| * commit 83fa548078b0b35030ba028676d6b5674d86ba18
| | Author: Edward Thomson <ethomson@edwardthomson.com>
| | Date:   Wed Nov 10 21:58:12 2021 -0500
| | 
| |     cmake: refactor WinHTTP selection
| |     
| |     Move WinHTTP selection into its own cmake module.
| | 
...skipping...
| Date:   Fri Oct 31 10:43:20 2008 -0700
| 
|     Rename git_odb_sread to just git_odb_read
|     
|     Most read calls will use the small object format, as the
|     majority of the content within the database is very small
|     objects (under 20 KB when inflated).
|     
|     Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
| 
 * commit 44181c23ea6c39d51a4b481dc59ecf2cc3967e76
| Author: Shawn O. Pearce <spearce@spearce.org>
| Date:   Fri Oct 31 10:42:32 2008 -0700
| 
|     Mark git_oid parameters const when they shouldn't be modified
|     
|     Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
| 
 * commit c15648cbd059b92c177586ab1701a167222c7681
  Author: Shawn O. Pearce <spearce@spearce.org>
  Date:   Fri Oct 31 09:57:29 2008 -0700
  
      Initial draft of libgit2
      
      Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
  • git log --graph命令在后面提到的涉及到分支的开发中非常有用。

7, 排除合并:–no-merges 选项

为了避免显示的合并提交弄乱历史记录,可以为 log 加上 --no-merges 选项:
在这里插入图片描述

dang@DFLubuntu:~/libgit2$ git log --graph --no-merges
* commit 4e84ddd5b091b6e6e85ff6484e72d9f90da1c4b0
| Author: Edward Thomson <ethomson@edwardthomson.com>
| Date:   Wed Nov 10 21:59:46 2021 -0500
| 
|     cmake: refactor zlib selection
|     
|     Move zlib selection into its own cmake module.
| 
* commit 83fa548078b0b35030ba028676d6b5674d86ba18
| Author: Edward Thomson <ethomson@edwardthomson.com>
| Date:   Wed Nov 10 21:58:12 2021 -0500
| 
|     cmake: refactor WinHTTP selection
|     
|     Move WinHTTP selection into its own cmake module.
| 
* commit e35a22a080ad8127c1b3f058e6eea99d50fcfc79
| Author: Edward Thomson <ethomson@edwardthomson.com>
| Date:   Wed Nov 10 21:55:23 2021 -0500
| 
|     cmake: refactor libssh2 selection
|     
|     Move SSH selection into its own cmake module.
| 
* commit f0cb3788db73716247f20a69469d353d1178d2a7
...skipping...
| Date:   Fri Oct 31 10:43:20 2008 -0700
| 
|     Rename git_odb_sread to just git_odb_read
|     
|     Most read calls will use the small object format, as the
|     majority of the content within the database is very small
|     objects (under 20 KB when inflated).
|     
|     Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
| 
* commit 44181c23ea6c39d51a4b481dc59ecf2cc3967e76
| Author: Shawn O. Pearce <spearce@spearce.org>
| Date:   Fri Oct 31 10:42:32 2008 -0700
| 
|     Mark git_oid parameters const when they shouldn't be modified
|     
|     Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
| 
* commit c15648cbd059b92c177586ab1701a167222c7681
  Author: Shawn O. Pearce <spearce@spearce.org>
  Date:   Fri Oct 31 09:57:29 2008 -0700
  
      Initial draft of libgit2
      
      Signed-off-by: Shawn O. Pearce <spearce@spearce.org>

git log 的常用选项:
在这里插入图片描述

(三)查看具体提交的历史与差异:show

尽管 log 相当强大,但是有时候我们希望能直接一点:获取某次提交的 SHA-1 值,查看其中的修改。

执行 git show <cmoomit_SHA-1_value>能查看某次提交的信息

dang@DFLubuntu:~/testproject$ git log --pretty=oneline
b5c33cc4e0db85fe9380a3b58814c337e644070e (HEAD -> master) 向b.txt添加测试内容
2ae66240147fed550a5c73d82fa2693ead9fd5b0 向a.txt添加测试内容
639471b04b0acef8f40b1cb8c98091bf9c013f4d 新增两个用于测试的文本文件以及一个说明文件
5a4052cf13aef78e15d3ae0fb71057e0996b3bad 再次修改问候语
c56e23dc020651f88c959c7f0242c49632779772 修改问候语
60ba7bc17fa192c73da07c5c78505f41557f9581 第一次提交
dang@DFLubuntu:~/testproject$ git log --oneline
b5c33cc (HEAD -> master) 向b.txt添加测试内容
2ae6624 向a.txt添加测试内容
639471b 新增两个用于测试的文本文件以及一个说明文件
5a4052c 再次修改问候语
c56e23d 修改问候语
60ba7bc 第一次提交
dang@DFLubuntu:~/testproject$ git show b5c33cc
commit b5c33cc4e0db85fe9380a3b58814c337e644070e (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 22:39:24 2021 +0800

    向b.txt添加测试内容

diff --git a/b.txt b/b.txt
index e69de29..ba62923 100644
--- a/b.txt
+++ b/b.txt
@@ -0,0 +1 @@
+BBB

七,后悔药

在任何一个阶段,你都有可能想要撤消某些操作或者删除一些已有东西。

(一)关于文件本身

前面说过,本地文件只有两种岑在情况:已跟踪(=已修改+已暂存+已提交)未跟踪

1,未被跟踪的文件

未被跟踪的文件在工作目录中无论如何增与改,除了在类似status -s时前面有 ?? 之外,在 VCS 中都不会产生任何影响,删出的话更是没有影响:
在这里插入图片描述

2,已被跟踪的文件

这里主要来说一下如何删除已被跟踪的文件。

在 testproject 中创建一个文件并添加到暂存区中:

dang@DFLubuntu:~/testproject$ vim AUTHORS
dang@DFLubuntu:~/testproject$ git status -s
?? AUTHORS
dang@DFLubuntu:~/testproject$ git add AUTHORS
dang@DFLubuntu:~/testproject$ git status -s
A  AUTHORS
dang@DFLubuntu:~/testproject$ git diff HEAD
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..fe64388
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+xiaolu2333
dang@DFLubuntu:~/testproject$ git diff --staged
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..fe64388
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+xiaolu2333

执行普通的rm <filename>删除,文件在暂存区中依然会存在,它只是被从工作目录中删除:
在这里插入图片描述

dang@DFLubuntu:~/testproject$ rm AUTHORS		# 直接删除文件
dang@DFLubuntu:~/testproject$ git status -s		
AD AUTHORS
dang@DFLubuntu:~/testproject$ git diff HEAD		# 工作目录中没有变更
dang@DFLubuntu:~/testproject$ git diff --staged	# 但暂存区已经添加了变更
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..fe64388
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+xiaolu2333

执行 git rm <filename>命令将该文件从已跟踪文件清单中移除(确切地说,是从暂存区域移除),并连带从工作目录中删除

dang@DFLubuntu:~/testproject$ git rm AUTHORS
rm 'AUTHORS'
dang@DFLubuntu:~/testproject$ git status -s
dang@DFLubuntu:~/testproject$ git diff HEAD
dang@DFLubuntu:~/testproject$ git diff --staged

执行 git rm --cached <filename>命令将只是从暂存区中移除该文件而工作目录中任然保留

dang@DFLubuntu:~/testproject$ git rm --cached AUTHORS
rm 'AUTHORS'
dang@DFLubuntu:~/testproject$ git status -s
?? AUTHORS
dang@DFLubuntu:~/testproject$ git diff HEAD
dang@DFLubuntu:~/testproject$ git diff --staged
dang@DFLubuntu:~/testproject$ 

那么,怎样才能将文件从工作目录、暂存区和本地仓库中都删除呢?

甚至执行 git checkout -- <filename> 命令能撤销删除文件这一操作

看见没,这就是暂存区存在时提供的强大版本控制能力的表现之一。

还可以执行 git mv file_from file_to命令移动或重命名(暂存区中)已跟踪文件。

(二)关于 Git 中文件级别的撤销操作

1,修正上次不完整的提交:commit --amend

场景一:提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。

# 现状:AUTHORS尚未被追踪,其余文件均已提交
dang@DFLubuntu:~/testproject$ git status -s
?? AUTHORS
dang@DFLubuntu:~/testproject$ ls -l
总用量 12
-rw-rw-r-- 1 dang dang 11 1115 19:07 AUTHORS
-rw-rw-r-- 1 dang dang 23 1115 13:59 README.md
-rw-rw-r-- 1 dang dang 70 1115 14:24 test.py

# 目的:新建两个测试文件,准备与AUTHORS说明文件一同提交
dang@DFLubuntu:~/testproject$ touch a.txt
dang@DFLubuntu:~/testproject$ touch b.txt
dang@DFLubuntu:~/testproject$ git status -s
?? AUTHORS
?? a.txt
?? b.txt

# 失误:仅暂存了并提交了两个测试文件,AUTHORS说明文件甚至都还未暂存
dang@DFLubuntu:~/testproject$ git add a.txt b.txt
dang@DFLubuntu:~/testproject$ git status -s
A  a.txt
A  b.txt
?? AUTHORS
dang@DFLubuntu:~/testproject$ git commit -m "新增两个用于测试的文本文件"
[master 68867e1] 新增两个用于测试的文本文件
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 a.txt
 create mode 100644 b.txt
dang@DFLubuntu:~/testproject$ git status -s
?? AUTHORS

# 补救:暂存AUTHORS说明文件,撤销上一次操作并提交
dang@DFLubuntu:~/testproject$ git add AUTHORS
dang@DFLubuntu:~/testproject$ git status -s
A  AUTHORS
dang@DFLubuntu:~/testproject$ git commit --amend
[master 639471b] 新增两个用于测试的文本文件以及一个说明文件
 Date: Mon Nov 15 21:14:50 2021 +0800
 3 files changed, 1 insertion(+)
 create mode 100644 AUTHORS
 create mode 100644 a.txt
 create mode 100644 b.txt
dang@DFLubuntu:~/testproject$ git status -s
dang@DFLubuntu:~/testproject$ 

看起来,git commit --amend命令能完成对上次提交的修正
而实际上,执行这条命令后,它会将上次提交的内容与本次提交的内容进行合并(包括重新编辑提交说明),然后作为一个新的整体一并提交,而旧提交”消失不见“,看起来就像是总共只执行了一次提交。

2,取消暂存:restore --staged

场景二:向暂存区添加了多余的文件,想取消暂存这些文件。

# 现状:自上次提交后还未有任何变更
dang@DFLubuntu:~/testproject$ git status -s
dang@DFLubuntu:~/testproject$

# 目的:编辑两个测试文件,但只暂存其中一个文件。
dang@DFLubuntu:~/testproject$ vim a.txt
dang@DFLubuntu:~/testproject$ vim b.txt
dang@DFLubuntu:~/testproject$ git status -s
 M a.txt		
 M b.txt
dang@DFLubuntu:~/testproject$ git diff
diff --git a/a.txt b/a.txt
index e69de29..642c7f2 100644
--- a/a.txt
+++ b/a.txt
@@ -0,0 +1 @@
+AAAAAAA
diff --git a/b.txt b/b.txt
index e69de29..ba62923 100644
--- a/b.txt
+++ b/b.txt
@@ -0,0 +1 @@
+BBB

# 失误:不小心将两个文件都暂存了
dang@DFLubuntu:~/testproject$ git add .
dang@DFLubuntu:~/testproject$ git status -s
M  a.txt
M  b.txt

# 补救:撤销暂存其中一个文件
dang@DFLubuntu:~/testproject$ git restore --staged b.txt
dang@DFLubuntu:~/testproject$ git status -s
M  a.txt
 M b.txt
dang@DFLubuntu:~/testproject$ git diff --staged
diff --git a/a.txt b/a.txt
index e69de29..642c7f2 100644
--- a/a.txt
+++ b/a.txt
@@ -0,0 +1 @@
+AAAAAAA
dang@DFLubuntu:~/testproject$ git commit -m "向a.txt添加测试内容"
[master 2ae6624] 向a.txt添加测试内容
 1 file changed, 1 insertion(+)
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
dang@DFLubuntu:~/testproject$ git status -s
 M b.txt
dang@DFLubuntu:~/testproject$ 

status -sdiff --staged都表明,git restore --staged <filename>命令能撤销暂存某文件,等价于git reset HEAD <filename>
实际上就是将暂存区的修改重新放回工作区(包括对文件自身的操作,如添加文件、修改、删除文件)。

3,丢弃工作目录中的修改:restore

场景三:修改了文件,但思索后又不想保留对它文件的修改了。

# 现状:a.txt文件修改后已经被暂存并提交,b.txt修改后还未暂存
dang@DFLubuntu:~/testproject$ git status -s
 M b.txt

# 目的:暂存并提交这两个文件

# 失误:修改了a.txt文件,但又不想修改了
dang@DFLubuntu:~/testproject$ vim a.txt
dang@DFLubuntu:~/testproject$ git status -s
 M a.txt
 M b.txt
dang@DFLubuntu:~/testproject$ git diff
diff --git a/a.txt b/a.txt
index 642c7f2..43d5a8e 100644
--- a/a.txt
+++ b/a.txt
@@ -1 +1 @@
-AAAAAAA
+AAA
diff --git a/b.txt b/b.txt
index e69de29..ba62923 100644
--- a/b.txt
+++ b/b.txt
@@ -0,0 +1 @@
+BBB

# 补救:撤消对a.txt文件的修改
dang@DFLubuntu:~/testproject$ git restore a.txt
dang@DFLubuntu:~/testproject$ git status -s
 M b.txt
dang@DFLubuntu:~/testproject$ git diff
diff --git a/b.txt b/b.txt
index e69de29..ba62923 100644
--- a/b.txt
+++ b/b.txt
@@ -0,0 +1 @@
+BBB
dang@DFLubuntu:~/testproject$ git add .
dang@DFLubuntu:~/testproject$ git status -s
M  b.txt
commit 60ba7bc17fa192c73da07c5c78505f41557f9581
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 02:09:15 2021 +0800

    第一次提交
dang@DFLubuntu:~/testproject$ git log -1
commit 2ae66240147fed550a5c73d82fa2693ead9fd5b0 (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 22:23:19 2021 +0800

    向a.txt添加测试内容
dang@DFLubuntu:~/testproject$ git commit -m "向b.txt添加测试内容"
[master b5c33cc] 向b.txt添加测试内容
 1 file changed, 1 insertion(+)

还是根据status -sdiff --staged看出来,git restore <filename>命令能丢弃工作区的修改,等价于git checkout -- <file_name>
实际上,撤销修改某文件就是丢弃工目录中的的变更(包括对文件自身的操作,如添加、修改、删除文件),这会让这个文件还原成上次提交时的样子、或者刚克隆完的样子、或者刚把它放入工作目录时的样子。

在后两种场景中,当执行了编辑操作后,再执行 git status的话,Git 会对你进行一些提示:

  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
  (使用 "git restore --staged <文件>..." 以取消暂存)

总结一下:

功能命令
修正上次不完整的提交git commit --amend
取消文件暂存git restore --staged <filename>git reset HEAD <filename>
丢弃工作目录中的文件修改git restore <filename>git checkout -- <file_name>

(三)关于 Git 中提交级别的撤销操作

前面都是文件级别的撤销操作,这就来看看如何在提交历史中实现穿梭。

首先我们要确认两个”点“,

  • 我们当前处于哪个快照版本。
  • 我们打算去到哪个快照版本。

1,父提交和重新认识 HEAD

一般情况下,在查看提交的历史与差异中就能看到HEAD,也可能看到别人用 git reset HEAD <filename> 来撤销刚刚某文件的暂存,但 HEAD 到底是什么呢?

head 是对提交的引用。在谈论提交时,我们不谈提交名,而是说 head 。
当在不同的提交之间切换时,我们需要一种方法——当前磁头(被检出的磁头)即HEAD——来告知知道我们在哪个head上:

dang@DFLubuntu:~/testproject$ git log --oneline
b5c33cc (HEAD -> master) 向b.txt添加测试内容
2ae6624 向a.txt添加测试内容
639471b 新增两个用于测试的文本文件以及一个说明文件
5a4052c 再次修改问候语
c56e23d 修改问候语
60ba7bc 第一次提交
dang@DFLubuntu:~/testproject$ git show HEAD
commit b5c33cc4e0db85fe9380a3b58814c337e644070e (HEAD, master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 22:39:24 2021 +0800

    向b.txt添加测试内容

diff --git a/b.txt b/b.txt
index e69de29..ba62923 100644
--- a/b.txt
+++ b/b.txt
@@ -0,0 +1 @@
+BBB
  • 当前提交就是最新提交。

这里就需要区别两个概念,当前提交最新提交

  • 没有其他分支且没有切换提交时,情况是这样:这里只有一个master主分支,HEAD 指向 master 告诉我们正工作在名为 master 的 head 上,而 master 始终引用最新的提交,所以说 head 就是对最新提交的引用并且当前提交就是最新提交:
    在这里插入图片描述
  • 切换提交的操作就会改变 HEAD 的指向,我们可以通过检出等操作将当前状态定位到之前的某个提交,这就使得当前提交不是最新提交。此时的HEAD状态被称为HEAD的分离态:
    在这里插入图片描述
  • 当我们在当前提交后又创建一次提交,新提交会已分支的形式扩展出去,此时当前提交就又是最新提交了:
    在这里插入图片描述
  • 如果又切换回master时,当前提交就变为b5c33cc,它始终被master引用,而最新提交5a4202d由于没有被谁引用,它最终会被当成垃圾回收处理,除非我们在它被回收前创建一个分支名或者标签名来引用它:
    在这里插入图片描述

当切换提交时:

dang@DFLubuntu:~/testproject$ git checkout 5a4052c
注意:正在切换到 '5a4052c'。

您正处于分离头指针状态。您可以查看、做试验性的修改及提交,并且您可以在切换
回一个分支时,丢弃在此状态下所做的提交而不对分支造成影响。

如果您想要通过创建分支来保留在此状态下所做的提交,您可以通过在 switch 命令
中添加参数 -c 来实现(现在或稍后)。例如:

  git switch -c <新分支名>

或者撤销此操作:

  git switch -

通过将配置变量 advice.detachedHead 设置为 false 来关闭此建议

HEAD 目前位于 5a4052c 再次修改问候语

# 已回到具体的历史中的提交的状态
dang@DFLubuntu:~/testproject$ git show HEAD
commit 5a4052cf13aef78e15d3ae0fb71057e0996b3bad (HEAD)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 14:45:05 2021 +0800

    再次修改问候语

diff --git a/README.md b/README.md
index 7bcfe7c..acd3ef0 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-TESTPROJECT
+WELCOME TO TESTPROJECT
diff --git a/test.py b/test.py
index 3b0b1ed..509056f 100644
--- a/test.py
+++ b/test.py
@@ -1,4 +1,4 @@
 from datetime import datetime
 
-print("What's the time?")
+print("Now: ")
 print(datetime.today())
dang@DFLubuntu:~/testproject$ git log --oneline
5a4052c (HEAD) 再次修改问候语
c56e23d 修改问候语
60ba7bc 第一次提交
  • checkout 5a4052c 后 HEAD 指向了 5a4052c 提交。

再来看一个相关的概念:父提交
在我们的所有提交中,当前的提交是 b5c33cc ,那么它的父提交就是 2ae6624,所以说 HEAD 是对当前提交的引用时,那么 HEAD^ 或者 master^ 就引用当前提交的父提交:
在这里插入图片描述
之所以执行git reset HEAD <filename> 能撤销刚刚某文件的暂存,实际上是因为filename文件只是被添加到了暂存区而尚未被提交,这就尚未改变 HEAD 引用的当前提交,reset 只不过是重置了当前提交中filename文件的相关操作,也就是取消将它暂存到暂存区这一操作,从而达到撤销该文件的暂存的目的。

2,检出——在提交历史中穿梭:checkout

Git 中有一种被称为 检出(check out) 的操作,Git 通过检出操作能让我们浏览某个历史提交状态中某些文件的内容,实际上就是改变 HEAD 的指向。

可以执行 git checkout <cmoomit_SHA-1_value>检出操作将工作目录暂时还原为之前某个提交的状态。

  • 前提是必须确保工作目录中没有任何未暂存的文件!
  • 执行检出操作后,处于HEAD分离态。
# 先查看所有提交历史
dang@DFLubuntu:~/testproject$ git log --oneline
b5c33cc (HEAD -> master) 向b.txt添加测试内容
2ae6624 向a.txt添加测试内容
639471b 新增两个用于测试的文本文件以及一个说明文件
5a4052c 再次修改问候语
c56e23d 修改问候语
60ba7bc 第一次提交

# 查看当前提交与上次已提交的差异
dang@DFLubuntu:~/testproject$ git show b5c33cc
commit b5c33cc4e0db85fe9380a3b58814c337e644070e (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 22:39:24 2021 +0800

    向b.txt添加测试内容

diff --git a/b.txt b/b.txt
index e69de29..ba62923 100644
--- a/b.txt
+++ b/b.txt
@@ -0,0 +1 @@
+BBB

# 查看要检出的提交与上次已提交的差异
dang@DFLubuntu:~/testproject$ git show 5a4052c
commit 5a4052cf13aef78e15d3ae0fb71057e0996b3bad
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 14:45:05 2021 +0800

    再次修改问候语

diff --git a/README.md b/README.md
index 7bcfe7c..acd3ef0 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-TESTPROJECT
+WELCOME TO TESTPROJECT
diff --git a/test.py b/test.py
index 3b0b1ed..509056f 100644
--- a/test.py
+++ b/test.py
@@ -1,4 +1,4 @@
 from datetime import datetime
 
-print("What's the time?")
+print("Now: ")
 print(datetime.today())
 
# 在确定当前工作目录中没有变更后就能进行检出操作
dang@DFLubuntu:~/testproject$ la -l
总用量 28
-rw-rw-r-- 1 dang dang    8 1115 22:30 a.txt
-rw-rw-r-- 1 dang dang   11 1115 19:07 AUTHORS
-rw-rw-r-- 1 dang dang    4 1115 21:39 b.txt
drwxrwxr-x 8 dang dang 4096 1116 14:55 .git
-rw-rw-r-- 1 dang dang    1 1114 23:48 .gitignore
-rw-rw-r-- 1 dang dang   23 1115 13:59 README.md
-rw-rw-r-- 1 dang dang   70 1115 14:24 test.py
dang@DFLubuntu:~/testproject$ git diff
dang@DFLubuntu:~/testproject$ git checkout 5a4052c
注意:正在切换到 '5a4052c'。

您正处于分离头指针状态。您可以查看、做试验性的修改及提交,并且您可以在切换
回一个分支时,丢弃在此状态下所做的提交而不对分支造成影响。

如果您想要通过创建分支来保留在此状态下所做的提交,您可以通过在 switch 命令
中添加参数 -c 来实现(现在或稍后)。例如:

  git switch -c <新分支名>

或者撤销此操作:

  git switch -

通过将配置变量 advice.detachedHead 设置为 false 来关闭此建议

HEAD 目前位于 5a4052c 再次修改问候语

# 已回到具体的历史中的提交的状态
dang@DFLubuntu:~/testproject$ git show HEAD
commit 5a4052cf13aef78e15d3ae0fb71057e0996b3bad (HEAD)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 14:45:05 2021 +0800

    再次修改问候语

diff --git a/README.md b/README.md
index 7bcfe7c..acd3ef0 100644
--- a/README.md
+++ b/README.md
@@ -1 +1 @@
-TESTPROJECT
+WELCOME TO TESTPROJECT
diff --git a/test.py b/test.py
index 3b0b1ed..509056f 100644
--- a/test.py
+++ b/test.py
@@ -1,4 +1,4 @@
 from datetime import datetime
 
-print("What's the time?")
+print("Now: ")
 print(datetime.today())
dang@DFLubuntu:~/testproject$ git log --oneline
5a4052c (HEAD) 再次修改问候语
c56e23d 修改问候语
60ba7bc 第一次提交
dang@DFLubuntu:~/testproject$ ls -l		# 查看这个提交中的工作目录的内容
总用量 8
-rw-rw-r-- 1 dang dang 23 1115 13:59 README.md
-rw-rw-r-- 1 dang dang 70 1115 14:24 test.py
dang@DFLubuntu:~/testproject$ git diff	只是改变了

# 退回到最新提交的状态,完成本次提交历史的穿梭
dang@DFLubuntu:~/testproject$ git checkout b5c33cc
之前的 HEAD 位置是 5a4052c 再次修改问候语
HEAD 目前位于 b5c33cc 向b.txt添加测试内容
dang@DFLubuntu:~/testproject$ git show HEAD
commit b5c33cc4e0db85fe9380a3b58814c337e644070e (HEAD, master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Mon Nov 15 22:39:24 2021 +0800

    向b.txt添加测试内容

diff --git a/b.txt b/b.txt
index e69de29..ba62923 100644
--- a/b.txt
+++ b/b.txt
@@ -0,0 +1 @@
+BBB
dang@DFLubuntu:~/testproject$ git log --oneline
b5c33cc (HEAD, master) 向b.txt添加测试内容
2ae6624 向a.txt添加测试内容
639471b 新增两个用于测试的文本文件以及一个说明文件
5a4052c 再次修改问候语
c56e23d 修改问候语
60ba7bc 第一次提交

整个在提交历史中穿梭的过程就是 HEAD 指针指向的变更:
在这里插入图片描述
在状态 2 中, HEAD 指向了某个具体的提交记录而不是分支名,这个过程称为 detaching head ,此时的HEAD就是一个分离的HEAD。

3,重置提交——在提交历史中回溯:reset

如果说检出通过HEAD的分离态实现了历史穿越,那么重置将直接回溯到某个历史中的提交,这就不再只是浏览历史了,而是成为历史。

为了精细控制回溯后的历史提交所应该拥有的状态, reset提供三个选项控制重置历史快照时使用的数据范围:

  • --soft:仅 HEAD 回溯到指定状态,而保留工作目录和暂存区不变。
  • --mixed:让的 HEAD 和暂存区回溯到指定状态,而保留工作目录不变。
  • --hard:让 HEAD 、暂存区和工作目录都回溯到指定状态,不保留任何内容。

实际上就是选择指定状态的 HEAD、暂存区、工作目录三者中的哪些去覆盖最新状态:
在这里插入图片描述

  • 就像在前面说的,当我们回溯到历史中某处后,不做额外引用的话,一段时间后目标提交之后的所用提交都将被回收,看起来就像是被删除了一样。

做一些准备工作:

# 重新创建 git-tutorial 并初始化 Git 本地仓库
dang@DFLubuntu:~$ mkdir git-tutorial
dang@DFLubuntu:~$ cd git-tutorial
dang@DFLubuntu:~/git-tutorial$ git init
已初始化空的 Git 仓库于 /home/dang/git-tutorial/.git/
dang@DFLubuntu:~/git-tutorial$ ls -l
总用量 0
dang@DFLubuntu:~/git-tutorial$ git status
位于分支 master

尚无提交

无文件要提交(创建/拷贝文件并使用 "git add" 建立跟踪)
dang@DFLubuntu:~/git-tutorial$ git status -s
dang@DFLubuntu:~/git-tutorial$ git diff
dang@DFLubuntu:~/git-tutorial$ git diff --staged

# 编辑a.md并第一次提交
dang@DFLubuntu:~/git-tutorial$ vim a.md
dang@DFLubuntu:~/git-tutorial$ git status		# 查看工作目录与暂存区的变更,由于刚创建并编辑a.md文件且暂未暂存,所以显示工作目录有未跟踪的新文件
位于分支 master

尚无提交

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	a.md

提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于刚创建并编辑a.md文件且暂未暂存,所以显红色??
?? a.md
dang@DFLubuntu:~/git-tutorial$ git diff			# 查看工作目录相对于暂存区的变更,由于刚创建并编辑a.md文件且暂未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于刚创建并编辑a.md文件且暂未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git add a.md		# 暂存a.md
dang@DFLubuntu:~/git-tutorial$ git status		# 查看工作目录与暂存区的变更,由于a.md文件已暂存且暂未提交,所以显示暂存区要提交的变更
位于分支 master

尚无提交

要提交的变更:
  (使用 "git rm --cached <文件>..." 以取消暂存)
	新文件:   a.md

dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于a.md文件已暂存且暂未提交,所以显示绿色A
A  a.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件已暂未暂存且未变更,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于a.md文件已暂存且暂未提交,所以显示暂存区中的变更
diff --git a/a.md b/a.md
new file mode 100644
index 0000000..987e615
--- /dev/null
+++ b/a.md
@@ -0,0 +1 @@
+第一次输入的内容
dang@DFLubuntu:~/git-tutorial$ git commit -m "第一次提交"	# 第一次提交a.md
[master (根提交) e85b9a5] 第一次提交
 1 file changed, 1 insertion(+)
 create mode 100644 a.md
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md文件提交后暂未变更,所以显示工作目录干净
位于分支 master
无文件要提交,干净的工作区
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后暂未变更,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后暂未变更,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后暂未变更,所以无显示
dang@DFLubuntu:~/git-tutorial$ vim a.md		# 变更a.md
dang@DFLubuntu:~/git-tutorial$ touch b.md	# 新增b.md
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且尚未暂存,还新增了新文件b.md,所以显示所以显示工作目录有文件变更且有未跟踪的文件
位于分支 master
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
	修改:     a.md

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	b.md

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且尚未暂存,还新增了新文件b.md,所以显示 红M 和 红??
 M a.md
?? b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后已变更且尚未暂存,所以显示工作目录中的变更:在a.md中新增一行内容
diff --git a/a.md b/a.md
index 987e615..aba5dbd 100644
--- a/a.md
+++ b/a.md
@@ -1 +1,2 @@
 第一次输入的内容
+第二次输入的内容
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后已变更但暂未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git add a.md		# 暂存a.md
dang@DFLubuntu:~/git-tutorial$ git status		# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,新文件b.md还是暂未暂存,所以显示暂存区有文件变更且有未跟踪的文件
位于分支 master
要提交的变更:
  (使用 "git restore --staged <文件>..." 以取消暂存)
	修改:     a.md

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	b.md

dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,新文件b.md还是暂未暂存,所以显示 绿M 和 红??
M  a.md
?? b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,所以显示工作目录中的变更:在a.md中新增一行内容
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后已变更且暂存,所以显示暂存区中的变更:在a.md中新增一行内容
diff --git a/a.md b/a.md
index 987e615..aba5dbd 100644
--- a/a.md
+++ b/a.md
@@ -1 +1,2 @@
 第一次输入的内容
+第二次输入的内容
dang@DFLubuntu:~/git-tutorial$ git commit -m "第二次提交"	# 第一次提交a.md
[master eda8fb0] 第二次提交
 1 file changed, 1 insertion(+)
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md文件提交后暂未变更且尚未暂存,新文件b.md还是暂未暂存,所以显示有未跟踪的文件
位于分支 master
未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	b.md

提交为空,但是存在尚未跟踪的文件(使用 "git add" 建立跟踪)
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件提交后暂未变更且尚未暂存,新文件b.md还是暂未暂存,所以显示 红??
?? b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后暂未变更且尚未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后暂未变更且尚未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ vim a.md		# 变更a.md
dang@DFLubuntu:~/git-tutorial$ vim b.md		# 变更b.md
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md文件提交后已变更且尚未暂存,新文件b.md还是暂未暂存,所以显示暂存区变更且有未跟踪的文件
位于分支 master
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
	修改:     a.md

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	b.md

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件提交后已变更且尚未暂存,文件b.md还是暂未暂存,所以显示 红M 和 红??
 M a.md
?? b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后已变更且尚未暂存,文件b.md还是暂未暂存,所以显示工作目录有文件变更
diff --git a/a.md b/a.md
index aba5dbd..e0c0d0f 100644
--- a/a.md
+++ b/a.md
@@ -1,2 +1,3 @@
 第一次输入的内容
 第二次输入的内容
+第三次输入的内容
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后已变更但暂未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git add a.md b.md	#暂存所有
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,新文件b.md也已暂存,所以显示暂存区有文件变更且有新文件暂存
位于分支 master
要提交的变更:
  (使用 "git restore --staged <文件>..." 以取消暂存)
	修改:     a.md
	新文件:   b.md

dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,文件b.md也已暂存,所以显示 绿M 和 绿A
M  a.md
A  b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md文件自上次提交后已变更且已暂存,b.md自暂存后未变更,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md文件自上次提交后已变更且暂存,文件b.md也已暂存,所以显示暂存区中的变更:在a.md中新增一行内容,在新暂存的b.md中有一行内容
diff --git a/a.md b/a.md
index aba5dbd..e0c0d0f 100644
--- a/a.md
+++ b/a.md
@@ -1,2 +1,3 @@
 第一次输入的内容
 第二次输入的内容
+第三次输入的内容
diff --git a/b.md b/b.md
new file mode 100644
index 0000000..cd74efb
--- /dev/null
+++ b/b.md
@@ -0,0 +1 @@
+第一次插入内容
dang@DFLubuntu:~/git-tutorial$ git commit -m "第三次提交"	# 第三次提交
[master 6dfd1d9] 第三次提交
 2 files changed, 2 insertions(+)
 create mode 100644 b.md
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于工作目录a.md和b.md自上次提交后暂未变更且尚未暂存,所以显示工作目录干净
位于分支 master
无文件要提交,干净的工作区
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于工作目录a.md和b.md自上次提交后暂未变更且尚未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于工作目录a.md和b.md自上次提交后暂未变更且尚未暂存,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于工作目录a.md和b.md自上次提交后暂未变更且尚未暂存,所以无显示

# 查看提交历史及其变更
dang@DFLubuntu:~/git-tutorial$ git log -p	
commit 6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Wed Nov 17 01:05:55 2021 +0800

    第三次提交

diff --git a/a.md b/a.md
index aba5dbd..e0c0d0f 100644
--- a/a.md
+++ b/a.md
@@ -1,2 +1,3 @@
 第一次输入的内容
 第二次输入的内容
+第三次输入的内容
diff --git a/b.md b/b.md
new file mode 100644
index 0000000..cd74efb
--- /dev/null
+++ b/b.md
@@ -0,0 +1 @@
+第一次插入内容

commit eda8fb01f0f0adc1d7355cb5a2cc0b20b33a22bf
Author: xiaolu2333 <2694977226@qq.com>
Date:   Wed Nov 17 01:02:45 2021 +0800

    第二次提交

diff --git a/a.md b/a.md
index 987e615..aba5dbd 100644
--- a/a.md
+++ b/a.md
@@ -1 +1,2 @@
 第一次输入的内容
+第二次输入的内容

commit e85b9a559a84b3a5ff8719463755a3ab5791c67d
Author: xiaolu2333 <2694977226@qq.com>
Date:   Wed Nov 17 00:59:56 2021 +0800

    第一次提交

diff --git a/a.md b/a.md
new file mode 100644
index 0000000..987e615
--- /dev/null
+++ b/a.md
@@ -0,0 +1 @@
+第一次输入的内容

例如使用 --soft 选项回溯到第一次的提交:

# 查看提交历史
dang@DFLubuntu:~/git-tutorial$ git log --oneline
6dfd1d9 (HEAD -> master) 第三次提交
eda8fb0 第二次提交
e85b9a5 第一次提交

# 确认工作目录无变更后soft重置到第一次提交
dang@DFLubuntu:~/git-tutorial$ git reset --soft e85b9a5		# 未提会重置任何东西
dang@DFLubuntu:~/git-tutorial$ git show HEAD	# 此时 HEAD 已分离,指向第一次提交,查看到第一次提交的变更
commit e85b9a559a84b3a5ff8719463755a3ab5791c67d (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Wed Nov 17 00:59:56 2021 +0800

    第一次提交

diff --git a/a.md b/a.md
new file mode 100644
index 0000000..987e615
--- /dev/null
+++ b/a.md
@@ -0,0 +1 @@
+第一次输入的内容
dang@DFLubuntu:~/git-tutorial$ git log --oneline	# 第一次提交时的历史提交
e85b9a5 (HEAD -> master) 第一次提交
dang@DFLubuntu:~/git-tutorial$ ls -l	# 此时,不会用第一次提交时的工作目录覆盖最新提交时的工作目录,所以此时工作目录的内容相对最新提交无变化
总用量 8
-rw-rw-r-- 1 dang dang 75 1117 01:03 a.md
-rw-rw-r-- 1 dang dang 22 1117 01:04 b.md
dang@DFLubuntu:~/git-tutorial$ cat a.md
第一次输入的内容
第二次输入的内容
第三次输入的内容
dang@DFLubuntu:~/git-tutorial$ cat b.ma
cat: b.ma: 没有那个文件或目录
dang@DFLubuntu:~/git-tutorial$ cat b.md
第一次插入内容
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,(由于工作目录a.md文件提交后已变更且已暂存,文件b.md也已暂存,所以显示暂存区变更)这就是最新提交中的内容,得到保留
位于分支 master
要提交的变更:
  (使用 "git restore --staged <文件>..." 以取消暂存)
	修改:     a.md
	新文件:   b.md

dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,(由于工作目录a.md文件提交后已变更且已暂存,文件b.md也已暂存,所以显示暂存区变更)这就是最新提交中的内容,得到保留
M  a.md
A  b.md
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,(由于工作目录a.md文件自上次提交后已变更且已暂存,b.md暂存后未变更,所以无显示)这就是最新提交中的内容,得到保留
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看当前暂存区相对于最新提交的变更,内容无变化,仅显示出差异
diff --git a/a.md b/a.md
index 987e615..e0c0d0f 100644
--- a/a.md
+++ b/a.md
@@ -1 +1,3 @@
 第一次输入的内容
+第二次输入的内容
+第三次输入的内容
diff --git a/b.md b/b.md
new file mode 100644
index 0000000..cd74efb
--- /dev/null
+++ b/b.md
@@ -0,0 +1 @@
+第一次插入内容

# 重置回最新提交
dang@DFLubuntu:~/git-tutorial$ git reset --soft 6dfd1d9
dang@DFLubuntu:~/git-tutorial$ git show HEAD	# 此时 HEAD 未分离,指向第三次(最新)提交
commit 6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 (HEAD -> master)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Wed Nov 17 01:05:55 2021 +0800

    第三次提交

diff --git a/a.md b/a.md
index aba5dbd..e0c0d0f 100644
--- a/a.md
+++ b/a.md
@@ -1,2 +1,3 @@
 第一次输入的内容
 第二次输入的内容
+第三次输入的内容
diff --git a/b.md b/b.md
new file mode 100644
index 0000000..cd74efb
--- /dev/null
+++ b/b.md
@@ -0,0 +1 @@
+第一次插入内容
dang@DFLubuntu:~/git-tutorial$ git log --oneline	# 第三次(最新)提交时的历史提交
6dfd1d9 (HEAD -> master) 第三次提交
eda8fb0 第二次提交
e85b9a5 第一次提交
dang@DFLubuntu:~/git-tutorial$ ls -l	# 切回后,工作目录无变化
总用量 8
-rw-rw-r-- 1 dang dang 75 1117 01:03 a.md
-rw-rw-r-- 1 dang dang 22 1117 01:04 b.md
dang@DFLubuntu:~/git-tutorial$ cat a.md
第一次输入的内容
第二次输入的内容
第三次输入的内容
dang@DFLubuntu:~/git-tutorial$ cat b.md
第一次插入内容
dang@DFLubuntu:~/git-tutorial$ git status	# 查看工作目录与暂存区的变更,由于切回后工作目录与暂存区均无变化,所以显示工作目录干净
位于分支 master
无文件要提交,干净的工作区
dang@DFLubuntu:~/git-tutorial$ git status -s	# 查看工作目录与暂存区的变更,由于切回后工作目录与暂存区均无变化,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff		# 查看工作目录相对于暂存区的变更,由于切回后工作目录与暂存区均无变化,所以无显示
dang@DFLubuntu:~/git-tutorial$ git diff --staged	# 查看暂存区相对于上次提交的变更,由于切回后暂存区无变化,所以无显示

重置揭密

4,撤销切换提交——使用记录切换历史提交的历史:reflog

假如我们切换到某处提交后又后悔了,想撤销这次切换,可能会想到用前面讲过 log 来查看提交历史,依据其展示的七位 SHA-1 值切换(检出或回溯)回来。
但此时 log 的结果中一部分提交数据就却没展示出来了,没有了之前所在提交的 SHA-1 值就回不去了呀。还是能回去的。

还记得 .git/logs/ 目录吗?记录了本地仓库和远程仓库的每一个分支的提交信息,即所有 commit 对象都会被记录在此:

dang@DFLubuntu:~/git-tutorial$ tree .git/logs/
.git/logs/
├── HEAD
└── refs
    └── heads
        └── master

2 directories, 2 files
dang@DFLubuntu:~/git-tutorial$ cat .git/logs/HEAD
0000000000000000000000000000000000000000 e85b9a559a84b3a5ff8719463755a3ab5791c67d xiaolu2333 <2694977226@qq.com> 1637081996 +0800	commit (initial): 第一次提交
e85b9a559a84b3a5ff8719463755a3ab5791c67d eda8fb01f0f0adc1d7355cb5a2cc0b20b33a22bf xiaolu2333 <2694977226@qq.com> 1637082165 +0800	commit: 第二次提交
eda8fb01f0f0adc1d7355cb5a2cc0b20b33a22bf 6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 xiaolu2333 <2694977226@qq.com> 1637082355 +0800	commit: 第三次提交
6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 e85b9a559a84b3a5ff8719463755a3ab5791c67d xiaolu2333 <2694977226@qq.com> 1637082467 +0800	reset: moving to e85b9a5
e85b9a559a84b3a5ff8719463755a3ab5791c67d 6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 xiaolu2333 <2694977226@qq.com> 1637082590 +0800	reset: moving to 6dfd1d9
6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 eda8fb01f0f0adc1d7355cb5a2cc0b20b33a22bf xiaolu2333 <2694977226@qq.com> 1637082703 +0800	reset: moving to eda8fb0
eda8fb01f0f0adc1d7355cb5a2cc0b20b33a22bf 6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 xiaolu2333 <2694977226@qq.com> 1637082833 +0800	reset: moving to 6dfd1d9
6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 e85b9a559a84b3a5ff8719463755a3ab5791c67d xiaolu2333 <2694977226@qq.com> 1637144177 +0800	reset: moving to e85b9a5
dang@DFLubuntu:~/git-tutorial$ cat .git/logs/refs/heads/master
0000000000000000000000000000000000000000 e85b9a559a84b3a5ff8719463755a3ab5791c67d xiaolu2333 <2694977226@qq.com> 1637081996 +0800	commit (initial): 第一次提交
e85b9a559a84b3a5ff8719463755a3ab5791c67d eda8fb01f0f0adc1d7355cb5a2cc0b20b33a22bf xiaolu2333 <2694977226@qq.com> 1637082165 +0800	commit: 第二次提交
eda8fb01f0f0adc1d7355cb5a2cc0b20b33a22bf 6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 xiaolu2333 <2694977226@qq.com> 1637082355 +0800	commit: 第三次提交
6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 e85b9a559a84b3a5ff8719463755a3ab5791c67d xiaolu2333 <2694977226@qq.com> 1637082467 +0800	reset: moving to e85b9a5
e85b9a559a84b3a5ff8719463755a3ab5791c67d 6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 xiaolu2333 <2694977226@qq.com> 1637082590 +0800	reset: moving to 6dfd1d9
6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 eda8fb01f0f0adc1d7355cb5a2cc0b20b33a22bf xiaolu2333 <2694977226@qq.com> 1637082703 +0800	reset: moving to eda8fb0
eda8fb01f0f0adc1d7355cb5a2cc0b20b33a22bf 6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 xiaolu2333 <2694977226@qq.com> 1637082833 +0800	reset: moving to 6dfd1d9
6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 e85b9a559a84b3a5ff8719463755a3ab5791c67d xiaolu2333 <2694977226@qq.com> 1637144177 +0800	reset: moving to e85b9a5
  • HEAD 记录了每次 HEAD 移动的历史:从哪里来,到哪里去、是通过什么方式移动的。
  • 这样就能查到所有 SHA-1 值了。

但先查目录内容再切换雀食有点麻烦,所以 Git 提供 git reflog 命令查看HEAD 的所有移动记录
在这里插入图片描述

  • 与上面相比,顺序是反过来的。

找到 SHA-1 值后就能执行 git reset --hard <commit_SHA-1_value>命令回溯到指定提交了:

dang@DFLubuntu:~/git-tutorial$ git reset --hard 6dfd1d9
HEAD 现在位于 6dfd1d9 第三次提交
dang@DFLubuntu:~/git-tutorial$ git log --oneline
6dfd1d9 (HEAD -> master) 第三次提交
eda8fb0 第二次提交
e85b9a5 第一次提交

还有更简单的方法,执行类似 git reset --hard HEAD^命令回溯到上次提交

dang@DFLubuntu:~/git-tutorial$ git log --oneline
6dfd1d9 (HEAD -> master) 第三次提交
eda8fb0 第二次提交
e85b9a5 第一次提交
dang@DFLubuntu:~/git-tutorial$ git reset --hard HEAD^
HEAD 现在位于 eda8fb0 第二次提交
dang@DFLubuntu:~/git-tutorial$ git reset --hard 6dfd1d9
HEAD 现在位于 6dfd1d9 第三次提交
dang@DFLubuntu:~/git-tutorial$ git reset --hard HEAD~1
HEAD 现在位于 eda8fb0 第二次提交
dang@DFLubuntu:~/git-tutorial$ git reset --hard 6dfd1d9
HEAD 现在位于 6dfd1d9 第三次提交
dang@DFLubuntu:~/git-tutorial$ 
  • git reset --hard HEAD~n命令回溯到前n次提交。

在后面对分支的介绍中还有分支级别的撤销操作,还有如何进行数据恢复。
记住,在 Git 中任何已提交的东西几乎总是可以恢复的。 甚至那些被删除的分支中的提交或使用 --amend 选项覆盖的提交也可以恢复。然而,任何你未提交的东西丢失后很可能再也找不到了。

Git系列之Refs 与 Reflog

5,常用的撤销场景与命令

Git & GitHub 杂记:直接操作文件的后悔药
Git & GitHub 杂记:直接操作提交的后悔药

八,打标签:tag

像其他 VCS一样,Git 可以给历史中的某一个提交打上标签,以示重要,比如使用类似 v1.0.1的形式来标记软件版本结点。

(一)查看标签

执行 git tag 命令能列出已有的标签

dang@DFLubuntu:~/git-tutorial$ git tag
v0.0.1
v0.0.2
dang@DFLubuntu:~/git-tutorial$ 
  • -l '通配符'选项可以按通配符要求列出符合条件的标签:
dang@DFLubuntu:~/git-tutorial$ git tag -l "v0.0.*"
v0.0.1
v0.0.2
dang@DFLubuntu:~/git-tutorial$

执行 git show tagname 命令能查看标签中的标签信息

dang@DFLubuntu:~/git-tutorial$ git show v0.0.3
tag v0.0.3
Tagger: xiaolu2333 <2694977226@qq.com>
Date:   Thu Nov 18 16:05:43 2021 +0800

基础功能开发完毕

commit 6dfd1d90432e5804b2575022e0e5bbcb673d7ea8 (HEAD -> master, tag: v0.0.3, tag: v0.0.2, tag: v0.0.1)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Wed Nov 17 01:05:55 2021 +0800

    第三次提交

diff --git a/a.md b/a.md
index aba5dbd..e0c0d0f 100644
--- a/a.md
+++ b/a.md
@@ -1,2 +1,3 @@
 第一次输入的内容
 第二次输入的内容
+第三次输入的内容
diff --git a/b.md b/b.md
new file mode 100644
index 0000000..cd74efb
--- /dev/null
+++ b/b.md
@@ -0,0 +1 @@
+第一次插入内容
dang@DFLubuntu:~/git-tutorial$

dang@DFLubuntu:~/git-tutorial$ git show v0.0.1
commit e85b9a559a84b3a5ff8719463755a3ab5791c67d (tag: v0.0.1)
Author: xiaolu2333 <2694977226@qq.com>
Date:   Wed Nov 17 00:59:56 2021 +0800

    第一次提交

diff --git a/a.md b/a.md
new file mode 100644
index 0000000..987e615
--- /dev/null
+++ b/a.md
@@ -0,0 +1 @@
+第一次输入的内容
dang@DFLubuntu:~/git-tutorial$ 
  • v0.0.3是一个附注标签,”基础功能开发完毕“就是附注的标签信息

(二)创建标签

Git 支持两种标签:

  • 轻量标签(lightweight):只是对某个特定提交的引用(即 SHA-1 值),是固定不变的。
  • 附注标签(annotated):也是 Git 对象中的一种——标签对象,其中包含打标签者的名字、电子邮件地址、日期时间、标签信息以及对特定提交的引用(也是 SHA-1 值,因此标签可以标注到任意 Git 对象身上)。

执行 git tag tagname命令创建轻量标签

dang@DFLubuntu:~/git-tutorial$ git tag v0.0.1
dang@DFLubuntu:~/git-tutorial$ git tag v0.0.2
dang@DFLubuntu:~/git-tutorial$ git tag
v0.0.1
v0.0.2
dang@DFLubuntu:~/git-tutorial$ 

执行 git tag -a tagname -m "taginfo"命令创建带有标签信息的附注标签

dang@DFLubuntu:~/git-tutorial$ git tag -a v0.0.3 -m "基础功能开发完毕"
dang@DFLubuntu:~/git-tutorial$ git tag
v0.0.1
v0.0.2
v0.0.3
dang@DFLubuntu:~/git-tutorial$ 

如果只是创建标签而不将标签与具体提交关联起来,那么默认将这个最新标签打到最新提交上。可以执行 git log 命令能查看提交历史及其标签

dang@DFLubuntu:~/git-tutorial$ git log --oneline
6dfd1d9 (HEAD -> master, tag: v0.0.3, tag: v0.0.2, tag: v0.0.1) 第三次提交
eda8fb0 第二次提交
e85b9a5 第一次提交
dang@DFLubuntu:~/git-tutorial$

(三)删除与修改标签

假如标签有误,执行 git tag -d tagname命令能删除指定标签

dang@DFLubuntu:~/git-tutorial$ git tag -d v0.0.1
已删除标签 'v0.0.1'(曾为 6dfd1d9)
dang@DFLubuntu:~/git-tutorial$ git tag -d v0.0.2
已删除标签 'v0.0.2'(曾为 6dfd1d9)
dang@DFLubuntu:~/git-tutorial$ git tag -d v0.0.3
已删除标签 'v0.0.3'(曾为 16fb2e9)
dang@DFLubuntu:~/git-tutorial$ 

假如要修改标签名,可以先重新打一个新标签再删除旧标签:

dang@DFLubuntu:~/git-tutorial$ git tag v0.1.0 v0.0.1
dang@DFLubuntu:~/git-tutorial$ git log --oneline
6dfd1d9 (HEAD -> master, tag: v0.0.3) 第三次提交
eda8fb0 第二次提交
e85b9a5 (tag: v0.1.0, tag: v0.0.1) 第一次提交
dang@DFLubuntu:~/git-tutorial$ git tag -d v0.0.1
已删除标签 'v0.0.1'(曾为 e85b9a5)
dang@DFLubuntu:~/git-tutorial$ git log --oneline
6dfd1d9 (HEAD -> master, tag: v0.0.3) 第三次提交
eda8fb0 第二次提交
e85b9a5 (tag: v0.1.0) 第一次提交
dang@DFLubuntu:~/git-tutorial$ 
  • 一旦已将标签推送到远程仓库,最好就别重命名标签了。
  • 修改附注标签的辅助信息的操作也是先重新打一个新标签再删除旧标签。

(四)打标签

最好在创建标签时就将它与具体提交关联上,执行 git tag [-a] tagname [-m taginfo] commit_SHA-1_value 命令能对过去的提交打标签

dang@DFLubuntu:~/git-tutorial$ git log --oneline
6dfd1d9 (HEAD -> master) 第三次提交
eda8fb0 第二次提交
e85b9a5 第一次提交
dang@DFLubuntu:~/git-tutorial$ git tag v0.0.1 eda8fb0
dang@DFLubuntu:~/git-tutorial$ git log --oneline
6dfd1d9 (HEAD -> master) 第三次提交
eda8fb0 (tag: v0.0.1) 第二次提交
e85b9a5 第一次提交
dang@DFLubuntu:~/git-tutorial$ git tag -a v0.0.2 -m '完成基础功能开发' 6dfd1d9
dang@DFLubuntu:~/git-tutorial$ git log --oneline
6dfd1d9 (HEAD -> master, tag: v0.0.2) 第三次提交
eda8fb0 (tag: v0.0.1) 第二次提交
e85b9a5 第一次提交
dang@DFLubuntu:~/git-tutorial$ 

(五)检出——通过标签在提交历史中穿梭

如果你想查看某个标签所指向的历史提交,执行 git checkout tagname 命令能检出该标签引用的提交的状态

dang@DFLubuntu:~/git-tutorial$ git log --oneline
6dfd1d9 (HEAD -> master, tag: v0.0.2) 第三次提交
eda8fb0 第二次提交
e85b9a5 (tag: v0.0.1) 第一次提交
dang@DFLubuntu:~/git-tutorial$ ls -l
总用量 8
-rw-rw-r-- 1 dang dang 75 1117 19:25 a.md
-rw-rw-r-- 1 dang dang 22 1117 19:25 b.md
dang@DFLubuntu:~/git-tutorial$ git checkout v0.0.1
注意:正在切换到 'v0.0.1'。

您正处于分离头指针状态。您可以查看、做试验性的修改及提交,并且您可以在切换
回一个分支时,丢弃在此状态下所做的提交而不对分支造成影响。

如果您想要通过创建分支来保留在此状态下所做的提交,您可以通过在 switch 命令
中添加参数 -c 来实现(现在或稍后)。例如:

  git switch -c <新分支名>

或者撤销此操作:

  git switch -

通过将配置变量 advice.detachedHead 设置为 false 来关闭此建议

HEAD 目前位于 e85b9a5 第一次提交
dang@DFLubuntu:~/git-tutorial$ ls -l
总用量 4
-rw-rw-r-- 1 dang dang 25 1118 17:23 a.md
dang@DFLubuntu:~/git-tutorial$ 

九,别名

Git 并不会在你输入部分命令时自动推断出你想要的命令,但你可以为命令创建别名来使用简写的别名替代完整命令。

在当前用户环境下创建命令别名,例如设置git status -s的别名为git s-s

ang@DFLubuntu:~/git-tutorial$ git config --global alias.s-s 'status -s'
dang@DFLubuntu:~/git-tutorial$ cd ~
dang@DFLubuntu:~$ ls -la
总用量 128
drwxr-xr-x 22 dang dang  4096 1118 18:00 .
drwxr-xr-x  3 root root  4096 115 23:37 ..
drwxr-xr-x  2 dang dang  4096 116 00:40 公共的
drwxr-xr-x  2 dang dang  4096 116 00:40 模板
drwxr-xr-x  2 dang dang  4096 116 00:40 视频
drwxr-xr-x  2 dang dang  4096 116 00:40 图片
drwxr-xr-x  2 dang dang  4096 116 00:40 文档
drwxr-xr-x  3 dang dang  4096 116 01:27 下载
drwxr-xr-x  2 dang dang  4096 116 00:40 音乐
drwxr-xr-x  2 dang dang  4096 116 00:40 桌面
-rw-------  1 dang dang  3473 1115 21:05 .bash_history
-rw-r--r--  1 dang dang   220 115 23:37 .bash_logout
-rw-r--r--  1 dang dang  3771 115 23:37 .bashrc
drwx------ 15 dang dang  4096 116 01:36 .cache
drwx------ 14 dang dang  4096 1115 20:16 .config
-rw-rw-r--  1 dang dang   118 1118 18:00 .gitconfig
drwxrwxr-x  3 dang dang  4096 1118 17:38 git-tutorial
drwx------  3 dang dang  4096 116 01:29 .gnupg
drwxrwxr-x  4 dang dang  4096 116 01:18 .java
drwxrwxr-x 16 dang dang  4096 1116 23:06 libgit2
drwx------  3 dang dang  4096 116 00:40 .local
drwx------  5 dang dang  4096 116 00:44 .mozilla
-rw-r--r--  1 dang dang   807 115 23:37 .profile
drwxrwxr-x  4 dang dang  4096 1114 01:14 projects
-rw-------  1 dang dang    27 1115 20:17 .python_history
drwx------  4 dang dang  4096 116 01:18 snap
drwx------  2 dang dang  4096 1114 03:08 .ssh
-rw-r--r--  1 dang dang     0 116 01:30 .sudo_as_admin_successful
drwxrwxr-x  3 dang dang  4096 1118 13:41 testproject
-rw-------  1 dang dang 11636 1117 01:04 .viminfo
-rw-rw-r--  1 dang dang    19 116 01:59 .vimrc
dang@DFLubuntu:~$ cat .gitconfig
[user]
	email = 2694977226@qq.com
	name = xiaolu2333
[color]
	ui = true
[core]
	editor = vim
[alias]
	s-s = status -s
dang@DFLubuntu:~$ cd -
/home/dang/git-tutorial
dang@DFLubuntu:~/git-tutorial$ git s-s
dang@DFLubuntu:~/git-tutorial$ ls -l
总用量 8
-rw-rw-r-- 1 dang dang 75 1118 17:38 a.md
-rw-rw-r-- 1 dang dang 22 1118 17:38 b.md
dang@DFLubuntu:~/git-tutorial$ cat a.md
第一次输入的内容
第二次输入的内容
第三次输入的内容
dang@DFLubuntu:~/git-tutorial$ echo "测试s-s" >> a.md
dang@DFLubuntu:~/git-tutorial$ git s-s
 M a.md
 dang@DFLubuntu:~/git-tutorial$ cat a.md
第一次输入的内容
第二次输入的内容
第三次输入的内容
测试s-s
dang@DFLubuntu:~/git-tutorial$ 
  • 用户界别的配置内容保存在 /home/username/.gitconfig文件中(Linux环境)。

Git 别名允许你定义更复杂的别名,比如执行外部 shell 命令,可以在别名前加上 ! 字符:

git config --global alias.se '!git rev-list --all | xargs git grep -F'	# 搜索提交中的特定字符串

一些别名示例:

git config --global alias.unstage 'reset HEAD --'	# 取消暂存
git config --global alias.last 'log -1 HEAD'		# 查看最后一次提交
git config --global alias.s-sb 'status -sb'			# 查看工作目录与暂存区状态
git config --global alias.ll 'log --oneline'		# 单行日志
git config --global alias.cmm 'commit -m'			# 创建提交
git config --global alias.gl 'config --global -l'	# 查看git配置
git config --global alias.lgd "log --graph --oneline --all --decorate"			# 定制log格式一
git config --global alias.lgp-1 "log --graph  --pretty=format:'%h    %an    %s    %ai'"	# 定制log格式一
"
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值