Изучаем Python. Программирование игр, визуализация данных, веб-приложения

Мэтиз Эрик

Приложение Г. Git и контроль версий

 

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

Благодаря программам контроля версий программист может работать над усовершенствованием и совершать ошибки, не опасаясь нарушить работоспособность проекта. Это особенно важно в больших проектах, но также может быть полезно и в меньших проектах — даже для программ, содержащихся в одном файле.

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

 

Установка Git

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

 

Установка Git в Linux

Чтобы установить Git в Linux, введите следующую команду:

$ sudo apt-get install git

Все, теперь вы можете использовать Git в своих проектах.

 

Установка Git в OS X

Возможно, программа Git уже установлена в вашей системе; попробуйте ввести команду git --version. Если в выводе будет указан конкретный номер версии, Git устанавливается в вашей системе. Если в сообщении будет предложено установить или обновить Git, просто выполните инструкции на экране.

Также есть другой способ: зайдите на сайт https://git-scm.com/, перейдите по ссылке Downloads и выберите подходящую программу установки для вашей системы.

 

Установка Git в Windows

Вы можете установить Git в системе Windows с сайта http://msysgit.github.io/.

 

Настройка Git

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

$ git config --global user.name "имя_пользователя"

$ git config --global user.email "[email protected]"

Если вы забудете это сделать, Git запросит информацию при первом закреплении.

 

Создание проекта

Для начала создадим проект для работы. Создайте в системе папку с именем git_practice. В этой папке разместите файл с простой программой Python:

hello_world.py

print("Hello Git world!")

Эта программа поможет нам изучить базовую функциональность Git.

 

Игнорирование файлов

Файлы с расширением .pyc автоматически строятся на основе файлов .py, и отслеживать их в Git не нужно. Эти файлы хранятся в каталоге с именем __pycache__. Чтобы приказать Git игнорировать этот каталог, создайте специальный файл с именем .gitignore (с точкой в начале имени и без расширения) и включите в него следующую строку:

.gitignore

__pycache__/

В результате Git будет игнорировать любые файлы, находящиеся в каталоге __pycache__. Файл .gitignore избавляет проект от излишнего «балласта» и упрощает работу с ним.

примечание

Если вы используете Python 2.7, замените эту строку на *.pyc. Python 2.7 не создает каталог __pycache__; каждый файл .pyc хранится в одном каталоге с соответствующим файлом .py. Звездочка (*) приказывает Git игнорировать все файлы с расширением .pyc.

Возможно, для открытия файла .gitignore вам придется изменить настройки своего текстового редактора, чтобы в нем отображались скрытые файлы. Некоторые редакторы настроены на игнорирование имен файлов, начинающихся с точки.

 

Инициализация репозитория

Теперь, когда у вас имеется каталог с файлом Python и файлом .gitignore, можно переходить к инициализации репозитория Git. Откройте терминал, перейдите в каталог git_practice и выполните следующую команду:

git_practice$ git init

Initialized empty Git repository in git_practice/.git/

git_practice$

Из выходных данных видно, что Git инициализирует пустой репозиторий в каталоге git_practice. Репозиторий представляет собой набор файлов программы, который активно отслеживается системой Git. Все файлы, используемые Git для управления репозиторием, хранятся в скрытом каталоге .git/, с которым вам вообще не придется работать. Просто не удаляйте этот каталог, иначе вся история проекта будет потеряна.

 

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

Прежде чем делать что-либо, проверьте статус проекта:

git_practice$ git status

(1) # On branch master

#

# Initial commit

#

(2)# Untracked files:

# (use "git add ..." to include in what will be committed)

#

# .gitignore

# hello_world.py

#

(3)nothing added to commit but untracked files present (use "git add" to track)

git_practice$

В Git ветвью (branch) называется версия проекта, над которым вы работаете; из ­вывода видно, что текущей является ветвь с именем master (1) . Каждый раз, когда вы проверяете статус своего проекта, программа должна сообщать, что текущей является ветвь master. После этого мы видим, что система готова к исходному закреплению. Закреплением (commit) называется «моментальный снимок» проекта на определенный момент времени.

Git сообщает, что в проекте имеются неотслеживаемые файлы (2), потому что мы еще не сообщили Git, какие файлы должны отслеживаться. Затем мы узнаем, что в текущее закрепление еще ничего не добавлено, но существуют неотслеживаемые файлы, которые следует добавить в репозиторий (3).

 

Добавление файлов в репозиторий

Добавим в репозиторий два файла и снова проверим статус:

(1) git_practice$ git add .

(2)git_practice$ git status

# On branch master

#

# Initial commit

#

# Changes to be committed:

# (use "git rm --cached ..." to unstage)

#

(3)# new file: .gitignore

# new file: hello_world.py

#

git_practice$

Команда git добавляет в репозиторий все файлы проекта, которые еще не отслеживаются (1) . Закрепление при этом не выполняется; команда просто сообщает Git, что эти файлы нужно отслеживать. При проверке статуса проекта мы видим, что Git находит изменения, которые необходимо закрепить (2). Метка new file означает, что эти файлы были только что добавлены в репозиторий (3).

 

Закрепление

Выполним первое закрепление:

(1) git_practice$ git commit -m "Started project."

(2)[master (root-commit) c03d2a3] Started project.

(3) 2 files changed, 1 insertion(+)

create mode 100644 .gitignore

create mode 100644 hello_world.py

(4)git_practice$ git status

# On branch master

nothing to commit, working directory clean

git_practice$

Команда git commit -m "сообщение" (1) создает «моментальный снимок» состояния проекта. Флаг -m приказывает Git сохранить следующее сообщение ("Started project.") в журнале проекта. Из вывода следует, что текущей является ветвь master (2), а в проекте изменились два файла (3).

Проверка статуса показывает, что текущей является ветвь master, а рабочий каталог чист (4). Это сообщение должно выводиться каждый раз, когда вы закрепляете рабочее состояние своего проекта. Если вы получите другое сообщение, внимательно прочитайте его; скорее всего, вы забыли добавить файл после закрепления.

 

Просмотр журнала

Git ведет журнал всех закреплений, выполненных в проекте. Проверим содержимое журнала:

git_practice$ git log

commit a9d74d87f1aa3b8f5b2688cb586eac1a908cfc7f

Author: Eric Matthes

Date: Mon Mar 16 07:23:32 2015 -0800

. .Started project.

git_practice$

Каждый раз, когда вы выполняете закрепление, Git генерирует ­уникальный идентификатор из 40 символов. Сохраняется информация о том, кто выполнил изменение, когда оно было выполнено, а также передаваемое сообщение. Не вся эта информация вам понадобится, поэтому Git предоставляет возможность вывести упрощенный вариант записи журнала:

git_practice$ git log --pretty=oneline

a9d74d87f1aa3b8f5b2688cb586eac1a908cfc7f Started project.

git_practice$

Флаг --pretty=oneline выводит два важнейших атрибута: идентификатор закреп­ления и сохраненное для этого закрепления сообщение.

 

Второе закрепление

Чтобы увидеть всю мощь системы контроля версий, следует внести в проект ­изменение и закрепить его. Добавим еще одну строку в hello_world.py:

hello_world.py

print("Hello Git world!")

print("Hello everyone.")

Проверяя статус проекта, мы видим, что изменение в файле было замечено Git:

git_practice$ git status

(1) # On branch master

# Changes not staged for commit:

# (use "git add ..." to update what will be committed)

# (use "git checkout -- ..." to discard changes in working directory)

#

(2)# modified: hello_world.py

#

(3)no changes added to commit (use "git add" and/or "git commit -a")

git_practice$

В результатах указывается текущая ветвь (1) , имя измененного файла (2), а также то, что изменения не были закреплены (3). Закрепим изменения и снова проверим статус:

(1)

git_practice$ git commit -am "Extended greeting."

[master 08d4d5e] Extended greeting.

1 file changed, 1 insertion(+)

(2)git_practice$ git status

# On branch master

nothing to commit, working directory clean

(3)git_practice$ git log --pretty=oneline

08d4d5e39cb906f6cff197bd48e9ab32203d7ed6 Extended greeting.

be017b7f06d390261dbc64ff593be6803fd2e3a1 Started project.

git_practice$

Команда git commit с флагом -am выполняет новое закрепление. Флаг -a приказывает Git добавить все измененные файлы в репозитории в текущее закрепление. (Если вы создали новые файлы между закреплениями, просто снова выполните команду git add., чтобы включить новые файлы в репозиторий.) Флаг -m приказывает Git сохранить сообщение в журнале.

При проверке статуса проекта рабочий каталог снова оказывается чистым (2). Наконец, в журнале хранится информация о двух закреплениях (3).

 

Отмена изменений

А теперь посмотрим, как отменить изменение и вернуться к предыдущему работоспособному состоянию. Сначала добавьте в файл hello_world.py новую строку:

hello_world.py

print("Hello Git world!")

print("Hello everyone.")

print("Oh no, I broke the project!")

Сохраните и запустите этот файл.

Из информации статуса видно, что Git видит изменения:

git_practice$ git status

# On branch master

# Changes not staged for commit:

# (use "git add ..." to update what will be committed)

# (use "git checkout -- ..." to discard changes in working directory)

#

(1) # modified: hello_world.py

#

no changes added to commit (use "git add" and/or "git commit -a")

git_practice$

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

git_practice$ git checkout .

git_practice$ git status

# On branch master

nothing to commit, working directory clean

git_practice$

Команда git checkout позволяет работать с любым предшествующим закрепле­нием. Команда git checkout . отменяет все изменения, внесенные с момента последнего закрепления, и восстанавливает проект в последнем закрепленном состоянии.

Вернувшись в текстовый редактор, вы увидите, что файл hello_world.py вернулся к следующему состоянию:

print("Hello Git world!")

print("Hello everyone.")

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

