2016-06-09 2 views
6

Я работаю над курсом git и хотел бы упомянуть, что потерянные ссылки действительно не потеряны до запуска git gc. Но, подтвердив это, я узнал, что это не так. Даже после запуска git gc --prune=all --aggressive потерянные ссылки все еще там.Когда именно git обрезает объекты: почему «git gc» не удаляет коммиты?

Очевидно, я что-то не понял. И прежде чем сказать что-то неправильное в курсе, я хочу получить мои факты прямо! Ниже приведен пример сценарий иллюстрирует эффект:

#!/bin/bash 

git init 

# add 10 dummy commits 
for i in {1..10}; do 
    date > foo.txt 
    git add foo.txt 
    git commit -m "bump" foo.txt 
    sleep 1 
done; 

CURRENT=$(git rev-parse HEAD) 
echo HEAD before reset: ${CURRENT} 

# rewind 
git reset --hard HEAD~5 

# add another 10 commits 
for i in {1..10}; do 
    date > foo.txt 
    git add foo.txt 
    git commit -m "bump" foo.txt 
    sleep 1 
done; 

Этот скрипт добавит 10 манекена совершившее, сбросить до 5 фиксаций в прошлом, и добавить еще 10 фиксаций. Как раз перед сбросом, он напечатает хеш текущего HEAD.

Я хотел бы ожидать, чтобы потерять объект в CURRENT после запуска git gc --prune=all. Тем не менее, я все еще могу запустить git show на этом хэше.

Я понимаю, что после запуска git reset и добавления новых коммитов я по существу создал новую ветку. Но у моей оригинальной ветки больше нет ссылок, поэтому она не отображается в git log --all. Я также предполагаю, что это не будет перенесено на любой отдаленный объект.

Мое понимание git gc было удалено из этих объектов. Кажется, это не так.

Почему? И , когда точно git gc удалить объекты?

+2

Ваш рефлок по-прежнему содержит ссылки на то, что вы «удалили». Пока этот тайм-аут или вы явно не закончите их, они не будут обрезаны. – twalberg

+0

Интересно. Я просмотрел https://git-scm.com/docs/git-reflog и запустил 'git reflog --expire = all'. После чего объект был * еще * там. Затем я запустил еще один «gc», и он все еще был там. Даже другой «git gc --aggressive --prune = all» не помог. – exhuma

+0

Вам нужно '--expire = all -all' или запустить его как на' HEAD' (по умолчанию), так и на 'master'. Или вы можете вручную удалить определенные записи (или посмотреть ответ ниже). – torek

ответ

10

Для объекта, подлежащего обрезке, он должен соответствовать двум критериям. Один из них связан с датой/временем: он должен быть создан достаточно долго, чтобы созреть для коллекции. Часть «достаточно долго назад» - это то, что вы устанавливаете с помощью --prune=all: вы переопределяете обычную настройку «по крайней мере две недели».

Второй критерий - ваш эксперимент идет не так. Для обрезки объект должен быть также be недоступен. Как twalberg noted in a comment, каждый из ваших якобы заброшенных коммитов (и, следовательно, их соответствующих деревьев и капель) на самом деле ссылается на записи «reflog» Git.

Есть два reflog записи для каждой такой фиксации: один для HEAD, и один для имени ветви, к которой HEAD сам говорил в то время коммита, было сделано (в данном случае, в reflog для refs/heads/master, то есть филиал master). Каждая запись reflog имеет свою собственную метку времени, и git gc также истекает для вас записями журнала, хотя с более сложным набором правил, чем простой «14 дней» по умолчанию для истечения срока действия объекта.

Следовательно, git gcможет сначала удалить все reflog записи, которые сохраняющие старый объект вокруг, затем подрезать объект. Это просто не происходит здесь.

Чтобы просмотреть или удалить записи reflog вручную, используйте git reflog.Обратите внимание, что git reflogотображает записей с помощью git log с опцией -g/--walk-reflogs (плюс некоторые дополнительные опции форматирования экрана). Вы можете запустить git reflog --all --expire=all, чтобы очистить все, хотя это дубинка, когда скальпель может быть более уместным. Используйте --expire-unreachable для немного большей селективности. Для получения дополнительной информации см. the git log documentation и, конечно, the git reflog documentation.


Некоторые файловые системы Unix-у не создание магазина файла («рождение») времени на все: st_ctime поле stat структуры является изменение времени инф.узлов, а не время создания. Если есть время создания, оно находится в st_birthtime или st_birthtimespec. Однако каждый объект Git доступен только для чтения, поэтому время создания файла также является временем его модификации. Следовательно, st_mtime, который равен, всегда доступен, дает время создания объекта.

Точных правила описаны в the git gc documentation, но я думаю, что По умолчанию 30 дней для недостижимых фиксаций и 90 дней для достижимы совершают порядочное резюме. Однако определение достигает: это означает, что доступен из текущего значения ссылки, для которой этот рефль хранит старые значения. То есть, если мы смотрим на reflog для master, мы находим, что обязательство master идентифицирует (например, 1234567), а затем увидеть, если каждый reflog вход для master (например, [email protected]{27}) достижим от конкретной фиксацией (1234567).

Это конкретное имя путаницы представлено вам специалистами по стандартизации POSIX. :-) Поле st_birthtimespec - это struct timespec, в котором записаны секунды и наносекунды.

+0

Обратите внимание, что записи reflog в конечном итоге собираются с мусором. Поскольку ['git gc' documentation] (https://www.kernel.org/pub/software/scm/git/docs/git-gc.html) говорит, что необязательная переменная конфигурации' gc.reflogExpire' по умолчанию равна 90 дней и 'gc.reflogExpireUnreachable' по умолчанию - 30 дней. Доступные и недоступные записи в журнале reflog будут удалены, если они будут старше этих переменных при запуске 'git gc'. –

+0

@ RoryO'Kane: справа; Я оставил это ссылки на документацию, но, возможно, я должен упомянуть об этом непосредственно в ответе? – torek

+0

Да, я думаю, что было бы полезно обратиться к названию вопроса напрямую, сказав, что 'git gc' иногда удаляет коммиты. Это также не позволит предположить, что 'git reflog' - единственная команда, которая удаляет записи reflog. Однако писать это в свой ответ не так важно, учитывая, что читатели могут получать ту же информацию из этих комментариев. –