Файл: Система управления версиями git и российский сервис хранения исходного кода gitflic.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 06.12.2023

Просмотров: 213

Скачиваний: 7

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

39 цифры хеш-значения используются для обозначения директории для того, чтобы файл было легче искать.
3. Текстовой файл, полученный на первом шаге, сжимается. После сжатия получается двоичный файл, и blob-объект начинает оправдывать своё название.
2.9. Добавление файла в индекс, команда git add
Команда git add выполняет три действия:
− Создаёт blob-объект для выбранного файла.
− Сохраняет blob-объект в директории .git/objects.
− Записывает сведения о blob-объекте в файл index.
Файл index хранится в директории .git/. В каждой строке файла хра- нится служебная информация, хеш-значение, соответствующее файлу, ко- торый планируется добавить в коммит, и имя файла. Все три части разде- лены пробелами. Файл index хранится в сжатом виде.
Формат команды git add:
git add <имя файла> <флаги>
В имени файла допускается использовать символы групповых опера- ций для добавления нескольких файлов в одной команде.
Некоторые из возможных флагов:
-A или –all – в индекс будут добавлены все файлы, находящиеся в ра- бочей директории.
Продолжение примера.
После добавления файлов File1.txt и File2.txt репозиторий содержит следующие файлы и директории:
│ File1.txt
│ File2.txt
├───.git
│ │ config
│ │ description
│ │ HEAD
│ ├───hooks
│ ├───info
│ ├───objects
│ │ ├───info
│ │ └───pack
│ └───refs
└───Dir1
Ниже показан результат последовательного выполнения команд:
− git add File1.txt;

40
− git ststus.
$ git add File_1.txt
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached ..." to unstage) new file: File1.txt
Untracked files:
(use "git add ..." to include in what will be committed)
File2.txt
Файл File_1.txt поменял статус. Теперь он находится в числе файлов, которые планируется добавить в коммит. Файл File_2.txt по-прежнему не отслеживаемый.
Теперь директория .git/ выглядит так:
│ File1.txt
│ File2.txt
├───.git
│ │ config
│ │ description
│ │ HEAD
│ │ index
│ ├───hooks
│ ├───info
│ ├───objects
│ │ ├───84
│ │ │ 9327df401a74dd0148b99b532d290f7da80eae
│ │ ├───info
│ │ └───pack
│ └───refs
└───Dir1
Произошли следующие изменения:
− В директории .git/ появился файл index.
− В директории ./git/objects появилась директория 84 и в ней файл
9327df401a74dd0148b99b532d290f7da80eae.
Файл index – двоичный сжатый файл. Посмотреть его содержимое обычными средствами Windows не представляется возможным. Однако это возможно сделать, используя команду git: git ls-file –stage.
$ git ls-files --stage
100644 849327df401a74dd0148b99b532d290f7da80eae 0 File1.txt
Файл index содержит одну строку, соответствующую одному файлу, подготовленному для коммита (см. результат команды git ststus).


41
Строка состоит из четырёх секций:
− Служебная информация 100644 говорит о том, что в строке описы- вается обычный файл.
− 849327df401a74dd0148b99b532d290f7da80eae – хеш-значение.
− 0 – признак отсутствия конфликтов в готовящемся коммите.
− File1.txt – имя файла, который предполагается добавить в коммит.
В процессе выполнения команды git add File1.txt был создан blob- объект с хеш-значением 849327df401a74dd0148b99b532d290f7da80eae. Этот blob-объект хранится в директории ./git/objects/84 под именем
9327df401a74dd0148b99b532d290f7da80eae (см. дерево директории выше).
Для просмотра blob-объекта используется команда git: git cat-file –p <имя blob-объекта>
/c/Learn_git
(Main_branch)
$ git cat-file -p 849327df401a74dd0148b99b532d290f7da80eae
Example1
Таким образом, при выполнении команды git add File1.txt произошло следующее:
− Для файла File1.txt был создан blob-объект с хеш-значением
849327df401a74dd0148b99b532d290f7da80eae;
− blob-объект был записан в файл с именем
9327df401a74dd0148b99b532d290f7da80eae и размещён в директории
.git/objects/84;
− в файл index была добавлена строка:
100644 849327df401a74dd0148b99b532d290f7da80eae 0 File1.txt
Добавим в индекс файл File2.txt и определим статус файлов в репози- тории.
/c/Learn_git
(Main_branch)
$ git add File2.txt
/c/Learn_git
(Main_branch)
$ git status
On branch Main_branch
No commits yet
Changes to be committed:
(use "git rm --cached ..." to unstage) new file: File1.txt new file: File2.txt

