Git原理(02)

11. pack文件

11.1 背景

新建一个代码仓库作为演示

1
2
3
xiong@Surface-pro6 MINGW64 /c/Files/git-demo2
$ git init
Initialized empty Git repository in C:/Files/git-demo2/.git/

将一个大小为7.32M的文件放到工作区

image-20210822171427745
  1. 将该文件进行添加和提交,使用du -h来查看文件夹的占用情况

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ git add word_note.docx

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ git commit -m "1st commit"
    [master (root-commit) 534c54e] 1st commit
    1 file changed, 0 insertions(+), 0 deletions(-)
    create mode 100644 word_note.docx

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ du -h .git/objects
    1.0K .git/objects/17
    1.0K .git/objects/53
    7.0M .git/objects/b8
    0 .git/objects/info
    0 .git/objects/pack
    7.0M .git/objects
  2. 将文件进行小的改动,随之再进行添加和提交

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ git add word_note.docx

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ git commit -m "2nd commit"
    [master 67a095b] 2nd commit
    1 file changed, 0 insertions(+), 0 deletions(-)

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ git add word_note.docx

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ git commit -m "3rd commit"
    [master 5153efa] 3rd commit
    1 file changed, 0 insertions(+), 0 deletions(-)
  3. 查看此时文件夹占用情况

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ du -h .git/objects
    1.0K .git/objects/17
    7.0M .git/objects/4b
    1.0K .git/objects/51
    1.0K .git/objects/53
    1.0K .git/objects/67
    1.0K .git/objects/ae
    7.0M .git/objects/b8
    7.0M .git/objects/e4
    1.0K .git/objects/fc
    0 .git/objects/info
    0 .git/objects/pack
    21M .git/objects
    1
    2
    3
    4
    5
    6
    7
    8
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ ls -lh
    total 7.4M
    -rw-r--r-- 1 xiong 197609 7.4M Aug 22 17:21 word_note.docx

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ git ls-files -s
    100644 e4d8fff037528cc82c6f923a5200f3dfa1876d6b 0 word_note.docx

    进行三次提交后objects文件夹已经达到了21M,虽然此时工作区内容只有7.4M

​ 在git里,文件会先压缩成blob对象进行存储。这虽在一定程度上减小了内存开销,但是由于每次对文件在工作区修改后,对文件进行添加和提交时,都会存储整个对象的压缩文件。根据开发实际场景,每次文件的改动都不会有较大的改动,而每次再新生成一份blob文件,就会增大内存开销。在此背景下提出了使用git gc进行压缩的方案

11.2 git gc 进行文件压缩

①使用git gc进行文件压缩

1
2
3
4
5
6
7
8
xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
$ git gc
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 8 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (9/9), done.
Total 9 (delta 2), reused 0 (delta 0), pack-reused 0

②查看现在.git文件夹中的内存占用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
$ du -h .git
35K .git/hooks
2.0K .git/info
1.0K .git/logs/refs/heads
1.0K .git/logs/refs
2.0K .git/logs
3.0K .git/objects/info
7.3M .git/objects/pack
7.3M .git/objects
0 .git/refs/heads
0 .git/refs/tags
0 .git/refs
7.3M .git

21M内容压缩成7.3M

③查看objects中的内容

1
2
3
4
5
6
7
8
9
10
11
12
xiong@SURFACE-PRO6 C:\Files\git-demo2
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO2\.GIT\OBJECTS
├─info
│ commit-graph
│ packs

└─pack
pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.idx
pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.pack

blob文件全部被压缩,生成了pack

  1. 查看pack文件夹中文件的大小

    1
    2
    3
    4
    5
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ ls -lh .git/objects/pack
    total 7.3M
    -r--r--r-- 1 xiong 197609 1.3K Aug 22 20:18 pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.idx
    -r--r--r-- 1 xiong 197609 7.3M Aug 22 20:18 pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.pack
  2. 查看.dex文件里存储的内容:git verify-pack -v 文件路径

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ git verify-pack -v .git/objects/pack/pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.idx
    5153efa4cf47077622e7771888cae3deb87db41e commit 225 149 12
    67a095b95ff121fb3e1bc648b98814e1c8f6c148 commit 225 148 161
    534c54ea578f0d6517cb5d38ddced88d4c4158b4 commit 177 119 309
    b80edea2a581ed6917723b45871f0af11beb714d blob 7683972 7330028 428
    4b574b366e9bb3ad454462ba510db98a01837b66 blob 167961 166370 7330456 1 b80edea2a581ed6917723b45871f0af11beb714d
    e4d8fff037528cc82c6f923a5200f3dfa1876d6b blob 98578 97543 7496826 2 4b574b366e9bb3ad454462ba510db98a01837b66
    fcd21cca77d88e7c8bda0ac43e72c8b5a6c7a4be tree 42 53 7594369
    aef20abb0786e52ac2234180cf18ad488023f7f2 tree 42 52 7594422
    172344478aef4544529c644e29130d7d8f1b041f tree 42 53 7594474
    non delta: 7 objects
    chain length = 1: 1 object
    chain length = 2: 1 object
    .git/objects/pack/pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.pack: ok

    里面存储有之前三次添加和提交所产生对象的完整记录

    只有b80ede所对应的blob文件所存储的是第一次提交时对象的完整内容,另外两个blob文件(后面跟有一串SHA1值),所记录的是与原始文件存在的差异

应用场景

当从远程克隆仓库到本地时,使用pack文件进行传输就可以节省传输时间,不过在传输到本地后,如果要检索到特定的某一次commit,则需要花费一点时间和内存去解压缩pack文件

