Skip to content

Latest commit

 

History

History
700 lines (497 loc) · 54.3 KB

git-ext.md

File metadata and controls

700 lines (497 loc) · 54.3 KB

Задание 1. Init Repo

  1. Создай папку my-test-project

  2. Создай внутри файл hello.txt

  3. Выполни в контекстном меню папки my-test-project команду GitExt Create new repository

  4. Убедись, что появилась скрытая папка .git

Для Windows: чтобы отображались скрытые файлы и папки, в Проводнике нужно отметить галочку Вид / Скрытые элементы. Лучше рядом также отметить галочку Расширения имен файлов.

  1. Выполни в контекстном меню папки my-test-project команду GitExt Open repository. Пока в репозитории пусто. Так и должно быть.

  2. Удали папку my-test-project, она дальше не понадобится

Задание 2. Fork and Config

  1. Найди в GitHub репозиторий https://github.com/kontur-courses/git-rules, сделай его fork в свой профиль, а затем склонируй репозиторий, полученный после форка.

НЕ СПУТАЙ: это НЕ репозиторий с презентацией и текстом этого задания!

Адрес репозитория можно узнать, нажав на зеленую кнопку «Code» на странице репозитория.
НЕ СПУТАЙ: если ты клонируешь репозиторий, у которого в адресе есть kontur-courses, то ты забыл сделать форк!
Если настраивал SSH для GitHub, то в меню, открывшемся после нажатия на кнопку, выбери вкладку SSH и используй адрес из этой вкладки! Не забудь после этого перейти в папку с репозиторием в терминале: cd git-rules.

  1. В склонированной папке найди файлы apply-gitconfig-for-win.cmd и apply-gitconfig-for-nix.sh. Файл apply-gitconfig-for-win.cmd подключает к конфигурации репозитория настройки для Windows, а файл apply-gitconfig-for-nix.sh подключает настройки для Linux и Mac. В зависимости от своей операционной системы, выполни один из файлов. Если на Linux или Mac не хватает прав, то выполни в терминале sh apply-gitconfig-for-nix.sh. Подключение этих файлов позволит настроить Git в этом репозитории для выполнения заданий, при этом твои личные настройки Git не поменяются.

Если git status все равно не показывает изменения, то проверь имя созданного файла: должно быть init.md.

  1. Открой папку git-rules в VS Code (File / Open Folder в главном меню)

  2. Открой репозиторий с помощью контекстного меню Проводника. Убедись, что в нем есть коммит с названием Initial commit.

История коммитов должна выглядеть так:

Задание 3. Commits

  1. Через VS Code создай файл init.md со следующим содержимым:
## S1. Все локально
#### Все данные хранятся в локальных репозиториях, изменения между ними можно синхронизировать
1. `git init` — создать пустой репозиторий
2. `git clone <url>` — склонировать репозиторий в новую директорию
  1. Нажми кнопку Commit, чтобы открыть окно коммита

  2. Переведи init.md из верхней части в нижнюю часть окна кнопкой Stage либо двойным нажатием по имени файла. Теперь init.md находится в Commit index.

Если Git Extensions не показывает изменений, то ты скорее всего забыл сохранить файл, потому что привык работать в IDE, которые делают это за тебя. VS Code тоже умеет сохранять изменения автоматически: в главном меню открой File и поставь галочку Auto Save.

Если Git Extensions все равно не показывает изменения, то проверь имя созданного файла: должно быть init.md.

  1. Введи в качестве сообщения к коммиту Add init.md и сделай коммит кнопкой Commit

  2. Убедись, что коммит появился в истории коммитов

  3. Создай файл commit.md со следующим содержимым:

## S2. Хранятся состояния директории, постепенная сборка коммита
#### Хранятся файлы, разница вычисляется на лету
#### Commit index для сборки коммита
  1. Выбери в истории коммитов Working directory и убедись, что там не появились изменения в файле commit.md. А все потому что есть файл .gitignore, который сейчас заставляет Git игнорировать все файлы с расширением .md, кроме init.md.

  2. Удали правило *.md из .gitignore и сохрани изменения

  3. Снова выбери в истории коммитов Working directory и убедись, что там теперь есть изменения в файлах .gitignore и commit.md

  4. Открой окно коммита и переведи .gitignore и commit.md в Commit index и закрой окно коммита

  5. Выбери в истории коммитов Commit index и убедись, что измененные файлы .gitignore и commit.md теперь находится там

  6. Замени содержимое commit.md на следующее:

## S2. Хранятся состояния директории, постепенная сборка коммита
#### Хранятся файлы, разница вычисляется на лету
#### Commit index для сборки коммита
1. `git add .` — добавить все измененные файлы в индекс
2. `git commit -m <msg>` — записать изменения из индекса в репозиторий
3. `git status -sb` — вывести состояние директории и индекса кратко с указанием текущей ветки
4. `git restore .` или `git checkout .` — отменить изменения в директории по индексу
5. `git restore -S .` или `git reset .` — отменить изменения индекса по коммиту (отмена `git add .`)
6. `git rm <filename>` — удалить файл из индекса, чтобы перестать хранить его историю в репозитории
  1. Посмотри историю коммитов. Убедись, что commit.md изменен как в в Working directory, так и в Commit index

  2. Открой окно коммита и убедись, что commit.md находится как в верхней части окна, так и в нижней, причем содержимое у файлов разное и при выборе commit.md в верхней части показывается отличия от Commit index, а не предыдущего коммита

  3. Выполни коммит с сообщением Add commit.md header

  4. В истории коммитов найди только что созданный коммит и убедись, что в него попали только изменения из Commit index

  5. Закоммить оставшиеся в Working directory изменения с сообщением Change commit.md. Здесь и далее под фразой «закоммить изменения» будет подразумеваться добавление изменений в Commit index и само выполнение коммита.

Теперь история коммитов должна выглядеть так:

Задание 4. Tag

  1. Выбери в дереве коммитов последний коммит и создай в нем тег v0.1 с помощью контекстного меню

  2. Перейди на Initial commit с помощью команды Checkout this commit в контекстном меню

  3. Используй пункт главного меню Commands / Checkout revision, чтобы вернуться обратно на помеченный тегом коммит. Для этого введи имя тега v0.1 в поле для ввода ревизии.

  4. Выполни Checkout branch на ветку master с помощью контекстного меню на текущем коммите

Теперь история коммитов должна выглядеть так:

Задание 5. Feature Branches

  1. Создай новый файл branch.md со следующим содержимым:
