Пересмотрев свою вводную статью о том, как работать с Git я осознал, что разобрался в нём уже лучше. Предыдущая статья включала в себя информацию о том, как начать работать с Git используя контроль версий только на локальном компьютере, в этой же статье я опишу основные случаи, с которыми приходится иметь дело в реальных проектах и уже в работе с удаленным гит сервером. Что значит «запулится», «пушнуться», «стешнуть» или создать ветку на удалённом репозитории? Со всем этим вы сможете ознакомиться, изучив материал текущей статьи. Естественно, вы можете прочитать обо всём этом более детально в чудо-книге ProGit о которой я упоминал ранее, но информации там настолько много, и расписана она настолько детально, что можно смело говорить о её переизбытке как для начинающего профи, у которого нету времени на пустое «прогиточтение»!

Представим реальный процесс разработки программы в команде. Первым делом админы или же кто-либо другой (например, вы) должны создать Git репозиторий на сервере. Акцентировать внимание на создании такого репозитория я умышлено не буду. Информации об этом в доступной форме в просторах Интернета можно найти очень много. Для примера, был создан репозиторий на GitHub (git@github.com:P1119r1m/HowToDoItExample.git). Считаем этот момент запуском командной работы над проектом. Ниже, представлены возможные случаи по работе с удалённым репозиторием.

Генерирование закрытого и открытого ssh ключей

root@PILIGRIM ~
$ ssh-keygen -t rsa -C "e-mail@domain"
Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /c/Users/root/.ssh/id_rsa.
Your public key has been saved in /c/Users/root/.ssh/id_rsa.pub.
The key fingerprint is:

 Генерировать ключи необходимо для того, чтобы доступ сервером гита предоставлялся только авторизированным пользователям.

Закачка или же клонирование удалённого репозитория себе на компьютер

Для клонирования проекта достаточно открыть консоль «Git Bash» и набрать в ней следующее:

root@PILIGRIM ~
$ git clone git@github.com:P1119r1m/HowToDoItExample.git
Cloning into 'HowToDoItExample'...
Warning: Permanently added the RSA host key for IP address '192.30.252.131' to t
he list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

В результате, скорее всего у вас ничего не получится, потому что консоль потребует ввести пароль для доступа к серверу. Кроме всего этого сервер должен знать о вас, т. е. у него должен быть зарегистрирован ваш публичный .ssh ключ, который находится в директории «c:\Users\ПОЛЬЗОВАТЕЛЬ\.ssh\id_rsa.pub«. Проблема с клонированием (закачкой проекта себе на компьютер) исчезнет, если открытый ключ указать (записать) на сервер. Как это делать зависит от самого сервера. Как это сделать в ГитХабе показано тут (https://github.com/P1119r1m/HowToDoItExample/settings/keys -> Add a deploy key) .

После всего этого можно смело клонировать проект.

root@PILIGRIM ~
$ git clone git@github.com:P1119r1m/HowToDoItExample.git
Cloning into 'HowToDoItExample'...
Enter passphrase for key '/c/Users/root/.ssh/id_rsa':
warning: You appear to have cloned an empty repository.
Checking connectivity... done.

Поздравляю! Этим самым действием мы с вами скопировали удалённый репозиторий себе на машину.

Добавление нового файла на удалённый сервер

Для примера, создаём текстовый файл. Главное – делать это  внутри директории локального репозитория (в нашем случае это «C:\Users\root\HowToDoItExample\«, тут должна быть скрытая директория с именем «.git«)!

root@PILIGRIM ~
$ cd HowToDoItExample/

Добавляем файл в «стейджинг» зону. Добавить файл в «стейджинг» зону значит сказать гиту, что данный файл будет изменен (или же добавлен, удален) и мы хотим в будущем закомитить все локальные изменения этого файла и возможно, отправить полученный комит на сервер.

root@PILIGRIM ~/HowToDoItExample (master)
$ git add main.c

Перед комитом смотрим, что нового мы сделали с репозиторием:

root@PILIGRIM ~/HowToDoItExample (master)
$ git status
On branch master

Initial commit

Changes to be committed:
(use "git rm --cached ..." to unstage)

new file:   main.c

Как видим, он показывает, что мы «сидим» на мастере и нами добавлен один новый файл, но пока его не закомитили. Так давайте же закомитим его:

root@PILIGRIM ~/HowToDoItExample (master)
$ git commit -m "Added new file to the repository"
[master (root-commit) 528a180] Added new file to the repository
1 file changed, 4 insertions(+)
create mode 100644 main.c

На этом месте стоит объяснить. Только что мы сделали комит, но сделали мы его на локальной машине. На сервер данный комит мы пока не передали. Другими словами, внешний мир не знает о том, что мы сделали комит. Так давайте же передадим (запушим) на сервер наш(и) локальный(е) комит(ы):

root@PILIGRIM ~/HowToDoItExample (master)
$ git push origin master
Warning: Permanently added the RSA host key for IP address '192.30.252.128' to t
he list of known hosts.
Enter passphrase for key '/c/Users/root/.ssh/id_rsa':
Counting objects: 3, done.
Writing objects: 100% (3/3), 247 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:P1119r1m/HowToDoItExample.git
* [new branch]      master -> master

Данной командой мы передали наш локальный бранч с названием «master» в удалённый репозиторий, тот самый, откуда создавали (его название «origin») наш локальный.

Обновление локального репозитория с удалённого

Предположим, прошло много времени и на сервер, кто-то кроме нас «запушил» свои (чужые для нас) изменения. Наш локальный слепок гита ни сном, ни духом об этом ничего не знает. Мы же хотим знать, что творится на удалённом сервере гита. Для этого нам нужно обновить локальную версию гита у себя на компьютере, т. е. «запулится»:

root@PILIGRIM ~/HowToDoItExample (master)
$ git pull
Enter passphrase for key '/c/Users/root/.ssh/id_rsa':
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:P1119r1m/HowToDoItExample
528a180..aa4621f  master     -> origin/master
Updating 528a180..aa4621f
Fast-forward
dummy.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 dummy.txt

Конфликты и удобное стеш сохранение/извлечение

Ну, всё, теперь у нас самая новая версия репозитория (включая сделанные нами возможные локальные изменения). Замечу, что боятся насчет того, что данная команда напрочь перетрёт все наши незакомиченные локальные изменения не стоит. Гит настолько умный, что безболезненно «склеит» («смержит») локальные изменения с удалёнными. Может случится и так, что сделать ему это не удастся. Не настолько всё-таки он умный чтобы догадаться, что приоритетней строчка, написанная вами, или же хранящаяся на удалённом сервере. Дело идёт о конфликтных ситуациях. Что это такое и с чем его едят? Рассмотрим пример. Предположим, на удалённый сервер кто-то отправил изменённый во второй строчке файл dummy.txt. Мы, не зная этого, тоже сделали свои локальные изменения тоже во вторую строчку файла dummy.txt. Тут, мы захотели обновить свой локальный репозиторий до самой новой версии и набрали:

root@PILIGRIM ~/HowToDoItExample (master)
$ git pull
Enter passphrase for key '/c/Users/root/.ssh/id_rsa':
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:P1119r1m/HowToDoItExample
aa4621f..47f3acd  master     -> origin/master
Updating aa4621f..47f3acd
error: Your local changes to the following files would be overwritten by merge:
        dummy.txt
Please, commit your changes or stash them before you can merge.
Aborting

Как можно заметить, прошло всё не совсем гладко:(. Сообщение об ошибке всё объясняет. В нашем случае, файл dummy.txt с локальными изменениями будет перезаписан файлом с удалённого репозитория. Сразу же после этого следует рекомендация гита: «»Закомитьте» ваши изменения или же сделайте «стеш»». Стеш сохранение — это сохранение всех локальных изменений в специальное, если вам будет удобно, магическое место с которого позже можно будет забрать локальные изменения обратно. Текущее состояние репозитория сбросится в то состояние, в котором оно находилось на момент предыдущего обновления. Стоит заметить, что стеш — это своеобразно правильная замена старому-доброму обезьяньему методу копипаста рабочей директории. Так давайте же «застешимся»!

root@PILIGRIM ~/HowToDoItExample (master)
$ git stash
Saved working directory and index state WIP on master: aa4621f Added dummy file
with dummy content
HEAD is now at aa4621f Added dummy file with dummy content

В каком состоянии мы сейчас находимся, любезно уведомляет гит. Вот такой он любезный!

Не забываем, что мы хотим сделать! Мы хотим закачать последнюю версию с удалённого репозитория. Опять пытаемся «запулится» (обновиться):

root@PILIGRIM ~/HowToDoItExample (master)
$ git pull
Warning: Permanently added the RSA host key for IP address '192.30.252.129' to t
he list of known hosts.
Enter passphrase for key '/c/Users/root/.ssh/id_rsa':
Updating aa4621f..47f3acd
Fast-forward
dummy.txt | 1 +
1 file changed, 1 insertion(+)

Ну вот! Всё прошло успешно! Мы имеем самую свежую версию. Но что делать с нашими без вести «пропавшими» локальными изменениями? Их можно «накатить» поверх существующей локальной версии репозитория вытянув их из «стеша»:

root@PILIGRIM ~/HowToDoItExample (master)
$ git stash pop
Auto-merging dummy.txt
CONFLICT (content): Merge conflict in dummy.txt

Тут у нас возникли проблемы. Гит нам пишет о том, что в файле существуют конфликты. Это означает, что нам их необходимо решить. Можно себя почувствовать конфликт-менеджером. Для этого я обычно использую мой любимый TortoiseGit. Как решать конфликты — это отдельная и глубокая тема. Мы же с вами можем просто открыть конфликтный файл вручную и сделать его таким, каким он должен быть на наш взгляд. Содержимое конфликтного файла:

dummy
<<<<<<< Updated upstream
line from remote git repository
=======
Our local changes of line 2
>>>>>>> Stashed changes

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

dummy
Our local changes of line 2

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

root@PILIGRIM ~/HowToDoItExample (master)
$ git add dummy.txt

 После этого можно смело «комитится» и «пушиться».

root@PILIGRIM ~/HowToDoItExample (master)
$ git commit -m "Our local stashed changes commited"
[master 019fd1b] Our local stashed changes commited
1 file changed, 1 insertion(+), 1 deletion(-)
root@PILIGRIM ~/HowToDoItExample (master)
$ git push
Enter passphrase for key '/c/Users/root/.ssh/id_rsa':
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 317 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:P1119r1m/HowToDoItExample.git
   47f3acd..019fd1b  master -> master

Работа с бранчами

Бранч, в переводе — ветвление, удобен, когда мы хотим реализовать дополнительный, отдельный функционал. Для его создания набираем:

root@PILIGRIM ~/HowToDoItExample (master)
$ git branch "new_feature"

Этим, была создана новая ветка с именем «new_feature«. Посмотреть перечень всех локальных бранчей можно, набрав:

root@PILIGRIM ~/HowToDoItExample (master)
$ git branch
* master
  new_feature

Мы видим, что у нас имеется в наличии 2 бранча и сейчас мы «сидим» на мастере (тот, на котором «сидим» отмечен знаком «*»). Чтобы переключится на любой из доступных бранчей достаточно набрать:

root@PILIGRIM ~/HowToDoItExample (master)
$ git checkout new_feature
Switched to branch 'new_feature'

Давайте реализуем новую фичу в этой ветке. Для этого я добавлю в файл main.c новую функцию, сохраню файл, обновлю индексы в стейджинг зоне, и закомичу изменения в эту (пока локальную ветку):

root@PILIGRIM ~/HowToDoItExample (new_feature)
$ git add --update

root@PILIGRIM ~/HowToDoItExample (new_feature)
$ git commit -m "New feature implemented"
[new_feature c90bb89] New feature implemented
 1 file changed, 5 insertions(+)

Отправка локально созданного бранча на удалённый сервер

Возможно, нам будет нужно отправить локальный бранч на удалённый сервер, дабы другие пользователи принимали участие в разработке новой фичи или же просто подсматривали за процессом разработки (ведь люди так любят подсматривать). Это сделать совсем нетрудно:

root@PILIGRIM ~/HowToDoItExample (new_feature)
$ git push origin new_feature
Enter passphrase for key '/c/Users/root/.ssh/id_rsa':
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 336 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:P1119r1m/HowToDoItExample.git
 * [new branch]      new_feature -> new_feature

Вот так просто мы добавили на сервер наш локальный бранч.

Слияние бранчей (интеграция или же мерджинг)

Допустим, мы завершили работу над разработкою суперфичи и теперь её нужно интегрировать в главную ветку, в master. Для этого существует отдельная команда. Переключимся на ветку мастера:

root@PILIGRIM ~/HowToDoItExample (new_feature)
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

Осуществим саму процедуру слияния:

root@PILIGRIM ~/HowToDoItExample (master)
$ git merge master new_feature
Updating 019fd1b..c90bb89
Fast-forward
 main.c | 5 +++++
 1 file changed, 5 insertions(+)

Все сделанное выполнено локально, теперь эти изменения можно отправить на удалённый сервер:

root@PILIGRIM ~/HowToDoItExample (master)
$ git push
Enter passphrase for key '/c/Users/root/.ssh/id_rsa':
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:P1119r1m/HowToDoItExample.git
   019fd1b..c90bb89  master -> master

Просмотр истории ветки

Не будет лишним упомянуть о такой важной функции как просмотр истории ветки. Сразу уточню, что пока мы локально изменяем историю, её в тот же самый час может менять и кто-то другой и тот «кто-то другой» может запулится на удалённый сервер. Получается, что история для нашего локального бранча будет отличаться от той, которая «висит» на удалённом сервере. Проверить локальную историю можно, набрав:

root@PILIGRIM ~/HowToDoItExample (master)
$ git log
commit c90bb89f9f44d248936444391f9c2bfc04e1aeb8
Author: Piligrim <piligrim2007@meta.ua>
Date:   Wed Dec 31 15:52:55 2014 +0200

    New feature implemented

commit 019fd1b773fcbcac9c7108e58b7a45715834f5b2
Author: Piligrim <piligrim2007@meta.ua>
Date:   Sun Dec 28 22:36:09 2014 +0200

    Our local stashed changes commited

commit 47f3acd10eab0c7f33f2d11d41ade3273f9b3357
Author: Piligrim <piligrim2007@meta.ua>
Date:   Sun Dec 28 22:02:54 2014 +0200

    dummy.txt, line 2, remote git server change

...

Просмотреть историю на удалённом сервере можно так:

root@PILIGRIM ~/HowToDoItExample (master)
$ git fetch && git log origin/master
Enter passphrase for key '/c/Users/root/.ssh/id_rsa':
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:P1119r1m/HowToDoItExample
   c90bb89..f43868e  master     -> origin/master
commit f43868e7553d951581bbcd4db18a590605e409c4
Author: Piligrim <piligrim2007@meta.ua>
Date:   Wed Dec 31 16:22:10 2014 +0200

    Other guy commit into remote server

commit c90bb89f9f44d248936444391f9c2bfc04e1aeb8
Author: Piligrim <piligrim2007@meta.ua>
Date:   Wed Dec 31 15:52:55 2014 +0200

    New feature implemented

commit 019fd1b773fcbcac9c7108e58b7a45715834f5b2
Author: Piligrim <piligrim2007@meta.ua>
Date:   Sun Dec 28 22:36:09 2014 +0200

    Our local stashed changes commited

...

Просмотр статуса ветки

Ну а это, наверное, самая часто используемая функция, с которой приходится работать. Перед комитом, после «удачных» выходных, после обеда и в прочих подобных случаях всегда хочется посмотреть, в каком состоянии находится локальная копия репозитория гита. Для этого то и существует следующая команда:

root@PILIGRIM ~/HowToDoItExample (master)
$ git status
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)

nothing to commit, working directory clean

В данном случае гит уведомляет нас о том, что мы находимся на один комит ранее чем самый последний. Объясню. Мы закачали удалённый репозиторий вызвав git fetch. Эта команда выкачивает удалённый репозиторий нам на локальную машину, но кроме этого она не делает ровным счётом ничего. Я имею в виду, что эта команда не перетирает и не мержит изменения сделанные на удалённый репозиторий с изменениями, сделанными нами локально.

P.S.

Конечно, это далеко не полный перечень команд гита! Это тот базис, зная который можно хоть как то начать работу с ним. И ещё… По каждой из команд всегда можно посмотреть файл помощи, набрав после неё «—help«, например:

root@PILIGRIM ~/HowToDoItExample (master)
$ git add --help
Launching default browser to display HTML ...