11.3 解压缩

使用git unpack-objects < 输入流

使用git help unpack-objects查看命令描述

  • 名字

    git 拆包对象 - 从包装的存档中拆开对象

  • 概要

    1
    git unpack-objects [-n] [-q] [-r] [--strict]
  • 描述

    从标准输入中读取包装的存档 (.pack),扩展其中包含的对象,并以”松散”(每个文件一个对象)格式将其写入存储库。

    存储库中已经存在的对象不会从包装文件中拆开。因此,如果您在目标存储库内的包装文件上使用此命令,则不会拆开任何内容

  • 选项

    -n

    干运行。检查包文件,而不实际拆开对象。

    -q

    命令通常显示百分比进度。此标志将抑制它。

    -r

    解包损坏的打包文件时,该命令在第一次损坏时终止。这个标志告诉它继续前进,尽最大努力恢复尽可能多的对象。

    -严格

    不要编写内容或链接中断的对象。

    -最大输入大小=<尺寸>

    如果包大于<大小>, 则死亡

注意点

1
2
3
4
5
6
7
8
9
10
11
12
xiong@SURFACE-PRO6 C:\Files\git-demo2
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO2\.GIT\OBJECTS
├─info
│ commit-graph
│ packs

└─pack
pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.idx
pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.pack

当我们要使用unpack时,我们需要将.pack文件移到外面。虽然此时的objects文件夹里没有objects文件,但是所有的文件都被存储在pack里,所以系统任然会认为存储库中已经存在这些文件,验证如下:

1
2
3
xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
$ git unpack-objects < .git/objects/pack/pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.pack
Unpacking objects: 100% (9/9), 7.24 MiB | 32.96 MiB/s, done.
1
2
3
4
5
6
7
8
9
10
11
12
xiong@SURFACE-PRO6 C:\Files\git-demo2
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO2\.GIT\OBJECTS
├─info
│ commit-graph
│ packs

└─pack
pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.idx
pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.pack

虽然使用了unpack文件,但是系统仍然认为仓库里有对象

如果要解压当前pack文件,做法如下

  1. 将pack文件移出object文件夹

    1
    2
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ mv .git/objects/pack/pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.pack .git/

    此时git会认为代码仓库是空的

  2. 使用unpack进行解压

    1
    2
    3
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo2 (master)
    $ git unpack-objects < .git/pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.pack
    Unpacking objects: 100% (9/9), 7.24 MiB | 6.10 MiB/s, done.
  3. 查看objects文件目录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    xiong@SURFACE-PRO6 C:\Files\git-demo2
    $ tree .git/objects /f
    卷 Local Disk 的文件夹 PATH 列表
    卷序列号为 C0000100 F296:2801
    C:\FILES\GIT-DEMO2\.GIT\OBJECTS
    ├─17
    │ 2344478aef4544529c644e29130d7d8f1b041f

    ├─4b
    │ 574b366e9bb3ad454462ba510db98a01837b66

    ├─51
    │ 53efa4cf47077622e7771888cae3deb87db41e

    ├─53
    │ 4c54ea578f0d6517cb5d38ddced88d4c4158b4

    ├─67
    │ a095b95ff121fb3e1bc648b98814e1c8f6c148

    ├─ae
    │ f20abb0786e52ac2234180cf18ad488023f7f2

    ├─b8
    │ 0edea2a581ed6917723b45871f0af11beb714d

    ├─e4
    │ d8fff037528cc82c6f923a5200f3dfa1876d6b

    ├─fc
    │ d21cca77d88e7c8bda0ac43e72c8b5a6c7a4be

    ├─info
    │ commit-graph
    │ packs

    └─pack
    pack-3181db0c2b5d97f6d38c69d9a43358790246aa10.idx

    解压成功,将对象写入到objects文件夹里

12. git垃圾对象的清理

12.1 多次添加产生垃圾对象

在使用git进行版本控制的时候,通常会对一个文件在本地进行多次的修改和添加,最后才提交代码仓库。只有最后提交到代码仓库的那次才是有效的,之前所添加到索引区的文件就成为了垃圾对象。对于此类垃圾对象,使用git prune进行垃圾对象清理

初始新的代码仓库git-demo3进行测试,新建文件test.txt,每次做一点修改就进行添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3
$ git init
Initialized empty Git repository in C:/Files/git-demo3/.git/

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ echo 'abc' > test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git add test.txt
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ vim test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git add test.txt
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ vim test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git add test.txt
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory

查看此时objects中的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
xiong@SURFACE-PRO6 C:\Files\git-demo3                  
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO3\.GIT\OBJECTS
├─5d
│ 8a5566f0e8b2794b60559ecaa3cf8986e23d47

├─74
│ ec2e70bd5e4936b3d076b469751e584f434a9a

├─8b
│ aef1b4abc478178b004d62031cf7fe6db6f903

├─info
└─pack

经过3次add,产生了三个blob对象

进行一次commit,并使用git gc进行文件压缩,查看结果

1
2
3
4
5
6
7
8
9
10
11
12
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git commit -m '1st commit'
[master (root-commit) 63a6480] 1st commit
1 file changed, 3 insertions(+)
create mode 100644 test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git gc
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
xiong@SURFACE-PRO6 C:\Files\git-demo3
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO3\.GIT\OBJECTS
├─5d
│ 8a5566f0e8b2794b60559ecaa3cf8986e23d47

├─8b
│ aef1b4abc478178b004d62031cf7fe6db6f903

├─info
│ commit-graph
│ packs

