Базове використання Git

Напевне кожен з нас стикався з ситуацією, коли втративши якісь дані, ми задумуємося: а чому я не зробив резервну копію ? Ми ж, звичайно, вчимося на своїх помилках, і починаємо робити резервні копії. Тоді випливють інші проблеми: резервних копій стає велика куча, ми не знаємо яка коли і для чого була створена; ми зробили резервну копію давно, і деякі зміни нам потрібно залишити, а деякі відкинути; проект складаєтья не з одного єдиного файлу, вручну за цим всім слідкувати стає ой як складно. Це сумно. Знову вчимося на своїх помилках: починаємо використовувати системи контролю версій.

Система контролю версіями - це програмний комплекс, який веде історію всіх змін в файлі/файлах, дає можливість вернутися до попередніх версій, об`єднувати зміни зроблені одночасно кількома програмістами і т.д. Сказано дуже лаконічно, правда.

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

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

Децентралізовані системи контролю версій

Це коли кожен з програмістів має на своєму комп`ютері повну копію робочого проекта (а з ним і всю історію змін), і може обмінюватися з іншими програмістами напряму. Звичайно, ніхто не забороняє влаштувати на загально-доступному сервері основну копію проекту, але це не є обов`язковим. Головним плюсом такої системи є непотрібність використовувати мережу для роботи (крім обміну, звичайно). Це схематично можна показати так:

Git

Git є децентралізованою системою контролю версій, створеною Лінусом Торвальдсом (творець ОС Лінукс) для управління розробкою ядра Лінукс. Система доволі молода, була представлена лише в 2005 році. Цим топіком я хочу навчити базовому використанню цієї системи.
Я користуюсь ОС Лінукс, тому в прикладах використовую команди сумісні з bash. Хоча більша частина їх повинна працювати і в інших системах.
Для початку встановимо git. В Лінуксі це робиться доволі просто:
// у Red Hat-подібних системах
$ yum install git-core

// у Debian-подібних
# apt-get install git-core

// у Debian-подібних, якщо користувач root заблокований
$ sudo apt-get install git-core
Для win-користувачів раджу заглянути сюди.

Після встановлення бажано трошки настроїти git, а саме прописати ім'я/нік, електронну адресу, і зробити деякі косметичні настройки. Варто згадати про особливість конфігураційних файлів git. Є системий конфігураційний файл, який використовується для всіх, це /etc/gitconfig. Також в кожного користувача є свій конфігураційний файл - ~/.gitconfig, настройки з якого перекривають системні. І в кожного проекту є свій конфігураційний файл .git/config, який перекриває настройки користувача. Зміни в ці файли вносяться наступним чином:
// вносимо зміни в системний файл
$ git config --system var.name "value"
// вносимо зміни в файл користувача
$ git config --global var.name "value"
// вносимо зміни в файл конкретного проекту
$ git config var.name "value"
Не забувайте використовувати клавiшу <Tab> при наборі команд, git встановлює свій скрипт автодоповнення, тому <Tab> вам дуже допоможе.
І так, конфугуруємо нашу систему контролю версій:
// вказуємо своє і`мя
$ git config --global user.name "slik"
// вказуємо свою поштову скриньку
$ git config --global user.email "slik.jay@gmail.com"
// вказуємо редактор, який git буде запускати для редугавання повідомлень або конфліктів
# git config --system core.editor mcedit
// а це потрібно щоб при виводі повідомлень в консоль git їх розфарбовував трошки, так зручніше читати :)
# git config --system color.status "auto"
# git config --system color.branch "auto"
# git config --system color.interactive "auto"
# git config --system color.diff "auto"
Дивимось чи збереглись наші настройки:
$ git config --list
Для тих хто не розуміє для чого перед командами знаки $ і # поясню: $ означає що команда виконується від звичайного користувача, а # означає, що команда виконується від імені root`а, себто адміністратора
Щоб створити новий репозиторій (проект) достатньо створити папку, в якій він буде розміщений, і виконати команду:
$ git init
У мене це виглядає так:
slik@slik-laptop:~$ cd /shared/www/
slik@slik-laptop:/shared/www$ mkdir test
slik@slik-laptop:/shared/www$ cd test
slik@slik-laptop:/shared/www/test$ git init
Initialized empty Git repository in /shared/www/test/.git/
Як бачимо, створилася прихована папка .git, в ній знаходяться всі потрібні для роботи git файли. Попробуємо створити файл і додати його до репозиторію:
// створюємо файл test.txt і записуємо в нього текст test
$ echo "test" > test.txt
// додаємо файл test.txt до stage
$ git add test.txt
// фіксуємо зміни в локальному репозиторії
$ git commit -m "initial commit"
Що таке stage ? Робота з файлами в git відбувається в 3 етапи:
  • checkout - це стадія "без змін", тільки що зафіксований або створений репозиторій знаходиться на цій стадії, змін поки що не відбувалося
  • stage - це стадія "зі змінами", ми можемо проводити любі зміни, але повинні додавати потрібні нам файли до цієйї стадії, інакше при наступній фіксації зміни не зафуксуються
  • commit - стадія фіксації змін
