2015-05-06 16 views
8

Tôi có một repo với bốn cam kết:Điều gì xảy ra với các cam kết mồ côi?

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

tôi reset -- soft đến C2 cam kết và bây giờ tôi có một repo như vậy:

$ git reset e27b22c --soft 

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

Bây giờ tôi thêm một thêm cam kết, vì vậy vẻ log như thế này:

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

Điều gì đã xảy ra với cam kết C3C4? Tôi chưa xóa chúng, vì vậy tôi cho rằng chúng vẫn ở đó, cha mẹ của C3 vẫn là C2.

Trả lời

7

Câu trả lời ngắn: Cam kết C3C4 sẽ vẫn còn trong cơ sở dữ liệu đối tượng Git cho đến khi chúng được thu thập rác.

Câu trả lời dài: Việc thu gom rác sẽ tự động diễn ra bằng các lệnh sứ Git khác nhau hoặc khi thu gom rác một cách rõ ràng. Có rất nhiều kịch bản có thể kích hoạt một bộ sưu tập rác tự động; hãy xem gc.* configuration settings để có ý tưởng. Bạn có thể kiếm tiền một cách rõ ràng bằng cách sử dụng git gc builtin command. Hãy xem một ví dụ để xem điều gì xảy ra.

Trước tiên, hãy thiết lập môi trường của chúng tôi (tôi đang sử dụng Linux; thực hiện thay đổi khi cần thiết cho môi trường của bạn).

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 

Kể từ khi băm đối tượng cam kết được tạo bằng cách sử dụng cùng một giá trị tác giả và giá trị, tất cả chúng ta đều có cùng một giá trị băm.

Bây giờ chúng ta hãy khởi tạo một chức năng để đăng nhập thông tin đối tượng sử dụng git log, git reflog, git count-objects, git 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 
} 

Bây giờ chúng ta hãy khởi tạo một kho lưu trữ Git.

git --version 
git init 
git_log_objects 

nào, đối với tôi, kết quả đầu ra:

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 ... 

Đúng như dự đoán, chúng ta có một kho khởi tạo không có đối tượng trong đó. Hãy thực hiện một số cam kết và xem xét các đối tượng.

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 

nào mang lại cho tôi kết quả như sau:

[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 

Bây giờ chúng ta có sáu đối tượng trong kho: năm cam kết và một cây rỗng. Chúng ta có thể thấy Git có các tham chiếu branch, tag và/hoặc reflog cho tất cả năm đối tượng commit. Miễn là Git tham chiếu đến một đối tượng, đối tượng đó sẽ không được thu thập rác. Rõ ràng chạy một bộ sưu tập gabage sẽ dẫn đến không có đối tượng nào bị xóa khỏi kho lưu trữ. (Tôi sẽ để lại xác minh điều này như một bài tập cho bạn để hoàn thành.)

Bây giờ chúng ta hãy loại bỏ tài liệu tham khảo Git đến C3, C4C5 cam kết.

git reset --soft T1 
git reflog expire --expire=all --all 
git_log_objects 

Những kết quả đầu ra:

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 

Bây giờ chúng ta thấy chỉ có hai cam kết đang được tham chiếu bởi Git. Tuy nhiên, tất cả sáu đối tượng vẫn còn trong kho. Chúng sẽ vẫn còn trong kho lưu trữ cho đến khi chúng được thu thập tự động hoặc một cách rõ ràng. Bạn thậm chí có thể, ví dụ, làm sống lại một cam kết không được chấp nhận với git cherry-pick hoặc xem nó với git show. Tuy nhiên, bây giờ, chúng ta hãy thu gom rác một cách rõ ràng các đối tượng không được quan tâm và xem Git làm gì đằng sau hậu trường.

GIT_TRACE=1 git gc --aggressive --prune=now 

Điều này sẽ tạo ra một chút thông tin.

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' 

Và cuối cùng, hãy nhìn vào các đối tượng.

git_log_objects 

Những kết quả đầu ra:

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 

Bây giờ chúng ta thấy chúng ta chỉ có ba đối tượng: hai cam kết và một cây rỗng.

+0

Câu trả lời đó là * tuyệt vời *, có một số thứ khác mà tôi không biết ở đó, như '--allow-empty'. – BanksySan

+0

Tốt nhất, cảm ơn bạn! – Peddipaga

4

Cam kết mồ côi chỉ ở đó cho đến khi chúng được thu gom rác bằng cách chạy rõ ràng git gc.

+0

Câu hỏi tiếp theo sau đó. Tôi đã thay đổi lịch sử hoặc chỉ cần thêm vào lịch sử? – BanksySan

+0

Về những gì trong nhánh (ví dụ: 'git log') - bạn đã thay đổi lịch sử. Về điều gì đã xảy ra trong repo (tức là, 'git reflog'), bạn đã thêm vào nó. – Mureinik

+0

Vì vậy, nếu các cam kết này được xuất bản, đây có phải là 'điều xấu' không? – BanksySan

5

Chạy git show 6c35831 để xem C4 chẳng hạn, vẫn còn ở đó. Chạy git reflog master để xem (nhiều) cái gì masterđược sử dụng để tham chiếu. Một trong các mục nhập (master^{1} hầu như có khả năng, nhưng có lẽ một cũ hơn nếu bạn đã thực hiện các thay đổi khác) phải tương ứng với 6c35831git show master^{1} (hoặc bất kỳ mục nhập nào) sẽ hiển thị cùng một đầu ra của lệnh git show đầu tiên tôi đã đề cập.

Các vấn đề liên quan