└─pack
pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.idx
pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.pack
1
2
3
4
5
6
7
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git verify-pack -v .git/objects/pack/pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.idx
63a64804613dbfaa16cfc5c7fb320b501f539d75 commit 177 120 12
74ec2e70bd5e4936b3d076b469751e584f434a9a blob 12 15 132
85d321b0acc1f7618da3b8a24a51c743a0133932 tree 36 46 147
non delta: 3 objects
.git/objects/pack/pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.pack: ok

被压缩的对象是最后一次的blob、tree和commit对象

此时可以看到有两个对象并未被压缩到pack文件里,这两个文件就是垃圾对象

12.1.2 使用git prune清理垃圾对象

git prune

  • 名字

    git prune从对象数据库中修剪所有无法到达的对象

  • 概要

    1
    git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>…]
  • 描述

    注意:在大多数情况下,用户应该运行git gc,它会调用git prune。请参阅下面的”注意”部分。

    运行git fsck --unreachable使用refs/下所有可用的refs,可以选择在命令行上指定其他对象集,并从对象数据库中删除无法从这些head对象中访问的所有未打包对象。此外,它还通过运行git prune-packed来修剪包中的未打包对象。它还从.git/shallow中删除任何ref.ref都无法访问的条目/

  • 选项

    • -n

      –dry-run

      不移除任何事物,只是显示哪些事物将会被移除

    • -v

      –verbose

      显示所有背移除的对象

    • –progress

      显示所有进程

    • expire

      仅使早于

    • 不要将任何其他参数解释为选项

    • ...

      除了从我们的任何引用中都可以访问的对象之外,还要保持从列出的s中可以访问的对象。

  • 例子

    要修剪存储库未使用的对象或通过其从存储库借用的其他对象,请执行以下操作:.git/objects/info/alternates

    1
    $ git prune $(cd ../another && git rev-parse --all)

git fsck

  • 名字

    git-fsck - 验证数据库中对象的连接和有效性

  • 概要

    1
    2
    3
    4
    git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
    [--[no-]full] [--strict] [--verbose] [--lost-found]
    [--[no-]dangling] [--[no-]progress] [--connectivity-only]
    [--[no-]name-objects] [<object>*]
  • 描述

    验证数据库中对象的连接和有效性。

  • 选项

    • <object>

      要作为不可访问性跟踪的头部处理的对象。
      如果未提供任何对象,git fsck默认使用索引文件、refs命名空间中的所有SHA-1引用以及所有reflogs(除非提供了–no reflogs)作为头。

    • –unreachable

      打印存在但无法从任何引用节点访问的对象。

    • –[no-]dangling

      打印存在但从未直接使用的对象(默认)–不能使用任何悬空来从输出中忽略此信息。

    • –root

      显示根节点

    • –tags

      显示标签

    • –cache

      将索引中记录的任何对象也作为不可达跟踪的头节点。

    • –no-reflogs

      不要考虑仅由reflog中的条目引用的可到达的提交。此选项仅用于搜索以前在ref中但现在不在ref中但仍在相应reflog中的提交。

    • –full

      不仅要检查GIT_OBJECT_目录($GIT_DIR/objects)中的对象,还要检查GIT_alternate_OBJECT_目录或$GIT_DIR/objects/info/alternates中列出的备用对象池中的对象,以及备用对象池中的$GIT_DIR/objects/pack和相应的pack子目录中的打包GIT归档中的对象。现在这是默认值;你可以关闭它,不需要完全关闭。

      ……

使用prune -n显示会被删除的对象

1
2
3
4
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git prune -n
5d8a5566f0e8b2794b60559ecaa3cf8986e23d47 blob
8baef1b4abc478178b004d62031cf7fe6db6f903 blob

使用git fsck查看悬空的对象

1
2
3
4
5
6
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 8baef1b4abc478178b004d62031cf7fe6db6f903
dangling blob 5d8a5566f0e8b2794b60559ecaa3cf8986e23d47
  1. 使用git prune删除

    1
    2
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git prune
  2. 查看objects

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    xiong@SURFACE-PRO6 C:\Files\git-demo3
    $ tree .git/objects /f
    卷 Local Disk 的文件夹 PATH 列表
    卷序列号为 C0000100 F296:2801
    C:\FILES\GIT-DEMO3\.GIT\OBJECTS
    ├─info
    │ commit-graph
    │ packs

    └─pack
    pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.idx
    pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.pack

    悬空的两个对象被删除了

12.2 删除未合并分支产生的对象

对于新建的分支,如果想完整的删除分支,先使用git -D 分支名强制删除,但是这样操作,分支上所做的操作还是可以被还原,分支上的文件也仍然存在,而且使用git prune不会认为是

  1. 创建分支,在分支上添加内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git checkout -b tmp
    Switched to a new branch 'tmp'

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp)
    $ echo 'tmp'>tmp.txt

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp)
    $ ls
    test.txt tmp.txt

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp)
    $ git add tmp.txt
    warning: LF will be replaced by CRLF in tmp.txt.
    The file will have its original line endings in your working directory
  2. 分析一次add的情况

    1. 切换到master分支

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp)
      $ git checkout master
      Switched to branch 'master'
      A tmp.txt

      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
      $ git prune -n

      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
      $ git fsck
      Checking object directories: 100% (256/256), done.
      Checking objects: 100% (3/3), done.
    2. 切换到tmp分支

      1
      2
      3
      4
      5
      6
      7
      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
      $ git checkout tmp
      Switched to branch 'tmp'
      A tmp.txt

      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp)
      $ git prune -n

      对于只add过一次但还没提交的文件,系统不认为是悬空文件

  3. 分析add两次,提交一次的情况

    1. 修改tmp.txt文件,进行一次提交

      1
      2
      3
      4
      5
      6
      7
      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp)
      $ vim tmp.txt

      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp)
      $ git add tmp.txt
      warning: LF will be replaced by CRLF in tmp.txt.
      The file will have its original line endings in your working directory
    2. 在tmp分支上查看悬空对象

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp)
      $ git commit -m '1st commit from tmp'
      [tmp 1915cf6] 1st commit from tmp
      1 file changed, 2 insertions(+)
      create mode 100644 tmp.txt

      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp)
      $ git fsck
      Checking object directories: 100% (256/256), done.
      Checking objects: 100% (3/3), done.
      dangling blob a9a5aecf429fd8a0d81fbd5fd37006bfa498d5c1
    3. 切换到master分支上查看悬空对象

      1
      2
      3
      4
      5
      6
      7
      8
      9
      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp)
      $ git checkout master
      Switched to branch 'master'

      xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
      $ git fsck
      Checking object directories: 100% (256/256), done.
      Checking objects: 100% (3/3), done.
      dangling blob a9a5aecf429fd8a0d81fbd5fd37006bfa498d5c1

      分支上的悬空对象,其他分支也能检测到

  4. 切换到master分支强制删除tmp

    1
    2
    3
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git branch -D tmp
    Deleted branch tmp (was 1915cf6).

    objects目录没有任何变化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    xiong@SURFACE-PRO6 C:\Files\git-demo3
    $ tree .git/objects /f
    卷 Local Disk 的文件夹 PATH 列表
    卷序列号为 C0000100 F296:2801
    C:\FILES\GIT-DEMO3\.GIT\OBJECTS
    ├─0c
    │ 190188dbbf78236873f4d98402eb35440cf292

    ├─19
    │ 15cf671b63040967ff38cf434df3a6860da113

    ├─62
    │ 189d1a10cc2a544c4e5b9c4aba9493cf5782dc

    ├─a9
    │ a5aecf429fd8a0d81fbd5fd37006bfa498d5c1

    ├─info
    │ commit-graph
    │ packs

    └─pack
    pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.idx
    pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.pack

    在此种情况下,tmp分支上的对象可以认为是垃圾对象

  5. 执行git prune删除对象:不会认为tmp分支上的add(最后一次的)和commit是垃圾对象

    1
    2
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git prune
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    xiong@SURFACE-PRO6 C:\Files\git-demo3
    $ tree .git/objects /f
    卷 Local Disk 的文件夹 PATH 列表
    卷序列号为 C0000100 F296:2801
    C:\FILES\GIT-DEMO3\.GIT\OBJECTS
    ├─0c
    │ 190188dbbf78236873f4d98402eb35440cf292

    ├─19
    │ 15cf671b63040967ff38cf434df3a6860da113

    ├─62
    │ 189d1a10cc2a544c4e5b9c4aba9493cf5782dc

    ├─info
    │ commit-graph
    │ packs

    └─pack
    pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.idx
    pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.pack

    只有一个之前被检测到的悬空对象被删除了

  6. 执行git gc:不会认为tmp分支上的add(最后一次的)和commit是垃圾对象,并将其压缩到pack里

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git gc
    Enumerating objects: 6, done.
    Counting objects: 100% (6/6), done.
    Delta compression using up to 8 threads
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (6/6), done.
    Total 6 (delta 0), reused 3 (delta 0), pack-reused 0

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git verify-pack -v .git/objects/pack/pack-17c963e06e14119b3281aa3a1fa16ebbc8817341.idx
    1915cf671b63040967ff38cf434df3a6860da113 commit 234 154 12
    63a64804613dbfaa16cfc5c7fb320b501f539d75 commit 177 120 166
    74ec2e70bd5e4936b3d076b469751e584f434a9a blob 12 15 286
    85d321b0acc1f7618da3b8a24a51c743a0133932 tree 36 46 301
    0c190188dbbf78236873f4d98402eb35440cf292 tree 71 74 347
    62189d1a10cc2a544c4e5b9c4aba9493cf5782dc blob 8 15 421
    non delta: 6 objects
    .git/objects/pack/pack-17c963e06e14119b3281aa3a1fa16ebbc8817341.pack: ok

对于这种情况,使用下面的命令可以进行解决file - How to remove unused objects from a git repository? - Stack Overflow

1
2
3
git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
-c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
-c gc.pruneExpire=now gc "$@"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
> -c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
> -c gc.pruneExpire=now gc "$@"
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), done.
Total 3 (delta 0), reused 3 (delta 0), pack-reused 0

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git verify-pack -v .git/objects/pack/pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.idx
63a64804613dbfaa16cfc5c7fb320b501f539d75 commit 177 120 12
74ec2e70bd5e4936b3d076b469751e584f434a9a blob 12 15 132
85d321b0acc1f7618da3b8a24a51c743a0133932 tree 36 46 147
non delta: 3 objects
.git/objects/pack/pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.pack: ok

不仅经过压缩了的可以这样进行处理,未压缩的也可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git checkout -b tmp2
Switched to a new branch 'tmp2'

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp2)
$ echo 'tmp2' > tmp2.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp2)
$ git add tmp2.txt
warning: LF will be replaced by CRLF in tmp2.txt.
The file will have its original line endings in your working directory

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp2)
$ git commit -m '1st commit from tmp2'
[tmp2 92cb3a6] 1st commit from tmp2
1 file changed, 1 insertion(+)
create mode 100644 tmp2.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (tmp2)
$ git checkout master
Switched to branch 'master'

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git branch -D tmp2
Deleted branch tmp2 (was 92cb3a6).