Щоб всі змінені файли не додавати до стадії stage (трошки смішно виглядає, так як stage само по собі перекладається як стадія) вручну, можна використовувати при фіксаціі ключ -а:
$ git commit -a -m "initial commit"
Звісно ж нам знадобиться можливість робити копії вже існуючих проектів. В git це називається клонуванням, і виконується з допомогою відповідної команди:
$ git clone address folder
Де address - адреса/шлях до клонованого репозиторія. Git вміє використовувати в роботі багато протоколів (git, http, ssh і т.д.), а також для клонування можна використати свій проект, який лежить в сусідній папці, потрібно просто вказати шлях до його папки .git.
folder - це назва папки, яку git створить при потребі, і в яку клонує проект, якщо не вказати folder, то створиться папка з назвою проекту.

В любий момент ми можемо провірити статус нашого проекта. Це потрібно для того щоб побачити, які файли було змінено/додано/видалено, які занесено до stage, а які ще ні. Якщо ми зараз виконаємо команду git status то побачимо такий результат:
slik@slik-laptop:/shared/www/test$ git status
# On branch master
nothing to commit (working directory clean)
Що значить, що ми ще нічого не змінювали. Попробуємо змінити наш файл test.txt
$ echo "test changed" > test.txt
// І подивимось статус проекта
slik@slik-laptop:/shared/www/test$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#       modified:   test.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
Як бачите, git помітив зміни в файлі, і повідомляє нам про це. Тепер додамо файл до stage
slik@slik-laptop:/shared/www/test$ git add test.txt
slik@slik-laptop:/shared/www/test$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   test.txt
#
Статус змінився. А тепер попробуємо змінити файл вже після того як він був занесений до stage, але до того, як зміни було зафіксовані (до commit), і подивимось на статус
slik@slik-laptop:/shared/www/test$ echo "test changed twice" > test.txt
slik@slik-laptop:/shared/www/test$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   test.txt
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#       modified:   test.txt
#
Файл test.txt одночасно і занесений і незанесений до stage. Як це так ? Це означає що існує попередня копія файлу test.txt (з текстом "test changed"), яка і буде зафіксована при наступному комміті, а от теперішній test.txt (з текстом "test changed twice") git просто проігнорує, якщо ви не додасьте його до stage.

