-
Создай папку
my-project -
Создай внутри файл
hello.txt -
Выполни в контекстном меню папки
my-projectкомандуGitExt Create new repository -
Убедись, что появилась скрытая папка
.git
Для Windows: чтобы отображались скрытые файлы и папки, в проводнике нужно отметить галочку Вид - Скрытые элементы. Лучше рядом также отметить галочку Расширения имен файлов
- Выполни в контекстном меню папки
my-projectкомандуGitExt Open repository. Пока в репозитории пусто. Так и должно быть.
-
Найди в GitHub репозиторий https://github.com/kontur-courses/git-sheet, сделай его fork в свой профиль, а затем склонируй форкнутый репозиторий. НЕ СПУТАЙ: это НЕ репозиторий с презентацией и текстом этого задания!
-
Открой папку
git-sheetв VS Code (File - Open Folder). -
Через VS Code создай файл
init.mdсо следующим содержимым (здесь и далее копировать надо то, что междутройных бэктиков как этот текст, но не сами «бэктики»):
## S1. Everything Is Local
### Все работает локально
1. `git init` — создать пустой репозиторий
2. `git clone <url>` — склонировать репозиторий в новую директорию
-
Открой репозиторий, убедись, что в нем есть коммит с названием
Initial commit -
Нажми кнопку
Commit, чтобы открыть окно коммита -
Переведи
init.mdиз верхней части в нижнюю часть окна кнопкойStageлибо двойным нажатием по имени файла. Теперьinit.mdнаходится вCommit index -
Введи в качестве сообщения к коммиту
Add init.mdи сделай коммит кнопкойCommit -
Убедись, что коммит появился в истории коммитов
-
Создай файл
commit.mdсо следующим содержимым:
## S2. Tree Of Commits
### Хранится последовательность состояний некоторой директории
- Выбери в истории коммитов
Working directoryи убедись, что там есть измененный файлcommit.md - Открой окно коммита и переведи
commit.mdвCommit indexи закрой окно коммита - Выбери в истории коммитов
Commit indexи убедись, что измененный файлcommit.mdтеперь находится там - Замени содержимое
commit.mdна следующее:
## S2. Tree Of Commits
### Хранится последовательность состояний некоторой директории
1. `git add .` — добавить все измененные файлы в индекс
2. `git commit -m <msg>` — записать изменения из индекс в репозиторий
3. `git status -sb` — вывести состояние директории и индекса кратко с указанием текущей ветки
4. `git log --oneline` — вывести список коммитов, связанных с HEAD, в кратком виде
5. `git log --oneline --graph` — вывести историю коммитов, связанных с HEAD, в виде дерева
6. `git log --oneline --graph --all` — вывести историю всех коммитов в виде дерева
- Посмотри историю коммитов. Убедись, что
commit.mdизменен как в вWorking directory, так и вCommit index - Открой окно коммита и убедись, что
commit.mdнаходится как в верхней части окна, так и в нижней, причем содержимое у файлов разное и при выбореcommit.mdв верхней части показывается отличия отCommit index, а не предыдущего коммита - Выполни коммит с сообщением
Add commit.md header - В истории коммитов найди только что созданный коммит и убедись, что в него попали только изменения из
Commit index - Закоммить оставшиеся в
Working directoryизменения с сообщениемChange commit.md
- Выбери в дереве коммитов последний коммит и создай в нем тег
v0.1с помощью контекстного меню - Перейди на
Initial commitс помощью командыCheckout this commitв контекстном меню - Используй пункт главного меню
Commands / Checkout revision, чтобы вернуться обратно на помеченный тегом коммит. Для этого введи имя тегаv0.1в поле для ввода ревизии.
-
Создай новую ветку
branch-featureс помощью контекстного меню. Git Extensions автоматически сделает checkout на нее, а значит при следующем коммите именно она сдвинется вслед заHEAD. -
Создай новый файл
branch.mdсо следующим содержимым:
## S3. Refer To Branch
### Используются именованные ссылки
1. `git tag` — вывести список тегов
2. `git tag <tagname>` — создать тег
3. `git branch` — вывести список локальных веток
4. `git branch -av` - вывести список локальных и удаленных веток
5. `git branch <branchname>` — создать ветку
6. `git branch -d <branchname>` — удалить ветку
7. `git checkout <commit>` — переместить HEAD на коммит
8. `git checkout <branch>` — переместить HEAD на ветку
9. `git checkout -m <branch>` — переместить HEAD, объединить текущие изменения с состоянием ветки
10. `git checkout -b <new_branch>` — создать новую ветку и перейти на нее
-
Закоммить изменения с сообщением
Add branch.md -
Перейди назад на ветку
master, используя контекстное меню и создай веткуbullet-feature -
Во всех доступных md-файлах замени нумерованные списки на ненумерованные списки. На примере init.md это выглядит следующим образом. Было:
## S1. Everything Is Local
### Все работает локально
1. `git init` — создать пустой репозиторий
2. `git clone <url>` — склонировать репозиторий в новую директорию
Стало:
## S1. Everything Is Local
### Все работает локально
- `git init` — создать пустой репозиторий
- `git clone <url>` — склонировать репозиторий в новую директорию
Аналогично сделай для commit.md.
-
Закоммить изменения с сообщением
Replace with bullets -
Перейди назад на ветку
master, используя контекстное меню -
Замени содержимое
commit.mdна следующее:
## S2. Tree Of Commits
### Хранится последовательность состояний некоторой директории
1. `git add .` — добавить все измененные файлы в индекс
2. `git commit -m <msg>` — записать изменения из индекс в репозиторий
3. `git status -sb` — вывести состояние директории и индекса кратко с указанием текущей ветки
4. `git show <commit>` — показать содержимое коммита
5. `git log --oneline` — вывести список коммитов, связанных с HEAD, в кратком виде
6. `git log --oneline --graph` — вывести историю коммитов, связанных с HEAD, в виде дерева
7. `git log --oneline --graph --all` — вывести историю всех коммитов в виде дерева
- Закоммить изменения с сообщением
show command for commit.md - Обрати внимание, что история коммитов стала похожа на дерево, а на концах веток этого дерева расположены
метки
master,branch-feature,bullet-feature. А вот тегv0.1, остался на своем месте.
Правильное дерево коммитов для этого этапа
-
Начни вливать
bullet-featureвmaster:HEADуже находится наmaster, поэтому укажи наbullet-featureи с помощью контекстного меню выбериMerge into current branch. Но выполнениеMergeзакончится конфликтом. Конфликт произошел, потому что в этот файл вносились изменения и вbullet-featureи вmaster. -
Git Extensions предложит сразу перейти ко второй части слияния — разрешению конфликтов. Согласись. Откроется окно
Resolve merge conflictsсо списком файлов с конфликтами. В списке будет только один файл —commit.md. Конфликт произошел, потому что в этот файл вносились изменения и вbullet-featureи вmaster. Нажми на кнопкуOpen in vscodeи в качестве инструмента для объединения изменений откроется VS Code. Часто конфликты разрешаются выбором варианта из одной из веток, но это не тот случай. В VS Code нажмиCompare Changesи убедись, что поменялось все. Придется объединять изменения аккуратно вручную. Сначала выбериAccept Both Changes— теперь текст обоих изменений станет доступен для редактирования. Затем напиши правильную версию блока. В ней должна быть командаgit showи перед каждой командой должны быть дефисы. Когда закончишь редактирование сохрани изменения (как обычноCtrl+S), закрой файл в VS Code и переключись на Git Extensions. -
Git Extensions сообщит, что все конфликты разрешены и предложит перейти к третьей части слияния — коммиту. Согласись. Откроектся знакомое окно коммита, в котором в
Commit indexбудут показаны все изменения относительноHEAD. ВCommit messageбудет указано хорошее подробное сообщение: его можно не менять. Закоммить результаты merge. -
Убедись, что в результате твоих действий был создан новый коммит, объединяющий две ветви изменений.
HEADсдвинулся на него, аmasterсдвинулся заHEAD.
Задание 6. Hidden Conflict
-
Начни вливать
branch-featureвmaster, как и в прошлый раз. Конфликтов в этот раз не будет, поэтому шаг разрешения конфликтов будет пропущен. А еще Git Extensions автоматически сделает commit. Таким образом слияние будет выполнено. -
Хоть «настоящих» конфликтов нет, после слияния появился «логический» конфликт. Дело в том, что файл
branch.mdдо сих пор содержит нумерованный список. Замени числа в нем на дефисы, аналогично другим файлам. -
Теперь пришло время добавить в историю эти изменения. Простой способ это сделать — коммит с сообщением вида
Fix after merge. Прекрасно работает. Но можно воспользоватьсяAmmend Commit. Эта команда позволяет дополнить последний коммит дополнительными изменениями. Открой окно коммита, выбери опциюAmmend Commit: вCommit messageпоявится сообщение из предыдущего коммита, затем добавь вCommit indexфайлbranch.mdи сделай commit. Появится предупреждение о том, что переписывается история. Да, так и есть. Соглашайся.
- Создай ветку
merge-featureи перейди на нее - Создай файл
merge.mdсо следующим содержимым:
## A1. Merge Them All
### Два состояния можно объединить через merge, mergetool и commit
- `git merge <commit>` — объединить текущую ветку с другой
- `git mergetool` — разрешить имеющиеся конфликты
- Закоммить изменения с сообщением
Add merge.md - Перейди назад на ветку
master - Влей
merge-featureвmaster - Заметь, что в этот раз не только конфликтов не было, но и новый коммит не был создан.
Потому что в
masterне было изменений и для объединения двух веток было достаточно передвинутьmasterна коммит, на который ссылаласьmerge-feature.
Правильное дерево коммитов для этого этапа
- Создай ветку
rebase-featureи перейди на нее. Используй сочетаниеCtrl+B, чтобы вызвать диалог создания ветки: так быстрее! - Создай файл
rebase.mdсо следующим содержимым:
## A2. Immutable History
### Нельзя переписать историю — можно создать новую
- `git commit --ammend` — заменить последний коммит ветки на отредактированный с дополнительными изменениями
- `git rebase <upstream>` — применить все коммиты от общего родителя до текущего к `<upstream>`
- `git rebase -i <upstream>` — применить заново все коммиты, указав действие с каждым коммитом
- `git cherry-pick <commit>` — применить указанный коммит к HEAD
- Закоммить изменения с сообщением
Add rebase.mdВоспользуйся сочетаниемCtrl+Space, чтобы открыть окно коммита: так быстрее! - Создай файл
reflog.mdсо следующим содержимым:
## A4. Hide The Garbage
### Видно только то, на что есть ссылки
- `git gc` — удалить ненужные файлы и оптимизировать локальный репозиторий
- `git clean` — удалить неотслеживаемые файлы из директории
- `git reflog show <ref>` — показать лог действий со ссылкой
- `git reflog` = `git reflog show HEAD` — показать лог действий с HEAD
-
Закоммить изменения с сообщением
Add reflog.md. ИспользуйCtrl+Space. -
Перейди на ветку
master. ИспользуйCtrl+.. -
Создай файл
reflog.mdсо следующим содержимым:
## A4. Hide The Garbage
### Lorem ipsum dolor sit amet, consectetur adipiscing elit
-
Закоммить изменения с сообщением
Add stub for reflog.md. ИспользуйCtrl+Space. -
Открой в главном меню пункт
Commands. У большинства команд задано сочетание клавиш. Ты можешь запомнить те из них, которые используешь часто, чтобы применять эти команды быстрее. -
Установи тег
old-rebase-featureна коммит, на который ссылаетсяrebase-feature -
Перейди на ветку
rebase-feature -
Выполни rebase
rebase-featureнаmaster:HEADуже находится наrebase-feature, поэтому укажи наmasterи с помощью контекстного меню выбериRebase current branch on, а затемSelected commit. При rebase возникнет конфликт. -
Первый коммит
Add rebase.mdуспешно скопирован, а вотAdd reflog.mdпо понятным причинам порождает конфликты. Нажми кнопкуSolve conflicts, чтобы разрешить конфликты в VS Code. Несмотря на то, что файлы были созданы в разных ветках, Git видит, что первые строчки совпадают и по ним конфликта нет. А вот оставшиеся строчки конфликтуют. Так как в веткеrebase-featureбыл правильный текст, нажмиAccept Incoming Change, затем сохрани изменения, закрой файл в VS Code, перейди в Git Extensions и нажмиContinue rebase. Раз оба коммита были успешно скопированы, rebase на этом будет закончен. -
Обрати внимание, что в результате rebase были созданы коммиты
Add rebase.mdиAdd reflog.md. Хоть они похожи на исходные, все же это новые коммиты с новыми ревизиями. Веткаrebase-featureбыла перемещена и теперь ссылается на новый коммит. Старые коммиты остались в репозитории и на последний из них все еще ссылается тегold-rebase-feature. -
Перейди на ветку
masterи влей в него изменения изrebase-feature. Это будет fast-forward merge.
- Удали тег
old-rebase-feature. Коммит, на который он ссылался будет скрыт, но продолжит существовать в репозитории. - Выбери пункт главного меню
Commands / Show reflog. В результате ты увидишь список коммитов, по которым передвигалсяHEAD. Найди в списке действиеcommit: Add reflog.mdи выполниCopy SHA-1из контекстного меню. Ревизия этого коммита скопируется в буфер обмена. - Используй пункт главного меню
Commands / Checkout revision, чтобы перейти на коммит с ревизией из буфера обмена. - Убедись, что скрытый коммит найден и снова виден. По крайней мере пока на него ссылается
HEAD. - Перейди на
master
-
Добавь новый репозиторий для синхронизации. Для этого в меню слева найди
Remotesи в контекстном меню выбериManage. В открывшемся окнеRemote repositoriesнажми плюс и введи параметры репозитория. Name: ext Url: https://github.com/kontur-courses/git-sheet-ext Сохрани изменения с помощьюSave changes. После сохранения Git Extensions сам предложит выполнить fetch из добавленного репозитория. Соглашайся. Если не справился с GUI, то то же самое можно сделать через консоль одной командой:git remote add ext https://github.com/kontur-courses/git-sheet-extИ убедиться, что удаленные репозиторий был добавлен с помощью командыgit remote -v -
Для тренировки выполни fetch вручную. Выбери пункт главного меню
Commands / Pull/Fetch. Откроется диалоговое окноFetch. В нем в качествеRemoteвыбериext. Также убедись, что вMerge optionsвыбран пунктDo not merge, only fetch remote changes. Нажми на кнопкуFetch, чтобы получить изменения из удаленного репозитория. Так как fetch уже был выполнен ранее, новых изменений не добавится. -
Убедись, что в истории появилась ветка
ext/sheet-featureиз удаленного репозитория, а также несколько новых коммитов.
-
Выполни
Checkout branchна веткуext/sheet-feature. Git Extensions предложить создать связанную локальную ветку с именемsheet-feature. Согласись. В удаленную ветку нельзя коммитить, поэтому создание локальной ветки чаще всего необходимо. Но не обязательно. -
Выполни интерактивный rebase
sheet-featureнаmaster: укажи наmasterи с помощью контекстного меню выбериRebase current branch to, а затемSelected commit interactively. Откроется текстовый редактор. -
В текстовом редакторе описан сценарий действий для rebase. Сейчас он заключается в том, что надо взять и переместить на новое место все коммиты последовательно: сначала первый, затем второй и т.д. Все как обычно. Ниже сценария приведены комментарии по возможным действиям с коммитами. Прочитай, что делает
reword,squashиfixup. -
В первой строчке файла замени
pickнаreword, а последующих строчках замениpickнаfixup. Сохрани изменения и закрой текстовый редактор. Редактор откроется снова и в нем надо будет ввести новое сообщение дляSheet markup. Введи в качестве сообщенияExtension. -
Убедись, что ветка
sheet-featureтеперь ссылается на новый коммит с названиемExtension. А внутри этого коммита объединены все изменения скопированных коммитов. -
Перейди на ветку
masterи влей в него изменения изsheet-feature. Это будет fast-forward merge. -
Удали ветку
sheet-featureиспользуя контекстное меню. При удалении выбериForce delete, потому что эта ветка связана сext/sheet-feature, которая вmasterне влита.
Правильное дерево коммитов для этого этапа
- Создай новый файл
push.mdсо следующим содержимым:
## R2. Will Push Force Be With You
### Изменить удаленный репозиторий — это push
- `git push <remote> <local_branch>:<remote_branch>` — добавить изменения из локальной ветки `<local_branch>` и переместить ветку `<remote_branch>` удаленного репозитория
- `git push` = `git push origin HEAD` — добавить изменения из текущей локальной ветки и переместить соответствующую ветку удаленного репозитория
-
Закоммить изменения с сообщением
Add push.md -
Сделай push локальной ветки
masterвmasterизoriginс помощьюCommands / Pushв главном меню. -
Замени содержимое
push.mdна следующее:
## R2. Will Push Force Be With You
### Изменить удаленный репозиторий — это push
- `git push <remote> <local_branch>:<remote_branch>` — добавить изменения из локальной ветки `<local_branch>` и переместить ветку `<remote_branch>` удаленного репозитория
- `git push` = `git push origin HEAD` — добавить изменения из текущей локальной ветки и переместить соответствующую ветку удаленного репозитория
- `git push -f` — выполнить `push`, даже если удаленная ветка находится в другом поддереве
- `git push <remote> -d <branch>` — удалить ветку в удаленном репозитории
- Закоммить изменения с опцией
Ammend Commit, чтобы не создавать лишний коммит. - Обрати внимание, что старый коммит остался видимым, ведь на него ссылается
origin/master. - Если сейчас выполнить push, то он завешится ошибкой, т.к. навозможно продвинуть
origin/masterвперед по истории так, чтобы он стал ссылаться на коммит, на который ссылаетсяmaster. Поэтому выполни push с опцией force. Простой способ это сделать — выполнить push, а при возникновении ошибки выбратьForce push.
- Создай ветку
upstream-featureи перейди на нее - Создай новый файл
upstream.mdсо следующим содержимым:
## R3. Upstream Mapping
### Связь локальных и удаленных веток устанавливается явно
- `git branch -vv` — вывести список локальных веток с указанием привязанных к ним upstream-веток
- `git branch -u <upstream> [<branchname>]` — задать upstream-ветку для указанной или текущей ветки
- `git push -u origin HEAD` — создать удаленную ветку, соответствующую локальной и установить между ними upstream-связь, затем добавить изменения из локальной ветки в удаленный репозиторий
- `git checkout <remote_branchname>` — создать локальную ветку, соответствующую удаленной и установить между ними upstream-связь, затем переместить HEAD на нее
- `git pull` = `git pull origin` — получить содержимое основного удаленного репозитория и влить изменения из удаленной ветки в соответствующую локальную ветку
- `git pull --ff-only` — получить содержимое, а затем влить, если возможен fast-forward merge
- `git pull --rebase` — получить содержимое и выполнить rebase локальной ветки на удаленную ветку
- `git config --global push.default simple` — задать simple-режим действий с upstream-связями при push. Это режим по умолчанию в Git 2.0 и выше
- Закоммить изменения с сообщением
Add upstream.md - Начни делать push этой ветки.
Git Extensions предупредит, что ветки в удаленном репозитории еще нет. Надо согласиться.
Затем Git Extensions предупредит, что у ветки
upstream-featureеще нет связи с удаленной веткой и предложит ее установить. Тоже надо согласиться. В результате Git Extensions выполнит примерно такую команду:push -u origin upstream-feature:upstream-feature. То же самое можно сделать через консоль такой командой:push -u origin HEAD
- Перейди на ветку
master. - Создай ветку
reset-featureи перейди на нее - Создай новый файл
reset.mdсо следующим содержимым:
## A3. Reset The Difference
### Хранятся файлы, разница вычисляется на лету
-
Закоммить изменения с сообщением
Add reset.md -
Замени содержимое
reset.mdна следующее:
## A3. Reset The Difference
### Хранятся файлы, разница вычисляется на лету
- `git reset --hard <commit>` — переместить текущую ветку на `<commit>`, задать индекс и директорию согласно коммиту, устранив всю разницу
- `git reset --mixed <commit>` — переместить текущую ветку на `<commit>`, задать индекс согласно коммиту, оставить разницу между исходным и новым состоянием в директории
- `git reset --soft <commit>` — переместить текущую ветку на `<commit>`, не задавать индекс и директорию согласно коммиту, а оставить разницу между исходным и новым состоянием в индексе и директории
- `git reset --hard HEAD~1` — отменить последний коммит
- `git stash` — сохранить все модифицированные файлы в виде набора изменений
- `git stash pop` — восстановить последний сохраненный набор изменений и удалить его из списка
- `git stash list` — показать список сохраненных наборов изменений
- Ты не влил
upstream-featureвmaster, поэтому придется прервать работу. Выбери пункт главного менюCommands / Manage stashes. Откроется окноStashдля управления сохраненными изменениями. НажмиStash all changes, чтобы создать новый stash. Закрой окно. Обрати внимание, что вWorking directoryизменения пропали. - Перейди на ветку
master, влей в нее веткуupstream-feature, сделай push. - Перейди назад на ветку
reset-feature. - Верни изменения из stash. Для этого выбери пункт главного меню
Commands / Manage stashes. Так как пока сохранен только один stash, просто нажмиApply Selected Stash. Изменения попадут вWorking directory. - Закоммить изменения с сообщением
Change reset.md - Похоже разработка закончена, поэтому можно влить в нее
masterи отдать в тестирование. Влейmaster.
- К сожалению ты забыл добавить некоторые изменения в
reset-feature. Придется отменить merge. Хорошо, что ещеreset-featureне запушен. - Выбери коммит
Change reset.mdи с помощью контекстного меню выполниReset current branch to here. В открывшемся окне выбери опциюHard, чтобы полностью затереть все изменения, и выполни reset. - Замени содержимое
reset.mdна следующее:
## A3. Reset The Difference
### Хранятся файлы, разница вычисляется на лету
- `git reset --hard <commit>` — переместить текущую ветку на `<commit>`, задать индекс и директорию согласно коммиту, устранив всю разницу
- `git reset --mixed <commit>` — переместить текущую ветку на `<commit>`, задать индекс согласно коммиту, оставить разницу между исходным и новым состоянием в директории
- `git reset --soft <commit>` — переместить текущую ветку на `<commit>`, не задавать индекс и директорию согласно коммиту, а оставить разницу между исходным и новым состоянием в индексе и директории
- `git reset --hard HEAD~1` — отменить последний коммит
- `git stash` — сохранить все модифицированные файлы в виде набора изменений
- `git stash pop` — восстановить последний сохраненный набор изменений и удалить его из списка
- `git stash list` — показать список сохраненных наборов изменений
- `git revert <commit>` — создать коммит, отменяющий изменения из коммита
- `git diff <from_commit> [<to_commit>]` — вывести разницу между двумя коммитами
- `git diff --name-status <from_commit> [<to_commit>]` — список измененных файлов
- `git difftool <from_commit> [<to_commit>]` - вывести разницу с помощью difftool из настроек
- Закоммить изменения с сообщением
Change reset.md again - Снова влей
masterвreset-feature, чтобы в ней были все актуальные изменения. - Перейди в
master. Пришло запушить последнуюю версию. Для этого влейreset-featureвmasterи сделай push. Так как вmasterне произошло изменений с последнего влитияmasterвreset-feature, это будет fast-forward merge.
- Выбери начальный коммит
Initial commitи с помощью контекстного меню выполниReset current branch to here. В открывшемся окне выбери опциюSoft, чтобы вся разница между коммитами оказалась вCommit index, и выполни reset. - Создай ветку
solvedи перейди на нее - Закоммить изменения с сообщением
Solved - Сделай push