Git 孤儿犯怎么办?

Git 孤儿犯怎么办?,git,git-commit,git-reset,Git,Git Commit,Git Reset,我有一份包含四项承诺的回购协议: $ git log --oneline --decorate 6c35831 (HEAD, master) C4 974073b C3 e27b22c C2 9f2d694 C1 我reset--soft到C2提交,现在我有一个这样的回购协议: $ git reset e27b22c --soft $ git log --oneline --decorate e27b22c (HEAD, master) C2 9f2d694 C1 现在,我添加了一个额外的

我有一份包含四项承诺的回购协议:

$ git log --oneline --decorate
6c35831 (HEAD, master) C4
974073b C3
e27b22c C2
9f2d694 C1
reset--soft
C2
提交,现在我有一个这样的回购协议:

$ git reset e27b22c --soft

$ git log --oneline --decorate
e27b22c (HEAD, master) C2
9f2d694 C1
现在,我添加了一个额外的提交,因此日志如下所示:

$ git log --oneline --decorate
545fa99 (HEAD, master) C5
e27b22c C2
9f2d694 C1

提交
C3
C4
时发生了什么?我没有删除它们,所以我假设它们仍然存在,
C3
的父级仍然是
C2
孤立的提交只需停留在那里,直到它们通过显式运行
git gc
进行垃圾收集,然后运行
git show 6c35831
查看C4是否仍然存在。运行
git reflog master
查看
master
用于引用的内容(很多)。其中一个条目(
master^{1}
最有可能,但如果您进行了其他更改,则可能是一个较早的条目)应该对应于
6c35831
,并且
git show master^{1}
(或任何条目)应该显示与我提到的第一个
git show
命令相同的输出。

简短回答:提交
C3
C4
将保留在git对象数据库中,直到它们被垃圾回收

详细回答:垃圾收集将通过不同的Git命令自动发生,或者在显式垃圾收集时发生。有许多场景可能触发自动垃圾回收;看一看图片,想一想。您可以使用。让我们看一个例子,看看会发生什么

首先,让我们设置我们的环境(我正在使用Linux;对您的环境进行必要的更改),以便在不同的Git存储库中获得相同的对象哈希

export GIT_AUTHOR_NAME='Wile E. Coyote'
export GIT_AUTHOR_EMAIL=coyote@acme.com
export GIT_AUTHOR_DATE=2015-01-01T12:00:00
export GIT_COMMITTER_NAME='Roadrunner'
export GIT_COMMITTER_EMAIL=roadrunner@acme.com
export GIT_COMMITTER_DATE=2015-01-01T12:00:00
由于提交对象散列是使用此信息生成的,因此如果我们使用相同的author和committer值,我们现在都应该得到相同的散列

现在,让我们初始化一个函数,使用、和记录对象信息

现在让我们初始化一个Git存储库

git --version
git init
git_log_objects
对我来说,它的输出:

git version 2.4.0
Initialized empty Git repository in /tmp/test/.git/
Log ...
fatal: bad default revision 'HEAD'
Reflog ...
fatal: bad default revision 'HEAD'
Count ...
count: 0
size: 0
in-pack: 0
packs: 0
size-pack: 0
prune-packable: 0
garbage: 0
size-garbage: 0
Hashes ...
正如预期的那样,我们有一个初始化的存储库,其中没有对象。让我们进行一些提交并查看对象

git commit --allow-empty -m C1
git commit --allow-empty -m C2
git tag T1
git commit --allow-empty -m C3
git commit --allow-empty -m C4
git commit --allow-empty -m C5
git_log_objects
git_log_objects
这给了我以下输出:

[master (root-commit) c11e156] C1
 Author: Wile E. Coyote <coyote@acme.com>
[master 10bfa58] C2
 Author: Wile E. Coyote <coyote@acme.com>
[master 8aa22b5] C3
 Author: Wile E. Coyote <coyote@acme.com>
