Книга: Изучаем Python: программирование игр, визуализация данных, веб-приложения. 3-е изд. дополненное и переработанное
Назад: В. Помощь и поддержка
Дальше: Д. Устранение неполадок при развертывании

Г. Управление версиями с помощью Git

36435.png

 

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

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

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

Установка Git

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

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

Если на экране нет инструкций и вы пользуетесь операционной системой Windows или macOS, то можете скачать программу установки с сайта https://git-scm.com. Если вы пользователь apt-версии операционной системы Linux, то можете установить Git с помощью команды sudo apt install git.

Настройка Git

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

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

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

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

Кроме того, рекомендуется настроить имя по умолчанию для главной ветви каждого проекта. Подходящее имя для этой ветви — main:

$ git config --global init.defaultBranch main

Согласно этой конфигурации, каждый новый проект, для управления версиями которого используется Git, будет начинаться с единственной ветви фиксаций, названной main.

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

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

hello_git.py

print("Hello Git world!")

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

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

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

.gitignore

__pycache__/

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

Возможно, для открытия файла .gitignore вам придется изменить настройки своего файлового менеджера, чтобы в нем отображались скрытые файлы (имена которых начинаются с точки). В Проводнике установите флажок Hidden Items (Скрытые элементы) в меню View (Вид). В macOS нажмите сочетание клавиш +Shift+. (точка). В операционной системе Linux найдите настройку Show Hidden Files (Показать скрытые файлы).

примечание

Если вы используете macOS, то добавьте в .gitignore еще одну строку: имя .DS_Store. Это скрытые файлы, содержащие информацию о каждом каталоге в macOS, и они будут загромождать ваш проект, если вы не добавите их в .gitignore.

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

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

git_practice$ git init

Initialized empty Git repository in git_practice/.git/

git_practice$

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

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

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

git_practice$ git status

❶ On branch main

No commits yet

 

❷ Untracked files:

  (use "git add <file>..." to include in what will be committed)

      .gitignore

      hello_git.py

 

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

git_practice$

В Git ветвью (branch) называется версия проекта, над которым вы работаете; из вывода видно, что текущей является ветвь main . Каждый раз, когда вы проверяете статус своего проекта, программа должна сообщать имя текущей ветви. После этого мы видим, что система готова к начальной фиксации. Фиксацией (commit) называется снимок состояния проекта на определенный момент времени.

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

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

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

❶ git_practice$ git add .

git_practice$ git status

On branch main

No commits yet

 

Changes to be committed:

  (use "git rm --cached <file>..." to unstage)

      new file:   .gitignore

      new file:   hello_git.py

 

git_practice$

Команда git add . добавляет в репозиторий все файлы проекта, которые еще не отслеживаются , если они не внесены в список файла .gitignore. Фиксация при этом не выполняется; команда просто сообщает Git, что на эти файлы нужно обратить внимание. При проверке статуса проекта мы видим, что Git находит изменения, которые необходимо зафиксировать . Метка new file означает, что эти файлы были только что добавлены в репозиторий .

Фиксация изменений

Выполним первую фиксацию:

❶ git_practice$ git commit -m "Started project."

[main (root-commit) cea13dd] Started project.

2 files changed, 5 insertions(+)

  create mode 100644 .gitignore

  create mode 100644 hello_git.py

git_practice$ git status

On branch main

nothing to commit, working tree clean

git_practice$

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

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

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

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

git_practice$ git log

commit cea13ddc51b885d05a410201a54faf20e0d2e246 (HEAD -> main)

Author: eric <[email protected]>

Date:   Mon Jun 6 19:37:26 2022 -0800

 

    Started project.

git_practice$

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

git_practice$ git log --pretty=oneline

cea13ddc51b885d05a410201a54faf20e0d2e246 (HEAD -> main) Started project.

git_practice$

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

Последующая фиксация

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

hello_git.py

print("Hello Git world!")

print("Hello everyone.")

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

git_practice$ git status

❶ On branch main

Changes not staged for commit:

  (use "git add <file>..." to update what will be committed)

  (use "git restore <file>..." to discard changes in working directory)

 

modified:   hello_git.py

 

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

git_practice$

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

❶ git_practice$ git commit -am "Extended greeting."

[main 945fa13] Extended greeting.

1 file changed, 1 insertion(+), 1 deletion(-)

git_practice$ git status

On branch main

nothing to commit, working tree clean

git_practice$ git log --pretty=oneline

945fa13af128a266d0114eebb7a3276f7d58ecd2 (HEAD -> main) Extended greeting.

cea13ddc51b885d05a410201a54faf20e0d2e246 Started project.

git_practice$

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

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

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

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

hello_git.py

print("Hello Git world!")

print("Hello everyone.")

 

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

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

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

git_practice$ git status

On branch main

Changes not staged for commit:

  (use "git add <file>..." to update what will be committed)

  (use "git restore <file>..." to discard changes in working directory)

 

❶     modified:   hello_git.py

 

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

git_practice$

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

git_practice$ git restore .

git_practice$ git status

On branch main

nothing to commit, working tree clean

git_practice$

Команда git restore имя_файла позволяет откатить все изменения с момента последней фиксации в определенном файле. Команда git restore . откатывает все изменения, сделанные во всех файлах с момента последней фиксации; это действие восстанавливает проект до состояния последней фиксации.

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

print("Hello Git world!")

print("Hello everyone.")

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

ПРИМЕЧАНИЕ

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

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

Вы можете вернуться к любой фиксации в журнале с помощью команды checkout, указав первые шесть символов идентификатора ссылки. После проверки и просмотра предыдущей фиксации вы можете вернуться к последней фиксации или отказаться от внесенных изменений и продолжить разработку с предыдущей фиксации:

git_practice$ git log --pretty=oneline

945fa13af128a266d0114eebb7a3276f7d58ecd2 (HEAD -> main) Extended greeting.

cea13ddc51b885d05a410201a54faf20e0d2e246 Started project.

git_practice$ git checkout cea13d

Note: switching to 'cea13d'.

 

❶ 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 switching back to a branch.

 

If you want to create a new branch to retain commits you create, you may do so (now or later) by using -c with the switch command.

Example:

 

  git switch -c <new-branch-name>

 

Or undo this operation with:

 

  git switch -

 

Turn off this advice by setting config variable advice.detachedHead to false

 

HEAD is now at cea13d Started project.

git_practice$

При извлечении предыдущей фиксации вы покидаете ветвь main и входите в состояние, которое Git называет отсоединенным состоянием HEAD (detached HEAD) . HEAD — текущее состояние проекта; отсоединенным оно называется потому, что мы покинули именованную ветвь (main в данном случае).

Чтобы вернуться к ветви main, следуйте предложению , которое позволяет отменить предыдущую операцию:

git_practice$ git switch -

Previous HEAD position was cea13d Started project.

Switched to branch 'main'

git_practice$

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

❶ git_practice$ git status

On branch main

nothing to commit, working directory clean

git_practice$ git log --pretty=oneline

945fa13af128a266d0114eebb7a3276f7d58ecd2 (HEAD -> main) Extended greeting.

cea13ddc51b885d05a410201a54faf20e0d2e246 Started project.

git_practice$ git reset --hard cea13d

HEAD is now at cea13dd Started project.

git_practice$ git status

On branch main

nothing to commit, working directory clean

git_practice$ git log --pretty=oneline

cea13ddc51b885d05a410201a54faf20e0d2e246 (HEAD -> main) Started project.

git_practice$

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

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

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

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

❶ git_practice$ git status

On branch main

nothing to commit, working directory clean

git_practice$ rm -rf .git/

git_practice$ git status

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

git_practice$ git init

Initialized empty Git repository in git_practice/.git/

git_practice$ git status

On branch main

No commits yet

 

Untracked files:

  (use "git add <file>..." to include in what will be committed)

      .gitignore

      hello_git.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."

[main (root-commit) 14ed9db] Starting over.

2 files changed, 5 insertions(+)

create mode 100644 .gitignore

create mode 100644 hello_git.py

git_practice$ git status

On branch main

nothing to commit, working tree clean

git_practice$

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

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

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

Назад: В. Помощь и поддержка
Дальше: Д. Устранение неполадок при развертывании