Блог Синявского
  • Разделы
  • Метки
  • Все статьи

Записки про Git

1

Часть 1 из 3

Введение

Я подготовил этот документ для коллег, с кем работаю в команде. На нашем предприятии мы разрабатываем некоторые веб-приложении и я в качестве стандарта пытаюсь внедрить распределенную систему контроля версий Git. Для некоторых людей в нашей группе Git является нововведением. Эта статья адресована для них. В статье нет и не будет информации по установке.

Репозиторий - это место, где хранятся и поддерживаются какие-либо данные. Чаще всего данные в репозитории хранятся в виде файлов, доступных для дальнейшего распространения по сети

Что такое Git

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

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

Статьи в википедии:

Git - что такое Git

GitHub - что такое GitHub

Настоятельно рекомендую руководство git howto: GitHowTo

GitShop - магазин с сувенирами GitHub, на котором я заказал себе кружку с октокотиком:

Первые шаги

Работа с Git в основном начинается двумя способами:

  1. Создается новый проект и репозиторий
  2. Проект и репозиторий уже существует и мы хотим включиться в разработку

Рассмотрим оба варианта подробнее.

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.

Заключение

Вы знаете, как:

  1. Создать репозиторий
  2. Добавлять файлы к репозиторию
  3. Коммитить изменения
  4. Клонировать репозиторий
  5. Работать с удаленными репозиториями

Часть 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 с двумя вставками. Теперь обе папки синхронизированы с "центральным" репозиторием.

Заключение

Вы знаете, как:

  1. Создавать bare репозитории
  2. Удалять и добавлять remotes
  3. Push отправлять коммиты на удаленный репозиторий
  4. Pull получать изменеия с удаленного репозитория
  5. Работать с ветками (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 использовалось для примера. После двоеточия нужно указать имя ветки, которую нужно удалить. Убедитесь что в этой ветке больше никто не работает.

Заключение

Вы знаете, как:

  1. Создавать ветки (branches)
  2. Переключаться между ветками
  3. Сохранять и получать ветки
  4. Объединять ветки (merge)

Вывод

Git предоставляет больше возможностей, чем нужно для простых проектов.

Работая с коллегами программистами, уважайте их труд, помните несколько простых правил:

  1. Для каждой новой фичи в проекте создавайте отдельную ветку.
  2. В коммитах пишите комментарии, что было сделано.
  3. Попросите тим лида сделать код ревью.
  4. Прежде чем выложить код, заберите код с сервера и объедините свою ветку с главной веткой, разрешите все конфликты.
  5. Протеститруйте на локальном компьютере.
  6. Только после этих операций выкладывайте код.

Зачистка каталожной структуры после обучения

$ cd ~
$ rm my-project/ second-project/ tmp/my-project.git -R

Если у вас есть комментарии, вопросы или дополнения по этой теме, то пишите.



  • ← сюда
  • туда →

comments powered by Disqus

Опубликовано

07.07.2014

Обновление

05.05.2022

Категории

ubuntu

Тэги

  • bash 10
  • console 6
  • ubuntu 36

Всегда на связи

  • Блог Синявского - Ничего не переносить на завтра, это тоже проблема с прокастинацией?
  • © Алексей Синявский, по лицензии CC BY-SA если не указано иное.
  • С использованием Pelican. Тема: Elegant от Talha Mansoor