Часть 1 из 3
Введение
Я подготовил этот документ для коллег, с кем работаю в команде. На нашем предприятии мы разрабатываем некоторые веб-приложении и я в качестве стандарта пытаюсь внедрить распределенную систему контроля версий Git. Для некоторых людей в нашей группе Git является нововведением. Эта статья адресована для них. В статье нет и не будет информации по установке.
Репозиторий - это место, где хранятся и поддерживаются какие-либо данные. Чаще всего данные в репозитории хранятся в виде файлов, доступных для дальнейшего распространения по сети
Что такое Git
Вкратце: Git это система контроля версий, которая хранит все изменения сделанные с документом. В любое время можно посмотреть что было сделано с документом и вернуться к предыдущей версии (коммиту). Для проекта это своего рода "машина времени".
Git имеет гораздо больше возможностей, чем просто хранить изменения и переключаться между версиями.
Статьи в википедии:
Git - что такое Git
GitHub - что такое GitHub
Настоятельно рекомендую руководство git howto: GitHowTo
GitShop - магазин с сувенирами GitHub, на котором я заказал себе кружку с октокотиком:
Первые шаги
Работа с Git в основном начинается двумя способами:
- Создается новый проект и репозиторий
- Проект и репозиторий уже существует и мы хотим включиться в разработку
Рассмотрим оба варианта подробнее.
1. Мы создаем новый проект
Когда вы начинаете проект, необходимо инициализировать репозиторий.
Создаем директорию в которой мы будем работать.
$ mkdir ~/my-project
$ cd ~/my-project
Инициализируем репозиторий Git.
$ git init
В рабочей директории появилась новая скрытая папка ~/my-project/.git
Эта папка содержит всю информацию, с изменениями в рабочей директории. Никогда не нужно редактировать в этой директории ничего вручную. Если удалить эту директорию, то информация об истории изменений в проекте будет потеряна.
Теперь добавим файлы к проекту и начем работу над проектом.
Создадим 2 файла:
$ touch main_app.py
$ touch sub_routines.py
Вместе с созданием файлов, изменилось состояние репозитория. Если сейчас проверить состояние репозитория, мы увидим, что есть файлы невключенные в репозиторий:
$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# main_app.py
# sub_routines.py
nothing added to commit but untracked files present (use "git add" to track)
#
В проекте содержится два документа, но они не включены в коммит, поэтому история их изменений не ведется. Нужно их добавить в репозиторий.
$ git add main_app.py
$ git add sub_routines.py
Теперь они добавлены. Если много файлов, то можно их все добавить одной командой:
$ git add -A
Проверим статус репозитория:
$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached <file>..." to unstage)
#
new file: main_app.py
new file: sub_routines.py
#
Теперь файлы добавлены, но не закоммичены. Проверьте все ли необходимые файлы были добавлены. На этом этапе есть возможность удалить файлы из коммита git rm [somefile]
Закоммитим все файлы.
$ git commit -m 'Initial commit. I am adding here main_app.py which is the main code of the app, and it will call some sub routines from the sub_routin.py file. This last file is still empty'
Помните, необходимо написать в комментарии, что было сделано в этом коммите. Теперь когда мы сделали коммит, можно посмотреть статус репозитория:
$ git status
# On branch master
nothing to commit (working directory clean)
2. Проект уже существует
Git - это распределенноя система контроля версий. Ключевое слово распределенный. Это значит что на локальных компьютерах создаются полноценные копии центрального репозитория. Если вы клонируюете репозиторий проекта себе на компьютер, то вы можете работать с ним без необходимости подключаться к главному репозиторию. Кроме случая когда необходимо поделиться изменениями.
Клонируем репозиторий проекта в другую папку second-project
.
$ mkdir ~/second-project
$ cd ~/second-project/
$ git clone ../my-project/
Cloning into 'my-project'...
done.
Checking connectivity... done
$ cd ~/second-project/my-project/
Выведем список файлой в этой директории:
$ ls -a
. .. .git main_app.py sub_routines.py
Репозиторий успешно клонировался.
Другие примеры
Так же можно клонировать репозиторий с другого диска на локальном компьютере или удаленном используя различные протоколы, например:
git clone git://server.com/my-project.git
git clone /shared/network/project.git
git clone ssh://user@server.com:2240/repository/my-projects.git my-project
В данном случае мы подключаемся по протоколу ssh к нестандартному порту 2240 с правами пользователя user к репозиторию в директории repository/my-projects.git и копируем его в директорию my-project.
Сейчас вы можете работать с проектом, и передавать локальные изменения
в "центральный" репозиторий my-project
.
$ nano README.txt
Добавим в проект файл README.txt и посмотрим статус
git status
You will see this:
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
README.txt
nothing added to commit but untracked files present (use "git add" to track)
Необходимо добавить созданный файл к репозиторию и закоммитить его.
$ git add README.txt
$ git commit -m 'added a README file with description of the app, and instruction for installation'
Как-то да! Вы начали работу с Git.
Заключение
Вы знаете, как:
- Создать репозиторий
- Добавлять файлы к репозиторию
- Коммитить изменения
- Клонировать репозиторий
- Работать с удаленными репозиториями
Часть 2 из 3
В предыдущей части мы создали репозиторий в папке ~/my-project/
, и клонировали его в эту папку ~/second-project/
, таким образом вторая директория проекта: ~/second-project/my-project
. Во второй директори мы создали файл README.txt, добавили к репозиторию и закоммитили.
Перейдем в директорию с проектом.
$ cd ~/my-project/
Посмотрим лог изменений:
$ git log
Вывод на экране такой:
commit a6787b87ee36050f58014caa916bf85801771d34
Author: Sinyawskiy Alex - HOME_PC- <sinyawskiy@localhost>
Date: Mon May 13 15:28:37 2013 -0400
My first commit. I am adding here main_app.py which is the main code of the app, and it will call some sub routines from the sub_routine.py file. This last file is still empty
Если мы перейдем во вторую директорию.
$ cd ../second-project/my-project/
Посмотрим лог изменений:
$ git log
Вывод на экране такой:
commit b355a28868f5ac19b6ee949e110d0575dd5ed2dc
Author: Sinyawskiy Alex - HOME_PC- <sinyawskiy@localhost>
Date: Mon May 13 15:45:07 2013 -0400
added a README file with description of the app, and instruction for installation
commit a6787b87ee36050f58014caa916bf85801771d34
Author: Sinyawskiy Alex - HOME_PC- <sinyawskiy@localhost>
Date: Mon May 13 15:28:37 2013 -0400
My first commit. I am adding here main_app.py which is the main code of the app, and it will call some sub routines from the sub_routine.py file. This last file is still empty
Можно отметить, что второй репозиторий содержит на 1 коммит больше. Если вы хотите передать изменения во второй репозиторий, то необходимо выполнить комманду git push
. Но вначале рассмотрим bare репозитории.
Bare репозитории
origin - название центрального репозитория по-умолчанию
Представим, что два разработчика работают над одним проектом, один работает над проектом в папке ~/my-project/
, а второй ~/second-project/my-project/
. Нам необходим некий центральный элемент, в котором никто не работает. Для этого придуманы bare репозитории. bare репозитории не содержат рабочего дерева каталогов, рабочих файлов и состоят только из папки .git
.
Другими словами: В наших двух репозиториях рабочие каталоги содержат рабочие каталоги и папки .git
. bare репозитории содержат только папки .git
без рабочего дерева каталогов.
Создадим bare рерозиторий.
$ mkdir -p ~/tmp/my-project.git
$ cd ~/tmp/my-project.git
$ git init --bare
Теперь у нас есть bare репозиторий. Переходим во второй проект.
$ cd ~/second-project/my-project/
$ git remote rm origin
$ git remote add origin ~/tmp/my-project.git
Важно! На практике, естественно, эти репозитории будут созданы на разных хостах.
Мы удалили origin перед тем как добавить новый origin. У проекта в каталоге ~/second-project/
был установлен origin, потому что мы его клонировали. Можно было пропустить шаг удаления и просто добавить новый удаленный репозиторий, но я считаю что "центральный" репозиторий должен называться origin, поэтому мы его удалили и создали новый с таким же именем.
Проверим удаленный репозиторий:
$ git remote -v
Вывод на экране такой:
origin /Users/asinyawskiy/tmp/my-project.git (fetch)
origin /Users/asinyawskiy/tmp/my-project.git (push)
Мы можем теперь передать все изменения в "центральный" репозиторий:
$ git push origin master
Вывод на экране такой:
Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (7/7), 739 bytes, done.
Total 7 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (7/7), done.
To /Users/asinyawskiy/tmp/my-project.git
* [new branch] master -> master
Предположим, что первому разработчику потребовалось скачать изменения в свой каталог. Переходим в первый каталог
$ cd ~/my-project/
Нам необходимо добавить origin и скачать изменения.
$ git remote add origin ~/tmp/my-project.git
Не нужно удалять ничего потому, что это не клонированный репозиторий, в котором origin был не определен.
Получим изменения.
$ git pull origin master
Вывод на экране такой:
From /Users/asinyawskiy/tmp/my-project
* branch master -> FETCH_HEAD
Updating a6787b8..b355a28
Fast-forward
README.txt | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 README.txt
Мы видим, что скачался файл RADME.txt с двумя вставками. Теперь обе папки синхронизированы с "центральным" репозиторием.
Заключение
Вы знаете, как:
- Создавать bare репозитории
- Удалять и добавлять remotes
- Push отправлять коммиты на удаленный репозиторий
- Pull получать изменеия с удаленного репозитория
- Работать с ветками (branches)
Часть 3 из 3
Одна из самых мощных и полезных функций Git - это ветки (branches).
Ветка - это дополнительное пространство изменений, которое не пересекается с другими ветками. Например вы редактируете важный конфигурационный файл http.conf
. Вы хотите сделать несколько изменений, но что если будет ошибка и нужно будет вернуть изначальную версию. Обычно перед редактированием создается резервная копия cp http.conf http.conf.original
, которую можно восстановить. Git для этого использует ветки branches, если так можно сказать.
По умолчанию вы работаете в ветке master, и вы можете создать сколь угодно большое количество веток для локального тестирования перед смешиванием с веткой master.
Для примера, первый разработчик (Алексей) создал ветку testing и дал доступ к этой ветке другим разработчикам через "центральный репозиторий".
$ cd ~/my-project/
$ git checkout -b testing
Вывод на экране такой:
Switched to a new branch 'testing'
git создал новую ветку и переключился на нее. Внесем правки в файл sub_routing нашего приложения.
$ nano sub_routines.py
После сделанных изменений проверим статус
git status
Вывод на экране такой:
# On branch testing
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
modified: sub_routines.py
#
no changes added to commit (use "git add" and/or "git commit -a")
Теперь закоммитим эти изменения. Можно использовать git commit -a -m 'description'
с ключом -a, чтобы сразу добавить файлы с изменениями.
$ git add -A
$ git commit -m 'changes in main sub-routine, just for testing purposes. Debugging is hardly recommended before send it to production'
или тоже самое в одну строчку:
$ git commit -a -m 'changes in main sub-routine, just for testing purposes. Debugging is hardly recommended before send it to production'
Теперь мы можем посмотреть статус обоих веток (master и testing).
$ git branch -v
Вывод на экране такой:
master b355a28 added a README file with description of the app, and instruction for installation
* testing bf211b2 changes in main sub-routine, just for testing purposes. Debugging is hardly recommended before send it to production
As you can see, we are working on testing see the asterisk, and you can also see, that testing is ahead. Now the chief, wants to share his change with the other developer for him to debug.
Звездочкой отмечена текущая рабочая ветка.
$ git push origin testing
Отправим изменения этой ветки в "центральный" репозиторий. Вывод на экране такой:
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 429 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /Users/asinyawskiy/tmp/my-project.git
* [new branch] testing -> testing
Теперь второй разработчик может получить изменения и работать с ними:
$ cd ~/second-project/my-project/
$ git checkout -b testing
$ git pull origin testing
Вывод на экране такой:
From /Users/asinyawskiy/tmp/my-project
* branch testing -> FETCH_HEAD
Updating b355a28..bf211b2
Fast-forward
sub_routines.py | 8 ++++++++
1 file changed, 8 insertions(+)
Проверим статус:
$ git branch -v
Вывод на экране такой:
master b355a28 added a README file with description of the app, and instruction for installation
* testing bf211b2 changes in main sub-routine, just for testing purposes. Debugging is hardly recommended before send it to production
Второй разработчик может работать с изменениями.
$ nano sub_routines.py
$ git add sub_routines.py
$ git commit -m 'all tested, and corrected, ready for production'
$ git push origin testing
На другой стороне тим лид разработчиков делает копию, проводит финальное тестирование и мержит(объединяет) ветку testing в ветку master(production).
$ cd ~/my-project/
$ git checkout testing
$ git pull origin testing
После всех тестов, он ее мержит выполняя команду git merge
Объединение веток в Git
Тим лид хочет сейчас объединить ветку testing и master.
Посмотрим статус веток:
git branch -v
Вывод на экране такой:
master b355a28 added a README file with description of the app, and instruction for installation
* testing 0b38a32 all tested, and corrected, ready for production
Master is way behind testing. Switch to master
Переходим в ветку мастер
git checkout master
и выполняем объединение веток
git merge testing
Вывод на экране такой:
Updating b355a28..0b38a32
Fast-forward
sub_routines.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
Важно! Можно создать сколько угодно веток на локальном компьютере и работать с ними, но не передавать их, так как это может привести к неразберихе.
Для удаления ветки из origin используется следующая команда:
$ git push origin :testing
Наименование ветки testing использовалось для примера. После двоеточия нужно указать имя ветки, которую нужно удалить. Убедитесь что в этой ветке больше никто не работает.
Заключение
Вы знаете, как:
- Создавать ветки (branches)
- Переключаться между ветками
- Сохранять и получать ветки
- Объединять ветки (merge)
Вывод
Git предоставляет больше возможностей, чем нужно для простых проектов.
Работая с коллегами программистами, уважайте их труд, помните несколько простых правил:
- Для каждой новой фичи в проекте создавайте отдельную ветку.
- В коммитах пишите комментарии, что было сделано.
- Попросите тим лида сделать код ревью.
- Прежде чем выложить код, заберите код с сервера и объедините свою ветку с главной веткой, разрешите все конфликты.
- Протеститруйте на локальном компьютере.
- Только после этих операций выкладывайте код.
Зачистка каталожной структуры после обучения
$ cd ~
$ rm my-project/ second-project/ tmp/my-project.git -R
Если у вас есть комментарии, вопросы или дополнения по этой теме, то пишите.