42
Теперь оба файла являются отслеживаемыми и занесены в индекс, ко- торый выглядит так:
$ git ls-files --stage
100644 849327df401a74dd0148b99b532d290f7da80eae 0 File1.txt
100644 59100dc59802239b7e54eb8519d1f45f532b1d0a 0 File2.txt
В директории .git/objects появилась директория 59, в которой содер- жится blob-объект, соответствующий файлу File2.txt.
│ config
│ description
│ HEAD
│ index
├───hooks
├───info
│ exclude
├───objects
│ ├───59
│ │ 100dc59802239b7e54eb8519d1f45f532b1d0a
│ ├───84
│ │ 9327df401a74dd0148b99b532d290f7da80eae
│ ├───info
│ └───pack
└───refs
├───heads
└───tags
Изменим содержимое файла File2.txt и снова выполним команду git status.
/c/Learn_git
(Main_branch)
$ git status
On branch Main_branch
No commits yet
Changes to be committed:
(use "git rm --cached ..." to unstage) new file: File1.txt new file: File2.txt
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory) modified: File2.txt
Файлы File1 и File2.txt по-прежнему отслеживаемые и находятся в файле индекса. В то же время про файл File2.txt сказано, что он изменён и не включён в индекс. Таким образом, создаётся впечатление, что файл
File2.txt находится сразу в двух состояниях. Для того чтобы объяснить, что произошло, сначала необходимо сказать, как Git определяет, что файл изме- нился. Для сравнения файлов Git сравнивает хеш-значения этих файлов.
Если значения разные, значит, содержимое файлов различно. При выполне-


43 нии команды git status Git обращается к каждому из файлов в рабочей ди- ректории и определяет, были ли они включены в предыдущие коммиты или в текущий файл индекса. Если файл ни разу не был включён в коммит и не содержится в текущем файле индекса, значит, для него не вычислялось хеш- значение, и сравнивать текущее содержимое файла не с чем. Файл не отсле- живаемый. Если предыдущее хеш-значение существует, то оно сравнива- ется с текущим и определяется, был ли файл изменён.
При выполнении команды git status в рассматриваемом примере Git обнаружил, что для файла File2.txt ранее вычислялось хеш-значение (файл находится в Stagging area). Предыдущее и текущее хеш-значения различны, следовательно, после внесения файла File2.txt в индекс он был изменён. Об этом Git и сообщил в результатах команды git status. Если при таком состо- янии репозитория выполнить коммит, то в архиве будет сохранено неизме- нённое содержимое файла File2.txt (то, которое хранится в директории
.git/objects/59). Таким образом, Git хранит в папке .git/objects все версии файлов, но включает в коммит только последнюю из них.
Для рассматриваемого примера существуют три варианта действий:
1. Выполнить коммит и сохранить в архиве старое содержание файла
File2.txt.
2. Восстановить содержимое файла File2.txt из blob-объекта.
3. Выполнить команду git add для файла File2.txt и добавить в индекс ссылку на его новое содержание.
Выберем третий вариант.
/c/Learn_git
(Main_branch)
$ git add File2.txt
/c/Learn_git
(Main_branch)
$ git status
On branch Main_branch
No commits yet
Changes to be committed:
(use "git rm --cached ..." to unstage) new file: File1.txt new file: File2.txt
/c/Learn_git
(Main_branch)
$ git ls-files --stage
100644 849327df401a74dd0148b99b532d290f7da80eae 0 File1.txt
100644 36d9b23df2cdcd91759d69a291d04beddab2b091 0 File2.txt
Теперь File1.txt и File2.txt находятся в Staging area, но для файла