## S3. Манипуляции через ссылки, нет ссылки — в мусор
#### HEAD — текущая ссылка, tag — фиксированная ссылка, branch — движущаяся за HEAD ссылка
#### checkout — перемещение на ветку или коммит, reset — перемещение с веткой на коммит
#### Видно то, на что есть ссылки, остальное — мусор
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>` или `git switch --detach <commit|branch>` — переместить HEAD на коммит, причем получится detached HEAD
8. `git checkout <branch>`или `git switch <branch>` — переместить HEAD на ветку
9. `git checkout -b <new_branch>` или `git switch -c <new_branch>` — создать ветку и перейти на нее
10. `git reset --hard <commit>` — переместить HEAD и текущую ветку на `<commit>`
  1. Закоммить изменения с сообщением Add branch.md

  2. Ой! Эти же изменения надо было делать в новой ветке! Теперь придется исправлять! Сейчас ветка master находится на коммите Add branch.md, а должна находиться на коммите Change commit.md. А на коммите Add branch.md должна быть новая ветка branch-feature, которую надо было создать. Убедись, что в истории коммитов все именно так, как описано, и осознай проблему.

  3. То, что ветка branch-feature не была создана сразу — это не проблема. Просто возьми и создай новую ветку branch-feature с помощью контекстного меню на текущем коммите. Git Extensions автоматически сделает checkout на нее.

  4. Теперь надо вернуть master на коммит Change commit.md. С этим может помочь команда reset, которая не просто перемещает HEAD, но также перемещает ветку, на которую HEAD указывает. Но текущая ветка — это branch-feature, а нужно, чтобы текущей был master. Выполни Checkout branch на ветку master с помощью контекстного меню на текущем коммите.

  5. Наконец, выбери в истории коммит Change commit.md, найди в контекстном меню команду Reset current branch to here..., в открывшемся диалоговом окне выбери Hard, а затем OK. Перемещение HEAD и master должно произойти.

  6. Теперь master на месте и, чтобы продолжить развивать branch-feature, надо было бы перейти на нее с помощью Checkout branch. Но делать это не надо, ведь сейчас надо будет сделать новую фичу в новой ветке относительно master.

  7. Используя контекстное меню создай ветку bullet-feature

  8. Во всех доступных md-файлах замени нумерованные списки на ненумерованные списки. На примере init.md это выглядит следующим образом. Было:

## S1. Все локально
#### Все данные хранятся в локальных репозиториях, изменения между ними можно синхронизировать
1. `git init` — создать пустой репозиторий
2. `git clone <url>` — склонировать репозиторий в новую директорию

Стало:

## S1. Все локально
#### Все данные хранятся в локальных репозиториях, изменения между ними можно синхронизировать
- `git init` — создать пустой репозиторий
- `git clone <url>` — склонировать репозиторий в новую директорию

Аналогично сделай для commit.md.

  1. Закоммить изменения с сообщением Replace with bullets

  2. Перейди назад на ветку master, используя контекстное меню

  3. Замени содержимое commit.md на следующее:

## S2. Хранятся состояния директории, постепенная сборка коммита
#### Хранятся файлы, разница вычисляется на лету
#### Commit index для сборки коммита
1. `git add .` — добавить все измененные файлы в индекс
2. `git commit -m <msg>` — записать изменения из индекса в репозиторий
3. `git status -sb` — вывести состояние директории и индекса кратко с указанием текущей ветки
4. `git restore .` или `git checkout .` — отменить изменения в директории по индексу
5. `git restore -S .` или `git reset .` — отменить изменения индекса по коммиту (отмена `git add .`)
6. `git rm <filename>` — удалить файл из индекса, чтобы перестать хранить его историю в репозитории
7. `git show <commit>` — показать содержимое коммита
8. `git log --oneline --decorate --graph` — вывести историю коммитов от HEAD в виде дерева
9. `git log --oneline --decorate --graph --all` — вывести историю всех коммитов в виде дерева
10. `gitk` — открыть графическое представление репозитория
11. `git clean` — удалить неотслеживаемые файлы из директории
  1. Закоммить изменения с сообщением New commands for commit.md

  2. Обрати внимание, что история коммитов стала похожа на дерево, а на концах веток этого дерева расположены метки master, branch-feature, bullet-feature. А вот тег v0.1, остался на своем месте.

Теперь история коммитов должна выглядеть так:

Задание 6. Merge Conflict

  1. Начни вливать bullet-feature в master: HEAD уже находится на master, поэтому укажи на bullet-feature и с помощью контекстного меню выбери Merge into current branch. Но выполнение Merge закончится конфликтом в файле commit.md. Конфликт произошел, потому что в этот файл вносились изменения и в bullet-feature и в master.

  2. Git Extensions предложит сразу перейти ко второй части слияния — разрешению конфликтов. Согласись. Откроется окно Resolve merge conflicts со списком файлов с конфликтами. В списке будет только один файл — commit.md. Конфликт произошел, потому что в этот файл вносились изменения и в bullet-feature и в master. Нажми на кнопку Open in vscode и в качестве инструмента для объединения изменений откроется VS Code. Часто конфликты разрешаются выбором варианта из одной из веток, но это не тот случай. Придется объединять изменения аккуратно вручную. Сначала выбери Accept Both Changes — теперь текст обоих изменений станет доступен для редактирования. Затем напиши правильную версию блока. В ней должна быть команда git show и перед каждой командой должны быть дефисы. Когда закончишь редактирование сохрани изменения (как обычно Ctrl+S), закрой файл в VS Code (вкладку с файлом или полностью VS Code) и переключись на Git Extensions. Важно! Если вкладку с файлом в VS Code не закрыть, то Git Extensions не будет реагировать, т.к. будет продолжать ждать завершения разрешения конфликтов.

  3. Git Extensions сообщит, что все конфликты разрешены и предложит перейти к третьей части слияния — коммиту. Согласись. Откроектся знакомое окно коммита, в котором в Commit index будут показаны все изменения относительно HEAD. В Commit message будет указано хорошее сообщение: его можно не менять. Закоммить результаты merge.

  4. Убедись, что в результате твоих действий был создан новый коммит, объединяющий две ветви изменений. HEAD сдвинулся на него, а master сдвинулся за HEAD.

Теперь история коммитов должна выглядеть так:

Задание 7. Hidden Conflict

  1. Начни вливать branch-feature в master, как и в прошлый раз. Конфликтов в этот раз не будет, поэтому шаг разрешения конфликтов будет пропущен. А еще Git Extensions автоматически сделает commit. Таким образом слияние будет выполнено.

  2. Хоть «настоящих» конфликтов нет, после слияния появился «логический» конфликт. Дело в том, что файл branch.md до сих пор содержит нумерованный список. Замени числа в нем на дефисы, аналогично другим файлам.

  3. Теперь пришло время добавить в историю эти изменения. Но чтобы было понятно, что эти изменения относятся к слиянию, хочется их добавить не в новый коммит, а в предыдущий. Это можно сделать с помощью Amend Commit. Эта команда позволяет дополнить последний коммит дополнительными изменениями. Открой окно коммита, выбери опцию Amend Commit: в Commit message появится сообщение из предыдущего коммита, затем добавь в Commit index файл branch.md и сделай commit. Появится предупреждение о том, что переписывается история. Да, так и есть. Соглашайся.

Теперь история коммитов должна выглядеть так:

Задание 8. Fast-Forward Merge

  1. Создай ветку merge-feature и перейди на нее

  2. Создай файл merge.md со следующим содержимым:

## A1. Трехсторонний merge в три шага
#### Два состояния можно объединить через merge, mergetool и commit
#### Участвуют три стороны: current, incoming и base
- `git merge <commit>` — объединить текущую ветку с другой
- `git mergetool` — разрешить имеющиеся конфликты
- `git merge --abort` — отменить слияние
  1. Закоммить изменения с сообщением Add merge.md

  2. Перейди назад на ветку master

  3. Влей merge-feature в master

  4. Заметь, что в этот раз не только конфликтов не было, но и новый коммит не был создан. Потому что в master не было изменений и для объединения двух веток было достаточно передвинуть master на коммит, на который ссылалась merge-feature.

Теперь история коммитов должна выглядеть так:

Задание 9. Hot Rebase

  1. Создай ветку rebase-feature и перейди на нее. Используй сочетание Ctrl+B, чтобы вызвать диалог создания ветки: так быстрее!

  2. Создай файл rebase.md со следующим содержимым:

## A2. rebase, cherry-pick и amend, чтобы пересоздать историю
#### Нельзя переписать историю — можно создать новую
- `git commit --amend --no-edit` — заменить последний коммит ветки на отредактированный с дополнительными изменениями без изменения сообщения
- `git rebase <upstream>` — применить все коммиты от общего родителя до текущего к `<upstream>`
- `git rebase -i <upstream>` — применить заново все коммиты, указав действие с каждым коммитом
- `git rebase --continue` — продолжить rebase после разрешения конфликтов
- `git rebase --abort` — отменить rabase
- `git cherry-pick <commit>` — применить указанный коммит к HEAD
  1. Закоммить изменения с сообщением Add rebase.md. Воспользуйся сочетанием Ctrl+Space, чтобы открыть окно коммита: так быстрее!

  2. Замени содержимое branch.md на следующее:

## S3. Манипуляции через ссылки, нет ссылки — в мусор
#### HEAD — текущая ссылка, tag — фиксированная ссылка, branch — движущаяся за HEAD ссылка
#### checkout — перемещение на ветку или коммит, reset — перемещение с веткой на коммит
#### Видно то, на что есть ссылки, остальное — мусор
- `git tag` — вывести список тегов
- `git tag <tagname>` — создать тег
- `git branch` — вывести список локальных веток
- `git branch -av` — вывести список локальных и удаленных веток
- `git branch <branchname>` — создать ветку
- `git branch -d <branchname>` — удалить ветку
- `git checkout <commit>` или `git switch --detach <commit>` — переместить HEAD на коммит, причем получится detached HEAD
- `git checkout <branch>`или `git switch <branch>` — переместить HEAD на ветку
- `git checkout -b <new_branch>` или `git switch -c <new_branch>` — создать ветку и перейти на нее
- `git reset --hard <commit>` — переместить HEAD и текущую ветку на `<commit>`
- `git reflog show <ref>` — показать лог действий со ссылкой
- `git reflog` = `git reflog show HEAD` — показать лог действий с HEAD
- `git gc` — удалить ненужные файлы и оптимизировать локальный репозиторий
  1. Закоммить изменения с сообщением Change branch.md. Используй Ctrl+Space.

  2. Перейди на ветку master. Используй Ctrl+..

  3. Замени содержимое branch.md на следующее:

## S3. Манипуляции через ссылки, нет ссылки — в мусор
#### HEAD — текущая ссылка, tag — фиксированная ссылка, branch — движущаяся за HEAD ссылка
#### checkout — перемещение на ветку или коммит, reset — перемещение с веткой на коммит
#### Видно то, на что есть ссылки, остальное — мусор
- `git tag` — вывести список тегов
- `git tag <tagname>` — создать тег
- `git branch` — вывести список локальных веток
- `git branch -av` — вывести список локальных и удаленных веток
- `git branch <branchname>` — создать ветку
- `git branch -d <branchname>` — удалить ветку
- `git checkout <commit>` или `git switch --detach <commit>` — переместить HEAD на коммит, причем получится detached HEAD
- `git checkout <branch>`или `git switch <branch>` — переместить HEAD на ветку
- `git checkout -b <new_branch>` или `git switch -c <new_branch>` — создать ветку и перейти на нее
- `git reset --hard <commit>` — переместить HEAD и текущую ветку на `<commit>`
### Lorem ipsum dolor sit amet, consectetur adipiscing elit
  1. Закоммить изменения с сообщением Add reflog stub to branch.md. Используй Ctrl+Space.

  2. Открой в главном меню пункт Commands. У большинства команд задано сочетание клавиш. Ты можешь запомнить те из них, которые используешь часто, чтобы применять эти команды быстрее.

  3. Установи тег old-rebase-feature на коммит, на который ссылается rebase-feature

  4. Перейди на ветку rebase-feature

  5. Выполни rebase rebase-feature на master: HEAD уже находится на rebase-feature, поэтому укажи на master и с помощью контекстного меню выбери Rebase current branch on, а затем Selected commit. При rebase возникнет конфликт.

  6. Первый коммит Add rebase.md успешно скопирован, а вот Change branch.md по понятным причинам порождает конфликты. Нажми кнопку Solve conflicts, чтобы разрешить конфликты в VS Code. Несмотря на то, что файлы были созданы в разных ветках, Git видит, что первые строчки совпадают и по ним конфликта нет. А вот оставшиеся строчки конфликтуют. Так как в ветке rebase-feature был правильный текст, нажми Accept Incoming Change, затем сохрани изменения, закрой файл в VS Code (важно!), перейди в Git Extensions и нажми Continue rebase. Раз оба коммита были успешно скопированы, rebase на этом будет закончен.

  7. Обрати внимание, что в результате rebase были созданы коммиты Add rebase.md и Change branch.md. Хоть они похожи на исходные, все же это новые коммиты с новыми ревизиями. Ветка rebase-feature была перемещена и теперь ссылается на новый коммит. Старые коммиты остались в репозитории и на последний из них все еще ссылается тег old-rebase-feature.

  8. Перейди на ветку master и влей в нее изменения из rebase-feature. Влитие получится в режиме fast-forward.

Теперь история коммитов должна выглядеть так:

Задание 10. Reflog

  1. Удали тег old-rebase-feature. Коммит, на который он ссылался будет скрыт, но продолжит существовать в репозитории.

  2. Выбери пункт главного меню Commands / Show reflog. В результате ты увидишь список коммитов, по которым передвигался HEAD. Найди в списке действие commit: Change branch.md и выполни Copy SHA-1 из контекстного меню. Ревизия этого коммита скопируется в буфер обмена.

  3. Используй пункт главного меню Commands / Checkout revision, чтобы перейти на коммит с ревизией из буфера обмена.

  4. Убедись, что скрытый коммит найден и снова виден. По крайней мере пока на него ссылается HEAD.

Теперь история коммитов должна выглядеть так:

  1. Перейди на master

Теперь история коммитов должна выглядеть так:

Задание 11. Fetch From Remote

  1. Добавь новый репозиторий для синхронизации.
    Для этого в меню слева найди Remotes и в контекстном меню выбери Manage.
    В открывшемся окне Remote repositories нажми плюс и введи параметры репозитория.
    Name: ext
    Url: https://github.com/kontur-courses/git-rules-ext
    Сохрани изменения с помощью Save changes.
    После сохранения Git Extensions сам предложит выполнить fetch из добавленного репозитория. Соглашайся. Если не справился с GUI, то то же самое можно сделать через консоль одной командой:
    git remote add ext https://github.com/kontur-courses/git-rules-ext
    И убедиться, что удаленные репозиторий был добавлен с помощью команды git remote -v

  2. Для тренировки выполни fetch вручную. Выбери пункт главного меню Commands / Pull/Fetch. Откроется диалоговое окно Fetch. В нем в качестве Remote выбери ext. Также убедись, что в Merge options выбран пункт Do not merge, only fetch remote changes. Нажми на кнопку Fetch, чтобы получить изменения из удаленного репозитория. Так как fetch уже был выполнен ранее, новых изменений не добавится.

  3. Убедись, что в истории появилась ветка ext/sheet-feature из удаленного репозитория, а также несколько новых коммитов.

Теперь история коммитов должна выглядеть так:

Задание 12. Interactive Rebase

  1. Выполни Checkout branch на ветку ext/sheet-feature. Git Extensions предложить создать связанную локальную ветку с именем sheet-feature. Согласись на это. В удаленную ветку нельзя коммитить, поэтому создание локальной ветки чаще всего необходимо. Но не обязательно.

  2. Выполни интерактивный rebase sheet-feature на master: укажи на master и с помощью контекстного меню выбери Rebase current branch to, а затем Selected commit interactively. Откроется текстовый редактор.

  3. В текстовом редакторе описан сценарий действий для rebase. Сейчас он заключается в том, что надо взять и переместить на новое место все коммиты последовательно: сначала первый, затем второй и т.д. Все как обычно. Ниже сценария приведены комментарии по возможным действиям с коммитами. Прочитай, что делает reword, squash и fixup.

  4. В первой строчке файла замени pick на reword, а последующих строчках замени pick на fixup. Сохрани изменения и закрой файл со сценарием. После чего сценарий начнет выполняться.

  5. Сразу же редактор откроется снова, потому что команде reword требуется новое сообщение для коммита. В открывшемся редакторе замени текущее сообщение Sheet markup на новое сообщение Extension и закрой файл.

  6. Убедись, что ветка sheet-feature теперь ссылается на новый коммит с названием Extension. А внутри этого коммита объединены все изменения скопированных коммитов.

  7. Перейди на ветку master и влей в него изменения из sheet-feature. Влитие получится в режиме fast-forward.

  8. Удали ветку sheet-feature используя контекстное меню. При удалении выбери Force delete, потому что эта ветка связана с ext/sheet-feature, которая в master не влита.

Теперь история коммитов должна выглядеть так:

Задание 13. Cherry Pick

  1. Надо достать для ветки master изменения из коммита Add runner из ветки solved. В этом случае нужен только один коммит, который находится между другими — значит подойдет cherry-pick. Достань эту вишенку с помощью команды Cherry pick this commit в контекстном меню. В диалоговом окне команды выбери пункт Automatically create a commit. Хотя можно ее не нажимать, а сделать коммит самостоятельно сразу после cherry pick.

  2. Убедись, что в ветке master появилась копия коммита Add runner.

Теперь история коммитов должна выглядеть так:

Задание 14. Push

  1. Создай новый файл push.md со следующим содержимым:
## R2. Удаленное изменение — это push
- `git push <remote> <local_branch>:<remote_branch>` — добавить изменения из локальной ветки `<local_branch>` и переместить ветку `<remote_branch>` удаленного репозитория
- `git push` = `git push origin HEAD` — добавить изменения из текущей локальной ветки и переместить соответствующую ветку удаленного репозитория
  1. Закоммить изменения с сообщением Add push.md

  2. Сделай push локальной ветки master в master из origin с помощью Commands / Push в главном меню.

  3. Замени содержимое push.md на следующее:

## R2. Удаленное изменение — это push
- `git push <remote> <local_branch>:<remote_branch>` — добавить изменения из локальной ветки `<local_branch>` и переместить ветку `<remote_branch>` удаленного репозитория
- `git push` = `git push origin HEAD` — добавить изменения из текущей локальной ветки и переместить соответствующую ветку удаленного репозитория
- `git push -f` — выполнить `push`, даже если удаленная ветка уже не является предком
- `git push --force-with-lease` — выполнить `push`, если является предком или удаленная ветка не сдвигалась (использовать вместо предыдущей команды)
- `git push <remote> -d <branch|tag>` — удалить ветку или тег в удаленном репозитории
- `git push <remote> tag <tag>` — отправить тег в удаленный репозиторий
- `git push <remote> --tags` — отправить все локальные теги в удаленный репозиторий
- `git push --mirror` — выполнить агрессивный `push` для всех тегов, веток и HEAD, подходит для создания удаленной копии локального репозитория
  1. Добавь изменения в Commit Index и закоммить их с опцией Amend Commit, чтобы не создавать лишний коммит.

  2. Обрати внимание, что старый коммит остался видимым, ведь на него ссылается origin/master

Теперь история коммитов должна выглядеть так:

  1. Если сейчас выполнить push, то он завешится ошибкой, т.к. навозможно продвинуть origin/master вперед по истории так, чтобы он стал ссылаться на коммит, на который ссылается master. Поэтому выполни push с опцией Force With Lease. Чтобы ее выбрать в диалоговом окне команды Push нажми на ссылку Show options и выбери эту опцию.

Теперь история коммитов должна выглядеть так:

Задание 15. Upstream

  1. Создай ветку upstream-feature и перейди на нее

  2. Создай новый файл upstream.md со следующим содержимым:

## R3. Явное сопоставление локальных веток с upstream
- `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 pull --rebase --autostash` — сохранить локальные изменения, получить содержимое, выполнить rebase локальной ветки на удаленную ветку, применить сохраненные изменения
- `git config --global push.default simple` — задать simple-режим действий с upstream-связями при push. Это режим по умолчанию в Git 2.0 и выше
  1. Закоммить изменения с сообщением Add upstream.md

  2. Начни делать push этой ветки. Git Extensions предупредит, что ветки в удаленном репозитории еще нет. Надо согласиться. Затем Git Extensions предупредит, что у ветки upstream-feature еще нет связи с удаленной веткой и предложит ее установить. Тоже надо согласиться. В результате Git Extensions выполнит примерно такую команду: push -u origin upstream-feature:upstream-feature. То же самое можно сделать через консоль такой командой: push -u origin HEAD

Теперь история коммитов должна выглядеть так:

Задание 16. Stash

  1. Перейди на ветку master

  2. Создай ветку reset-feature и перейди на нее

  3. Создай новый файл reset.md со следующим содержимым:

## A3. stash, reset, revert для управления изменениями
#### Изменения можно временно припрятать
#### Можно получить разницу между любыми коммитами
#### Коммит можно отменить другим коммитом
  1. Закоммить изменения с сообщением Add reset.md

  2. Замени содержимое reset.md на следующее:

## A3. stash, reset, revert для управления изменениями
#### Изменения можно временно припрятать
#### Можно получить разницу между любыми коммитами
#### Коммит можно отменить другим коммитом
- `git stash` — сохранить все модифицированные файлы в виде набора изменений
- `git stash pop` — восстановить последний сохраненный набор изменений и удалить его из списка
- `git stash list` — показать список сохраненных наборов изменений
- `git reset --hard <commit>` — переместить текущую ветку на `<commit>`, задать индекс и директорию согласно коммиту, устранив всю разницу
- `git reset --mixed <commit>` — переместить текущую ветку на `<commit>`, задать индекс согласно коммиту, оставить разницу между исходным и новым состоянием в директории
- `git reset --soft <commit>` — переместить текущую ветку на `<commit>`, не задавать индекс и директорию согласно коммиту, а оставить разницу между исходным и новым состоянием в индексе и директории
- `git reset --hard HEAD~1` — отменить последний коммит
- `git revert <commit>` — создать коммит, отменяющий изменения из коммита
  1. Ты не влил upstream-feature в master, поэтому придется прервать работу. Выбери пункт главного меню Commands / Manage stashes. Откроется окно Stash для управления сохраненными изменениями. Нажми Stash all changes, чтобы создать новый stash. Закрой окно. Обрати внимание, что в Working directory изменения пропали.

  2. Перейди на ветку master, влей в нее ветку upstream-feature, сделай push

  3. Перейди назад на ветку reset-feature

  4. Верни изменения из stash. Для этого выбери пункт главного меню Commands / Manage stashes. Так как пока сохранен только один stash, просто нажми Apply Selected Stash. Изменения попадут в Working directory.

  5. Закоммить изменения с сообщением Change reset.md

  6. Похоже разработка в ветке reset-feature закончена, поэтому можно влить в нее master и отдать в тестирование. Влей master.

Теперь история коммитов должна выглядеть так:

Задание 17. Hard Reset

  1. К сожалению, ты забыл добавить некоторые изменения в reset-feature. Придется отменить merge. Хорошо, что reset-feature еще не запушен.

  2. Выбери коммит Change reset.md и с помощью контекстного меню выполни Reset current branch to here. В открывшемся окне выбери опцию Hard, чтобы полностью затереть все изменения, и выполни reset.

  3. Замени содержимое reset.md на следующее:

## A3. stash, reset, revert для управления изменениями
#### Изменения можно временно припрятать
#### Можно получить разницу между любыми коммитами
#### Коммит можно отменить другим коммитом
- `git stash` — сохранить все модифицированные файлы в виде набора изменений
- `git stash pop` — восстановить последний сохраненный набор изменений и удалить его из списка
- `git stash list` — показать список сохраненных наборов изменений
- `git reset --hard <commit>` — переместить текущую ветку на `<commit>`, задать индекс и директорию согласно коммиту, устранив всю разницу
- `git reset --mixed <commit>` — переместить текущую ветку на `<commit>`, задать индекс согласно коммиту, оставить разницу между исходным и новым состоянием в директории
- `git reset --soft <commit>` — переместить текущую ветку на `<commit>`, не задавать индекс и директорию согласно коммиту, а оставить разницу между исходным и новым состоянием в индексе и директории
- `git reset --hard HEAD~1` — отменить последний коммит
- `git revert <commit>` — создать коммит, отменяющий изменения из коммита
- `git diff <from_commit> [<to_commit>]` — вывести разницу между двумя коммитами
- `git diff --name-status <from_commit> [<to_commit>]` — список измененных файлов
- `git difftool <from_commit> [<to_commit>]` - вывести разницу с помощью difftool из настроек
  1. Закоммить изменения с сообщением Change reset.md again

  2. Снова влей master в reset-feature, чтобы в ней были все актуальные изменения

  3. Перейди в master. Пришло запушить последнуюю версию. Для этого влей reset-feature в master и сделай push. Так как в master не произошло изменений с последнего влития master в reset-feature, это будет fast-forward merge.

Теперь история коммитов должна выглядеть так:

Задание 18. Soft Reset

  1. Создай ветку solved и перейди на нее

  2. Выбери начальный коммит Initial commit и с помощью контекстного меню выполни Reset current branch to here. В открывшемся окне выбери опцию Soft, чтобы вся разница между коммитами оказалась в Commit index, и выполни reset.

  3. Все изменения уже в Commit index. Поэтому просто закоммить их с сообщением Solved

  4. Сделай push

Теперь история коммитов должна выглядеть так: