Система управления версиями Git. Система управления версиями git и российский сервис хранения исходного кода gitflic
Скачать 3.56 Mb.
|
Формат команды git status: git status <флаги> Возможные значения флагов: -s – короткий формат вывода информации; -b – показывать название ветви даже при коротком формате вывода; 37 -v – для изменённых файлов показывать текст, который был изменён. Для примера, рассмотренного ранее, в директорию Learn_git были до- бавлены два файла (File1.txt, File2.txt) и пустая директория Dir1. File1 содер- жит текст: Example1. File2 содержит текст: Example2. Ниже показан резуль- тат выполнения команды git status после добавления файлов и директории. $ git status On branch Main_branch No commits yet Untracked files: (use "git add File1.txt File2.txt nothing added to commit but untracked files present (use "git add" to track) Интерпретация информации, выведенной Git по команде git status, следующая: − текущая ветка – Main_branch; − до сих пор не было сделано ни одного коммита; − имеются не отслеживаемые файлы File1.txt, File2.txt. Git рекомен- дует добавить их в Staging area с помощью команды add; − сообщается, что ничего не добавлено в коммит, но имеются не от- слеживаемые файлы. Перед тем, как выполнять действия по добавлению файлов в Staging area и затем в коммит, необходимо рассмотреть, как Git хранит внутреннюю информацию. 2.8. Объекты Git Всё, что сохраняет Git в архиве, называется объектом. Объекты хра- нятся в директории .git/objects. В настоящий момент, для рассматриваемого примера, директория .git/objects содержит две директории info и pack (см. раздел 2.5) и ни одного файла с объектами. Объекты в Git бывают трёх типов: 1. Blob (binary large object) – большой двоичный объект. Из названия следует, что это двоичный файл. Blob создаётся для каждого файла и всех 38 его версий, сохранённых в архиве. Blob содержит имя файла и его содержи- мое в сжатом виде, Blob формируется, когда файл добавляется в Staging area. 2. Tree (дерево) – двоичное представление графа, описывающего связи между файлами, хранящимися в архиве. Граф формируется для каж- дой директории, включённой в архив. Формирование графа происходит в про- цессе выполнения коммита. Граф содержит информацию о том, какие файлы и директории содержатся в директории, которую описывает граф. Описание хранится в виде имён blob-объектов и имён других объектов типа Tree. 3. Коммит – содержит информацию об авторе коммита, дате и вре- мени выполнения коммита, комментарий и ссылку на объект Tree, который описывает корневую директорию репозитория. Ещё один элемент внутреннего устройства Git, не являющийся объек- том, это двоичный файл index (индекс). Этот файл хранит ссылки на blob- объекты, которые добавляются в Staging area. Фактически файл index и есть Staging area. В дальнейшем термин «добавить в Staging area» будет приме- няться как синоним термина «добавить в индекс». Во время выполнения ко- манды add, упоминавшейся в примере прошлого раздела, происходит формиро- вание blob-объекта для добавляемого файла. Blob-объект добавляется в дирек- торию .git/objects, а имя этого blob-объекта записывается в файл index. Blob-объект формируется по следующему алгоритму. 1. На первом шаге формируется текстовой файл, который начинается с ключевого слова blob. После слова blob через пробел записывается длина исходного текстового файла в байтах и нулевой байт (\0). После нулевого байта записывается содержимое исходного текстового файла. В рассмотрен- ном выше примере файл File1.txt содержит текст Example1. Для этого файла результат выполнения первого шага создания blob-объекта будет выглядеть следующим образом: blob 8\0Example1. 2. Для полученного на первом шаге файла с помощью алгоритма SHA-1 формируется хеш-значение, состоящее из 40 шестнадцатеричных цифр. Первые две цифры хеш-значения являются именем подкаталога каталога .git/objects, в котором будет храниться blob-объект. Остальные 38 шестна- дцатеричных цифр являются именем blob-объекта. Хеш-значение использу- ется для того, чтобы все хранящиеся в архиве файлы имели различные имена хранения. Даже если два файла имеют одинаковое исходное имя, но различное содержание, их хеш-значения будут различными. Первые две 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 Untracked files: (use "git add 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 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 Changes not staged for commit: (use "git add (use "git restore Файлы 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 /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 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 (use "git restore Теперь хеш-значения для файлов 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) 49 $ git ls-files --stage 100644 09478d7f26086b969ea8edac54bc98d0c1c9e750 0 Dir1/File3.txt 100644 d4a854445e5dab327199bdeca32f16878c874e05 0 File1.txt 100644 36d9b23df2cdcd91759d69a291d04beddab2b091 0 File2.txt Хеш-значения в индексе для файлов File1.txt, File3.txt изменились и теперь они не совпадают со значениями, хранящимися в последнем ком- мите. Git понимает, что файлы File2.txt, File3.txt подготовлены для добавле- ния в новый коммит. Выполнение коммита: /c/Learn_git (Main_branch) $ git commit -m 'Test commit 2' [Main_branch d58ea97] Test commit 2 2 files changed, 2 insertions(+), 2 deletions(-) В файле .git/HEAD хранится запись: ref: refs/heads/Main_branch В файле refs/heads/Main_branch хранится запись: d58ea9721672b176fdeda4a6550030a43f982d61 Это имя объекта, соответствующего новому коммиту. Содержание нового коммита: /c/Learn_git (Main_branch) $ git cat-file -p d58ea9721672b176fdeda4a6550030a43f982d61 tree a7325622d8c15306bc4f2c3b8825d7ffeaec0d1c parent 00edc80c522d4b79c517c7f377e99a3249e7b24b author Git_Book Test commit 2 В отличие от предыдущего (первого) коммита, добавлена строчка с признаком parent. В этой строке находится имя объекта, содержащего предыдущий коммит. Начиная со второго коммита в ветке, строчка parent будет присутствовать во всех коммитах, что даёт возможность переме- щаться от одного коммита к другому в обратном хронологическом порядке и, при необходимости, восстановить рабочую директорию для прошлого коммита. Чтение содержимого объектов «дерево» текущего коммита. /c/Learn_git (Main_branch) $ git cat-file -p a7325622d8c15306bc4f2c3b8825d7ffeaec0d1c 040000 tree 44fdafa264bef7c64378a1d070a034bf57d02979 Dir1 100644 blob d4a854445e5dab327199bdeca32f16878c874e05 File1.txt 100644 blob 36d9b23df2cdcd91759d69a291d04beddab2b091 File2.txt /c/Learn_git (Main_branch) $ git cat-file -p 44fdafa264bef7c64378a1d070a034bf57d02979 100644 blob 09478d7f26086b969ea8edac54bc98d0c1c9e750 File3.txt Графическое представление дерева рабочей директории для второго 50 коммита представлено на рисунке 2.4. Сравнив деревья рисунков 2.3 и 2.4, видим, что для файлов File1.txt, File3.txt созданы новые blob-объекты. Для File2.txt используется blob-объект из прошлого коммита, что позволяет эко- номить место на диске. Рисунок 2.4 – Дерево рабочей директории (второй коммит) |