2.4 Основи Git - Операції скасування
Будь-який момент вам може знадобитися що-небудь скасувати. Тут ми розглянемо кілька основних способів відміни зроблених змін. .
Скасування може знадобитися, якщо ви зробили коміт надто рано, наприклад, забувши додати якісь файли або коментар до комміту.
Ця команда використовує область підготовки (індекс) для внесення правок до комміту. це ваше повідомлення до комміту.
Запуститься той самий редактор, тільки він вже міститиме повідомлення попереднього комміту.
Наприклад, якщо ви зробили коміт і зрозуміли, що забули проіндексувати зміни у файлі, який хотіли додати до комміту, то можна зробити таке:
$git commit -m 'Initial commit' $git add forgotten_file $git commit --amend
У результаті вийде єдиний коміт – другий коміт замінить результати першого.
Дуже важливо розуміти, що коли ви вносите правки до останнього комітету, ви не так виправляєте його, скільки замінюєте новим, що його повністю перезаписує.
Очевидно, сенс зміни коммітів у додаванні незначних правок останні коміти і, у своїй, уникнення засмічення історії повідомленнями виду «Ой, забув додати файл» чи «Виправлення граматичної помилки».
Скасування індексації файлу
Наступні два розділи демонструють як працювати з індексом та змінами в робочому каталозі. Тішить, що команда, якою ви визначаєте стан цих областей, також нагадує вам як скасовувати зміни в них. Наприклад, ви змінили два файли і хочете додати їх до різних комітів, але випадково виконали команду git add * і додали в індекс обидва. Як виключити з індексу один із них? Команда git status нагадає вам:
$ git add * $ git status On branch master Зміна: (use "git reset HEAD . " to unstage) renamed: README.md -> README modified: CONTRIBUTING.md
Прямо під текстом Changes to be committed говориться: використовуйте git reset HEAD … для виключення з індексу. Давайте підемо цій пораді і скасуємо індексування файлу CONTRIBUTING.md :
$ git reset HEAD CONTRIBUTING.md Unstaged changes after reset: M CONTRIBUTING.md $ git status На сході майстра Зміни для керування: (use "git reset HEAD . " для unstage) renamed: README.md -> README Changes not stage commit: (use "git add . " to update what will be committed) (use "git checkout - . " для запису змін у робочій директорії) modified: CONTRIBUTING.md
Команда виглядає дещо дивно, але працює! Файл CONTRIBUTING.md змінено, але більше не додано до індексу.
Команда git reset може бути небезпечною якщо викликати її з параметром --hard. У наведеному прикладі файл не торкнувся, отже команда відносно безпечна.
На даний момент цей магічний виклик – все, що вам потрібно знати про команду git reset. Ми розглянемо в деталях, що саме робить reset і як з її допомогою робити дійсно цікаві речі в розділі Розкриття таємниць reset глави 7.
Скасування змін у файлі
Що робити, якщо ви зрозуміли, що не хочете зберігати свої зміни файлу CONTRIBUTING.md? Як можна просто скасувати зміни в ньому — повернути до того стану, який був в останньому коміті (або початкового після клонування, або ще якось отриманого)? Нам пощастило, що git status нагадує і це теж.
У виведенні команди з останнього прикладу список змін виглядає приблизно так:
Зміни не встановлені для коміті: (use "git add . " update what will be committed) (use "git checkout -- . " to discard changes in working directory) modified: CONTRIBUTING.md
Тут явно сказано, як скасувати існуючі зміни. Давайте так і зробимо:
$ git checkout -- CONTRIBUTING.md $ git status На сході master Зміна: (use "git reset HEAD . " to unstage) renamed: README.md -> README
Як бачите, відкат змін виконано.
Важливо розуміти, що git checkout - небезпечна команда. Усі локальні зміни у файлі пропадуть - Git просто замінить його версією з останнього комміту. У жодному разі не використовуйте цю команду, якщо ви не впевнені, що зміни у файлі вам не потрібні.
Якщо ви хочете зберегти зміни у файлі, але прямо зараз їх потрібно скасувати, тобто способи кращі, такі як розгалуження та приховування - ми розглянемо їх у розділі Розгалуження в Git.
Пам'ятайте, все, що потрапило в коміт майже завжди Git може відновити. Можна відновити навіть коміти з видалених гілок або комміти, перезаписані параметром --amend (див. Відновлення даних). Але все, що не було включено до комміту та втрачено — швидше за все, втрачено назавжди.
Скасування дій за допомогою git restore
Git версії 2.23.0 представив нову команду: git restore. По суті, це альтернатива git reset, яку ми щойно розглянули. Починаючи з версії 2.23.0, Git використовуватиме git restore замість git reset для багатьох операцій скасування.
Давайте простежимо наші кроки і скасуємо дії за допомогою git restore замість git reset.
Скасувати індексацію файлу за допомогою git restore
У наступних двох розділах показано, як працювати з індексом та змінами робочої копії за допомогою git restore . Приємно, що команда, яку ви використовуєте для визначення стану цих двох областей, також нагадує вам, як скасувати зміни в них. Наприклад, припустимо, що ви змінили два файли і хочете зафіксувати їх як дві окремі зміни, але випадково набираєте git add * і індексуєте їх обидва. Як ви можете прибрати з індексу один із двох? Команда git status нагадує вам:
$ git add * $ git status На сході master Зміна: (use "git restore --staged . " to unstage) modified: CONTRIBUTING.md renamed: README.md -> README
Прямо під текстом "Changes to be committed" написано використовувати git restore --staged ... для скасування індексації файлу. Отже, давайте скористаємося цією порадою, щоб прибрати з індексу файл CONTRIBUTING.md :
$ git restore --staged CONTRIBUTING.md $ git status On branch master Зміни: (use "git restore --staged . " to unstage) git add . " " to update what will be committed) discard changes in working directory) modified: CONTRIBUTING.md
Файл CONTRIBUTING.md змінено, але знову не індексовано.
Відкат зміненого файлу за допомогою git restore
Що, якщо ви зрозумієте, що не хочете зберігати зміни у файлі CONTRIBUTING.md? Як легко його відкотити - повернути назад до того, як він виглядав при останньому коміті (або спочатку клонований, або якимось чином поміщений у робочий каталог)? На щастя, git status теж каже, як це зробити. У висновку останнього прикладу неіндексована область виглядає наступним чином:
Зміни не встановлені для коміті: (використання "git add . ", щоб update what will be committed) (use "git restore . " для запису змін у робочій директорії) modified: CONTRIBUTING.md
Він досить недвозначно каже, як скасувати зроблені вами зміни. Давайте зробимо те, що написано:
$ git restore CONTRIBUTING.md $ git status На сході master Зміна: (use "git restore --staged . " to unstage) renamed: README.md -> README
Важливо розуміти, що git restore – небезпечна команда. Будь-які локальні зміни, внесені до цього файлу, зникнуть - Git просто замінить файл останньою зафіксованою версією. Ніколи не використовуйте цю команду, якщо не знаєте, чи потрібні вам ці незбережені локальні зміни.
git revert
Можна сказати, що команда git revert є типовою командою скасування. Однак принцип її дії відрізняється від звичного скасування змін. Замість видалення комміту з історії проекту ця команда скасовує внесені зміни та додає новий коміт з отриманим вмістом. В результаті історія в Git не втрачається, що важливо для забезпечення цілісної історії версій та надійної спільної роботи.
Скасування за допомогою команди revert необхідне, коли потрібно звернути зміни, внесені в якомусь коментарі з історії проекту. Це може бути корисним, якщо баг з'явився в проекті через конкретний комміт. Вам не потрібно вручну переходити до цього комміту, виправляти його та виконувати коміт нового знімка стану – команда git revert зробить це автоматично.
Порядок дій
Команда git revert використовується для відкату змін історії коммітів репозиторію. Інші команди скасування, такі як git checkout та git reset, переміщують покажчик HEAD та покажчики гілки на певний коміт. Команда git revert також працює з певним коммітом, проте використання git revert не переміщує покажчики. Під час операції revert відбувається перехід до зазначеного комміту, звертаються його зміни та створюється новий, «зворотний» коміт. Потім позиція покажчиків оновлюється - вони переміщаються до цього коміту наприкінці гілки.
Для наочності створимо тестовий репозиторій та напишемо у командному рядку наступне:
$ mkdir git_revert_test
$ cd git_revert_test/
$ git init.
Initialized empty Git repository in /git_revert_test/.git/
$ touch demo_file
$ git add demo_file
$ git commit -am"initial commit"
[main (root-commit) 299b15f] initial commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 demo_file
$echo "initial content" >> demo_file
$ git commit -am"add новий вміст до demo file"
[main 3602d88] add новий вміст до демо файлу
n 1 file changed, 1 insertion(+)
$ echo "знижка line content" >> demo_file
$ git commit -am"prepend content to demo file"
[main 86bb32e] prepend content to demo file
1 file changed, 1 insertion(+)
$ git log --oneline
86bb32e prepend content to demo file
3602d88 add новий вміст до demo file
299b15f initial commit