Розділ 6. Багатокористувацький Git

Спочатку я використовував Git для особистого проекту, в якому був єдиним розробником. Серед команд, які відносяться до розподілених властивостей Git, мені були потрібні тільки pull і clone, щоб зберігати один і той же проект у різних місцях.

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

Хто я?

Кожен комміт містить ім'я автора та адресу електронної пошти, які виводяться командою git log. За замовчуванням Git використовує системні налаштування для заповнення цих полів. Щоб встановити їх явно, введіть

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

Щоб встановити ці параметри лише для поточного сховища, пропустіть опцію --global.

Git через SSH, HTTP

Припустимо, у вас є SSH доступ до веб-сервера, але Git не встановлений. Git може зв'язуватися через HTTP, хоча це і менш ефективно, ніж його власний протокол.

Скачайте, скомпілюйте, встановіть Git у вашому акаунті; створіть сховище в каталозі, доступному через web:

$ GIT_DIR=proj.git git init
$ cd proj.git
$ git --bare update-server-info
$ cp hooks/post-update.sample hooks/post-update

Для старих версій Git команда копіювання не спрацює і ви повинні будете запустити

$ chmod a+x hooks/post-update

Тепер ви можете публікувати свої останні правки через SSH з будь-якого клону:

$ git push веб.сервер:/шлях/до/proj.git master

і хто завгодно зможе взяти ваш проект за допомогою

$ git clone http://веб.сервер/proj.git

Git через що завгодно

Хочете синхронізувати сховища без серверів або взагалі без мережевого підключення? Змушені імпровізувати на ходу в непередбаченій ситуації? Ми бачили, як git fast-export і git fast-import можуть перетворити сховища в один файл і назад. За допомогою обміну такими файлами ми можемо переносити сховища git будь-якими доступними засобами, але є більш ефективний інструмент: git bundle.

Відправник створює пакет (bundle):

$ git bundle create деякий_файл HEAD

Потім передає пакет, деякий_файл, іншій команді будь-якими засобами, такими як: електронна пошта, флешка, xxd друк і подальше розпізнавання тексту, надиктовка бітів по телефону, димові сигнали і так далі. Одержувач відновлює комміти з пакету, ввівши

$ git pull деякий_файл

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

У великих проектах для усунення надлишків обсягу пакетують тільки зміни, яких немає в інших сховищах. Наприклад, нехай комміт «1b6d…» — останній спільний для обох груп:

$ git bundle create деякий_файл HEAD ^1b6d

Якщо це робиться часто, можна легко забути, який комміт був відправлений останнім. Довідка пропонує для вирішення цієї проблеми використовувати теги. А саме, після передачі пакета введіть

$ git tag -f останній_пакет HEAD

і створюйте оновлені пакети за допомогою

$ git bundle create новий_пакет HEAD ^останній_пакет

Патчі: загальне застосування

Патчі — це тексти змін, цілком зрозумілі як для людини, так і комп’ютера. Це робить їх дуже привабливим форматом обміну. Патч можна послати розробникам по електронній пошті, незалежно від того, яку систему управління версіями вони використовують. Вашим кореспондентам достатньо можливості читати електронну пошту, щоб побачити ваші зміни. Точно так само, з Вашого боку потрібна лише адреса електронної пошти: немає потреби в налаштуванні онлайн сховища Git.

Пригадаємо з першого розділу:

$ git diff 1b6d

виводить патч, який може бути вставлений в лист для обговорення. У Git сховищі введіть

$ git apply < мій.patch

для застосування патча.

У більш формальних випадках, коли потрібно зберегти ім’я автора та підписи, створюйте відповідні патчі з заданої точки, набравши

$ git format-patch 1b6d

Отримані файли можуть бути відправлені за допомогою git-send-email або вручну. Ви також можете вказати діапазон коммітів:

$ git format-patch 1b6d..HEAD^^

На приймаючій стороні збережіть лист в файл і введіть:

$ git am < email.txt

Це застосує вхідні виправлення і створить комміт, що включає ім’я автора та іншу інформацію.

З web-інтерфейсом до електронної пошти вам, можливо, буде потрібно натиснути кнопку, щоб подивитися електронну пошту в своєму початковому вигляді перед збереженням патча в файл.

Для клієнтів електронної пошти, що використовують mbox, є невеликі відмінності, але якщо ви використовуєте один з них, то ви, очевидно, можете легко розібратися в цьому без читання описів!

