Розділ 2. Базові операції

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

Збереження стану

Збираєтеся спробувати внести якісь радикальні зміни? Попередньо створіть знімок всіх файлів у поточному каталозі за допомогою команд

$ git init
$ git add .
$ git commit -m "Моя перша резервна копія"

Тепер, якщо нові правки все зіпсували, можна відновити початкову версію:

$ git reset --hard

Щоб зберегти стан знову:

$ git commit -a -m "Друга резервна копія"

Додавання, видалення, перейменування

Наведений вище приклад відстежує лише ті файли, які існували при першому запуску git add. Якщо ви створили нові файли або підкаталоги, доведеться сказати Git'у:

$ git add readme.txt Documentation

Аналогічно, якщо хочете, щоб Git забув про деякі файли:

$ git rm kludge.h obsolete.c
$ git rm -r incriminating/evidence/

Git видалить ці файли, якщо ви не видалили їх самі.

Перейменування файлу — це те ж саме, що й видалення старого імені та додавання нового. Для цього є git mv, яка має той же синтаксис, що і команда mv. Наприклад:

$ git mv bug.c feature.c

Розширені скасування/повернення

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

$ git log

покаже список останніх коммітів і їхні хеші SHA1:

commit 766f9881690d240ba334153047649b8b8f11c664
Author: Іван <ivan@example.com>
Date:   Tue Mar 14 01:59:26 2000 -0800

    Замінив printf() на write().

commit 82f5ea346a2e651544956a8653c0f58dc151275c
Author: Марічка <marichka@example.com>
Date:   Thu Jan 1 00:00:00 1970 +0000

    Початковий комміт.

Щоб вказати комміт, достатньо перших декількох символів його хешу, але можете скопіювати і весь хеш. Наберіть:

$ git reset --hard 766f

для відновлення стану до зазначеного комміта і видалення всіх наступних безповоротно.

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

$ git checkout 82f5

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

Ця альтернативна реальність називається «гілкою» (branch) і трохи пізніше ми поговоримо про це докладніше. А зараз просто запам'ятайте, що команда

$ git checkout master

поверне вас назад у теперішнє. Крім того, щоб не отримувати попереджень від Git, завжди робіть commit або скидайте зміни перед запуском checkout.

Ще раз скористаємося аналогією з комп'ютерними іграми:

  • git reset --hard: завантажує раніше збережену гру і видаляє всі версії, збережені після тількищо завантаженої.
  • git checkout: завантажує стару гру, але якщо ви продовжуєте грати, стан гри буде відрізнятися від більш нових збережень, які ви зробили в перший раз. Будь-яка гра, яку ви тепер зберігаєте, потрапляє в окрему гілку, що представляє альтернативну реальність, в яку ви потрапили. Ми обговоримо це пізніше.

Можна також відновити тільки певні файли і підкаталоги, перерахувавши їх імена після команди:

$ git checkout 82f5 якийсь.файл інший.файл

Будьте уважні: така форма checkout може мовчки перезаписати файли. Щоб уникнути неприємних несподіванок, виконуйте commit перед checkout, особливо якщо ви тільки вивчаєте Git. Взагалі, якщо ви не впевнені у якісь операції, чи то команда Git чи ні, виконайте попередньо git commit -a.

Не любите копіювати і вставляти хеші? Використовуйте

$ git checkout :/"Моя перша р"

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

Можна також запитати 5-й з кінця збережений стан:

$ git checkout master~5

Повернення

У залі суду пункти протоколу можуть викреслювати прямо під час слухання. Подібним чином і ви можете вибирати комміти для скасування.

$ git commit -a
$ git revert 1b6d

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

Створення списку змін

Деяким проектам потрібен спискок змін (changelog). Створіть його такою командою:

$ git log > ChangeLog

Завантаження файлів

Отримати копію проекту під управлінням Git можна, набравши

$ git clone git://сервер/шлях/до/файлів

Наприклад, щоб отримати всі файли, які я використав для створення цього документу,

$ git clone git://git.or.cz/gitmagic.git

Пізніше ми поговоримо про команду clone докладніше.

Тримаючи руку на пульсі

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

$ git pull

Невідкладна публікація

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

Щоб зробити це за допомогою Git, виконайте в каталозі, де лежить ваш скрипт,

$ git init
$ git add .
$ git commit -m "Перший реліз"

Потім скажіть вашим користувачам запустити

$ git clone ваш.комп’ютер:/шлях/до/скрипту

щоб завантажити ваш скрипт. Тут мається на увазі, що у них є доступ по ssh. Якщо ні, запустіть git daemon і скажіть користувачам запустити цю команду замість вищенаведеної:

$ git clone git://ваш.комп’ютер/шлях/до/скрипту

З цих пір щоразу, коли ваш скрипт готовий до релізу, виконуйте

$ git commit -a -m "Наступний реліз"

і ваші користувачі зможуть оновити свої версії, перейшовши в каталог з вашим скриптом і набравши

$ git pull

Ваші користувачі ніколи не наткнуться на версію скрипта, яку ви не хочете їм показувати.

Що я зробив?

З'ясуйте, які зміни ви зробили з часу останнього комміта:

$ git diff

Чи з вчорашнього дня:

$ git diff "@{yesterday}"

Чи між певною версією і версією, зробленою 2 комміти назад:

$ git diff 1b6d "master~2"

У кожному разі на виході буде патч, який може бути застосований за допомогою git apply. Спробуйте також:

$ git whatchanged --since="2 weeks ago"

Часто замість цього я використовую для перегляду історії qgit, через приємний інтерфейс, або tig з текстовим інтерфейсом, який добре працює через повільне з'єднання. Як варіант, встановіть веб-сервер, введіть git instaweb і запустіть будь-який веб-браузер.

Вправа

Нехай A, B, C, D — чотири послідовні комміти, де В відрізняється від A лише кількома видаленими файлами. Ми хочемо повернути ці файли в D. Як ми можемо це зробити?

Існує як мінімум три розв’язки. Припустимо, що ми знаходимося на D.

  1. Різниця між A і B — видалені файли. Ми можемо створити патч, що відображає ці зміни, і застосувати його:

    $ git diff B A | git apply
    
  2. Оскільки в комміті A ми зберегли файли, то можемо відновити їх:

    $ git checkout A foo.c bar.h
    
  3. Ми можемо розглядати перехід від A до B як зміни, які хочемо скасувати:

    $ git revert B
    

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