Skip to content

Latest commit

 

History

History
715 lines (494 loc) · 55.4 KB

git-cli.md

File metadata and controls

715 lines (494 loc) · 55.4 KB

Задание 1. Init Repo

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

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

  3. Открой терминал Git Bash для Windows. Выполни команду cd путь_до_папки_my-project.

  4. Убедись что путь введен правильно: команда pwd должна вывести правильный путь до папки my-test-project

  5. Выполни команду git init

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

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

Для Mac: чтобы отображались скрытые файлы и папки, нужно в Finder нажать Cmd + Shift + .

Также можно просмотреть список файлов и папок в текущей директории из консоли с помощью команды ls -la

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

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

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

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

Склонировать репозиторий можно с помощью команды git clone. Адрес репозитория можно узнать, нажав на зеленую кнопку «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 не поменяются.

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

  3. Открой Git Graph (кнопка Git Graph в нижней панели VS Code). Убедись, что в нем есть коммит с названием Initial commit.

Также Git Graph можно найти с помощью бокового меню VS Code:

Если Git Graph нет, то возможно это расширение у тебя не установлено. Открой в VS Code в боковом меню пункт Extensions (Ctrl + Shift + X), найди через поиск расширение «Git Graph» и установи.

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

Задание 3. Commits

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

Создать файл можно так:

  1. Выполни команду git status. В секции Untracked files должен находиться init.md, подсвеченный красным цветом.
    Консольные команды здесь и далее удобнее выполнять через встроенный в VS Code терминал,
    который можно открыть сочетанием Ctrl + `, либо через главное меню View / Terminal

Выглядеть должно так:

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

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

  1. Выполни команду git add init.md. Теперь init.md должен находится в Commit Index.

  2. Выполни git status и убедись что init.md находится в секции Changes to be commited и подсвечен зеленым цветом

Выглядеть должно так:

  1. Сделай коммит с сообщением Add init.md. Для этого выполни команду git commit -m "Add init.md".

  2. Открой Git Graph и убедись, что коммит появился в истории коммитов

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

## S2. Хранятся состояния директории, постепенная сборка коммита
#### Хранятся файлы, разница вычисляется на лету
#### Commit index для сборки коммита
  1. Выполни git status и убедись что commit.md не появился в секции Untracked files, да и самой секции нет. А вместо этого есть сообщение «nothing to commit, working tree clean». А все потому, что есть файл .gitignore, который сейчас заставляет Git игнорировать все файлы с расширением .md, кроме init.md.

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

  3. Снова выполни git status и убедись что .gitignore и commit.md теперь появились и подсвечены красным

  4. Добавь все измененные файлы, т.е. .gitignore и commit.md, в Commit Index: git add .

  5. Выполни git status и убедись что .gitignore и commit.md находятся в секции Changes to be commited

  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. Выполни git status. Убедись, что commit.md находится как в Working Directory (секция Changes not staged for commit), так и в Commit Index (секция Changes to be commited)

  2. Открой в VS Code в боковом меню пункт Source Control (Ctrl + Shift + G) и убедись, что commit.md находится как в верхнем списке Staged Changes, так и в нижнем списке Changes, причем содержимое у файлов разное и при выборе commit.md в нижнем списке показываются отличия от Commit Index, а не предыдущего от коммита

  3. Выполни коммит с сообщением Add commit.md header (можешь посмотреть пункт 5, чтобы вспомнить как это делать)

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

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

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

Задание 4. Tag

  1. Создай тег с именем v0.1 с помощью команды git tag "v0.1" и убедись, что у коммита Change commit.md появился тег.

Теги также можно создавать в Git Graph с помощью контекстного меню

  1. Найди в Git Graph начальный коммит Initial commit, выбери его и с помощью контекстного меню выполни Checkout...

  2. Выполни команду git checkout v0.1, чтобы вернуться обратно на помеченный тегом коммит

  3. Выполни команду git checkout master, чтобы вернуться на ветку master на том же коммите

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

Задание 5. Feature Branches

  1. С помощью VS Code создай новый файл 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 Напоминание: сначала add, потом commit

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

  3. То, что ветка branch-feature не была создана сразу — это не проблема. Просто возьми и создай ее на текущем коммите: git branch branch-feature. При этом текущей веткой останется master.

  4. Теперь надо вернуть master на коммит Change commit.md. С этим может помочь команда reset, которая не просто перемещает HEAD, но также перемещает ветку, на которую HEAD указывает. Убедись, что текущая ветка — это master. Если почему-то это не так — надо перейти на master и скорее всего начать задание заново. Коммит Change commit.md — это предыдущий коммит от текущего положения HEAD, поэтому на него можно сослаться по относительному имени HEAD~1. Это удобнее, чем выбирать коммит по хэшу. Так что итоговая команда, которую надо выполнить такая: git reset --hard HEAD~1. Сделай это!

Обычно все же удобнее выполнять команду reset через контекстное меню Git Graph, ведь можно просто выбрать целевой коммит курсором

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

  2. Создай новую ветку bullet-feature и перейди на нее: git checkout -b bullet-feature

Команда git checkout -b <branch-name> создает новую ветку и сразу выполняет checkout на нее. Это эквивалентно паре команд git branch <branch-name> и git checkout <branch-name>

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

Было:

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

Стало:

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

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

  1. Закоммить изменения с сообщением Replace with bullets (ты же помнишь про добавление файлов Commit Index?)

  2. Перейди назад на ветку master (если забыл как, то посмотри как переходил на ветку в «Задание 4. Tag»)

  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 (последнее напоминание: Commit Index!)

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

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

Задание 6. Merge Conflict

  1. Начни вливать bullet-feature в master. Для этого сначала убедись, что HEAD находится на master, а затем выполни команду git merge bullet-feature.

Эта команда вливает указанную ветку в текущую (в ту, на которой сейчас находится HEAD)

Выполнение Merge закончится конфликтом в файле commit.md.
Конфликт произошел, потому что в этот файл вносились изменения и в bullet-feature и в master.

  1. Открой в VS Code в боковом меню пункт Source Control.
    В списке Merge Changes будет файл — commit.md. Выбери его.

Часто конфликты разрешаются выбором варианта из одной из веток, но это не тот случай. Придется объединять изменения аккуратно вручную. Сначала выбери Accept Both Changes — теперь текст обоих изменений станет доступен для редактирования. Затем напиши правильную версию блока. В ней должна быть команды git show, git log и другие, причем перед каждой командой должны быть дефисы. Когда закончишь редактирование, сохрани изменения и добавь commit.md в Commit Index: git add commit.md

  1. Выполни git status. Вывод сообщит, что все конфликты разрешены. Можно коммитить: выполни команду git commit (без опции -m). В VS Code откроется редактор сообщения коммита. Будет указано хорошее сообщение: его можно не менять. Чтобы завершить коммит, достаточно закрыть в редакторе открывшийся файл COMMIT_EDITMSG.

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

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

Задание 7. Hidden Conflict

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

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

  3. Теперь пришло время добавить в историю эти изменения. Но чтобы было понятно, что эти изменения относятся к слиянию, хочется их добавить не в новый коммит, а в предыдущий. Это можно сделать с помощью Amend Commit. Эта команда позволяет дополнить последний коммит дополнительными изменениями: git commit --amend. Добавь изменения файла branch.md в Commit Index (важно, иначе предыдущий коммит будет нечем дополнять!) и выполни Amend commit. Во время выполнения Amend commit откроется текстовый редактор с сообщением предыдущего коммита. Это позволяет изменить сообщение коммита при желании. Но в данном случае сообщение из предыдущего коммита подходит, поэтому просто закрой текстовый редактор. После этого Amend 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 и перейди на нее

  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

  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

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

  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

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

git tag old-rebase-feature rebase-feature

В этой команде первый аргумент — имя тега, а второй — идентификатор коммита. В качестве идентификатора коммита можно передать его хэш или ветку, которая на него указывает

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

  2. Выполни rebase rebase-feature на master: убедись что HEAD уже находится на rebase-feature и выполни команду git rebase master. При rebase возникнет конфликт.

  3. Первый коммит Add rebase.md успешно скопирован, а вот Change branch.md по понятным причинам порождает конфликты. Открой в VS Code в боковом меню пункт Source Control. Несмотря на то, что файлы были созданы в разных ветках, Git видит, что первые строчки совпадают и по ним конфликта нет. А вот оставшиеся строчки конфликтуют. Так как в ветке rebase-feature был правильный текст, нажми Accept Incoming Change. Добавь branch.md в Commit Index и выполни команду git rebase --continue. Раз оба коммита были успешно скопированы, rebase на этом будет закончен. Фанфар по этому поводу не будет. В терминале просто появится сообщение «Applying: Change branch.md» без каких-либо ошибок после.

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

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

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

Задание 10. Reflog

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

  2. Выполни команду git reflog -50

Опция -50 указывает лимит количества действий в рефлоге: будут показаны только последние 50 действий. Результат команды можно скроллить с помощью стрелок «Вверх» и «Вниз». Когда захочешь закрыть список — нажми q.

  1. В результате ты увидишь список коммитов, по которым передвигался HEAD. Найди в списке действие commit: Change branch.md и скопируй хэш коммита в буфер обмена.

  2. Перейди на этот коммит, подставив вместо COPIED_COMMIT_HASH скопированный хэш: git checkout COPIED_COMMIT_HASH

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

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

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

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

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

  1. Добавь новый репозиторий https://github.com/kontur-courses/git-rules-ext для синхронизации:
    git remote add ext https://github.com/kontur-courses/git-rules-ext
    Убедись, что удаленный репозиторий был добавлен: git remote -v

  2. Выполни fetch репозитория: git fetch ext

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

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

Задание 12. Interactive Rebase

  1. Выполни checkout на ветку ext/sheet-feature: git checkout sheet-feature

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

В удаленную ветку нельзя коммитить, поэтому создание локальной ветки чаще всего необходимо. Но не обязательно, ведь можно просто перейти на коммит, на который указывает удаленная ветка.

  1. Выполни интерактивный rebase sheet-feature на master: git rebase -i master, после чего откроется текстовый редактор

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

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

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

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

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

  7. Удали ветку sheet-feature. Это придется сделать с force, потому что эта ветка связана с ext/sheet-feature, которая в master не влита. Force обозначается -D вместо -d в команде. Выполни «усиленное» удаление: git branch -D sheet-feature

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

Задание 13. Cherry Pick

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

  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 с помощью git 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, чтобы не создавать лишний коммит. Если забыл какой командой делать Amend commit, то поищи по слову amend в предыдущих заданиях.

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

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

  1. Если сейчас выполнить push, то он завешится ошибкой, т.к. навозможно продвинуть origin/master вперед по истории так, чтобы он стал ссылаться на коммит, на который ссылается master. Поэтому выполни push с опцией force-with-lease: git push --force-with-lease.

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

Задание 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 push не сработает потому что ветки в удаленном репозитории еще нет. Чтобы она появилась, нужно выполнить команду git push -u origin upstream-feature:upstream-feature. Но Git поймет и более краткие варианты: git push -u origin upstream-feature, git push -u origin HEAD. Выполни push любым из этих способов.

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

Задание 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, поэтому придется прервать работу. Выполни команду git stash. Обрати внимание, что в Working Directory изменения пропали.

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

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

  4. Верни изменения из stash. Для этого выполни команду git stash apply.

Apply не удаляет сохраненные изменения из stash. Если хочется применить изменения и тут же их удалить, то вместо apply надо использовать команду git stash pop

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

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

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

Задание 17. Hard Reset

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

  2. В Git Graph найди коммит Change reset.md, выбери его и с помощью контекстного меню выполни Copy commit hash to clipboard. Хэш коммита будет скопирован в буфер обмена. После этого выполни git reset --hard COPIED_COMMIT_HASH

  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. Найди в Git Graph начальный коммит Initial commit, выбери его и с помощью контекстного меню выполни Reset current branch to this Commit. В открывшемся диалоговом окне выбери вариант Soft и выполни reset.

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

  4. Сделай push, чтобы получить подсказку как сделать push с upstream, а затем сделай push с upstream

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