Пересмотрев свою вводную статью о том, как работать с Git я осознал, что разобрался в нём уже лучше. Предыдущая статья включала в себя информацию о том, как начать работать с Git используя контроль версий только на локальном компьютере, в этой же статье я опишу основные случаи, с которыми приходится иметь дело в реальных проектах и уже в работе с удаленным гит сервером. Что значит «запулится», «пушнуться», «стешнуть» или создать ветку на удалённом репозитории? Со всем этим вы сможете ознакомиться, изучив материал текущей статьи. Естественно, вы можете прочитать обо всём этом более детально в чудо-книге ProGit о которой я упоминал ранее, но информации там настолько много, и расписана она настолько детально, что можно смело говорить о её переизбытке как для начинающего профи, у которого нету времени на пустое «прогиточтение»!
Представим реальный процесс разработки программы в команде. Первым делом админы или же кто-либо другой (например, вы) должны создать Git репозиторий на сервере. Акцентировать внимание на создании такого репозитория я умышлено не буду. Информации об этом в доступной форме в просторах Интернета можно найти очень много. Для примера, был создан репозиторий на GitHub ([email protected]:P1119r1m/HowToDoItExample.git). Считаем этот момент запуском командной работы над проектом. Ниже, представлены возможные случаи по работе с удалённым репозиторием.
Генерирование закрытого и открытого ssh ключей
[email protected] ~ $ ssh-keygen -t rsa -C "[email protected]" 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» и набрать в ней следующее:
[email protected] ~ $ git clone [email protected]: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) .
После всего этого можно смело клонировать проект.
[email protected] ~ $ git clone [email protected]: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«)!
[email protected] ~ $ cd HowToDoItExample/
Добавляем файл в «стейджинг» зону. Добавить файл в «стейджинг» зону значит сказать гиту, что данный файл будет изменен (или же добавлен, удален) и мы хотим в будущем закомитить все локальные изменения этого файла и возможно, отправить полученный комит на сервер.
[email protected] ~/HowToDoItExample (master)$ git add main.c
Перед комитом смотрим, что нового мы сделали с репозиторием:
[email protected] ~/HowToDoItExample (master) $ git status On branch master Initial commit Changes to be committed: (use "git rm --cached ..." to unstage) new file: main.c
Как видим, он показывает, что мы «сидим» на мастере и нами добавлен один новый файл, но пока его не закомитили. Так давайте же закомитим его:
[email protected] ~/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
На этом месте стоит объяснить. Только что мы сделали комит, но сделали мы его на локальной машине. На сервер данный комит мы пока не передали. Другими словами, внешний мир не знает о том, что мы сделали комит. Так давайте же передадим (запушим) на сервер наш(и) локальный(е) комит(ы):
[email protected] ~/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 [email protected]:P1119r1m/HowToDoItExample.git * [new branch] master -> master
Данной командой мы передали наш локальный бранч с названием «master» в удалённый репозиторий, тот самый, откуда создавали (его название «origin») наш локальный.
Обновление локального репозитория с удалённого
Предположим, прошло много времени и на сервер, кто-то кроме нас «запушил» свои (чужые для нас) изменения. Наш локальный слепок гита ни сном, ни духом об этом ничего не знает. Мы же хотим знать, что творится на удалённом сервере гита. Для этого нам нужно обновить локальную версию гита у себя на компьютере, т. е. «запулится»:
[email protected] ~/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. Тут, мы захотели обновить свой локальный репозиторий до самой новой версии и набрали:
[email protected] ~/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 с локальными изменениями будет перезаписан файлом с удалённого репозитория. Сразу же после этого следует рекомендация гита: «»Закомитьте» ваши изменения или же сделайте «стеш»». Стеш сохранение — это сохранение всех локальных изменений в специальное, если вам будет удобно, магическое место с которого позже можно будет забрать локальные изменения обратно. Текущее состояние репозитория сбросится в то состояние, в котором оно находилось на момент предыдущего обновления. Стоит заметить, что стеш — это своеобразно правильная замена старому-доброму обезьяньему методу копипаста рабочей директории. Так давайте же «застешимся»!
[email protected] ~/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
В каком состоянии мы сейчас находимся, любезно уведомляет гит. Вот такой он любезный!
Не забываем, что мы хотим сделать! Мы хотим закачать последнюю версию с удалённого репозитория. Опять пытаемся «запулится» (обновиться):
[email protected] ~/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(+)
Ну вот! Всё прошло успешно! Мы имеем самую свежую версию. Но что делать с нашими без вести «пропавшими» локальными изменениями? Их можно «накатить» поверх существующей локальной версии репозитория вытянув их из «стеша»:
[email protected] ~/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
Сохраняем файл и передобавляем файл в стейджинг зону. Таким образом, мы укажем гиту о том, что конфликт разрешён.
[email protected] ~/HowToDoItExample (master)$ git add dummy.txt
После этого можно смело «комитится» и «пушиться».
[email protected] ~/HowToDoItExample (master) $ git commit -m "Our local stashed changes commited" [master 019fd1b] Our local stashed changes commited 1 file changed, 1 insertion(+), 1 deletion(-) [email protected] ~/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 [email protected]:P1119r1m/HowToDoItExample.git 47f3acd..019fd1b master -> master
Работа с бранчами
Бранч, в переводе — ветвление, удобен, когда мы хотим реализовать дополнительный, отдельный функционал. Для его создания набираем:
[email protected] ~/HowToDoItExample (master) $ git branch "new_feature"
Этим, была создана новая ветка с именем «new_feature«. Посмотреть перечень всех локальных бранчей можно, набрав:
[email protected] ~/HowToDoItExample (master) $ git branch * master new_feature
Мы видим, что у нас имеется в наличии 2 бранча и сейчас мы «сидим» на мастере (тот, на котором «сидим» отмечен знаком «*»). Чтобы переключится на любой из доступных бранчей достаточно набрать:
[email protected] ~/HowToDoItExample (master) $ git checkout new_feature Switched to branch 'new_feature'
Давайте реализуем новую фичу в этой ветке. Для этого я добавлю в файл main.c новую функцию, сохраню файл, обновлю индексы в стейджинг зоне, и закомичу изменения в эту (пока локальную ветку):
[email protected] ~/HowToDoItExample (new_feature) $ git add --update [email protected] ~/HowToDoItExample (new_feature) $ git commit -m "New feature implemented" [new_feature c90bb89] New feature implemented 1 file changed, 5 insertions(+)
Отправка локально созданного бранча на удалённый сервер
Возможно, нам будет нужно отправить локальный бранч на удалённый сервер, дабы другие пользователи принимали участие в разработке новой фичи или же просто подсматривали за процессом разработки (ведь люди так любят подсматривать). Это сделать совсем нетрудно:
[email protected] ~/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 [email protected]:P1119r1m/HowToDoItExample.git * [new branch] new_feature -> new_feature
Вот так просто мы добавили на сервер наш локальный бранч.
Слияние бранчей (интеграция или же мерджинг)
Допустим, мы завершили работу над разработкою суперфичи и теперь её нужно интегрировать в главную ветку, в master. Для этого существует отдельная команда. Переключимся на ветку мастера:
[email protected] ~/HowToDoItExample (new_feature) $ git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'.
Осуществим саму процедуру слияния:
[email protected] ~/HowToDoItExample (master) $ git merge master new_feature Updating 019fd1b..c90bb89 Fast-forward main.c | 5 +++++ 1 file changed, 5 insertions(+)
Все сделанное выполнено локально, теперь эти изменения можно отправить на удалённый сервер:
[email protected] ~/HowToDoItExample (master) $ git push Enter passphrase for key '/c/Users/root/.ssh/id_rsa': Total 0 (delta 0), reused 0 (delta 0) To [email protected]:P1119r1m/HowToDoItExample.git 019fd1b..c90bb89 master -> master
Просмотр истории ветки
Не будет лишним упомянуть о такой важной функции как просмотр истории ветки. Сразу уточню, что пока мы локально изменяем историю, её в тот же самый час может менять и кто-то другой и тот «кто-то другой» может запулится на удалённый сервер. Получается, что история для нашего локального бранча будет отличаться от той, которая «висит» на удалённом сервере. Проверить локальную историю можно, набрав:
[email protected] ~/HowToDoItExample (master) $ git log commit c90bb89f9f44d248936444391f9c2bfc04e1aeb8 Author: PiligrimDate: Wed Dec 31 15:52:55 2014 +0200 New feature implemented commit 019fd1b773fcbcac9c7108e58b7a45715834f5b2 Author: Piligrim Date: Sun Dec 28 22:36:09 2014 +0200 Our local stashed changes commited commit 47f3acd10eab0c7f33f2d11d41ade3273f9b3357 Author: Piligrim Date: Sun Dec 28 22:02:54 2014 +0200 dummy.txt, line 2, remote git server change ...
Просмотреть историю на удалённом сервере можно так:
[email protected] ~/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
Date: Wed Dec 31 16:22:10 2014 +0200 Other guy commit into remote server commit c90bb89f9f44d248936444391f9c2bfc04e1aeb8 Author: Piligrim Date: Wed Dec 31 15:52:55 2014 +0200 New feature implemented commit 019fd1b773fcbcac9c7108e58b7a45715834f5b2 Author: Piligrim Date: Sun Dec 28 22:36:09 2014 +0200 Our local stashed changes commited ...
Просмотр статуса ветки
Ну а это, наверное, самая часто используемая функция, с которой приходится работать. Перед комитом, после «удачных» выходных, после обеда и в прочих подобных случаях всегда хочется посмотреть, в каком состоянии находится локальная копия репозитория гита. Для этого то и существует следующая команда:
[email protected] ~/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«, например:
[email protected] ~/HowToDoItExample (master) $ git add --help Launching default browser to display HTML ...