Git находит измененные файлы, начиная с ‹ref› из неглубокого клона

Я на CI-боксе, выполняю тесты. Чтобы ускорить это, я просто делаю поверхностный клон:

git clone --depth 1 [email protected]:JoshCheek/some_repo.git

Предполагая, что все тесты пройдены, я хочу запустить следующий шаг в конвейере. Что запускать, зависит от того, какие файлы были изменены между последним dразвертыванием (ref d123456) и current ref, который я только что протестировал (ref c123456). Если бы я сделал нормальный клон, я мог бы узнать вот так:

git diff --name-only d123456 c123456

Но мой клон неглубокий, поэтому он не знает об этих коммитах. Я вижу, что могу использовать git fetch --depth=n, чтобы получить больше истории, но я знаю только SHA, а не глубину SHA. Вот набор способов, которые предположительно могли бы ответить на этот вопрос:

# hypothetical remote diff
git diff --name-only origin/d123456 origin/c123456

# hypothetical ref based fetch
git fetch --shallow-through d123456
git diff --name-only d123456 c123456

# hypothetical way to find the depth I need
depth=`git remote depth-to d123456`
git fetch --depth "$depth"
git diff --name-only d123456 c123456

В противном случае мне, возможно, придется написать цикл и продолжать вызывать --deepen, пока в моей истории не появится фиксация. Это кажется болезненным (то есть раздражающим при написании/сопровождении) и дорогим (то есть медленным, помните, что цель поверхностного клонирования — уменьшить эту стоимость).


person Joshua Cheek    schedule 04.05.2017    source источник


Ответы (3)


В противном случае мне, возможно, придется написать цикл и продолжать вызывать --deepen, пока моя история не будет содержать фиксацию. Это кажется болезненным...

Это это болезненно (и медленно, как вы заметите чуть позже).

В современном Git (начиная с версии 2.11) есть новая опция git fetch:

--shallow-exclude=‹редакция›

    Deepen or shorten the history of a shallow repository to exclude commits reachable from a specified remote branch or tag. This option can be specified multiple times.

Я не пробовал это; неясно, разрешает ли он хэш-идентификатор (в тестах используются имена), и в любом случае вы должны указать родителя(ей) коммита, который вы хотите углубить, а не коммит, который вы хотите получить. Но может хватить.

(Я действительно думаю, что лучший способ — сохранить эталонные клоны, которые вы можете позаимствовать.)

person torek    schedule 04.05.2017
comment
О, хороший улов, я совсем пропустил это! К сожалению, кажется, что Github не поддерживает его, когда я пытаюсь, он говорит fatal: Server does not support --shallow-exclude :( - person Joshua Cheek; 05.05.2017
comment
Не могли бы вы подробнее остановиться на последнем примечании? Мне непонятно, что такое эталонный клон (вы говорите о полностью клонированном репо, кэшированном на сервере CI?). - person Joshua Cheek; 05.05.2017
comment
Да: с эталонным клоном вы запускаете git clone --reference <path> [options] <url>, и Git вызывает другой Git по URL-адресу, как обычно, но затем заимствует или копирует (см. --dissociate) объекты из эталонного клона, а не копирует их по сети. Измерив реальный проект, я сократил время настенных часов клонирования с почти двух часов до нескольких минут, используя эталонные клоны. (Это включало ряд довольно больших репозиториев.) - person torek; 05.05.2017
comment
Спасибо, я попробую сохранить кешированный клон, пока он выглядит многообещающе. - person Joshua Cheek; 09.05.2017
comment
Обновление 2021: Github теперь поддерживает мелкое исключение, но вы не можете использовать хэш фиксации в качестве аргумента (вы получаете сообщение об ошибке, когда удаленный конец неожиданно завис, если вы попытаетесь) - person Alice Purcell; 11.02.2021

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

1.git clone <url> -b <branch> --single-branch

Это извлекает только данные, доступные <branch>. Не так эффективно, как --depth=1, но все же лучше, чем полный клон. Он отлично работает, когда в репозитории много разветвленных ветвей.

2.git init;git fetch <url> <tag>

Точно так же он извлекает только данные, доступные <tag>.

3. Создайте и используйте зеркальный репозиторий.

git clone <url> --mirror -- /foo/mirror. /foo/mirror — это зеркальный репозиторий. Предположим, ваша система CI запускает несколько экземпляров одновременно. Клонируйте каждый через git clone <url> --reference=/foo/mirror -- <instanceN>. В каждом клоне из удаленного репозитория будут загружены только те данные, которых нет в зеркальном репозитории. Вы можете удалить экземпляры, чтобы сэкономить место, когда работа будет выполнена. Но просто сохраняйте и регулярно обновляйте зеркальный репозиторий git fetch в зависимости от частоты обновления удаленного репозитория. Например, один раз в день в полночь или один раз в неделю в воскресенье.

4.Используйте git worktree.

Сделайте клон, сохраните его и сначала обновите при запуске каждого экземпляра CI. Используйте git worktree для извлечения ревизий в разные рабочие деревья для каждого экземпляра.

person ElpieKay    schedule 05.05.2017
comment
Спасибо за идеи! В конечном итоге я выберу кешированный клон. Возможно, придется использовать некоторые идеи из других здесь, если его состояние станет шатким, но пока я надеюсь. - person Joshua Cheek; 09.05.2017

Я столкнулся с той же проблемой и использовал это

git clone --shallow-since=<date>

Мне пришлось хранить не только SHA моего последнего развертывания, но и дату моего последнего развертывания, но в остальном все работало отлично.

person Robert Antonucci    schedule 29.11.2018