清理前查看objects文件夹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO3\.GIT\OBJECTS
├─92
│ cb3a62ebb6ad8c15b5f85e9349f6342d0b2ed8

├─d0
│ c22e2dc4474240f8082a39ff275622b1221e82

├─f0
│ 206044e90fd5c77500ec550df0a0be6f0d0c46

├─info
│ commit-graph
│ packs

└─pack
pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.idx
pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.pack

清理

1
2
3
4
5
6
7
8
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
> -c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
> -c gc.pruneExpire=now gc "$@"
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), done.
Total 3 (delta 0), reused 3 (delta 0), pack-reused 0

清理后查看objects文件夹

1
2
3
4
5
6
7
8
9
10
11
12
xiong@SURFACE-PRO6 C:\Files\git-demo3
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO3\.GIT\OBJECTS
├─info
│ commit-graph
│ packs

└─pack
pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.idx
pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.pack

13. fast forward合并

image-20210823132936534

如果当前分支是在master上新建的,而且master分支并未再次进行commit,则满足fast forward的要求

将当前分支切换到master分支,再执行git merge 分支名进行分支合并,实际上只是做了一个指针的移动

image-20210823133312415

测试

当前仓库只有一次提交,且指针指向master分支

1
2
3
4
5
6
7
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git log
commit 63a64804613dbfaa16cfc5c7fb320b501f539d75 (HEAD -> master)
Author: xiongzhuo <xiongzhuo@outlook.com>
Date: Mon Aug 23 08:34:07 2021 +0800

1st commit

基于当前分支,创建一个新的分支进行演示

1
2
3
4
5
6
7
8
9
10
11
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git checkout -b dev
Switched to a new branch 'dev'

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (dev)
$ git log
commit 63a64804613dbfaa16cfc5c7fb320b501f539d75 (HEAD -> dev, master)
Author: xiongzhuo <xiongzhuo@outlook.com>
Date: Mon Aug 23 08:34:07 2021 +0800

1st commit

在新分支上产生一次commit:执行完毕后新分支超前master分支一次提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (dev)
$ echo 'test2' > test2.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (dev)
$ git add test2.txt
warning: LF will be replaced by CRLF in test2.txt.
The file will have its original line endings in your working directory

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (dev)
$ git commit -m '2nd commit'
[dev 596b3cd] 2nd commit
1 file changed, 1 insertion(+)
create mode 100644 test2.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (dev)
$ git log
commit 596b3cd55b27dc3cb5f85c291f73ac8e367aa930 (HEAD -> dev)
Author: xiongzhuo <xiongzhuo@outlook.com>
Date: Mon Aug 23 13:38:02 2021 +0800

2nd commit

commit 63a64804613dbfaa16cfc5c7fb320b501f539d75 (master)
Author: xiongzhuo <xiongzhuo@outlook.com>
Date: Mon Aug 23 08:34:07 2021 +0800

1st commit

切换到master分支,先查看.git文件,进行分支合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
xiong@SURFACE-PRO6 C:\Files\git-demo3
$ tree .git /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO3\.GIT
│ COMMIT_EDITMSG
│ config
│ description
│ HEAD
│ index
│ packed-refs

├─hooks
│ applypatch-msg.sample
│ commit-msg.sample
│ fsmonitor-watchman.sample
│ post-update.sample
│ pre-applypatch.sample
│ pre-commit.sample
│ pre-merge-commit.sample
│ pre-push.sample
│ pre-rebase.sample
│ pre-receive.sample
│ prepare-commit-msg.sample
│ push-to-checkout.sample
│ update.sample

├─info
│ exclude
│ refs

├─logs
│ │ HEAD
│ │
│ └─refs
│ └─heads
│ dev
│ master

├─objects
│ ├─18
│ │ 0cf8328022becee9aaa2577a8f84ea2b9f3827
│ │
│ ├─59
│ │ 6b3cd55b27dc3cb5f85c291f73ac8e367aa930
│ │
│ ├─ae
│ │ 3b0c9016b70ff7a211370616236c14571b7f0c
│ │
│ ├─info
│ │ commit-graph
│ │ packs
│ │
│ └─pack
│ pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.idx
│ pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.pack

└─refs
├─heads
│ dev

└─tags
1
2
3
4
5
6
7
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git merge dev
Updating 63a6480..596b3cd
Fast-forward
test2.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 test2.txt

Updating 63a6480..596b3cd:把指针从63a6480,指向596b3cd

合并后查看.git文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
xiong@SURFACE-PRO6 C:\Files\git-demo3
$ tree .git /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO3\.GIT
│ COMMIT_EDITMSG
│ config
│ description
│ HEAD
│ index
│ ORIG_HEAD #新增
│ packed-refs

├─hooks
│ applypatch-msg.sample
│ commit-msg.sample
│ fsmonitor-watchman.sample
│ post-update.sample
│ pre-applypatch.sample
│ pre-commit.sample
│ pre-merge-commit.sample
│ pre-push.sample
│ pre-rebase.sample
│ pre-receive.sample
│ prepare-commit-msg.sample
│ push-to-checkout.sample
│ update.sample

├─info
│ exclude
│ refs

├─logs
│ │ HEAD
│ │
│ └─refs
│ └─heads
│ dev
│ master

