2015-05-06 77 views
8

我有四次提交回購:孤立提交會發生什麼?

$ git log --oneline --decorate 
6c35831 (HEAD, master) C4 
974073b C3 
e27b22c C2 
9f2d694 C1 

reset -- softC2承諾,現在我有像這樣一個回購:

$ 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 

發生了什麼事提交C3C4?我沒有刪除它們,所以我認爲它們仍然存在,C3的父母仍然是C2

回答

7

簡短回答:提交C3C4將保留在Git對象數據庫中,直到它們被垃圾收集爲止。

長答案:垃圾收集將自動發生在不同的Git瓷器命令或明確垃圾收集。有很多情況可能會觸發自動垃圾收集;看看gc.* configuration settings來獲得一個想法。您可以使用git gc builtin command明確地進行gabage收集。我們來看一個例子來看看會發生什麼。首先,讓我們設置我們的環境(我正在使用Linux;根據您的環境需要進行更改),因此我們希望在不同的Git存儲庫中獲得相同的對象哈希值。

export GIT_AUTHOR_NAME='Wile E. Coyote' 
export [email protected] 
export GIT_AUTHOR_DATE=2015-01-01T12:00:00 
export GIT_COMMITTER_NAME='Roadrunner' 
export [email protected] 
export GIT_COMMITTER_DATE=2015-01-01T12:00:00 

由於使用這些信息,如果我們使用相同的作者和提交者價值觀產生commit對象的哈希值,我們都應該現在得到相同的哈希值。

現在我們初始化函數來登錄使用git loggit refloggit count-objectsgit rev-listgit fsck對象的信息。

function git_log_objects() { 
    echo 'Log ...' 
    git log --oneline --decorate 
    echo 'Reflog ...' 
    git reflog show --all 
    echo 'Count ...' 
    git count-objects -v 
    echo 'Hashes ...' 
    # See: https://stackoverflow.com/a/7350019/649852 
    { 
     git rev-list --objects --all --reflog 
     git rev-list --objects -g --no-walk --all 
     git rev-list --objects --no-walk $(
      git fsck --unreachable 2>/dev/null \ 
       | grep '^unreachable commit' \ 
       | cut -d' ' -f3 
     ) 
    } | sort | uniq 
} 

現在我們來初始化一個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 

這給了我下面的輸出:

[master (root-commit) c11e156] C1 
Author: Wile E. Coyote <[email protected]> 
[master 10bfa58] C2 
Author: Wile E. Coyote <[email protected]> 
[master 8aa22b5] C3 
Author: Wile E. Coyote <[email protected]> 
[master 1abb34f] C4 
Author: Wile E. Coyote <[email protected]> 
[master d1efc10] C5 
Author: Wile E. Coyote <[email protected]> 
Log ... 
d1efc10 (HEAD -> master) C5 
1abb34f C4 
8aa22b5 C3 
10bfa58 (tag: T1) C2 
c11e156 C1 
Reflog ... 
d1efc10 refs/heads/[email protected]{0}: commit: C5 
1abb34f refs/heads/[email protected]{1}: commit: C4 
8aa22b5 refs/heads/[email protected]{2}: commit: C3 
10bfa58 refs/heads/[email protected]{3}: commit: C2 
c11e156 refs/heads/[email protected]{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 

現在,我們已經在倉庫六個對象:五所提交和一個空的樹。我們可以看到Git對所有五個提交對象都有分支,標記和/或reflog引用。只要Git引用一個對象,那個對象就不會被垃圾回收。顯式運行gabage集合將導致從存儲庫中刪除任何對象。 (我將驗證這是一個練習,以供您完成。)

現在讓我們刪除Git對C3C4C5提交的引用。

git reset --soft T1 
git reflog expire --expire=all --all 
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 

現在我們只看到兩個提交正在被引用的Git。但是,所有六個對象仍在存儲庫中。它們將保留在存儲庫中,直到它們自動或明確地被垃圾收集爲止。例如,您甚至可以用git cherry-pick來恢復未提交的提交,或者用git show來查看它。現在,讓我們明確地垃圾收集未引用的對象,並看看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_log_objects 

,輸出:

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 

現在我們看到,我們只有三個對象:兩個提交和一個空的樹。

+0

這個答案是*真棒*,還有其他一些我不知道的東西,比如'--allow-empty'。 – BanksySan

+0

好的,謝謝! – Peddipaga

4

孤兒提交只是呆在那裏,直到他們通過明確運行垃圾收集git gc

+0

然後跟進問題。我是否改變了歷史記錄或添加了它? – BanksySan

+0

根據分支中的內容(即'git log') - 您已更改歷史記錄。根據回購中發生的事情(即'git reflog'),您添加了它。 – Mureinik

+0

所以,如果這些提交已經發布,這是否是一件'壞事'? – BanksySan

5

運行git show 6c35831以查看C4,例如,仍然存在。運行git reflog master查看(大量)什麼master使用來引用。其中一個條目(master^{1}最有可能,但也許更老,如果你也做了其他更改)應該對應於6c35831git show master^{1}(或其中任何一個入口)應該顯示與我提到的第一個git show命令相同的輸出。