Скасування змін у Git
Корисні статті про верстку для верстальників
Січень 28, 2015
Велика і досить складна тема. Однак необхідна, якщо стоїть завдання вивчити та мати можливість працювати у Git.
Ця тема стосується скасування змін до Git. Так як ця система контролю версій є три гілки - робоча директорія, буфер, репозиторій - то будуть розглянуті всі три способи.
Скасування змін у робочій директорії
Для скасування змін у робочій директорії необхідно виконати одну команду:
Ця команда каже Git повернути стан файлу name_of_file до того, яким він був зафіксований у репозиторії. Іншими словами, відбудеться скидання змін файлу в робочій директорії проекту.
Обов'язковою умовою використання команди checkout є подвійний дефіс. Це "каже" команді checkout, що в даному випадку потрібно залишатися в поточній гілці (branche).
Скасування змін у буфері
Для скасування змін у буфері потрібно використовувати команду:
Ця команда поверне файл name_of_file з буфера в робочу директорію.
Скасування змін у репозиторії
Щодо репозиторію, то тут ситуація набагато складніша. Пов'язано це з тим, що всі коміти у репозиторії взаємопов'язані між собою.
Не можна просто так взяти і змінити якийсь певний коміт - всі вони знаходяться у своєрідному ланцюжку і один коміт походить з попереднього комміту.
Іншими словами, кожен комміт має свій комміт-батько і комміт-нащадок. Змінити будь-який коміт - це означає вирвати його з цього ланцюжка взаємозв'язків. Тим самим порушиться цілісність всього репозиторію і робота Git також порушиться. Адже справа в тому, що сама суть системи контролю версій Git заснована на такому взаємопов'язаному ланцюжкукоммітів - один коміт походить з іншого, другий з першого, третій з другого тощо.
Як же вчинити у цій ситуації?
Не все так похмуро, як здається на перший погляд. Насправді існує багато способів скасування змін у репозиторії. Нижче ми познайомимося з ними.
Опція amend
Якщо випливати з логічного міркування, представленого вище, виходить, що у ланцюжку коммітів має бути крайній комміт - той, який було внесено зовсім недавно. Цей комміт має комміт-батька, але не має комміта-нащадка, оскільки цей коміт - крайній у ланцюжку.
Відповідно, якщо цей комміт не має нащадків, то зміна цього комміту не спричинить порушення цілісності всього ланцюжка коммітів. Змінитись тільки цей коміт – і тільки.
Змінити крайній коміт можна просто перезаписавши його. Для цього служить ключ --amend . Команда в цілому являє собою таке:
Як тільки буде виконана подібна команда, крайній коміт (той, на якому знаходиться вказівник HEAD) буде перезаписано і це дуже легко простежити досить порівняти контрольну суму SHA цього комміту до і після змін.
Команда checkout
За допомогою команди checkout можна виконувати відкат репозиторію до потрібної версії. Цей спосіб заснований на самому факті існування ланцюжка коммітів, в якому в ролі вузлів виступають самі комміти.
Образно можна уявити цю ситуацію дуже наочно – як звичайну магнітофонну стрічку у старих касетних магнітофонах. Те місце на стрічці, де сталася остання зупинка і на якому знаходиться головка звукозапису - це і є крайній коміт. Попередні комміти – це місця на стрічці, коли відбувалася зупинка запису у ті самі моменти.
Команда checkout можезмусити покажчик HEAD повернутися назад, на попереднє місце зупинки – на попередній коміт. І необов'язково цей коміт має бути попереднім - він може бути будь-яким більш раннім.
Все що для цього потрібно – це вказати той коміт, до якого має повернутися HEAD. Вказати комміт просто – у кожного комміту є унікальний ідентифікатор – контрольна SHA-сума.
Команда повернення до потрібного комміту виглядає так:
Можна вказати лише частину SHA-суми, оскільки це показано вище.
І тоді Git зробить скидання стану (які були зроблені в останньому коміті) файлу name_of_file в буфер. Якщо ввести команду git status, то побачимо, що в буфері будуть зміни, готові для комміту. Це ті самі зміни файлу name_of_file, які ми викинули з репозиторію.
Далі виконуємо "викид" змін файлу name_of_file з буфера в робочу директорію, щоб ми змогли внести правки до цього файлу:
Все, що буде внесено до цього файлу, а потім закоммічене, матиме вже іншу контрольну суму. А отже, це вже буде зовсім інший коміт.
Дзеркало комітів
Однією з різноманітних команд Git для внесення змін до репозиторію є команда revert.
Суть її дуже проста – вона скасовує всі зміни, зафіксовані у крайньому коміті; і створює новий коміт, який є нащадком попереднього комміту, але водночас його дзеркальною копією, протилежністю.
Синтаксис команди revert також простий:
де 4a2f59a32bd1074c42 – це частина SHA-суми крайнього комміту.
Команда reset
Команда reset може змінювати репозиторій Git. Робить вона це шляхом усунення покажчика HEAD на потрібний комміт.
Після такого усунення HEAD дедалі пізніші комміти нікуди непропадуть із репозиторію - вони все ще там. Але тепер будь-яка закоммічена зміна зробить перезапис пізніших коммітів - і тоді їх буде втрачено назавжди.
Ситуація дуже схожа на те образне порівняння ланцюжка коммітів Git із магнітофонною стрічкою. Варто відмотати стрічку на 10-20 хвилин тому і знову почати запис, то пізніші записи (щодо цього місця) будуть перезаписані.
У команди reset є три ключі, які трохи видозмінюють її роботу:
Команда git reset --soft 4a2f59a32bd1074c42 здійснить зміщення покажчика HEAD на вказаний коміт 4a2f59a32bd1074c42. При цьому Git зробить скидання змін у буфер. В результаті буфер та робоча директорія будуть ідентичними між собою; а репозиторій буде переведений у раніше стан.
Команда git reset --mixd 4a2f59a32bd1074c42 аналогічна до попередньої. Також буде зроблено зміщення покажчика HEAD. Але тепер Git скине зміни до робочої директорії. Репозиторій та буфер будуть ідентичними один одному і перебувати у більш ранньому стані.
Команда git reset --hard 4a2f59a32bd1074c42 "жорстка". Також буде проведено зміщення покажчика HEAD на вказаний коміт, але при цьому буде здійснено скидання всіх трьох дерев Git - репозиторію, буфера та робочої директорії. Усі три будуть ідентичними один одному.
Команда clean
У системі Git існує команда clean для видалення файлів, що не відстежуються, в робочій директорії.
Різниця між командою git rm і clean полягає в тому, що при видаленні файлів з робочої директорії першою командою вони начебто видаляються. Але насправді віддалені файли залишаються в системі Git. Просто вони поміщені в розділ сміття і тепер сміття.
Команда clean якраз і виконує очищеннясміття у системі. Вона видаляє всі файли, що не відстежуються і не використовуються.
Але це вона робить дуже обережно. Якщо просто запустити git clean, то нічого не станеться. Система Git скаже, що команду clean необхідно запускати з ключем -n , або з ключем -f .
Запуск git clean -n – це тестовий запуск команди видалення. Нічого видалено не буде - система покаже, що вона збирається видалити, які файли.
А ось запуск git clean -f здійснено реальне видалення всіх файлів, які Git вважає сміттям. І в цьому випадку ці файли будуть втрачені назавжди.