├─objects
│ ├─18
│ │ 0cf8328022becee9aaa2577a8f84ea2b9f3827
│ │
│ ├─59
│ │ 6b3cd55b27dc3cb5f85c291f73ac8e367aa930
│ │
│ ├─ae
│ │ 3b0c9016b70ff7a211370616236c14571b7f0c
│ │
│ ├─info
│ │ commit-graph
│ │ packs
│ │
│ └─pack
│ pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.idx
│ pack-b9d4bdcbfa833a54a35bc737eaba5f5088f6d956.pack

└─refs
├─heads
│ dev
│ master

└─tags

分别查看HEAD与ORIG_HEAD

1
2
3
4
5
6
7
8
9
10
11
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ cat .git/HEAD
ref: refs/heads/master

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ cat .git/refs/heads/master
596b3cd55b27dc3cb5f85c291f73ac8e367aa930

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ cat .git/ORIG_HEAD
63a64804613dbfaa16cfc5c7fb320b501f539d75

ORIG_HEAD指向前一次commit,git在进行版本控制时,认为merge是比较危险的操作,所以提供了上一次的HEAD指向,以便于进行回滚操作

回滚演示:将master回滚到未merge前的状态

1
2
3
4
5
6
7
8
9
10
11
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git reset ORIG_HEAD

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
test2.txt

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

在此种状态下不能立即切换到dev分支,需要先对当前回滚产生的test2.txt进行操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git checkout dev
error: The following untracked working tree files would be overwritten by checkout:
test2.txt
Please move or remove them before you switch branches.
Aborting

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ rm -rf test2.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git status
On branch master
nothing to commit, working tree clean

xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
$ git checkout dev
Switched to branch 'dev'

14. 3 way merge

14.1 无冲突的merge

在开发时,如果master分支上有人进行了一次commit

image-20210823151348518

  1. 在dev分支查看当前提交情况

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (dev)
    $ git log
    commit 596b3cd55b27dc3cb5f85c291f73ac8e367aa930 (HEAD -> dev)
    Author: xiongzhuo <xiongzhuo@outlook.com>
    Date: Mon Aug 23 13:38:02 2021 +0800

    2nd commit

    commit 63a64804613dbfaa16cfc5c7fb320b501f539d75 (master)
    Author: xiongzhuo <xiongzhuo@outlook.com>
    Date: Mon Aug 23 08:34:07 2021 +0800

    1st commit

    dev超前于master分支一次提交

  2. 切换到master分支进行一次提交,模拟描述的情况

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (dev)
    $ git checkout master
    Switched to branch 'master'

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ echo 'test3' > test3.txt

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git add test3.txt
    warning: LF will be replaced by CRLF in test3.txt.
    The file will have its original line endings in your working directory

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git commit -m '3rd commit'
    [master ee44067] 3rd commit
    1 file changed, 1 insertion(+)
    create mode 100644 test3.txt

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git log
    commit ee44067f519231c20405f26c9a9fbef7c45e296a (HEAD -> master)
    Author: xiongzhuo <xiongzhuo@outlook.com>
    Date: Mon Aug 23 14:23:08 2021 +0800

    3rd commit

    commit 63a64804613dbfaa16cfc5c7fb320b501f539d75
    Author: xiongzhuo <xiongzhuo@outlook.com>
    Date: Mon Aug 23 08:34:07 2021 +0800

    1st commit
  3. 进行git merge

    1
    2
    3
    4
    5
    6
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git merge dev
    Merge made by the 'recursive' strategy.
    test2.txt | 1 +
    1 file changed, 1 insertion(+)
    create mode 100644 test2.txt

    此时会进入一个编辑器,要求输入commit信息

    image-20210823143245060

    查看当前提交记录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git log
    commit 2040a9926e6c3f6647fbae96b067fa9ac4d1caac (HEAD -> master)
    Merge: ee44067 596b3cd
    Author: xiongzhuo <xiongzhuo@outlook.com>
    Date: Mon Aug 23 14:31:42 2021 +0800

    Merge branch 'dev'

    commit ee44067f519231c20405f26c9a9fbef7c45e296a
    Author: xiongzhuo <xiongzhuo@outlook.com>
    Date: Mon Aug 23 14:23:08 2021 +0800

    3rd commit

    commit 596b3cd55b27dc3cb5f85c291f73ac8e367aa930 (dev)
    Author: xiongzhuo <xiongzhuo@outlook.com>
    Date: Mon Aug 23 13:38:02 2021 +0800

    2nd commit

    commit 63a64804613dbfaa16cfc5c7fb320b501f539d75
    Author: xiongzhuo <xiongzhuo@outlook.com>
    Date: Mon Aug 23 08:34:07 2021 +0800

    1st commit

    此时commit状态如下:新的merge commit比较特殊,指向两个parent

    image-20210823145013674

    验证如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ git cat-file -p 2040a9
    tree 1838144278c4bdebda77473c8b269f173d7c5122
    parent ee44067f519231c20405f26c9a9fbef7c45e296a
    parent 596b3cd55b27dc3cb5f85c291f73ac8e367aa930
    author xiongzhuo <xiongzhuo@outlook.com> 1629700302 +0800
    committer xiongzhuo <xiongzhuo@outlook.com> 1629700302 +0800

    Merge branch 'dev'

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ cat .git/refs/heads/dev
    596b3cd55b27dc3cb5f85c291f73ac8e367aa930

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ cat .git/ORIG_HEAD
    ee44067f519231c20405f26c9a9fbef7c45e296a

    xiong@Surface-pro6 MINGW64 /c/Files/git-demo3 (master)
    $ cat .git/refs/heads/master
    2040a9926e6c3f6647fbae96b067fa9ac4d1caac

    此时状态

    image-20210823151244631

