Чорт забирай, Git!?!

Git - це складно: помилитися дуже легко, а зрозуміти як виправити свої помилки неможливо. Документація Git має проблему курки та яйця, так як неможливо знайти рішення своєї проблеми, якщо ти його вже не знаєш!

Так що ось декілька поганих ситуацій в яких я сам перебував і мої способи їх розв'язання по-людськи.

Чорт забирай, я зробив щось жахливе, будь ласка скажіть мені що git має машину часу!?!

git reflog
# ви побачите список усього, що ви
# робили в git, в усіх гілках!
# кожен елемент має індекс HEAD@{індекс}
# знайдіть індекс останнього елементу перед тим як все зламалось
git reset HEAD@{індекс}
# магічна машина часу

Ви можете користуватися цим, щоб повернути назад те, що ви випадково видалили, або просто щоб прибрати те, що ви спробували додати і воно все зламало, або щоб відновити репозиторій після поганого злиття, або просто щоб повернутися назад в часі до того моменту, коли все працювало. Я використовую reflog ДУЖЕ ЧАСТО. Величезне дякую всім тим багатьом-багатьом людям що просили додати цю фічу!

Чорт забирай, я комітнув і щойно зрозумів що треба внести одну невеличку зміну!

# внесіть вашу зміну
git add . # або додайте файли окремо
git commit --amend --no-edit
# тепер ваш останній коміт має цю зміну!
# ПОПЕРЕДЖЕННЯ: ніколи не виправляйте публічні коміти

Зі мною це звичайно трапляється якщо я спочатку комічу, а потім перевіряю тести/лінтери... і, кхм, я забув поставити пробіл після знаку "дорівнює". Ви також можете включити цю зміну в новий коміт і потім зробити rebase -i, щоб об'єднати два коміти в один, але цей спосіб десь в мільйон разів швидше.

Попередження: Ніколи не варто виправляти коміти, що були запушені на публічну/спільну гілку! Виправляйте тільки коміти, що існують лише у вас локально, інакше у вас будуть серйозні проблеми.

Чорт забирай, треба поміняти повідомлення останнього коміту!

git commit --amend
# дотримуйтесь вказівок щоб виправити повідомлення

Дурні вимоги по форматуванню повідомлень.

Чорт забирай, я випадково комітнув на master замість нової гілки!

# створити нову гілку з поточного стану master
git branch ім'я-нової-гілки
# прибрати останній коміт з master
git reset HEAD~ --hard
git checkout ім'я-нової-гілки
# тепер ваш коміт живе на новій гілці :)

Примітка: це не буде працювати якщо ви вже запушили коміт на публічну/спільну гілку, або якщо ви спробували якісь інші способи, тоді варто зробити git reset HEAD@{кількість-комітів-назад} замість HEAD~. Також багато-багато людей допомогли мені зкоротити цю підказку, дякую вам всім!

Чорт забирай, я випадково закомітив не на ту гілку!

# скасувати останній коміт, але залишити зміни в буфері
git reset HEAD~ --soft
git stash
# перейти на потрібну гілку
git checkout ім'я-правильної-гілки
git stash pop
git add . # або додайте файли по одному
git commit -m "ваше повідомлення"
# тепер ваші зміни на потрібній гілці

Також багато людей рекомендувало тут використовувати cherry-pick, отже вибирайте спосіб що вам більше подобається!

git checkout ім'я-правильної-гілки
# взяти останній коміт на master
git cherry-pick master
# видалити його з master
git checkout master
git reset HEAD~ --hard

Чорт забирай, я зробив diff але нічого не вивелось?!

Якщо ви впевнені, що ви змінили файли, але diff нічого не виводить, скоріш за все ви додали файли add-ом і варто використати спеціальний флаг.

git diff --staged

Можна зарахувати як ¯\_(ツ)_/¯ (та, я в курсі що це фіча, а не баг, але це так неочевидно в перший раз!)

Чорт забирай, мені треба скасувати коміт який я зробив блін 5 комітів тому!

# знайдіть коміт який треба скасувати
git log
# використовуйте стрілочки "вгору" та "вниз", щоб переглянути історію
# збережіть хеш коміту, який потрібно скасувати
git revert [ваш хеш]
# git створить новий коміт, що відмінить старий
# дотримуйтесь вказівок щоб створити повідомлення до коміту
# або просто збережіть і комітніть

Виявляється, що не треба вишукуати і копіювати вміст старого файлу в новий щоб скасувати зміни! Якщо ви комітнули баг, можна все скасувати за допомогою revert.

Також можна скасувати зміни в одному файлі замість цілого коміту! Але як завжди з git, це робиться зовсім іншими командами...

Чорт забирай, мені треба скасувати зміни до файлу!

# знайдіть хеш коміту, що був до того як файл був змінений
git log
# використовуйте стрілочки "вгору" та "вниз", щоб переглянути історію
# збережіть хеш коміту, який потрібно скасувати
git checkout [ваш хеш] -- шлях/до/файлу
# стара версія файлу буде у вас в індексі
git commit -m "Вау, не треба копіпастити щоб скасувати зміни"

Коли я до цього нарешті допер це було КЛАСНО. КЛАСНО. К-Л-А-С-Н-О. Але якщо серйозно, якого фіга checkout -- це найкращий спосіб скасувати зміни до файлу? :погрожує-лінусу-торвальдсу:

Пішло воно все, я здаюся

cd ..
sudo rm -r сраний-репозиторій
git clone https://some.github.url/сраний-репозиторій.git
cd сраний-репозиторій

Дякую Eric V. за цю підказку. Будь-які скарги щодо sudo в цьому жарті пишіть йому.

Якщо серйозно і ваша гілка настільки засрана, що вам треба повернути репозиторій до стану в remote по красивому, то спробуйте так, але знайте, що так ви знищуєте ваші дані які вже не можна буде повернути!

# отримати останню версію origin
git fetch origin
git checkout master
git reset --hard origin/master
# видалити все (навіть приховані та неіндексовані файли та директорії)
git clean -d --force
# повторіть checkout/reset/clean для кожної засраної гілки

*Попередження: Цей сайт - не вичерпний ресурс. І так, є інші способи зробити ці самі речі ще "чистіше" але я дійшов до цих способів через багато помилок, матів і перевернутих столів, так що я вирішив поділитися ними в людському форматі, самі вирішуйте, чи варто ними користуватися!

Дякую всім тим, хто допоміг перекласти цей сайт на багато різних мов, ви красавчики! Michael Botha (af) · Khaja Md Sher E Alam (bn) · Eduard Tomek (cs) · Moritz Stückler (de) · Franco Fantini (es) · Hamid Moheb (fa) · Senja Jarva (fi) · Michel (fr) · Alex Tzimas (gr) · Elad Leev (he) · Aryan Sarkar (hi) · Ricky Gultom (id) · fedemcmac (it) · Meiko Hori (ja) · Zhunisali Shanabek (kk) · Gyeongjae Choi (ko) · Rahul Dahal (ne) · Martijn ten Heuvel (nl) · Łukasz Wójcik (pl) · Davi Alexandre (pt_BR) · Catalina Focsa (ro) · Daniil Golubev (ru) · Nemanja Vasić (sr) · Björn Söderqvist (sv) · Kitt Tientanopajai (th) · Taha Paksu (tr) · Andriy Sultanov (ua) · Tao Jiayuan (zh) . З додатковою допомогою від Allie Jones · Artem Vorotnikov · David Fyffe · Frank Taillandier · Iain Murray · Lucas Larson · Myrzabek Azil

Якщо ви б хотіли допомогти додати переклад на вашу мову, зробіть PR тут GitHub