Git — жёсткий как первый анальный секс: прикрутить его очень легко, но вот выяснить, как исправить свои же ошибки, практически невозможно. В официальной документации к Git есть одна старая как мир проблема, похожая на делему с курицей и яйцом, — вы не можете найти решение своей проблемы, так как не знаете как спросить.
Предлагаю вам рассмотреть печальные ситуации, в которые я попадал, и как я, в конце концов, вышел из них на простом и понятном русском языке.
Машина времени
Вот дерьмо, git, я люто накосячил, скажи мне, пожалуйста, что у тебя есть машина времени!
# Смотрим список последних коммитов во всех ветках, # каждый из которых имеет вид `index HEAD@{index}`. # Выбираем первый коммит перед нашим косячным git reflog # Используем всю магию машины времени git reset HEAD@{index}
Это спасёт вас, если вы случайно удалили что-то из проекта, или сломали репозиторий, или криво смёрджили. Я использую reflog
очень часто и он реально спасает от самоубийства.
Исправить последний коммит
Вот дерьмо, git, я закоммитил последние правки, но мне нужно там кое-что поменять!
# Вносим правку git add . # или отдельный файл git commit --amend # Следуем подсказкам для изменения или сохранения последнего коммита # Теперь ваш последний коммит содержит нужные вам правки
Данный приём поможет вам, если после коммита вы запустили тесты или линтер кода и заметили, что нет пробела после открывающей скобки. Можно, конечно добавить пробелы и закоммитить еще раз, но так в миллион раз быстрее.
Исправить последний комментарий
Вот дерьмо, git, я закоммитил свои правки, но допустил ошибку в комментарии!
git commit --amend # Следуйте подсказкам системы
Спасибо тупой системе форматирования комментариев, в которой люди постоянно допускают ошибки.
Перенести коммит в новую ветку из мастера
Вот дерьмо, git, я случайно закоммитил правки в мастер ветку вместо новой!
# Создаём новую ветку git branch some-new-branch-name # Удаляем коммит из мастер-ветки git reset HEAD~ --hard # Теперь ваш коммит живет в новой ветке git checkout some-new-branch-name
Это НЕ работает, если вы уже запушили коммит в репозиторий. В такой ситуации нужно использовать git reset HEAD@{number}
вместо HEAD~
. Пчелиные соты бесконечности.
Перенести коммит между веток
Вот дерьмо, git, я случайно закоммитил правки не в ту ветку!
# Отменить последний коммит, оставив изменения git reset HEAD~ --soft git stash # Переносим всё в нудную ветку git checkout name-of-the-correct-branch git stash pop git add . # или добавить конкретный файл # Теперь ваш коммит сладко спит в правильной ветке git commit -m "Ваше ссобщение"
Многие люди предлагают использовать git cherry-pick
для этой ситуации, так что выбирайте то, что вам больше всего нравится!
# Тащим последний коммит в мастер git checkout name-of-the-correct-branch git cherry-pick master # Удаляем его из мастера git checkout master git reset HEAD~ --hard
Принудительно выполнить diff
Вот дерьмо, git, я попытался запустить diff, но ничего не произошло!
git diff --staged
Git НЕ будет делать diff
файлов, добавленных без этого флага и это не ошибка, а особенность ¯_(ツ)_/¯, так что примите это как должное!
Перезапустить локальный репозиторий
Давай по новой, Миша, всё хуйня!
cd .. sudo rm -r fucking-git-repo-dir git clone https://some.github.url/fucking-git-repo-dir.git cd fucking-git-repo-dir
Не смог удержаться, чтобы не прикрепить это видео.
Отличие rebase, merge и cherry-pick
Вот дерьмо, git, я не догоняю отличий
rebase
,merge
иcherry-pick
.
Что бы легче предствить разницу, представьте, что git merge
как «собачка» на молнии у одежды — «сшивает» комиты по дате их создания. В то время как git rebase
словно пожарная лестница — при применении ваши коммиты крепятся на конец родительской ветки.
git rebase devel
— собачка на молнии — «сшивает» коммиты по дате их создания (ветка devel «растворяется» в основной ветке)
git merge devel
— пожарная лестница, все коммиты ветки devel крепятся в конец, образуется пересечение (devel остается отдельной веткой, к которой можно вернуться)
git cherry-pick idea
— забрать коммиты из ветки idea
Продолжение следует…