44
File2.txt был создан новый blob-объект, который хранится в директории
.git/objects/36.
Закончим готовить тестовый репозиторий к коммиту. Создадим в ди- ректории Dir1 файл File3.txt, содержащий текст Example3. Добавим файл
File3.txt в индекс и посмотрим, что получилось.
/c/Learn_git
(Main_branch)
$ cd Dir1
/c/Learn_git/Dir1
(Main_branch)
$ echo Example3 > File3.txt
/c/Learn_git/Dir1
(Main_branch)
$ git add File3.txt
/c/Learn_git/Dir1
(Main_branch)
$ cd ..
/c/Learn_git
(Main_branch)
$ git ls-files --stage
100644 30aa3732af149122998338bcd99fc8a6fb52c988 0 Dir1/File3.txt
100644 849327df401a74dd0148b99b532d290f7da80eae 0 File1.txt
100644 36d9b23df2cdcd91759d69a291d04beddab2b091 0 File2.txt
В Staging area подготовлены для коммита три файла, blob-объекты для которых находятся в директориях .git/objects/30, .git/objects/84, .git/objects/
36. Два из этих файлов находятся в корне рабочей директории, один – в ди- ректории Dir1.
Теперь всё готово для объяснения того, что происходит при создании коммита.
2.10. Создание коммита, команда git commit
Формат команды git commit:
git commit <флаги>
Возможные значения флагов:
-m <описание> – коммит обязательно должен содержать текст, описы- вающий те изменения, ради которых был сделан коммит. Если команда git com- mit будет использована без флагов, указывающих, откуда взять описание, авто- матически откроется редактор и будет предложено ввести описание;
-с <коммит> – описание для нового коммита будет взято из указан- ного существующего коммита, будет автоматически открыт редактор и предложено внести изменения в описание;
-С – то же самое, что –с, только без открытия редактора.


45
При выполнении команды git commit происходят три действия:
1. Создаётся объект типа «дерево», который описывает текущую ра- бочую директорию.
2. Создаётся объект типа «коммит», который содержит информацию о коммите.
3. Изменяются указатели, отвечающие за создание цепочки комми- тов (ветки). Для этого новый коммит указывает на предыдущий коммит, а заголовок ветки указывает на новый коммит.
Далее будет создан коммит для Staging area, подготовленной в преды- дущем разделе, и на примере описан формат всех появившихся объектов.
/c/Learn_git
(Main_branch)
$ git commit
[Main_branch (root-commit) 00edc80] Try commit
3 files changed, 3 insertions(+) create mode 100644 Dir1/File3.txt create mode 100644 File1.txt create mode 100644 File2.txt
/c/Learn_git
(Main_branch)
$ git cat-file -p 00edc80c522d4b79c517c7f377e99a3249e7b24b tree fa0d51469255146719fe3aebdfedbe5e046a8278 author Git_Book 1658435516 +0300 committer Git_Book 1658435516 +0300
Try commit
/c/Learn_git
(Main_branch)
$ git cat-file -p fa0d51469255146719fe3aebdfedbe5e046a8278 040000 tree 8a63ac25a734b6e00b9808209fc0e9e41c76b893 Dir1 100644 blob 849327df401a74dd0148b99b532d290f7da80eae File1.txt
100644 blob 36d9b23df2cdcd91759d69a291d04beddab2b091 File2.txt
/c/Learn_git
(Main_branch)
$ git cat-file -p 8a63ac25a734b6e00b9808209fc0e9e41c76b893 100644 blob 30aa3732af149122998338bcd99fc8a6fb52c988 File3.txt
После успешного выполнения команды git commit будут выведены со- общения, описывающие результат создания коммита.
Строка
[Main_branch (root-commit) 00edc80] Try commit говорит о том, что:
− коммит добавлен в ветку Main_branch;
− хеш-значение объекта, описывающего коммит, начинается на
00edc80
и, следовательно, находится в директории .git/objects/00;
− описание коммита Try commit;
− в коммит добавлены 3 перечисленных blob-объекта.
Переходим в директорию .git/objects/00 и видим в ней файл с именем edc80c522d4b79c517c7f377e99a3249e7b24b, содержащий объект типа «ком- мит». Выполнив команду git cat-file для этого объекта, получаем хранящееся