Git дозволяє подивитися зміни, які ми внесли, з допомогою утиліти diff
slik@slik-laptop:/shared/www/test$ git diff
diff --git a/test.txt b/test.txt
index 66968d8..987b98e 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1 @@
-test changed
+test changed twice
Якщо ви будете використовувати комміти з автододаванням файлів (git commit -a), то вам варто знати про такий прихований файл як .gitignore, в якому записані правила ігнорування при додаванні. Його потрібно створити в корені проекту. Правила записувати дуже просто:
  • # це коментар, який ігнорується, пусті лінії також ігноруються
  • *.[ао] # всі файли в яких назва закінчується на .а і .о (С++ програмісти знають про що тут :) )
  • !lib.a # вийняток з вийнятків :) хоч в попередньому правилі lib.a виключається, так можна заставити git знову звертати уваги на lib.a
  • /Docs # все що знаходиться в /Docs (але не в subdir/Docs)
  • build/ # всі папки build (навіть ті що в підпаках)
  • *~ # всі тимчасові файли (в лінуксі тимчасові чи бекапні файли закінчуються на ~)
  • /assets/*.txt # думаю ви вже зроміли
Якщо ви не вкажете -m при комміті, git за вас згенерує повідомлення (по суті git status) і відкриє вказаний вами в настройках редактор, щоб ви підредактували його. Воно збережеться в файлі .git/COMMIT_EDITMSG, і буде використане при комміті.

Буває потрібно видалити файл. Якщо ви його видалите системною командою rm, то git замітить пропажу, але все одно запропонує видалити його з допомогою git rm. Якщо ви не скористаєтеся git rm, то цей файл, хоч і видалений, попаде в наступний комміт як існуючий. Те ж саме відноситься перенесення/перейменування
$ git rm filename
$ git mv filename new_filename
Всі комміти і ваші коментарі до них можна переглянути з допомогою git log
slik@slik-laptop:/shared/www/test$ git log
commit a227b8877284852c50043abbae5ca7cee5a1227b
Author: Slik <slik.jay@gmail.com>
Date:   Mon Oct 26 18:35:50 2009 +0200

        modified:   test.txt

commit ff6f054998cafffbbdf4d8aa5b4d33ff7aa1fbb0
Author: Slik <slik.jay@gmail.com>
Date:   Mon Oct 26 18:00:38 2009 +0200

    initial commit
Мітка комміту це 40-ка символьнa SHA-1 сума файлів, які ввійшли в нього. Одночасно вона є захистом від пошкоджень. Як бачимо, крім мітки також вписується автор, дата і коментар. Лог сортується в зворотньому порядку по даті додавання. Якщо ми шочемо подивитись леше останній коментар, ми можемо використати таку команду
// -1 - це кількість [-(n)] останніх повідомлень
$ git log -1
Лог підтримує багато параметрів, ось деякі з них:
// показувати не лише коментарі, але і зміни в форматі diff
$ git log -p
// тут також показуються зміни, але скорочено (кількість доданих/видалених рядків)
$ git log --stat
// --pretty може мати кілька значень: short, full, fuller, oneline, format, при чому з допомогою format можда задати свій формат виводу повідомлень, наприклад так, де %h - скорочений хеш, а %s - ваш коментар
$ git log --pretty=format:"%h %s"
// також є параметер --graph, який буде зручним, коли над проектом працює кілька програмістів
$ git log --pretty=format:"%h %s" --graph
// можна і відсіювати повідомлення з допомогою -(n) --since --after --until --before --author --commiter
$ git log --pretty=format:"%h %s" --author=slik --since="2009-10-26"
Бувають ситуації, коли після фіксування змін (комміту) ви згадуєте про те, що забули додати до stage якийсь файл. Звичайно, можна було б зробити ще один комміт, але git дозволяє вирішити цю проблему більш елегантним способом:
// робимо комміт
$ git commit -m "bla bla"
// згадали про файл, додаємо його
$ git add forgetten_file
// дописуємо попередній комміт, а не робимо новий
$ git commit --amend
Щоб виключити файл з stage, який, наприклад, був помилково доданий, можна скористатись командою
$ git reset HEAD filename
Щоб відмінити всі зміни зроблені в файлі починаючи з попереднього комміту достатньо скористатись такою командою
// між -- і filename стоїть пробіл
$ git checkout -- filename
Оскільки мій файрфокс вже жах як тормозить від кількості символів (я користуюсь транслітератором), то вимушений продовжити нашу розмову пізніше, в новому топіку. Чекайте розповідь про спільну (віддалену) розробку і інше.

коментарі:

slik 26.10.2009 17:40
Дайте підредагувати шапку :) а то картінко завелика..
+1tercius 26.10.2009 17:51
легко )
+2meako 26.10.2009 18:00
Добра стаття, базис який і так багато де описаний, але все ж корисно. Особливо для тих хто хоче познайомитися з гітом.

Ще рекомендую переглянути відео з Лінусом торвальдсом, де він розповідає про Гіт. Якраз недавно переклали.
+1slik 26.10.2009 18:08
Вносити зміни можна не швидше, ніж через 15 хвилин
%)

Так, матеріал є. Але на українській мові я не зустрічав.. Сам читаю англомовну документацію. Подумав що корисно би було на українській написати.
+3meako 26.10.2009 18:44
Тут народ трудиться над перекладом хорошої книги по Ґіт.

Я сам хочу долучитися, але блін руки не доходять.
slik 26.10.2009 19:26
Якраз читання цієї книги (на англійській) надихнуло мене на написання статті :) я нарешті дізнався ті речі, про які хотів знати, що довершило моє знання Гіт`а, і вирішив поділитись цим з іншими :)
+2slik 26.10.2009 18:10
До того ж, авторський матеріал для Енетрі піде тільки на користь :)
tercius 26.10.2009 18:27
кількість плюсів говоритиме сама за себе )

так тримати! )))
+1fedir.gontsa 26.10.2009 20:35
так, <b>git</b> чудова система контролю версій, але в своїй роботі мені більше до вподоби <b>bazzar</b> я його використовую: для локальних проектів (не web), для оновленні сайтів (web), для бекапів ...і для інших цікавих справ. Цим я не хочу розпалити "священну війну" просто кажу, що не git-ом єдиним.
Взагалі добре, що тут почали з'являтись цікаві статті. Успіхів автору!
slik 26.10.2009 20:46
Дякую :)
Enetri 29.10.2009 10:49
Перенесіть статтю у більш "професійну" секцію: програмування, системи контролю версій, *git, ...
slik 29.10.2009 11:32
переніс, хоча я і не зовсім згоден з тим що git обов'язково до програмування відноситься
tercius 24.03.2010 13:11
лінк з вікіпедії є, а обцяного продовження - йок (
а шкода, одна з найкращих (по-корисності) статей на енетрі..

буде?
+2slik 24.03.2010 13:31
Звичайно буде, я ж обіцяв. І по mootools обіцяв.. І по enetri API.. Проблема в тому що часу в обріз. Але постараюсь викроїти.. Може на вихідних...
+1slik 24.03.2010 13:37
А відносно лінку на цю строрінку з вікіпедії - приємно здивований :)

додати коментар: