02. Коммиты
Для выполнения этого задания вам нужен репозиторий, созданный в предыдущем задании.
Клонирование
Если у вас его нет на компьютере или лень искать, можно просто заново загрузить его с github
.
Для этого откройте свой репозиторий на сайте github.com и скопируйте путь к нему:
После этого нужно перейти в папку в которой будет лежать папка вашего репозитория. Если вы клонируете репозиторий, не нужно создавать папку, в которой он будет лежать. Онв создаётся автоматически.
У меня эта папка - D:\Repositories
.
Внутри папки для репозиториев запустим консоль git
и скачаем тестовый репозиторий
(вам нужно указать свой адрес вместо https://github.com/aoklyunin/test-repository.git
)
git clone https://github.com/aoklyunin/test-repository.git
Получим:
Cloning into 'test-repository'...
remote: Enumerating objects: 17, done.
remote: Counting objects: 100% (17/17), done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 17 (delta 1), reused 16 (delta 0), pack-reused 0
Receiving objects: 100% (17/17), done.
Resolving deltas: 100% (1/1), done.
Так git
показывает, сколько и чего загружено.
Команда git clone
всегда создаёт новую папку с таким же названием, как у удалённого репозитория.
Чтобы работать с ним, нужно перейти в созданную клонированием папку и запустить гит-консоль в ней.
В папке репозиториев появится папка с загруженными файлами, у вас она будет называться так же,
как репозиторий на github
:
Содержимое папки будет выглядеть примерно так:
Получение изменений
Если вы работаете на нескольких компьютерах, то после работы на одном, вам нужно получить изменения сделанные на втором. Для этого сначала с первого компьютера нужно отправить изменения на сервер, а на второй скачать их.
Чтобы получить информацию о всех изменениях на удалённом сервере,
используется команда git fetch <server-name>
git fetch pb master
Чтобы загрузить новые коммиты с сервера используют команду git pull <server-name>
Например:
git pull pb master
Обычно основной сервер называют origin
, поэтому если вы работаете только с одним,
команды будут выглядеть так:
git fetch origin master
git pull origin master
Состояния
Напомню: каждому файлу внутри выбранной нами папки git
присваивает своё состояние, их может быть
всего три:
- Зафиксированное - никаких новых изменений в файле нет, при создании коммита
git
просто пробросит ссылку на последнее изменение этого файла. Таким изменением может быть и просто сохранение файла после добавления его в список индексации; - Изменённое - файл изменён или просто создан, но пока что не добавлен в список индексации следующего коммита;
- Индексированное - изменения в файле будут учтены при создании нового коммита.
Узнаем теперь состояние нашего репозитория
git status
Если вы ничего не меняли, то получите примерно такой ответ:
On branch master
nothing to commit, working tree clean
Это означает, что всё окей, нет файлов, за которыми git
не следит, хотя мог бы. При этом нет
никаких изменений в отслеживаемых.
В первой строчке говорится о том, в какой ветке мы находимся. О ветках гит будет рассказано ниже.
Пока что у нас она одна и называется master
. Git говорит, что мы в ней. Вторая строчка говорит
о том, что нам нечего добавлять в коммит.
Если запустить статус для пустого репозитория, то ответ будет таким:
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)
Вторая строчка говорит нам, что пока что у нас нет коммитов, в третьей гит дополнительно
предлагает нам создать или скопировать откуда-то файлы и использовать git add
для добавления их в список индексации.
Чтобы получить короткий статус, используйте ключ -s
:
git status -s
Т.к. информацию выводить не о чем (у нас нет изменений), то гит вернёт просто пустую строку.
Напишем в файле test
нашего репозитория слово тест
.
Вызовем снова
git status
Получим:
On branch master
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: test1.txt
no changes added to commit (use "git add" and/or "git commit -a")
Так гит отображает список изменённых файлов и предлагает либо добавить их в список индексации
при помощи команды git add <file>...
, либо откатить изменения при помощи команды
git restore <file>...
Если запросить сжатое состояние репозитория
git status -s
то выдача будет такой:
M test1.txt
Восстановим файл до предыдущего состояния:
git restore test1.txt
Если всё ок, то файл снова станет пустым
Теперь напишите в файле test1.txt
строку:
Это тестовый файл
Чтобы сохранить файл, нужно либо нажать Ctrl+S
, либо закрыть блокнот. Система предложит
вам сохранить изменения, нажмите Сохранить
.
Если вы не сохраните изменения в файле, то и в список индексации добавлять нечего.
Теперь нам нужно добавить его в список индексации, можно снова вызвать команду git add test1.txt
,
но проще использовать git add *
. В этом случае в список индексации добавляются все изменённые
файлы, и вам не нужно помнить их названия.
Введём команду:
git add *
Между add
и *
обязательно должен быть пробел.
Снова запросим состояние репозитория:
git status
В ответ получим:
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test1.txt
В нём перечисленны изменения, добавленные в индексацию. У нас изменился один файл test1.txt
.
Создадим теперь второй коммит:
git commit -m "test1.txt filled"
В ответ получим:
$ git commit -m "test1.txt filled"
[master 85d79a4] test1.txt filled
1 file changed, 1 insertion(+)
В выдаче git перечислит все изменения, образующие новый коммит.
Снова запросим состояние репозитория:
git status
Получим:
On branch master
nothing to commit, working tree clean
Значит, несохранённых изменений нет, можно двигаться дальше.
Дополним содержимое файла test1.txt
:
- test1.txt
Это тестовый файл
Или нет
Также создадим пустой файл test2.txt
в папке нашего репозитория и выполним команду:
git status
Теперь выдача будет выглядеть так:
On branch master
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: test1.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
test2.txt
no changes added to commit (use "git add" and/or "git commit -a")
Гит отдельно выводит список изменённых файлов и отдельно список добавленных.
Вызовем теперь укороченный статус:
git status -s
Получим:
M test1.txt
?? test2.txt
Добавим все изменения
git add *
И снова запросим состояние:
git status
Получим:
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test1.txt
new file: test2.txt
Сжатая информация о состоянии будет такой:
M test1.txt
A test2.txt
Создадим новый коммит:
git commit -m "add test2.txt"
Получим:
[master 0bf151b] add test2.txt
2 files changed, 3 insertions(+), 1 deletion(-)
create mode 100644 test2.txt
Отображение изменений
Теперь напишите в файле test2.txt
следующее:
- test2.txt
Это второй тестовый файл
Но это неточно
Добавьте изменения в список индексации:
git add *
И создайте новый коммит:
git commit -m "test2.txt filled"
Теперь поменяйте текст в test2.txt
- test2.txt
Это второй тестовый файл
Однозначно тестовый
и запустите команду
git diff
В ответ вы получите примерно такой вывод:
diff --git a/test2.txt b/test2.txt
index a8f4692..87b925d 100644
--- a/test2.txt
+++ b/test2.txt
@@ -1,3 +1,3 @@
Это второй тестовый файл
-Но это неточно
\ No newline at end of file
+Однозначно тестовый
\ No newline at end of file
Эта команда показывает нам, какие именно изменения мы ещё не добавили в индекс. Но показывает она это как набор отличий последнего коммита от актуальных версий файлов.
Первая строка показывает, какие именно версии мы сравниваем.
В логике такой разности a
- это версия файла в последнем коммите, b
- актуальная версия.
Следующая строчка - это хэши рассматриваемых версий. Потом идёт две строчки до знаков @
.
Это - блок отображения цепочки изменений. Версии файлов могут пробрасываться из предыдущих
коммитов. Тогда строк может быть больше.
Между @@
указано, сколько строк удалено и сколько добавлено. В нашем случае мы удалили одну строку и
одну прибавили. Это там и выведено. После запятой указывается номер строки файла, с которой начинаются
изменения.
Потом выводятся сами изменения. Строка \ No newline at end of file
говорит о том, что в конце файла
нет символа перехода на новую строку. Её может и не быть, если вы добавили пустую строку в конец.
Также мы можем посмотреть список проиндексированных изменений, для этого нужно
добавить ключ --staged
git diff --staged
Пока что в ответ мы получим пустую строку, потому что у нас всего одно изменение, и оно не проиндексировано. Добавим изменения в список индексации и снова вызовем разность:
git add test2.txt
git diff --staged
Теперь получим такую же выдачу, как ранее у неиндексированных изменений:
diff --git a/test2.txt b/test2.txt
index a8f4692..87b925d 100644
--- a/test2.txt
+++ b/test2.txt
@@ -1,3 +1,3 @@
Это второй тестовый файл
-Но это неточно
\ No newline at end of file
+Однозначно тестовый
\ No newline at end of file
Теперь обычная команда git diff
вернёт нам пустую строку.
Создадим новый коммит:
git commit -m "test2.txt changed"
Получим:
[master e43dc46] test2.txt changed
1 file changed, 1 insertion(+), 1 deletion(-)
Удаление файлов
Удалим теперь файл test1.txt
и выполним снова команду git status
, получим:
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: test1.txt
no changes added to commit (use "git add" and/or "git commit -a")
Git говорит нам о том, что у нас есть непроиндексированные изменения. Раньше мы использовали команду git add <file>
. Для того,
чтобы удалить файл из списка индексации, когда он уже удалён, можно использовать ещё команду git rm <file>
.
Удалим наш файл из списка индексации:
git rm test1.txt
Получим:
rm 'test1.txt'
Чтобы удалить папку, нужно добавить ключ -r
(для выполнения задания это не нужно)
git rm -r folder_name
где folder_name
- название папки
Снова вызовем статус git status
, получим:
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: test1.txt
Теперь наши изменения будут учтены, создаём новый коммит:
git commit -m "test1 removed"
Получим:
[master cea6176] test1 removed
1 file changed, 3 deletions(-)
delete mode 100644 test1.txt
Если вы хотите удалить файл из индекса, но при этом оставить его на диске, то нужно использовать
ключ --cached
.
git rm --cached test2.txt
Получим:
rm 'test2.txt'
Вызовем статус, получим:
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: test2.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
test2.txt
При этом сам файл не удалился.
Добавим его снова в список индексации и вызовем статус
git add test2.txt
git status
Получим:
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
Гит говорит, что изменений нет. Так и должно быть: мы сначала извлекли файл из интдекса, а потом добавили.
Удаление с ключём --cached
очень полезно, когда вы забыли добавить в список
игнорирования(.gitignore
, о нём будет рассказано в следующих главах) большой файл
или папку и она уже есть в списке индексации. Если мы её просто удалим, то её предыдущие версии
всё равно останутся внутри git
.
Команда git rm
также, как и git add
на самом деле принимает регулярное выражение, поэтому вы можете
одной командой удалить сразу набор файлов, удовлетворяющих регулярному выражению.
Помимо удаления иногда мы перемещаем файлы внутри рабочей директории, переименовываем их.
Для того, чтобы гит
учёл такие изменения, нужно использовать команду git mv <source> <target>
Поменяем называние нашего файла с test2.txt
на test1.txt
:
git mv test2.txt test1.txt
В нашем случае перемещение происходит внутри папки, поэтому оно в своей сути переименование.
В логике git
и вообще
unix
переименование всегда является частным случаем перемещения.
Эта команда перемещает и физический файл, и его индекс. Т.е. выполненная команда эквивалентна тому, если бы мы вручную переместили(переименовали) файл, а потом выполнили эти две:
git rm test2.txt
git add test1.txt
Если вы вручную удалили файл, то не забудьте добавить все изменения в индекс:
git add *
Теперь создадим новый коммит
git commit -m "test2.txt moved to test1.txt"
История коммитов*
Вам нужно просто прочитать этот и следующий блоки и приступать к выполнению задания. Команды выполнять не требуется.
Чтобы посмотреть историю коммитов, выполним команду:
git log
Получим:
commit b110a9a89cdcf58f8493bec0f865029d0805b826 (HEAD -> master)
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:27:37 2022 +0300
test2.txt moved to test1.txt
commit cea61760b9ee1597baddbb5ee1d32d19a5bca029
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:21:13 2022 +0300
test1 removed
commit da3a16675b300de24c2e2d13ce75b05ca445d0d4
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:20:11 2022 +0300
test2.txt changed
commit f7dfda1acda795011800a1a392447396e643440c
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:14:33 2022 +0300
test2.txt filled
:
Ответ Git на команду git log
- это не просто вывод в консоль. Это - интерактивная консольная программа. В ней
уже не ввести обычные команды. Такие программы перехватывают управление консолью и сами обрабатывают нажатия на клавиатуру.
Попробуйте нажать пару раз кнопку "вниз" на клавиатуре. Выведется новый текст, если теперь нажать "вверх", то мы вернёмся к изначальной
выдаче. Обычно интерактивные команды завершаются при помощи сочетания клавиш Ctrl+C
, но в git чтобы выйти, нужно нажать
клавишу q
.
Снова выведем лог:
git log
При помощи этой команды гит выводит список коммитов в текущей ветке. Т.к. коммитов бывает очень много, то по умолчанию Git выводит несколько последних, а остальные можно посмотреть, переместившись к ним при помощи клавиши "вниз" на клавиатуре.
Посмотрим на описание последнего коммита
commit b110a9a89cdcf58f8493bec0f865029d0805b826 (HEAD -> master)
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:27:37 2022 +0300
test2.txt moved to test1.txt
В первой строчке указан хэш коммита, также у него в скобках указано, что он является актуальной версией в ветке master
.
Во второй указаны автор коммита и его почта, третья - это дата и время создания коммита, потом его описание.
У остальных коммитов после хэша ничего нет. Напомню хэш Git высчитвает по алгоритму SHA-1
, отображается он при помощи
40 шестнадцатиричных цифр.
Если добавить ключ -p
, то гит выведет список изменений в коммите, если добавить после
ключ -<num-of-pathces>
,
то будет выведено заданное количество изменений. Эти изменения называются патчами. Например, чтобы вывести
информацию только о двух коммитах, нужно ввести команду: git log -p -2
.
Посмотрим патчи:
git log -p
Получим:
commit b110a9a89cdcf58f8493bec0f865029d0805b826 (HEAD -> master)
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:27:37 2022 +0300
test2.txt moved to test1.txt
diff --git a/test2.txt b/test1.txt
similarity index 100%
rename from test2.txt
rename to test1.txt
commit cea61760b9ee1597baddbb5ee1d32d19a5bca029
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:21:13 2022 +0300
test1 removed
diff --git a/test1.txt b/test1.txt
deleted file mode 100644
index aecca03..0000000
--- a/test1.txt
+++ /dev/null
@@ -1,3 +0,0 @@
:
Т.е. в вывод добавилась информация о пачтчах в каждом из коммитов.
Если мы хотим получит краткую информацию по каждому коммиту, нужно использовать ключ --stat
Вводим команду:
git log --stat
Получим:
commit b110a9a89cdcf58f8493bec0f865029d0805b826 (HEAD -> master)
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:27:37 2022 +0300
test2.txt moved to test1.txt
test2.txt => test1.txt | 0
1 file changed, 0 insertions(+), 0 deletions(-)
commit cea61760b9ee1597baddbb5ee1d32d19a5bca029
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:21:13 2022 +0300
test1 removed
test1.txt | 3 ---
1 file changed, 3 deletions(-)
commit da3a16675b300de24c2e2d13ce75b05ca445d0d4
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:20:11 2022 +0300
test2.txt changed
:
Чтобы отфильтровать выдачу по нужным файлам, следует в конце команды добавить двойной дефис --
и
через пробел путь к файлу:
git log --stat -- test1.txt
Получим:
commit b110a9a89cdcf58f8493bec0f865029d0805b826 (HEAD -> master)
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:27:37 2022 +0300
test2.txt moved to test1.txt
test1.txt | 3 +++
1 file changed, 3 insertions(+)
commit cea61760b9ee1597baddbb5ee1d32d19a5bca029
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:21:13 2022 +0300
test1 removed
test1.txt | 3 ---
1 file changed, 3 deletions(-)
commit 0bf151bc6c5fbd646b818f69569555cbf4684307
Author: alex <aok@buran.rest>
Date: Wed Sep 7 17:54:13 2022 +0300
add test2.txt
test1.txt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
commit 85d79a40621cef6bc903347dab67583339bf7fdd
Author: alex <aok@buran.rest>
Date: Wed Sep 7 17:34:18 2022 +0300
test1.txt filled
test1.txt | 1 +
1 file changed, 1 insertion(+)
commit 7856af838da90be3db0674724050bbefc16b4116
Author: alex <aok@buran.rest>
Date: Wed Sep 7 16:51:26 2022 +0300
init
test1.txt | 0
1 file changed, 0 insertions(+), 0 deletions(-)
Обратите внимание: все коммиты уместились в выдаче, поэтому гит не запустил интерактивную программу, а просто вывел их.
Также есть возможность выводить информацию по каждому коммиту вообще в одну строку:
git log --pretty=oneline
Получим:
b110a9a89cdcf58f8493bec0f865029d0805b826 (HEAD -> master) test2.txt moved to test1.txt
cea61760b9ee1597baddbb5ee1d32d19a5bca029 test1 removed
da3a16675b300de24c2e2d13ce75b05ca445d0d4 test2.txt changed
f7dfda1acda795011800a1a392447396e643440c test2.txt filled
0bf151bc6c5fbd646b818f69569555cbf4684307 add test2.txt
85d79a40621cef6bc903347dab67583339bf7fdd test1.txt filled
7856af838da90be3db0674724050bbefc16b4116 init
Теперь рассмотрим параметр -S <changed-line>
, он выводит только те коммиты, в которых эта строка
присутствует в изменениях.
Например, если мы хотим найти коммиты, в которых изменился текст второй тестовый
git log -S "второй тестовый"
Получим:
Author: alex <aok@buran.rest>
Date: Wed Sep 7 18:14:33 2022 +0300
test2.txt filled
Операции отмены*
Вам нужно просто прочитать этот блок и приступать к выполнению задания. Команды выполнять не требуется.
Если вы создали коммит, но забыли добавить нужные изменения, просто добавьте их в индекс, после чего выполните комнаду:
git commit --amend
В этом случае все проиндексированные патчи просто добавятся в последний сделанный коммит.
Когда выполняете ту или иную отмену действий, будьте внимательны: если поступать бездумно, можно навсегда потерять ваш код.
Очистим содержимое файла test1.txt
и сохраним:
git status
Получим:
On branch master
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: test1.txt
no changes added to commit (use "git add" and/or "git commit -a")
Теперь отменим изменения в файле test1.txt
при помощи команды git checkout
:
git checkout test1.txt
Получим:
Updated 1 path from the index
Содержимое файла вернулось:
Задание
Если вы выполнили все блоки теории в этой главе, то вам останется
только опубликовать ваш локальный репозиторий на сервере github
.
Вам необходимо создать свой репозиторий, в котором добавлены следующие коммиты (для каждого сначала указывается название, потом требования):
test1.txt filled
- заполнить файлtest1.txt
текстомЭто тестовый файл
add test2.txt
- создать файлtest2.txt
и заполнить файлtest1.txt
текстомЭто тестовый файл
Или нетtest2.txt filled
- заполнить файлtest2.txt
текстомЭто второй тестовый файл
Но это неточноtest2.txt changed
- поменять текст файлаtest2.txt
на:Это второй тестовый файл
Однозначно тестовыйtest1 removed
- удалить файлtest1.txt
test2.txt moved to test1.txt
- переименовать файлtest2.txt
вtest1.txt
Когда задание будет выполнено, не забудьте сделать push
локальных изменений на сервер
командой
git push origin master
Ссылку на github-репозиторий необходимо отправить в поле ввода задания на сайте mdl.