46 в нём описание коммита. Описание коммита состоит из четырёх строк. Если текст, описывающий коммит, занимает более одной строки, то общее коли- чество строк в описании коммита может быть более 4.
В первой строке описания коммита находится ссылка на объект «дерево» для корня рабочей директории репозитория. Ссылка состоит из 2 полей:
− текстового обозначения объекта «дерево» (tree);
− хеш-значения объекта «дерево».
Во второй строке находятся данные об авторе коммита и времени вы- полнения коммита.
В третьей строке находятся данные о лице, выполнившем коммит, и времени выполнения коммита.
Вторая и третья строки будут содержать различные данные в том слу- чае, если происходит копирование коммита (один программист создал ком- мит, а другой скопировал его в свою ветку).
В четвёртой строке находится описание коммита.
Выполняем команду git cat-file для объекта «дерево», хеш-значение которого указано в первой строке описания коммита:
$ git cat-file -p fa0d51469255146719fe3aebdfedbe5e046a8278
Получаем описание дерева рабочей директории, состоящее из не- скольких строк, имеющих одинаковый формат.
Каждая строка объекта «дерево» описывает объект, входящий в де- рево и состоит из четырёх частей:
− числового обозначения типа объекта, которое может быть:
✓ 100644 – обычный файл (blob);
✓ 100755 – исполняемый файл;
✓ 040000 – дерево;
✓ 120000 – ссылка;
− текстового обозначения типа объекта;
− хеш-значения объекта;
− имени объекта.
В примере дерево рабочей директории состоит из трёх объектов: двух blob и одного дерева.
Выполняем команду git cat-file для объекта, описывающего дерево ка- талога Dir1:


47
$ git cat-file -p 8a63ac25a734b6e00b9808209fc0e9e41c76b893
Получаем описание дерева каталога Dir1. Это дерево состоит из од- ного blob-объекта для файла File3.txt.
На рисунке 2.3 показано дерево рабочей директории.
Рисунок 2.3 – Дерево рабочей директории (первый коммит)
Два из трёх действий, выполняемых в процессе коммита, завершены: созданы объекты дерево рабочей директории и коммит. Осталось поменять указатели. Поскольку текущий коммит является первым в ветке
Main_branch, он не может ссылаться на предыдущие коммиты, поэтому ука- затель на предыдущий коммит изменяться не будет. Указатель на начало те- кущей ветки (заголовок ветки) находится в файле .git/HEAD. Файл
.git/HEAD текстовой, и его можно прочитать в текстовом редакторе. Для рассматриваемого примера содержимое файла .git/HEAD: ref: refs/heads/Main_branch
Эта запись говорит о том, что указатель на начало ветки находится в файле, размещённом в директории .git/refs/heads. Название файла совпадает с названием текущей ветки: Main_branch. Файл Main_branch текстовой, его содержимое для рассматриваемого примера:
00edc80c522d4b79c517c7f377e99a3249e7b24b
Это хеш-значение для объекта коммита, с которого было начато по- строение дерева рабочей директории.
Таким образом, для того чтобы восстановить состояние рабочей ди- ректории, соответствующей последнему коммиту, необходимо:
− прочитать файл .git/HEAD;
− из файла, на который указывает содержимое .git/HEAD, узнать хеш-

48 значение объекта «коммит»;
− из объекта коммита узнать хеш-значение объекта «дерево рабочей директории»;
− построить дерево рабочей директории;
− в листьях дерева рабочей директории находятся blob-объекты фай- лов, содержащихся в рабочей директории. Из этих blob-объектов возможно восстановить оригиналы файлов.
Внесём изменения в файлы File1.txt и File3.txt, добавим их в индекс и выполним коммит.
Состояние до внесения изменений:
/c/Learn_git
(Main_branch)
$ git ls-files --stage
100644 30aa3732af149122998338bcd99fc8a6fb52c988 0 Dir1/File3.txt
100644 849327df401a74dd0148b99b532d290f7da80eae 0 File1.txt
100644 36d9b23df2cdcd91759d69a291d04beddab2b091 0 File2.txt
/c/Learn_git
(Main_branch)
$ git status
On branch Main_branch nothing to commit, working tree clean
В индексе находятся те же хеш-значения, которые в нём были на мо- мент выполнения предыдущего коммита. Хеш-значения для файлов, нахо- дящихся в рабочей директории, совпадают с хеш-значениями, хранящимися в индексе, поэтому Git делает вывод, что никаких изменений не было.
Состояние после внесения изменений в файлы File1.txt и File3.txt:
/c/Learn_git
(Main_branch)
$ git status
On branch Main_branch
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git restore ..." to discard changes in working directory) modified: Dir1/File3.txt modified: File1.txt no changes added to commit (use "git add" and/or "git commit -a")
Теперь хеш-значения для файлов File1.txt и File3.txt, находящихся в рабочей директории, не совпадают с хеш-значениями для этих же файлов, хранящихся в индексе. Git делает вывод, что в эти файлы были внесены из- менения.
Добавление модифицированных файлов File1.txt, File3.txt в индекс:
/c/Learn_git
(Main_branch)
$ git add File1.txt
/c/Learn_git
(Main_branch)
$ git add Dir1/File3.txt
/c/Learn_git
(Main_branch)