Предотвращение отправки git push всего репо, если оно не обновлено - PullRequest
3 голосов
/ 05 ноября 2010

Смежный вопрос: почему Git отправляет весь репозиторий каждый раз, когда мастер отправки отправляет

Краткая версия: При работе с двумя репозиториями Git, даже если 99% объектов коммитов идентичны, используйте git push для отправки коммита в репозиторий B при origin настроен на репо A вызывает передачу всех объектов (200 МБ +).

Гораздо более длинная версия: У нас есть второй репозиторий Git, настроенный на нашем сервере непрерывной интеграции. После того, как мы подготовили наши объекты коммитов локально, вместо того, чтобы прямо нажимать на origin/master, как обычно, мы вместо этого отправляем наши изменения в ветвь этого второго репозитория. Сервер CI выбирает новую ветку, автоматически перебазирует ее на master, запускает наши интеграционные тесты и, если все хорошо, выдвигает ветку на origin/master в главном репо.

Сервер CI также периодически вызывает git fetch для получения последней копии origin/master из основного репо, если кто-то обошел процесс CI и нажал прямо.

Это прекрасно работает, особенно если кто-то делает git fetch; git rebase origin/master перед тем, как перейти к репозиторию CI; Git отправляет только те объекты фиксации, которых нет в origin/master. Если пропустить шаг выборки / перебазирования перед нажатием, процесс все еще работает, но Git, по-видимому, отправляет, если не все, большинство объектов коммитов в репозиторий CI - в настоящее время стоимостью более 200 МБ. (Свежий клон нашего репо имеет размер 225 МБ.)

Мы что-то делаем не так? Есть ли способ исправить это поведение так, чтобы Git отправлял только те объекты фиксации, которые ему нужны для формирования ветви в репозитории CI? Очевидно, что мы можем обойти эту проблему, выполнив предварительный пуш git fetch; git rebase origin/master, но такое ощущение, что мы должны пропустить этот шаг, особенно потому, что пуш напрямую в мастер репо не представляет той же проблемы.

Наши репозитории обслуживаются Gitosis 0.2, и наши клиенты в подавляющем большинстве случаев запускают msysgit 1.7.3.1-preview.

Ответы [ 3 ]

2 голосов
/ 05 ноября 2010

... автоматически перебазирует его на master ...

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

В следующий разВы отправляете свой код на CI-сервер, на самом деле у него больше нет всех этих объектов (они недоступны ни для каких живых голов), поэтому он просит вашего клиента отправить их все снова.

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

1 голос
/ 12 ноября 2010

Оказывается, самое простое решение этой проблемы - это для извлечения прямо перед нажатием:

$ git fetch origin master
$ git push user@host:repo.git HEAD:refs/heads/commit128952690069

В нашем случае важно извлечь определенную ветку в FETCH_HEAD; таким образом, состояние локальной ветви пользователя будет неизменным , но мы все равно получим самый последний набор объектов из основного репозитория; в следующем git push всегда будет присутствовать коммит предка, когда Git начнет упаковывать объекты.

Я немного поработал с git pack-objects: если создается файл пакета, содержащий коммиты <common_ancestor>..HEAD, он упаковывает только столько данных, сколько требуется:

$ echo $(git merge-base master origin/master)..HEAD | git pack-objects --revs --thin --stdout --all-progress-implied > packfile

Однако при выдаче git push с хранилищем в том же состоянии все объекты упаковываются и отправляются.

Я подозреваю, что при подключении к репозиторию Git каждый получает SHA последней ревизии в репо - если Git не имеет объекта коммита, представленного этим SHA локально, он не может запустить git merge-base для определить общего предка; следовательно, он должен отправить все объекты в удаленное хранилище. Если этот объект фиксации существует, то git merge-base завершается успешно, и файл пакета может быть собран со ссылкой на общего предка.

0 голосов
/ 05 ноября 2010

Похоже, что ваши локальные репозитории вышли из синхронизации с репозиторием CI-сервера, тот факт, что от вас к CI-серверу происходит это, означает, что ваш локальный репозиторий имеет другой набор хэшей коммитов. Это может быть что-то вроде этого:

git clone master
(... do work ...)
git push ci branch
(... CI does a rebase that changes all the commits hashes you pushed ..)
(... CI does its' testing and pushes to master ...)
(... Now master and CI match but the hashes of all the commits you just pushed
     don't exist anywhere except your local machine ...)
(... do work ...)
git push ci branch

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

...