Git
Chapters ▾ 2nd Edition

2.4 Основы Git - Операции отмены

Операции отмены

В любой момент вам может потребоваться что-либо отменить. Здесь мы рассмотрим несколько основных способов отмены сделанных изменений. Будьте осторожны, не все операции отмены в свою очередь можно отменить! Это одна из редких областей Git’а, где неверными действиями можно необратимо удалить результаты своей работы.

Отмена может потребоваться, если вы сделали коммит слишком рано, например, забыв добавить какие-то файлы или комментарий к коммиту. Если вы хотите переделать коммит, можно запустить commit с параметром --amend (дополнить):

$ git commit --amend

Эта команда использует для дополнения коммита вашу область подготовки (индекс). Если вы ничего не меняли с момента последнего коммита (например, команда запущена сразу после предыдущего коммита), то снимок состояния останется в точности таким же, а изменится лишь комментарий к коммиту.

Запустится тот же редактор комментария к коммиту, но уже с комментарием к предыдущему коммиту. Комментарий можно отредактировать точно так же, как обычно, просто он заменит собой предыдущий.

Например, если вы фиксируете изменения, и понимаете, что забыли проиндексировать изменения в файле, который хотели включить в коммит, можно сделать примерно так:

$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

В итоге получится единый коммит — второй коммит заменит результаты первого.

Отмена подготовки файла

В следующих двух разделах показано, как разбираться с изменениями вашей области подготовки (staging area) и рабочего каталога. Радует, что команда, которой вы определяете состояние этих областей, также напоминает вам, как отменять их изменения. Например, скажем, вы изменили два файла, и хотите закоммитить их двумя раздельными изменениями, но случайно набрали git add *, и добавили оба в индекс. Как отменить добавление одного из них? Команда git status напомнит вам:

$ git add .
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README
    modified:   CONTRIBUTING.md

Прямо под текстом “Changes to be committed” говорится: git reset HEAD <file>... для отмены добавления в индекс. Давайте последуем этому совету, и отменим индексирование файла CONTRIBUTING.md:

$ git reset HEAD CONTRIBUTING.md
Unstaged changes after reset:
M	CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Команда выглядит несколько странно, но — работает! Файл CONTRIBUTING.md изменен, но снова не добавлен в область подготовки к коммиту.

Note

Хотя git reset может стать опасной командой, если ее вызвать с --hard, в приведенном примере файл в вашем рабочем каталоге не затрагивается. Вызов git reset без параметра не опасен — он затрагивает только область подготовки.

Пока этот волшебный вызов — всё, что вам нужно знать о команде git reset. Мы гораздо глубже погрузимся в подробности действия reset и научимся с ее помощью делать действительно интересные вещи в Раскрытие тайн reset.

Отмена изменения измененного файла

Что делать, если вы поняли, что не хотите сохранять свои изменения файла CONTRIBUTING.md? Как можно просто «разызменить» его — вернуть к тому виду, который был в последнем коммите (или к изначально склонированому, или еще как-то полученному в рабочий каталог)? Нам повезло, что git status рассказывает и это тоже. В последнем примере рассказ о неподготовленных изменениях выглядит примерно так:

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Здесь довольно ясно указано, как отбросить сделанные изменения. Давайте так и сделаем:

$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Как видите, откат изменений выполнен.

Important

Важно понимать, что git checkout -- [file] — опасная команда. Любые изменения соответствующего файла пропадают — вы просто копируете поверх него другой файл. Ни в коем случае не используйте эту команду, если вы не убеждены, что файл вам не нужен.

Если вы хотите сохранить изменения файла, но пока отложить их в сторону, давайте пройдемся по тому, как прятать (stash) и создавать ветки (branch) в Ветвление в Git; эти способы обычно лучше.

Помните, все, что зафиксировано коммитом в Git, почти всегда можно восстановить. Можно восстановить даже коммиты, сделанные в удаленных ветках, или коммиты, замещенные параметром --amend (см. Восстановление данных). Но все, что вы потеряете, не сделав коммит, скорее всего, вам больше не увидеть.