-
Создай папку
my-test-project -
Создай внутри файл
hello.txt -
Выполни в контекстном меню папки
my-test-projectкомандуGitExt Create new repository -
Убедись, что появилась скрытая папка
.git
Для Windows: чтобы отображались скрытые файлы и папки, в Проводнике нужно отметить галочку Вид / Скрытые элементы.
Лучше рядом также отметить галочку Расширения имен файлов.
-
Выполни в контекстном меню папки
my-test-projectкомандуGitExt Open repository. Пока в репозитории пусто. Так и должно быть. -
Удали папку
my-test-project, она дальше не понадобится
- Найди в GitHub репозиторий https://github.com/kontur-courses/git-rules, сделай его fork в свой профиль, а затем склонируй репозиторий, полученный после форка.
НЕ СПУТАЙ: это НЕ репозиторий с презентацией и текстом этого задания!
Адрес репозитория можно узнать, нажав на зеленую кнопку «Code» на странице репозитория.
НЕ СПУТАЙ: если ты клонируешь репозиторий, у которого в адресе есть kontur-courses, то ты забыл сделать форк!
Если настраивал SSH для GitHub, то в меню, открывшемся после нажатия на кнопку,
выбери вкладку SSH и используй адрес из этой вкладки!
Не забудь после этого перейти в папку с репозиторием в терминале: cd git-rules.
- В склонированной папке найди файлы
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.
-
Открой папку
git-rulesв VS Code (File / Open Folderв главном меню) -
Открой репозиторий с помощью контекстного меню Проводника. Убедись, что в нем есть коммит с названием
Initial commit.
История коммитов должна выглядеть так:

- Через VS Code создай файл
init.mdсо следующим содержимым:
## S1. Все локально
#### Все данные хранятся в локальных репозиториях, изменения между ними можно синхронизировать
1. `git init` — создать пустой репозиторий
2. `git clone <url>` — склонировать репозиторий в новую директорию
-
Нажми кнопку
Commit, чтобы открыть окно коммита -
Переведи
init.mdиз верхней части в нижнюю часть окна кнопкойStageлибо двойным нажатием по имени файла. Теперьinit.mdнаходится вCommit index.
Если Git Extensions не показывает изменений, то ты скорее всего забыл сохранить файл, потому что привык работать в IDE, которые делают это за тебя.
VS Code тоже умеет сохранять изменения автоматически: в главном меню открой File и поставь галочку Auto Save.
Если Git Extensions все равно не показывает изменения, то проверь имя созданного файла: должно быть init.md.
-
Введи в качестве сообщения к коммиту
Add init.mdи сделай коммит кнопкойCommit -
Убедись, что коммит появился в истории коммитов
-
Создай файл
commit.mdсо следующим содержимым:
## S2. Хранятся состояния директории, постепенная сборка коммита
#### Хранятся файлы, разница вычисляется на лету
#### Commit index для сборки коммита
-
Выбери в истории коммитов
Working directoryи убедись, что там не появились изменения в файлеcommit.md. А все потому что есть файл.gitignore, который сейчас заставляет Git игнорировать все файлы с расширением.md, кромеinit.md. -
Удали правило
*.mdиз.gitignoreи сохрани изменения -
Снова выбери в истории коммитов
Working directoryи убедись, что там теперь есть изменения в файлах.gitignoreиcommit.md -
Открой окно коммита и переведи
.gitignoreиcommit.mdвCommit indexи закрой окно коммита -
Выбери в истории коммитов
Commit indexи убедись, что измененные файлы.gitignoreиcommit.mdтеперь находится там -
Замени содержимое
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>` — удалить файл из индекса, чтобы перестать хранить его историю в репозитории
-
Посмотри историю коммитов. Убедись, что
commit.mdизменен как в вWorking directory, так и вCommit index -
Открой окно коммита и убедись, что
commit.mdнаходится как в верхней части окна, так и в нижней, причем содержимое у файлов разное и при выбореcommit.mdв верхней части показывается отличия отCommit index, а не предыдущего коммита -
Выполни коммит с сообщением
Add commit.md header -
В истории коммитов найди только что созданный коммит и убедись, что в него попали только изменения из
Commit index -
Закоммить оставшиеся в
Working directoryизменения с сообщениемChange commit.md. Здесь и далее под фразой «закоммить изменения» будет подразумеваться добавление изменений вCommit indexи само выполнение коммита.
Теперь история коммитов должна выглядеть так:

-
Выбери в дереве коммитов последний коммит и создай в нем тег
v0.1с помощью контекстного меню -
Перейди на
Initial commitс помощью командыCheckout this commitв контекстном меню -
Используй пункт главного меню
Commands / Checkout revision, чтобы вернуться обратно на помеченный тегом коммит. Для этого введи имя тегаv0.1в поле для ввода ревизии. -
Выполни
Checkout branchна веткуmasterс помощью контекстного меню на текущем коммите
Теперь история коммитов должна выглядеть так:

- Создай новый файл
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>`
-
Закоммить изменения с сообщением
Add branch.md -
Ой! Эти же изменения надо было делать в новой ветке! Теперь придется исправлять! Сейчас ветка
masterнаходится на коммитеAdd branch.md, а должна находиться на коммитеChange commit.md. А на коммитеAdd branch.mdдолжна быть новая веткаbranch-feature, которую надо было создать. Убедись, что в истории коммитов все именно так, как описано, и осознай проблему. -
То, что ветка
branch-featureне была создана сразу — это не проблема. Просто возьми и создай новую веткуbranch-featureс помощью контекстного меню на текущем коммите. Git Extensions автоматически сделает checkout на нее. -
Теперь надо вернуть
masterна коммитChange commit.md. С этим может помочь командаreset, которая не просто перемещаетHEAD, но также перемещает ветку, на которуюHEADуказывает. Но текущая ветка — этоbranch-feature, а нужно, чтобы текущей былmaster. ВыполниCheckout branchна веткуmasterс помощью контекстного меню на текущем коммите. -
Наконец, выбери в истории коммит
Change commit.md, найди в контекстном меню командуReset current branch to here..., в открывшемся диалоговом окне выбериHard, а затемOK. ПеремещениеHEADиmasterдолжно произойти. -
Теперь
masterна месте и, чтобы продолжить развиватьbranch-feature, надо было бы перейти на нее с помощьюCheckout branch. Но делать это не надо, ведь сейчас надо будет сделать новую фичу в новой ветке относительноmaster. -
Используя контекстное меню создай ветку
bullet-feature -
Во всех доступных md-файлах замени нумерованные списки на ненумерованные списки. На примере
init.mdэто выглядит следующим образом. Было:
## S1. Все локально
#### Все данные хранятся в локальных репозиториях, изменения между ними можно синхронизировать
1. `git init` — создать пустой репозиторий
2. `git clone <url>` — склонировать репозиторий в новую директорию
Стало:
## S1. Все локально
#### Все данные хранятся в локальных репозиториях, изменения между ними можно синхронизировать
- `git init` — создать пустой репозиторий
- `git clone <url>` — склонировать репозиторий в новую директорию
Аналогично сделай для commit.md.
-
Закоммить изменения с сообщением
Replace with bullets -
Перейди назад на ветку
master, используя контекстное меню -
Замени содержимое
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` — удалить неотслеживаемые файлы из директории
-
Закоммить изменения с сообщением
New commands for commit.md -
Обрати внимание, что история коммитов стала похожа на дерево, а на концах веток этого дерева расположены метки
master,branch-feature,bullet-feature. А вот тегv0.1, остался на своем месте.
Теперь история коммитов должна выглядеть так:

-
Начни вливать
bullet-featureвmaster:HEADуже находится наmaster, поэтому укажи наbullet-featureи с помощью контекстного меню выбериMerge into current branch. Но выполнениеMergeзакончится конфликтом в файлеcommit.md. Конфликт произошел, потому что в этот файл вносились изменения и вbullet-featureи вmaster. -
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 не будет реагировать, т.к. будет продолжать ждать завершения разрешения конфликтов. -
Git Extensions сообщит, что все конфликты разрешены и предложит перейти к третьей части слияния — коммиту. Согласись. Откроектся знакомое окно коммита, в котором в
Commit indexбудут показаны все изменения относительноHEAD. ВCommit messageбудет указано хорошее сообщение: его можно не менять. Закоммить результаты merge. -
Убедись, что в результате твоих действий был создан новый коммит, объединяющий две ветви изменений.
HEADсдвинулся на него, аmasterсдвинулся заHEAD.
Теперь история коммитов должна выглядеть так:

Задание 7. Hidden Conflict
-
Начни вливать
branch-featureвmaster, как и в прошлый раз. Конфликтов в этот раз не будет, поэтому шаг разрешения конфликтов будет пропущен. А еще Git Extensions автоматически сделает commit. Таким образом слияние будет выполнено. -
Хоть «настоящих» конфликтов нет, после слияния появился «логический» конфликт. Дело в том, что файл
branch.mdдо сих пор содержит нумерованный список. Замени числа в нем на дефисы, аналогично другим файлам. -
Теперь пришло время добавить в историю эти изменения. Но чтобы было понятно, что эти изменения относятся к слиянию, хочется их добавить не в новый коммит, а в предыдущий. Это можно сделать с помощью
Amend Commit. Эта команда позволяет дополнить последний коммит дополнительными изменениями. Открой окно коммита, выбери опциюAmend Commit: вCommit messageпоявится сообщение из предыдущего коммита, затем добавь вCommit indexфайлbranch.mdи сделай commit. Появится предупреждение о том, что переписывается история. Да, так и есть. Соглашайся.
Теперь история коммитов должна выглядеть так:

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

-
Создай ветку
rebase-featureи перейди на нее. Используй сочетаниеCtrl+B, чтобы вызвать диалог создания ветки: так быстрее! -
Создай файл
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
-
Закоммить изменения с сообщением
Add rebase.md. Воспользуйся сочетаниемCtrl+Space, чтобы открыть окно коммита: так быстрее! -
Замени содержимое
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` — удалить ненужные файлы и оптимизировать локальный репозиторий
-
Закоммить изменения с сообщением
Change branch.md. ИспользуйCtrl+Space. -
Перейди на ветку
master. ИспользуйCtrl+.. -
Замени содержимое
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
-
Закоммить изменения с сообщением
Add reflog stub to branch.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успешно скопирован, а вотChange branch.mdпо понятным причинам порождает конфликты. Нажми кнопкуSolve conflicts, чтобы разрешить конфликты в VS Code. Несмотря на то, что файлы были созданы в разных ветках, Git видит, что первые строчки совпадают и по ним конфликта нет. А вот оставшиеся строчки конфликтуют. Так как в веткеrebase-featureбыл правильный текст, нажмиAccept Incoming Change, затем сохрани изменения, закрой файл в VS Code (важно!), перейди в Git Extensions и нажмиContinue rebase. Раз оба коммита были успешно скопированы, rebase на этом будет закончен. -
Обрати внимание, что в результате rebase были созданы коммиты
Add rebase.mdиChange branch.md. Хоть они похожи на исходные, все же это новые коммиты с новыми ревизиями. Веткаrebase-featureбыла перемещена и теперь ссылается на новый коммит. Старые коммиты остались в репозитории и на последний из них все еще ссылается тегold-rebase-feature. -
Перейди на ветку
masterи влей в нее изменения изrebase-feature. Влитие получится в режиме fast-forward.
Теперь история коммитов должна выглядеть так:

-
Удали тег
old-rebase-feature. Коммит, на который он ссылался будет скрыт, но продолжит существовать в репозитории. -
Выбери пункт главного меню
Commands / Show reflog. В результате ты увидишь список коммитов, по которым передвигалсяHEAD. Найди в списке действиеcommit: Change branch.mdи выполниCopy SHA-1из контекстного меню. Ревизия этого коммита скопируется в буфер обмена. -
Используй пункт главного меню
Commands / Checkout revision, чтобы перейти на коммит с ревизией из буфера обмена. -
Убедись, что скрытый коммит найден и снова виден. По крайней мере пока на него ссылается
HEAD.
Теперь история коммитов должна выглядеть так:

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

-
Добавь новый репозиторий для синхронизации.
Для этого в меню слева найди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 -
Для тренировки выполни 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. Сохрани изменения и закрой файл со сценарием. После чего сценарий начнет выполняться. -
Сразу же редактор откроется снова, потому что команде
rewordтребуется новое сообщение для коммита. В открывшемся редакторе замени текущее сообщениеSheet markupна новое сообщениеExtensionи закрой файл. -
Убедись, что ветка
sheet-featureтеперь ссылается на новый коммит с названиемExtension. А внутри этого коммита объединены все изменения скопированных коммитов. -
Перейди на ветку
masterи влей в него изменения изsheet-feature. Влитие получится в режиме fast-forward. -
Удали ветку
sheet-featureиспользуя контекстное меню. При удалении выбериForce delete, потому что эта ветка связана сext/sheet-feature, которая вmasterне влита.
Теперь история коммитов должна выглядеть так:

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

- Создай новый файл
push.mdсо следующим содержимым:
## R2. Удаленное изменение — это 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. Удаленное изменение — это 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, подходит для создания удаленной копии локального репозитория
-
Добавь изменения в Commit Index и закоммить их с опцией
Amend Commit, чтобы не создавать лишний коммит. -
Обрати внимание, что старый коммит остался видимым, ведь на него ссылается
origin/master
Теперь история коммитов должна выглядеть так:

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

-
Создай ветку
upstream-featureи перейди на нее -
Создай новый файл
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 и выше
-
Закоммить изменения с сообщением
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. stash, reset, revert для управления изменениями
#### Изменения можно временно припрятать
#### Можно получить разницу между любыми коммитами
#### Коммит можно отменить другим коммитом
-
Закоммить изменения с сообщением
Add reset.md -
Замени содержимое
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>` — создать коммит, отменяющий изменения из коммита
-
Ты не влил
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 -
Похоже разработка в ветке
reset-featureзакончена, поэтому можно влить в нееmasterи отдать в тестирование. Влейmaster.
Теперь история коммитов должна выглядеть так:

-
К сожалению, ты забыл добавить некоторые изменения в
reset-feature. Придется отменить merge. Хорошо, чтоreset-featureеще не запушен. -
Выбери коммит
Change reset.mdи с помощью контекстного меню выполниReset current branch to here. В открывшемся окне выбери опциюHard, чтобы полностью затереть все изменения, и выполни reset. -
Замени содержимое
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 из настроек
-
Закоммить изменения с сообщением
Change reset.md again -
Снова влей
masterвreset-feature, чтобы в ней были все актуальные изменения -
Перейди в
master. Пришло запушить последнуюю версию. Для этого влейreset-featureвmasterи сделай push. Так как вmasterне произошло изменений с последнего влитияmasterвreset-feature, это будет fast-forward merge.
Теперь история коммитов должна выглядеть так:

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