14.2 带冲突的3 way merge

上述merge时所修改的文件不是同一个,如果修改的是同一个文件,则需要解决冲突

image-20210823152448688

初始化一个新的代码仓库进行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4
$ git init
Initialized empty Git repository in C:/Files/git-demo4/.git/

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ ls

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ echo 'test'>test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ git add test.txt
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ git commit -m '1st commit'
[master (root-commit) 300e689] 1st commit
1 file changed, 1 insertion(+)
create mode 100644 test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ git checkout -b dev
Switched to a new branch 'dev'

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (dev)
$ vim test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (dev)
$ git add test.txt
warning: LF will be replaced by CRLF in test.txt.
The file will have its original line endings in your working directory

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (dev)
$ git commit -m '2nd commit'
[dev fd44315] 2nd commit
1 file changed, 1 insertion(+)

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (dev)
$ git checkout master
Switched to branch 'master'

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ vim test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ git add test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ git commit -m '3rd commit'
[master e5cdf78] 3rd commit
1 file changed, 1 insertion(+)

查看master分支上的提交记录

1
2
3
4
5
6
7
8
9
10
11
12
13
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ git log
commit e5cdf7844b4ec84a213a743ae50ce7e75f050da5 (HEAD -> master)
Author: xiongzhuo <xiongzhuo@outlook.com>
Date: Mon Aug 23 15:57:24 2021 +0800

3rd commit

commit 300e689767c0e77cd950bc7f7562da1211d8a837
Author: xiongzhuo <xiongzhuo@outlook.com>
Date: Mon Aug 23 15:28:01 2021 +0800

1st commit

切换到dev分支查看提交记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ git checkout dev
Switched to branch 'dev'

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (dev)
$ git log
commit fd443159acf34ca861ef84adcd8f4da5703e859b (HEAD -> dev)
Author: xiongzhuo <xiongzhuo@outlook.com>
Date: Mon Aug 23 15:29:25 2021 +0800

2nd commit

commit 300e689767c0e77cd950bc7f7562da1211d8a837
Author: xiongzhuo <xiongzhuo@outlook.com>
Date: Mon Aug 23 15:28:01 2021 +0800

1st commit

执行git merge dev

1
2
3
4
5
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$ git merge dev
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.

Automatic merge failed; fix conflicts and then commit the result.:自动merge失败,解决冲突之后提交结果

查看当前git状态

1
2
3
4
5
6
7
8
9
10
11
12
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)

Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: test.txt

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

指出test.txt被共同修改了

查看文件内容

1
2
3
4
5
6
7
8
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ cat test.txt
test
<<<<<<< HEAD
add from master
=======
add from dev
>>>>>>> dev

列举出来了二者冲突的地方

查看当前索引区文件

1
2
3
4
5
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ git ls-files -s
100644 9daeafb9864cf43055ae93beb0afd6c7d144bfa4 1 test.txt
100644 25059ba70062bc9ca5e6bc169a02b9e03928d383 2 test.txt
100644 94032e5599cd953e1245bedddf18cc3ad6d5b297 3 test.txt

列出了test.txt的三个版本,查看这三个文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ git cat-file -p 9daeaf
test

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ git cat-file -p 25059b
test
add from master

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ git cat-file -p 94032e
test
add from dev

通过编辑器打开文件,解决冲突

1
2
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ vim test.txt

将修改添加到索引区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)

Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: test.txt

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

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ git add test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ git ls-files -s
100644 c638404ba9aedab9251326c3418b8948ad9344f4 0 test.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ git cat-file -p c63840
test
add from master
add from dev

修改完后此时git仍然显示test.txt文件是共同修改状态,我们需要进行add和commit就可以解决,而且此时索引区的文件又变回了一个,查看内容,正是我们修改过后的。表示此时冲突已经解决

进行commit

1
2
3
4
5
6
xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master|MERGING)
$ git commit -m 'fix conflicts'
[master e486395] fix conflicts

xiong@Surface-pro6 MINGW64 /c/Files/git-demo4 (master)
$

提交完之后,(master|MERGING)变成了(master),完成了所有操作,结果也和普通的3way merge一样

16. git rebase

git rebase

当我们遇到需要分支合并的时候,而且此时想让合并的分支呈线性,可以再分支上使用git reabse master,将master分支上的最近一次提交同步到当前分支上,然后系统会改写分支上的commit,使分支上的commit在master之后,最后在使用git merge的时候就使得提交呈现出线性。不过要注意这种操作不适合团队开发使用,因为容易涉及到带冲突合并的问题。

17. 标签tag

标签在创建时,指向的是当前所在分支的最新一次commit

  • 创建tag

    • git tag <tag name>:创建一个轻量级的tag(i.e. git tag v1.0)
    • git tag -a <tag name> -m <tag message>:创建一个拥有关联元数据的注解tag( email,date,etc…)(i.e. git tag -a v1.0 -m “version” )
    • git tag -a <tag name> <commit SHA1 value> :为以前的commit生成一个注解tag(i.e. git tag -a v1.0 c638404ba9aedab9251326c3418b8948ad9344f4)
  • tag列表

    git tag

  • 删除tag

    git tag -d <tag name> (i.e. git tag -d v1.0)

①初始化代码仓库,为master分支的最近一次commit使用git tag <tag name>创建tag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
xiong@Surface-pro6 MINGW64 /c/Files/git-demo5
$ git init
Initialized empty Git repository in C:/Files/git-demo5/.git/

xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ echo 'test1' > test1.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git add test1.txt
warning: LF will be replaced by CRLF in test1.txt.
The file will have its original line endings in your working directory

xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git commit -m '1st commit'
[master (root-commit) 8a7e377] 1st commit
1 file changed, 1 insertion(+)
create mode 100644 test1.txt

xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git tag v1.0.0
1
2
3
4
5
6
7
8
9
10
xiong@SURFACE-PRO6 C:\Files\git-demo5
$ tree .git/refs /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO5\.GIT\REFS
├─heads
│ master

└─tags
v1.0.0

查看tag内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ cat .git/refs/tags/v1.0.0
8a7e3772b496dcaa2c11ede0d3397371529fe0f1

xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git cat-file -t 8a7e
commit

xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git cat-file -p 8a7e
tree c0da834e42dcbf7b2b1c4a97925bef105d3863a3
author xiongzhuo <xiongzhuo@outlook.com> 1629726589 +0800
committer xiongzhuo <xiongzhuo@outlook.com> 1629726589 +0800

1st commit

删除tag

1
2
3
xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git tag -d v1.0.0
Deleted tag 'v1.0.0' (was 8a7e377)
1
2
3
4
5
6
7
8
9
xiong@SURFACE-PRO6 C:\Files\git-demo5
$ tree .git/refs /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO5\.GIT\REFS
├─heads
│ master

└─tags

②使用git tag -a <tag name> -m <tag message>创建tag

1
2
xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git tag -a v1.0.0 -m "version v1.0.0"

查看objects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
xiong@SURFACE-PRO6 C:\Files\git-demo5
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO5\.GIT\OBJECTS
├─88
│ 1062f4ca137827d78a6f5e4e48996f3ed7722e #新增

├─8a
│ 7e3772b496dcaa2c11ede0d3397371529fe0f1

├─a5
│ bce3fd2565d8f458555a0c6f42d0504a848bd5

├─c0
│ da834e42dcbf7b2b1c4a97925bef105d3863a3

├─info
└─pack

查看新增objects文件类型和文件内容

1
2
3
4
5
6
7
8
9
10
11
12
xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git cat-file -t 881062
tag

xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git cat-file -p 881062
object 8a7e3772b496dcaa2c11ede0d3397371529fe0f1
type commit
tag v1.0.0
tagger xiongzhuo <xiongzhuo@outlook.com> 1629727707 +0800

version v1.0.0

查看refs

1
2
3
4
5
6
7
8
9
10
xiong@SURFACE-PRO6 C:\Files\git-demo5
$ tree .git/refs /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO5\.GIT\REFS
├─heads
│ master

└─tags
v1.0.0 #新增

删除tag

1
2
3
xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git tag -d v1.0.0
Deleted tag 'v1.0.0' (was 881062f)

查看refs,标签被删除

1
2
3
4
5
6
7
8
9
xiong@SURFACE-PRO6 C:\Files\git-demo5
$ tree .git/refs /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO5\.GIT\REFS
├─heads
│ master

└─tags

查看objects,tag对象未被删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
xiong@SURFACE-PRO6 C:\Files\git-demo5
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO5\.GIT\OBJECTS
├─88
│ 1062f4ca137827d78a6f5e4e48996f3ed7722e #tag对象未被删除,产生垃圾对象

├─8a
│ 7e3772b496dcaa2c11ede0d3397371529fe0f1

├─a5
│ bce3fd2565d8f458555a0c6f42d0504a848bd5

├─c0
│ da834e42dcbf7b2b1c4a97925bef105d3863a3

├─info
└─pack

③使用git tag -a <tag name> <commit SHA1 value>创建tag

1
2
xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git tag -a v1.0.0 8a7e37 -m "version 1"

查看objects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
xiong@SURFACE-PRO6 C:\Files\git-demo5
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO5\.GIT\OBJECTS
├─88
│ 1062f4ca137827d78a6f5e4e48996f3ed7722e

├─8a
│ 7e3772b496dcaa2c11ede0d3397371529fe0f1

├─a5
│ bce3fd2565d8f458555a0c6f42d0504a848bd5

├─c0
│ da834e42dcbf7b2b1c4a97925bef105d3863a3

├─ec
│ 1fd8c3998b32051be0c19affdd49c20e4938fe #新增tag

├─info
└─pack

虽然名字一样,但是并未使用之前的tag对象,因为在生成tag对象时里面有时间戳

使用git fsck可以检测出垃圾tag

1
2
3
4
5
6
7
xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git fsck
Checking object directories: 100% (256/256), done.
dangling tag 881062f4ca137827d78a6f5e4e48996f3ed7722e

xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git prune

使用git prune 可以进行垃圾清理

1
2
xiong@Surface-pro6 MINGW64 /c/Files/git-demo5 (master)
$ git prune
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
xiong@SURFACE-PRO6 C:\Files\git-demo5
$ tree .git/objects /f
卷 Local Disk 的文件夹 PATH 列表
卷序列号为 C0000100 F296:2801
C:\FILES\GIT-DEMO5\.GIT\OBJECTS
├─8a
│ 7e3772b496dcaa2c11ede0d3397371529fe0f1

├─a5
│ bce3fd2565d8f458555a0c6f42d0504a848bd5

├─c0
│ da834e42dcbf7b2b1c4a97925bef105d3863a3

├─ec
│ 1fd8c3998b32051be0c19affdd49c20e4938fe

├─info
└─pack

18. 本地分支和远程分支

新建文件夹,将远程仓库克隆到本地

19. git fetch & git pull

20. fetch_head

21. git pull

22. 本地git hook

23. pre-commit钩子

24. git hook和python