Система управления версиями Git. Система управления версиями git и российский сервис хранения исходного кода gitflic
Скачать 3.56 Mb.
|
2.11. Технология использования веток Работа над проектом разработки программного продукта может стро- иться по-разному. Как бы работа не строилась, предполагаем, что для сохра- нения истории создания кода используется Git. Самый простой вариант по- строения репозитория – это репозиторий с одной веткой. Как говорилось ранее, ветка – это последовательность коммитов. Репозиторий, содержащий одну ветку, изображён на рисунке 2.5. 51 Рисунок 2.5 – Репозиторий с одной веткой На рисунке показаны 5 коммитов главной ветки (ГВ) ГВ1, ГВ2, ГВ3, ГВ4, ГВ5. Коммиты ссылаются друг на друга в обратном хронологическом порядке. В файле HEAD находится имя файла из директории .git/refs/head, в котором записано хеш-значение последнего в ветке объекта «коммит». При таком построении репозитория, для управления состоянием рабо- чей директории, возможно выполнить следующие действия: 1. Переместить указатель HEAD на любой из коммитов. При таком перемещении Git автоматически восстановит в рабочей директории состоя- ние файлов, каким оно было на момент коммита, к которому переместился указатель HEAD. Указатель HEAD в любой момент можно вернуть к по- следнему коммиту, и Git восстановит соответствующее состояние рабочей директории. 2. Удалить часть коммитов, идущих подряд в обратном хронологи- ческом порядке. Git восстановит состояние рабочей директории, каким оно было до выполнения удалённых коммитов. 3. Посмотреть историю изменения файлов рабочей директории. 4. Сравнить версии файлов из различных коммитов. Репозиторий с одной веткой возникает крайне редко в ситуации, когда проект выполняет один программист. Среди программистов существует не- гласное правило, согласно которому в главную ветку помещается только проверенный код, не содержащий грубых ошибок. Именно грубых, так как ни один программист не будет утверждать, что в его коде нет ни одной ошибки. Тестирование кода перед размещением в главной ветке происходит в боковых ветках. На рисунке 2.6 показан репозиторий с боковой веткой, когда HEAD указывает на боковую ветку. На рисунке 2.7 показан репозито- рий с боковой веткой, когда HEAD указывает на главную ветку. 52 Рисунок 2.6 – Репозиторий с двумя ветками (HEAD указывает на боковую ветку) Рисунок 2.7 – Репозиторий с двумя ветками (HEAD указывает на главную ветку) В репозитории может быть неограниченное количество веток, однако стараются сохранять такое количество веток, при котором не теряется обозримость репозитория. При построении репозитория по схеме с несколь- кими ветками, для управления состоянием рабочей директории возможно выполнять все действия, которые доступны для репозитория с одной веткой, и в дополнение ряд других действий: 1. Переключение с одной ветки на другую. При этом Git обеспечивает состояние рабочей директории, соответствующее последнему коммиту ветки. 2. Сохранение состояния рабочей директории из одной ветки в ком- мите для другой ветки. Необходимость такого сохранения возникает, когда работа над кодом в боковой ветке завершена, и необходимо перенести ре- 53 зультат в главную ветку. При этом боковая ветка сохраняется, и в дальней- шем возможно продолжить вносить изменения в код этой ветки. 3. Слияние последних коммитов двух веток. Выполняется, когда окончательный результат складывается из двух коммитов. В этом случае продолжить работу с боковой веткой нельзя. 4. Удаление ветки. Когда задача решена или стало понятно, что был выбран ошибочный путь решения задачи, боковая ветка удаляется без вреда для остальных веток проекта. Проект, над которым работают несколько программистов, обяза- тельно содержит боковые ветки (их минимальное количество равно количе- ству программистов). Таким образом, технология использования веток включает следую- щие действия: 1. Создание ветки. 2. Удаление ветки. 3. Переключение между ветками. 4. Слияние веток. В следующих разделах будет подробно рассмотрено каждое из этих действий. 2.12. Создание ветки Для создания ветки используется команда git branch. Формат команды git branch: git branch <ключ> <имя ветки> Одно из возможных значений ключа: -m. При использовании команды git branch с ключом -m произойдёт переименование текущей ветки. Команду git branch можно использовать без ключа, в этом случае бу- дет выполнено создание новой ветки. При выполнении команды git branch без ключа происходят следую- щие действия: 1. В директории .git/refs/heads создаётся файл, имя которого совпа- дает с именем новой ветки, указанным в команде git branch. 2. В созданный файл записывается хеш-значение текущего коммита, 54 того, на который указывает HEAD через соответствующий файл в директо- рии .git/refs/heads. На рисунке 2.8 показана ситуация, которая возникнет при добавлении ветки New_branch в репозиторий, главная ветка которого называется Main_branch. Если продолжить делать коммиты, то они будут добавляться в главную ветку, после коммита ГВ3. Для добавления коммитов в новую ветку на неё необходимо переключиться. Для переключения между ветками предназначена команда git checkout. Формат команды git checkout: git checkout <ключ> <имя ветки> Рисунок 2.8 – Создание новой ветки Одним из возможных ключей является -b. Использование команды git checkout с ключом -b эквивалентно последовательности команд git branch и git checkout. Произойдёт создание новой ветки и переключение на неё. После выполнения команды git checkout в файл HEAD будет записано имя файла из директории .git/refs/heads, совпадающее с именем ветки, на которую произошло переключение. Если выполнить несколько коммитов, то ситуация будет выглядеть, как показано на рисунке 2.9. 55 Рисунок 2.9 – Добавление коммитов в новую ветку Для просмотра веток, существующих в репозитории, используется команда git branch с ключами -a или -r или без ключей. Использование ключа -a или команды git branch без ключей приведёт к выводу полного списка веток. Использование ключа -r приведёт к выводу списка веток из удалённого репозитория (об удалённых репоиториях речь пойдёт в одном из следующих разделов). Так выглядит список веток из примера: $ git branch -a * Main_branch New_branch Текущая ветка в списке отмечена звёздочкой. При переключении на другую ветку происходит не только изменение содержимого файла HEAD, но и изменение состояния рабочей директории. Проще всего представить себе перестройку рабочей директории следующим образом. Назовём последний коммит в текущей ветке «источником», а последний коммит в ветке, на которую происходит переход, «приёмником». Все файлы, имена которых присутствуют одновременно в «источнике» и «приёмнике», удаляются из рабочей директории. После этого в рабочую директорию записываются файлы, восстановленные из blob-объектов «приёмника». 56 При переходе между ветками нужно иметь в виду следующее: 1. Все изменения, сделанные в текущей рабочей директории в отслеживаемых файлах и не включённые в коммит, буду потеряны. 2. Все неотслеживаемые файлы перейдут в «приёмник». Эти особенности перехода между ветками могут стать источником серьёзных проблем. Для того чтобы избежать проблем, есть два пути: − сделать коммит перед переходом на другую ветку; − использовать команду stash того, чтобы «складировать» изменения во временном хранилище. 2.13. Команда git stash Если выполненные изменения рано добавлять в коммит, и есть необ- ходимость переключиться на другую ветку для выполнения срочной ра- боты, чтобы не потерять изменения, их можно «складировать». Для «складирования» изменений нужно выполнить команду: git stash save или git stash. git stash save позволяет добавить коммента- рий к «складируемым» файлам. При выполнении команды git stash происходит следующее: − создаётся резервный коммит; − резервный коммит сохраняется в изолированном хранилище, построенном по принципу стека; − состояние рабочей директории восстанавливается из последнего коммита текущей ветки. Для того чтобы добавить в резервный коммит неотслеживаемые файлы, необходимо использовать ключ -u (напимер, git stash save -u ‘Резервная копия 1’). Посмотреть, что хранится на «складе», можно с помощью команды: git stash list Пример выполнения команды git stash list: $ git stash list stash@{0}: On Main_branch: Склад для ветки Main_Branch stash@{1}: On New_Branch: Склад для ветки New_Branch 57 Каждый хранимый на «складе» временный коммит имеет номер stash@{число}. К временному коммиту можно обращаться либо с использова- нием правила стека («последний пришёл, первый ушёл), либо по номеру. При извлечении временного коммита со «склада» происходит восста- новление рабочей директории в соответствии с описанием, хранящимся в этом коммите. Команда: git stash apply извлекает со «склада» временный коммит с номером 0. Можно указать номер того коммита, который необходимо извлечь: git stash apply stash@{число} Команда git stash pop выполняет те же действия, что и git stash apply, и удаляет временный коммит со «склада». Без указания номера команда git stash pop будет применена к временному коммиту с номером 0. Команда git stash show показывает, какие изменения были сохранены во временном коммите c номером 0. $ git stash show File_1.txt | 3 ++ - 1 file changed, 2 insertions(+), 1 deletion(-) Детали изменения можно посмотреть при использовании ключа -p. $ git stash show -p diff --git a/File_1.txt b/File_1.txt index 1da2014..2fb2027 100644 --- a/File_1.txt +++ b/File_1.txt @@ -1 +1,2 @@ -This is first file we will use for tests. \ No newline at end of file +This is first file we will use for tests. +Changes for test stash. \ No newline at end of file Как и в других командах, относящихся к stash, можно указать номер временного коммита, который будет использован для просмотра изменений. Команда git stash branch <имя новой ветки> создаёт новую ветку с указанным именем и переносит в неё содержимое временного коммита. Без указания номера для создания ветки будет использован временный коммит с номером 0. Команда git stash drop удаляет временный коммит. Без указания но- мера будет удалён временный коммит с номером 0. 58 Команда git stash clear удаляет весь «склад». 2.14. Просмотр истории коммитов История коммитов бывает полезна в следующих ситуациях: − необходимо посмотреть историю коммитов, чтобы составить пред- ставление о том, как развивается проект; − необходимо выяснить, кто внёс те или иные изменения; − необходимо определить хеш-номер коммита, к которому нужно вернуться. Для просмотра истории коммитов используется команда git log. Формат команды git log: git log <ключи> --<путь> Возможные значения ключей: -<число> или -n<число> – выводит последние коммиты в количестве, заданном числом; --pretty = <значение> – значение задаёт формат вывода, может быть oneline, short, medium, full; -p – показывает изменения, сделанные в текущем коммите; --all – выводит историю всех коммитов для всех веток. Правило, которым руководствуется Git при выводе истории, гласит: «Переходить от одного предка к другому, пока они не закончатся». Рассмотрим для примера репозиторий, граф которого изображён на рисунке 2.10. 59 Рисунок 2.10 – Тестовый репозиторий Выполним для этого репозитория команду git log –pretty = full. Git начал формировать список коммитов с того из них, на который указывает содержимое файла HEAD через файл с именем New_Branch. В список коммитов попали все коммиты, составляющие дерево репозитория. Два из них принадлежат ветке New_Branch и один – ветке Main_branch. git log --pretty=full commit 09a543aaa4b8adaced3ea2e4b98b9973dfcfc002 (HEAD -> New_Branch) Author: Git_Book git_book@home.com Commit: Git_Book Третий коммит. commit 905b38d0d881bb229252127c0ee1c988ab84acd3 Author: Git_Book git_book@home.com Commit: Git_Book Проверка перехода между ветками commit 79a9f3a521f77bed2c94115cbe7a6a7316abd276 (Main_branch) Author: Git_Book Commit: Git_Book Test commit 1 В первой строке результата выполнения команды в скобках записано, что текущая ветка New_Branch (на неё указывает HEAD). Следующий ком- мит принадлежит текущей ветке (отсутствует информация, заключённая в скобки). Последний коммит принадлежит ветке Main_branch (название ветки в скобках). Если необходимо вывести список коммитов только для одной ветки, то для ветки Main_branch это сделать легко: git log Main_branch commit 79a9f3a521f77bed2c94115cbe7a6a7316abd276 (Main_branch) Author: Git_Book Date: Thu Jul 21 21:12:24 2022 +0300 Test commit 1 Для ветки New_Branch команда будет выглядеть сложнее: 60 $ git log Main_Branch..New_Branch commit 09a543aaa4b8adaced3ea2e4b98b9973dfcfc002 (HEAD -> New_Branch) Author: gitflic-muiv-gmbulan Date: Sun Jul 24 21:52:43 2022 +0300 Третий коммит. commit 905b38d0d881bb229252127c0ee1c988ab84acd3 Author: gitflic-muiv-gmbulan Date: Sun Jul 24 19:36:06 2022 +0300 Проверка перехода между ветками В команде git log Main_Branch..New_Branch указано, что нужно выве- сти сведения о коммитах, расположенных в ветке New_Branch от её начала до того места на дереве репозитория, где эта ветка примыкает к ветке Main_Branch. 2.15. Сравнение версий файлов, команды git diff, git show При анализе истории изменений файлов в репозитории нередко бы- вает необходимо сравнить версии одного и того же файла. Для выполнения этой операции используется команда git diff. Формат команды git diff: Git diff <ключ> <файл1> <файл2> Возможные значения ключей: --diff-filter=<признак>; признак может иметь одно из значений: А – сравнение для файлов, добавленных в индекс; D – сравнение для удалённых файлов; М – сравнение для изменённых файлов; --word-diff=color – выделять удалённые слова красным цветом, а до- бавленные – зелёным. Этот ключ действует по умолчанию. Файл1, файл2 – имена файлов и/или коммитов, для которых будет производиться сравнение. <ключ> <файл1> <файл2> являются необязатель- ными атрибутами команды git diff. Рассмотрим на примере, как задаются файлы, для которых будет выпол- няться операция сравнения, и как «расшифровывать» результаты сравнения. В рабочую директорию был добавлен файл с именем Learn_diff.txt. Вначале этот файл содержал следующие строчки (версия 1): Файл Изменения, добавленный в коммит. Неизменяемая строка. 61 Изменяемая строка: коммит. Этот файл был добавлен в коммит: /c/Learn_git (Main_branch) $ git add Learn_diff.txt /c/Learn_git (Main_branch) $ git commit -m 'Изучение команды git diff' [Main_branch b5fd14d] Изучение команды git diff 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Learn_diff.txt Содержимое файла Learn_diff.txt было изменено (версия 2): Файл Изменения, добавленный в индекс. Неизменяемая строка. Изменяемая строка: индекс. Изменённый файл был добавлен в индекс: /c/Learn_git (Main_branch) $ git add Learn_diff.txt Файл Learn_diff.txt был изменён ещё раз (версия 3): Файл Изменения, не отслеживаемый. Неизменяемая строка. Изменяемая строка: рабочая директория. После выполнения этих действий существуют три версии файла Learn_diff.txt: первая хранится в последнем коммите, вторая хранится в ин- дексе, третья хранится в рабочей директории. Выполним команду git diff без ключей и указания имён файлов: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 /c/Learn_git (Main_branch) $ git diff diff --git a/Learn_diff.txt b/Learn_diff.txt index c0901fb..d687242 100644 --- a/Learn_diff.txt +++ b/Learn_diff.txt @@ -1,3 +1,3 @@ -Файл Изменения, добавленный в индекс. +Файл Изменения, не отслеживаемый. Неизменяемая строка. -Изменяемая строка: индекс. \ No newline at end of file +Изменяемая строка: рабочая директория. \ No newline at end of file Результат выполнения команды расшифровывается следующим образом. Строка 3. Git сообщает, что будут сравниваться два файла a/Learn_diff.txt и b/Learn_diff.txt. Строка 4. Git выводит хеш-значения сравниваемых файлов. Замечание! 62 Не обязательно указывать в команде 40 символов хеш-значения, достаточно ука- зать несколько первых символов (не менее 5). Строки 5, 6. Git сообщает, что для обозначения изменений в файле a/Learn_diff.txt будет использоваться знак минус, а для обозначения измене- ний в файле b/Learn_diff.txt – знак плюс. Строка 7. Заголовок блока описания изменений. Заголовок с двух сто- рон ограничен символами @@ и указывает, что из файла а в блок сравнения будут добавлены 3 строки, начиная с первой, и из файла b – три строки, начиная с первой. Строки с 8 по 14. Git описывает, какие изменения были выполнены в файле а, чтобы получить файл b. Красным цветом выделены удалённые строки, зелёным цветом – добавленные строки и чёрным цветом – неизме- нившиеся строки. Текст «\ No newline at end of file» говорит о том, что строка, указанная перед ним, последняя в файле. Таким образом, из файла a были удалены строки: − Файл Изменения, добавленный в индекс. − Изменяемая строка: индекс. В файл b были добавлены строки: − Файл Изменения, не отслеживаемый. − Изменяемая строка: рабочая директория. Строка «Неизменяемая строка.» присутствует в обоих файлах. Сравнивая приведённые выше версии файлов, понимаем, что сравни- вались файлы, сохранённые в индексе и в рабочей директории. Делаем вывод, что команда git diff без указания ключа и имён файлов сравнивает изменения в файлах, хранящихся в индексе и в рабочей дирек- тории. Если существуют несколько файлов, в которых произошли измене- ния, описания изменений будут для всех файлов. Выполним команду |