примечание

Щелкните в окне редактора, чтобы обновить файл и увидеть предыдущую версию.

 

Извлечение предыдущих закреплений

Git позволяет извлечь из журнала любое закрепление, не только последнее. Для этого в команде вместо точки указываются первые 6 символов идентифи­катора. Выполняя извлечение, вы можете просмотреть более раннее закрепление и либо вернуться к своему последнему закреплению, либо отказаться от всей ­последней работы и продолжить разработку с более раннего закрепления:

git_practice$ git log --pretty=oneline

08d4d5e39cb906f6cff197bd48e9ab32203d7ed6 Extended greeting.

be017b7f06d390261dbc64ff593be6803fd2e3a1 Started project.

git_practice$ git checkout be017b

Note: checking out 'be017b'.

(1) You are in 'detached HEAD' state. You can look around, make experimental

changes and commit them, and you can discard any commits you make in this

state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may

do so (now or later) by using -b with the checkout command again. Example:

git checkout -b new_branch_name

HEAD is now at be017b7... Started project.

git_practice$

При извлечении предыдущего закрепления вы покидаете ветвь master и входите в состояние, которое Git называет отсоединенным состоянием HEAD (1) . HEAD — текущее состояние проекта; «отсоединенным» оно называется потому, что мы покинули именованную ветвь (master в данном случае).

Чтобы вернуться к ветви master, извлеките ее:

git_practice$ git checkout master

Previous HEAD position was be017b7... Started project.

Switched to branch 'master'

git_practice$

Вы снова возвращаетесь к ветви master. Не вносите изменения в проект при извлечении старого закрепления, если не хотите использовать использовать расширенные возможности Git. Но вы можете вернуться к предыдущему состоянию, если над проектом больше никто не работает. Работая в ­ветви master, введите следующую команду:

(1) git_practice$ git status

# On branch master

nothing to commit, working directory clean

(2)git_practice$ git log --pretty=oneline

08d4d5e39cb906f6cff197bd48e9ab32203d7ed6 Extended greeting.

be017b7f06d390261dbc64ff593be6803fd2e3a1 Started project.

(3)git_practice$ git reset --hard be017b

HEAD is now at be017b7 Started project.

(4)git_practice$ git status

# On branch master

nothing to commit, working directory clean

(5)git_practice$ git log --pretty=oneline

be017b7f06d390261dbc64ff593be6803fd2e3a1 Started project.

git_practice$

Сначала мы проверяем статус и убеждаемся в том, что текущей является ветвь master (1) . В журнале присутствуют оба закрепления (2). Затем выдается команда git reset --hard с первыми шестью символами идентификатора того закрепления, к которому нужно вернуться (3). Далее повторная проверка статуса показывает, что мы находимся в главной ветви, а закреплять нечего (4). Повторное обращение к журналу показывает, что проект находится в том состоянии, к которому мы решили вернуться (5).

 

Удаление репозитория

Случается, что история репозитория нарушается и вы не знаете, как ее восста­новить. Если это произойдет, для начала обратитесь за помощью методами, ­описанными в приложении В. Если исправить ошибку не удалось, а вы работаете над проектом в одиночку, продолжайте работать с файлами, но сотрите историю проекта, удалив каталог .git. Это не повлияет на текущее состояние файлов, но приведет к удалению всех закреплений, так что вы потеряете возможность извлекать другие состояния проекта.

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

(1) git_practice$ git status

# On branch master

nothing to commit, working directory clean

(2)git_practice$ rm -rf .git

(3)git_practice$ git status

fatal: Not a git repository (or any of the parent directories): .git

(4)git_practice$ git init

Initialized empty Git repository in git_practice/.git/

(5)git_practice$ git status

# On branch master

#

# Initial commit

#

# Untracked files:

# (use "git add ..." to include in what will be committed)

#

# .gitignore

# hello_world.py

#

nothing added to commit but untracked files present (use "git add" to track)

? git_practice$ git add .

git_practice$ git commit -m "Starting over."

[master (root-commit) 05f5e01] Starting over.

2 files changed, 2 insertions(+)

create mode 100644 .gitignore

create mode 100644 hello_world.py

? git_practice$ git status

# On branch master

nothing to commit, working directory clean

git_practice$

Сначала мы проверяем статус и видим, что рабочий каталог чист (1) . Затем команда rm -rf .git (rmdir /s .git в Windows) удаляет каталог .git (2). При проверке статуса после удаления каталога .git выдается сообщение об отсутствии репозитория Git (3). Вся информация, используемая Git для отслеживания репозитория, хранится в каталоге .git, поэтому его удаление приводит к уничтожению всего репозитория.

Тогда мы можем использовать команду git init для создания нового репозитория (4). Проверка статуса показывает, что все вернулось к исходному состоянию, ожидая первого закрепления (5). Мы добавляем файлы и выполняем первое закрепление ?. Теперь проверка статуса показывает, что проект находится в новой ветви master, а закреплять пока нечего ?.

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