2015-05-06 1 views
8

У меня есть репо с четырьмя фиксаций:Что происходит с сиротами?

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

ответ

7

Короткий ответ: Commets C3 и C4 останутся в базе данных объектов Git, пока не будут собраны мусор.

Долгий ответ: сбор мусора будет происходить автоматически различными командами фарфора Git или при сборке явного сбора мусора. Существует много сценариев, которые могут вызвать автоматическую сборку мусора; посмотрите на gc.* configuration settings, чтобы получить представление об этом. Вы можете явно собирать габарит, используя git gc builtin command. Давайте посмотрим на пример, чтобы узнать, что произойдет.

Прежде всего, давайте настроим нашу среду (я использую 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 

Поскольку совершающие объект хэши генерируются с использованием этой информации, если мы будем использовать тот же автор и коммиттер ценности, мы все должны теперь получить те же хэши.

Теперь давайте инициализировать функцию для регистрации информации об объекте с помощью git log, git reflog, git count-objects, git rev-list и git 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 на все пять объектов commit. Пока Git ссылается на объект, этот объект не будет собираться мусором. Явное использование коллекции габарей приведет к тому, что объекты не будут удалены из репозитория. (Я останусь проверять это как упражнение для вас.)

Теперь давайте удалим ссылки Git на ссылки C3, C4 и C5.

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. Однако все шесть объектов все еще находятся в репозитории. Они останутся в хранилище до тех пор, пока они автоматически или явно не будут собраны мусор. Вы могли бы даже, например, оживить unreferated commit с 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} скорее всего, но, возможно, одна старая, если вы внесли другие изменения), должна соответствовать 6c35831, а git show master^{1} (или какая бы она ни была) должна показывать тот же вывод первой команды git show, о которой я упоминал.

Смежные вопросы