[master 1abb34f] C4
 Author: Wile E. Coyote <coyote@acme.com>
[master d1efc10] C5
 Author: Wile E. Coyote <coyote@acme.com>
Log ...
d1efc10 (HEAD -> master) C5
1abb34f C4
8aa22b5 C3
10bfa58 (tag: T1) C2
c11e156 C1
Reflog ...
d1efc10 refs/heads/master@{0}: commit: C5
1abb34f refs/heads/master@{1}: commit: C4
8aa22b5 refs/heads/master@{2}: commit: C3
10bfa58 refs/heads/master@{3}: commit: C2
c11e156 refs/heads/master@{4}: commit (initial): C1
Count ...
count: 6
size: 24
in-pack: 0
packs: 0
size-pack: 0
prune-packable: 0
garbage: 0
size-garbage: 0
Hashes ...
10bfa58a7bcbadfc6c9af616da89e4139c15fbb9
1abb34f82523039920fc629a68d3f82bc79acbd0
4b825dc642cb6eb9a060e54bf8d69288fbee4904 
8aa22b5f0fed338dd13c16537c1c54b3496e3224
c11e1562835fe1e9c25bf293279bff0cf778b6e0
d1efc109115b00bac9d4e3d374a05a3df9754551
哪些产出:

Log ...
10bfa58 (HEAD -> master, tag: T1) C2
c11e156 C1
Reflog ...
Count ...
count: 6
size: 24
in-pack: 0
packs: 0
size-pack: 0
prune-packable: 0
garbage: 0
size-garbage: 0
Hashes ...
10bfa58a7bcbadfc6c9af616da89e4139c15fbb9
1abb34f82523039920fc629a68d3f82bc79acbd0
4b825dc642cb6eb9a060e54bf8d69288fbee4904 
8aa22b5f0fed338dd13c16537c1c54b3496e3224
c11e1562835fe1e9c25bf293279bff0cf778b6e0
d1efc109115b00bac9d4e3d374a05a3df9754551
Log ...
10bfa58 (HEAD -> master, tag: T1) C2
c11e156 C1
Reflog ...
Count ...
count: 0
size: 0
in-pack: 3
packs: 1
size-pack: 1
prune-packable: 0
garbage: 0
size-garbage: 0
Hashes ...
10bfa58a7bcbadfc6c9af616da89e4139c15fbb9
4b825dc642cb6eb9a060e54bf8d69288fbee4904 
c11e1562835fe1e9c25bf293279bff0cf778b6e0
现在我们看到Git只引用了两个提交。但是,所有六个对象仍在存储库中。它们将保留在存储库中,直到它们被自动或显式地垃圾回收。例如,您甚至可以使用或查看未引用的提交。不过现在,让我们显式地对未引用的对象进行垃圾收集,看看Git在幕后做了什么

GIT_TRACE=1 git gc --aggressive --prune=now
这将输出一些信息

