== Додаток 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 результату вимагає значного ручного втручання.

=== Чудасії інтерфейсу ===

Для коммітів А і Б значення виразів "A..B" і "A...B" залежать від того, чи очікує команда вказівки двох кінцевих точок або проміжку. Дивіться *git help diff* та *git help rev-parse*.
