Почему git нажимал столько данных?

Мне интересно, что делает git, когда он подталкивает изменения и почему кажется, что время от времени выводит больше данных, чем изменения, которые я сделал. Я внес некоторые изменения в два файла, которые добавили около 100 строк кода - менее 2 тыс. Текста.

Когда я отправил данные до начала координат, git превратил это в более чем 47 мб данных:

git push -u origin foo
Counting objects: 9195, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6624/6624), done.
Writing objects: 100% (9195/9195), 47.08 MiB | 1.15 MiB/s, done.
Total 9195 (delta 5411), reused 6059 (delta 2357)
remote: Analyzing objects... (9195/9195) (50599 ms)
remote: Storing packfile... done (5560 ms)
remote: Storing index... done (15597 ms)
To <<redacted>>
 * [new branch]      foo -> foo
Branch foo set up to track remote branch foo from origin.

Когда я меняю свои изменения, (origin/master..HEAD), только два файла и одна фиксация, которую я обнаружил. Откуда взялось 47 мб данных?

Я видел это: Когда я делаю "git push" , что означает статистика? (Итого, дельта и т.д.) и это: Предскажите, сколько данных будет нажато в git push но это на самом деле не рассказывало мне, что происходит... Почему пакет/пакет огромны?

Ответы

Ответ 1

Я только что понял, что есть очень реалистичный сценарий, который может привести к необычайно большому толчку.

Какие объекты push отправляет? Которые еще не существуют на сервере. Или, скорее, который он не обнаружил как существующий. Как он проверяет существование объекта? В начале push, сервер отправляет ссылки (ветки и теги), которые есть. Так, например, если у них есть следующие коммиты:

  CLIENT                                     SERVER
 (foo) -----------> aaaaa1
                      |
 (origin/master) -> aaaaa0                (master) -> aaaaa0
                      |                                 |
                     ...                               ...

Затем клиент получит что-то вроде /refs/heads/master aaaaa0 и обнаружит, что он должен отправлять только то, что является новым в commit aaaaa1.

Но, если кто-то что-то выдвинул на удаленный мастер, это другое:

  CLIENT                                     SERVER
 (foo) -----------> aaaaa1                      (master) --> aaaaa2
                      |                                       /
 (origin/master) -> aaaaa0                                 aaaaa0
                      |                                      |
                     ...                                    ...

Здесь клиент получает refs/heads/master aaaaa2, но он ничего не знает о aaaaa2, поэтому он не может сделать вывод, что aaaaa0 существует на сервере. Таким образом, в этом простом случае только 2 веток будет отправлена вся история, а не только инкрементная.

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

Чтобы избежать этого, вы можете запустить git fetch перед push. Тогда, в моем примере, aaaaa2 уже существует на клиенте, и git push foo будет знать, что он не должен отправлять aaaaa0 и более старую историю.

Читайте здесь для реализации push в протоколе.

PS: недавняя функция git commit graph могла бы помочь с этим, но я не пробовал.

Ответ 2

Когда я отправил данные до начала координат, git превратил это в более чем 47 Мб данных.

Похоже, ваш репозиторий содержит много данных двоичных файлов.


Сначала посмотрим, что делает git push?

git-push - обновить удаленные ссылки ref вместе со связанными объектами


Что это за associated objects?

После каждой фиксации вы выполняете git выполнение pack ваших данных в файлы с именем XX.pack && `XX.idx '


Хорошее чтение о упаковке здесь

введите описание изображения здесь

Как git упаковывать файлы?

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

Создается пакетный индексный файл .idx для быстрого и произвольного доступа к объектам в пакете.

Размещение индексного файла .idx и упакованного архива .pack в подкаталоге pack $GIT_OBJECT_DIRECTORY (или любой из каталогов на $GIT_ALTERNATE_OBJECT_DIRECTORIES) позволяет git читать из архива пакетов.

Когда git упаковывает ваши файлы, он делает это разумно, поэтому для извлечения данных будет очень быстро.

Для достижения этого git используйте pack-heuristics, который в основном ищет подобную часть контента в вашем пакете и сохраняет их как единый, то есть - если у вас есть один и тот же заголовок (например, лицензионное соглашение) во многих файлах, git "найдет" его и сохранит его один раз.

Теперь все файлы, которые включают эту лицензию, будут содержать указатель в коде заголовка. В этом случае git не нужно хранить один и тот же код снова и снова, поэтому размер пакета минимален.

Это одна из причин, почему это не очень хорошая идея, и не рекомендуется хранить двоичные файлы в git, так как вероятность сходства очень низкая, поэтому размер пакета не будет оптимальным.

Git сохраняйте свои данные в зашифрованном формате, чтобы уменьшить пространство, поэтому двоичный файл не будет оптимальным, а также zip (размер wize).


Вот образец git blob с использованием сжатого сжатия:

введите описание изображения здесь