11:03:03.123194 git.c:348               trace: built-in: git 'gc' '--aggressive' '--prune=now'
11:03:03.123625 run-command.c:347       trace: run_command: 'pack-refs' '--all' '--prune'
11:03:03.124038 exec_cmd.c:129          trace: exec: 'git' 'pack-refs' '--all' '--prune'
11:03:03.126895 git.c:348               trace: built-in: git 'pack-refs' '--all' '--prune'
11:03:03.128298 run-command.c:347       trace: run_command: 'reflog' 'expire' '--all'
11:03:03.128635 exec_cmd.c:129          trace: exec: 'git' 'reflog' 'expire' '--all'
11:03:03.131322 git.c:348               trace: built-in: git 'reflog' 'expire' '--all'
11:03:03.133179 run-command.c:347       trace: run_command: 'repack' '-d' '-l' '-f' '--depth=250' '--window=250' '-a'
11:03:03.133522 exec_cmd.c:129          trace: exec: 'git' 'repack' '-d' '-l' '-f' '--depth=250' '--window=250' '-a'
11:03:03.136915 git.c:348               trace: built-in: git 'repack' '-d' '-l' '-f' '--depth=250' '--window=250' '-a'
11:03:03.137179 run-command.c:347       trace: run_command: 'pack-objects' '--keep-true-parents' '--honor-pack-keep' '--non-empty' '--all' '--reflog' '--indexed-objects' '--window=250' '--depth=250' '--no-reuse-delta' '--local' '--delta-base-offset' '.git/objects/pack/.tmp-8973-pack'
11:03:03.137686 exec_cmd.c:129          trace: exec: 'git' 'pack-objects' '--keep-true-parents' '--honor-pack-keep' '--non-empty' '--all' '--reflog' '--indexed-objects' '--window=250' '--depth=250' '--no-reuse-delta' '--local' '--delta-base-offset' '.git/objects/pack/.tmp-8973-pack'
11:03:03.140367 git.c:348               trace: built-in: git 'pack-objects' '--keep-true-parents' '--honor-pack-keep' '--non-empty' '--all' '--reflog' '--indexed-objects' '--window=250' '--depth=250' '--no-reuse-delta' '--local' '--delta-base-offset' '.git/objects/pack/.tmp-8973-pack'
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), done.
Total 3 (delta 1), reused 0 (delta 0)
11:03:03.153843 run-command.c:347       trace: run_command: 'prune' '--expire' 'now'
11:03:03.154255 exec_cmd.c:129          trace: exec: 'git' 'prune' '--expire' 'now'
11:03:03.156744 git.c:348               trace: built-in: git 'prune' '--expire' 'now'
11:03:03.159210 run-command.c:347       trace: run_command: 'rerere' 'gc'
11:03:03.159527 exec_cmd.c:129          trace: exec: 'git' 'rerere' 'gc'
11:03:03.161807 git.c:348               trace: built-in: git 'rerere' 'gc'
最后,让我们看看这些对象

git commit --allow-empty -m C1
git commit --allow-empty -m C2
git tag T1
git commit --allow-empty -m C3
git commit --allow-empty -m C4
git commit --allow-empty -m C5
git_log_objects
git_log_objects
哪些产出:

Log ...
10bfa58 (HEAD -> master, tag: T1) C2
c11e156 C1
Reflog ...
Count ...
count: 6
size: 24
in-pack: 0
packs: 0
size-pack: 0
prune-packable: 0
garbage: 0
size-garbage: 0
Hashes ...
10bfa58a7bcbadfc6c9af616da89e4139c15fbb9
1abb34f82523039920fc629a68d3f82bc79acbd0
4b825dc642cb6eb9a060e54bf8d69288fbee4904 
8aa22b5f0fed338dd13c16537c1c54b3496e3224
c11e1562835fe1e9c25bf293279bff0cf778b6e0
d1efc109115b00bac9d4e3d374a05a3df9754551
Log ...
10bfa58 (HEAD -> master, tag: T1) C2
c11e156 C1
Reflog ...
Count ...
count: 0
size: 0
in-pack: 3
packs: 1
size-pack: 1
prune-packable: 0
garbage: 0
size-garbage: 0
Hashes ...
10bfa58a7bcbadfc6c9af616da89e4139c15fbb9
4b825dc642cb6eb9a060e54bf8d69288fbee4904 
c11e1562835fe1e9c25bf293279bff0cf778b6e0

现在我们看到只有三个对象:两个提交和一个空树。

接下来的问题。我是否更改了历史记录或只是添加了历史记录?就分支中的内容而言(即,
git log
),您已经更改了历史记录。就回购协议(即,
git reflog
)中发生的事情而言,您添加了它。因此,如果这些提交被发布,这会是一件“坏事”吗?您通常会发布一个分支,因此它们不会被包括在内。不过,重置公共分支通常被认为是一种不好的做法——它会迫使所有在其上重新设置基础的人强制更新其本地分支。这个答案太棒了,还有一些我不知道的事情,比如
——allow empty