Приносимо вибачення, ми переїхали

Після клонування сховища команди git push або git pull автоматично відправляють і отримують його за початковою адресою. Яким чином Git це робить? Секрет полягає в налаштуваннях, заданих при створенні клона. Давайте поглянемо:

$ git config --list

Опція remote.origin.url задає вихідний адресу; «origin» — ім'я початкового сховища. Як і ім'я гілки «master», це домовленість. Ми можемо змінити або видалити це скорочене ім'я, але як правило, немає причин для цього.

Якщо оригінальне сховище переїхало, можна оновити його адресу командою

$ git config remote.origin.url git://новий.url/proj.git

Опція branch.master.merge задає віддалену гілку за замовчуванням для git pull. В ході початкового клонування вона встановлюється на поточну гілку джерельного сховища, так що навіть якщо HEAD джерельного сховища згодом переміститься на іншу гілку, pull буде вірно слідувати початковій гілці.

Цей параметр звертається тільки до сховища, яке ми спочатку клонували і яке записано в параметрі branch.master.remote. При виконанні pull з інших сховищ ми повинні вказати потрібну гілку:

$ git pull git://приклад.com/other.git master

Це пояснює, чому деякі з наших попередніх прикладів push і pull не мали аргументів.

Віддалені гілки

При клонуванні сховища ви також клонуєте всі його гілки. Ви можете не помітити цього, тому що Git приховує їх: ви повинні запитати їх явно. Це запобігає протиріччю між гілками у віддаленому сховищі і вашими гілками, а також робить Git простішим для початківців.

Список віддалених гілок можна подивитися командою

$ git branch -r

Ви повинні побачити щось подібне

origin/HEAD
origin/master
origin/experimental

Ці імена відповідають гілкам і „голові“ у віддаленому сховищі; їх можна використовувати в звичайних командах Git. Наприклад, ви зробили багато коммітів, і хотіли б порівняти поточний стан з останньою завантаженою версією. Ви можете шукати в журналах потрібний SHA1 хеш, але набагато легше набрати

$ git diff origin/HEAD

Також можна побачити, для чого була створена гілка «experimental»:

$ git log origin/experimental

Кілька віддалених сховищ

Припустимо, що над нашим проектом працюють ще два розробники і ми хочемо стежити за обома. Ми можемо спостерігати більш ніж за одним сховищем одночасно, ось так:

$ git remote add other git://приклад.com/деяке_сховище.git
$ git pull other деяка_гілка

Зараз ми зробили злиття з гілкою з другого сховища. Тепер у нас є легкий доступ до всіх гілок у всіх сховищах:

$ git diff origin/experimental^ other/деяка_гілка~5

Але що якщо ми просто хочемо порівняти їх зміни, не зачіпаючи свою роботу? Іншими словами, ми хочемо вивчити чужі гілки, не даючи їх змінам вторгатися в наш робочий каталог. Тоді замість pull наберіть

$ git fetch # Перенести із origin, типово.
$ git fetch other # Перенести від другого програміста.

Так ми лише переносимо їх історію. Хоча робочий каталог залишається недоторканими, ми можемо звернутися до будь-якої гілки в будь-якому сховищі команди, працюючої з Git, оскільки тепер у нас є локальна копія.

Пригадаємо, що pull це просто fetch, а потім merge. Зазвичай ми використовуємо pull, тому що ми хочемо влити до себе останній комміт після отримання чужої гілки. Описана ситуація — помітний виняток.

Про те, як відключити віддалені сховища, ігнорувати окремі гілки і багато іншого дивіться у git help remote.

Мої вподобання

Я віддаю перевагу тому, щоб люди, що приєднуються до моїх проектів, створювали сховища, з яких я зможу отримувати зміни за допомогою pull. Деякі хостинги Git дозволяють створювати власні розгалуження (форки) проекту в один дотик.

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

Хоча зі мною мало співпрацюють, я вірю, що цей підхід добре масштабується. Дивіться цей запис в блозі Лінуса Торвальдса.

Залишатися в світі Git трохи зручніше, ніж використовувати файли патчів, оскільки це позбавляє мене від перетворення їх в комміти Git. Крім того, Git керує деталями на зразок збереження імені автора та адреси електронної пошти, а також дати і часу, і просить авторів описувати свої зміни.