== Приложение A: Недостатки Git ==

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

=== Слабости SHA1 ===

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

Надеюсь, Git перейдет на лучшую хеш-функцию прежде чем дальнейшие исследования уничтожат SHA1.

=== Microsoft Windows ===

Git на Microsoft Windows может быть громоздким:

- http://cygwin.com/[Cygwin], Linux-подобная среда для Windows, содержащая http://cygwin.com/packages/git/[порт Git на Windows].

- http://code.google.com/p/msysgit/[Git на MSys], вариант, требующий минимальной рантайм поддержки, хотя некоторые комманды нуждаются в доработке.

=== Несвязанные файлы ===

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

Решение — разбить проект на части, каждая из которых состоит из взаимосвязанных файлов. Используйте *git submodule* если вы все же хотите держать все в одном хранилище.

=== Кто и что редактировал ? ===

Некоторые системы управления версиями вынуждают вас явным образом пометить файл перед редактированием. Хотя такой подход особенно раздражает, когда подразумевает работу с центральным сервером, однако он имеет два преимущества:

  1. Diff'ы быстры, так как нужно проверить только отмеченные файлы.

  2. Можно обнаружить, кто еще работает с этим файлом, спросив центральный сервер, кто отметил его для редактирования.

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

=== История файла ===

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

Потери как правило незначительны, и это неплохая цена за то, что другие операции невероятно эффективны. Например, git checkout быстрее, чем cp -a, а дельта всего проекта сжимается лучше, чем коллекция по-файловых дельт.

=== Начальное Клонирование ===

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

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

=== Изменчивые Проекты ===

Git был написан, чтобы быть быстрым при относительно небольших изменениях. Люди вносят незначительные правки от версии к версии. Однострочное исправление ошибки здесь, новая функция там, исправленные комментарии и тому подобное. Но если ваши файлы радикально различаются в соседних ревизиях, то с каждым коммитом ваша история неизбежно увеличится на размер всего проекта.

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

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

Возможно, вам была нужна база данных или система резервного/архивного копирования, а не система управления версиями. Например, управление версиями может быть плохо приспособлено для обращения с фотографиями периодически получаемыми с веб-камеры.

Если файлы действительно должны постоянно изменяться и при этом версироваться, может иметь смысл использовать Git централизованным образом. Можно создавать мелкие клоны, с небольшой историей или без истории вообще. Конечно, многие инструменты Git будут недоступны, и исправления придется представлять в виде патчей. Возможно, это и хорошо, так как неясно, зачем кому-либо понадобится история крайне нестабильных файлов.

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

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

=== Глобальный счетчик ===

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

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

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

=== Пустые подкаталоги ===

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

В этом виноват не дизайн Git, а его текущая реализация. Если повезет и пользователи Git будут поднимать больше шума вокруг этой функции, возможно она будет реализована.

=== Первоначальный коммит ===

Шаблонный компьютерщик считает с 0, а не с 1. К сожалению, в отношении коммитов Git не придерживается этого соглашения. Многие команды недружелюбны до первоначального коммита. Кроме того, некоторые частные случаи требуют специальной обработки, к примеру rebase ветки с другим начальным коммитом.

Git'у было бы выгодно определить нулевой коммит: при создании хранилища HEAD был бы установлен в строку, состоящую из 20 нулевых байтов. Этот специальный коммит представлял бы собой пустое дерево, без родителей, которое предшествует каждому хранилищу Git.

Тогда запуск *git log*, например, показывал бы пользователю, что коммиты еще не были сделаны, вместо того чтобы завершаться с фатальной ошибкой. Аналогично для других инструментов.

Каждый первоначальный коммит — неявный потомок этого нулевого коммита.

Однако здесь, к сожалению, есть некоторые проблемные случаи. Если несколько ветвей с различными начальными коммитами сливаются, то rebase результата требует значительного ручного вмешательства.

=== Причуды интерфейса ===

Для коммитов А и Б значения выражений «А..Б» и «А...Б» зависят от того, ожидает ли команда указания двух конечных точек или промежутка. Смотрите *git help diff* и *git help rev-parse*.
