Git Reset vs Revert vs Rebase

Опубликовано: 2021-05-20

В этой статье вы узнаете о различных способах работы с коммитами в Git.

Как разработчик, вы бы неоднократно сталкивались с такими ситуациями, когда вам хотелось бы откатиться к одному из ваших предыдущих коммитов, но вы не знаете, как это сделать. И даже если вы знаете команды Git, такие как reset, revert, rebase, вы не знаете о различиях между ними. Итак, давайте начнем и разберемся, что такое git reset, revert и rebase.

Git Reset

Git reset - сложная команда, и она используется для отмены изменений.

Вы можете думать о git reset как о функции отката. С помощью git reset вы можете переключаться между различными коммитами. Есть три режима выполнения команды git reset: –soft, –mixed и –hard. По умолчанию команда git reset использует смешанный режим. В рабочем процессе git reset в картину входят три внутренних механизма управления git: HEAD , промежуточная область (индекс) и рабочий каталог .

git сбросить - geekflare

Рабочий каталог - это место, где вы в настоящее время работаете, это место, где находятся ваши файлы. Используя команду git status, вы можете увидеть, какие все файлы / папки присутствуют в рабочем каталоге.

Промежуточная область (индекс) - это место, где git отслеживает и сохраняет все изменения в файлах. Сохраненные изменения отражаются в каталоге .git. Вы используете git add «filename», чтобы добавить файл в область подготовки. И, как и раньше, когда вы запустите git status, вы увидите, какие файлы присутствуют в промежуточной области.

Текущая ветка в Git называется HEAD. Он указывает на последнюю фиксацию, которая произошла в текущей ветке оформления заказа. Он рассматривается как указатель на любую ссылку. Как только вы оформляете заказ в другую ветку, HEAD также перемещается в новую ветку.

Позвольте мне объяснить, как git reset работает в жестком, мягком и смешанном режимах. Жесткий режим используется для перехода к указанной фиксации, рабочий каталог заполняется файлами этой фиксации, а промежуточная область сбрасывается. При мягком сбросе изменяется только указатель на указанную фиксацию. Файлы всех коммитов остаются в рабочем каталоге и промежуточной области до сброса. В смешанном режиме (по умолчанию) и указатель, и промежуточная область сбрасываются.

Git Reset Hard

Цель git hard reset - переместить HEAD в указанную фиксацию. Он удалит все коммиты, которые произошли после указанного коммита. Эта команда изменит историю фиксации и укажет на указанную фиксацию.

В этом примере я добавлю три новых файла, зафиксирую их, а затем выполню полный сброс.

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

 $ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean

Теперь я создам 3 файла и добавлю в них некоторый контент.

 $ vi file1.txt $ vi file2.txt $ vi file3.txt

Добавьте эти файлы в существующий репозиторий.

 $ git add file*

Когда вы повторно запустите команду status, она отобразит только что созданные мной новые файлы.

 $ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: file1.txt new file: file2.txt new file: file3.txt

Перед фиксацией позвольте мне показать вам, что в настоящее время у меня есть журнал из 3 коммитов в Git.

 $ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Теперь я фиксируюсь в репозитории.

 $ git commit -m 'added 3 files' [master d69950b] added 3 files 3 files changed, 3 insertions(+) create mode 100644 file1.txt create mode 100644 file2.txt create mode 100644 file3.txt

Если я сделаю ls-files, вы увидите, что были добавлены новые файлы.

 $ git ls-files demo dummyfile newfile file1.txt file2.txt file3.txt

Когда я запускаю команду log в git, у меня есть 4 коммита, а HEAD указывает на последний коммит.

 $ git log --oneline d69950b (HEAD -> master) added 3 files 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Если я удаляю файл file1.txt вручную и выполняю статус git, он покажет сообщение о том, что изменения не предназначены для фиксации.

 $ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: file1.txt no changes added to commit (use "git add" and/or "git commit -a")

Теперь я выполню команду полного сброса.

 $ git reset --hard HEAD is now at d69950b added 3 files

Если я перепроверю статус, я обнаружу, что фиксировать нечего, и удаленный мной файл вернулся в репозиторий. Откат произошел, потому что после удаления файла я не зафиксировал фиксацию, поэтому после аппаратного сброса он вернулся в предыдущее состояние.

 $ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) nothing to commit, working tree clean

Если я проверю журнал git, он будет выглядеть вот так.

 $ git log commit d69950b7ea406a97499e07f9b28082db9db0b387 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 19:53:31 2020 +0530 added 3 files commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 test

Цель аппаратного сброса - указать на указанную фиксацию и обновить рабочий каталог и промежуточную область. Приведу еще один пример. В настоящее время визуализация моих коммитов выглядит следующим образом:

мерзко

Здесь я запускаю команду с HEAD ^, что означает, что я хочу вернуться к предыдущей фиксации (одна фиксация назад).

 $ git reset --hard HEAD^ HEAD is now at 0db602e one more commit

Вы можете видеть, что указатель головы теперь изменился на 0db602e с d69950b.

 $ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

git hard 1

Если вы проверите журнал, фиксация d69950b исчезла, и теперь заголовок указывает на 0db602e SHA.

 $ git log commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 Test

Если вы запустите ls-файлы, вы увидите, что file1.txt, file2.txt и files3.txt больше не находятся в репозитории, потому что этот коммит и его файл были удалены после жесткого сброса.

 $ git ls-files demo dummyfile newfile

Мягкий сброс Git

Точно так же сейчас я покажу вам пример мягкого сброса. Учтите, я снова добавил 3 файла, как упоминалось выше, и зафиксировал их. Журнал git появится, как показано ниже. Вы можете видеть, что «мягкий сброс» - это моя последняя фиксация, и HEAD также указывает на это.

 $ git log --oneline aa40085 (HEAD -> master) soft reset 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Подробную информацию о фиксации в журнале можно увидеть с помощью следующей команды.

 $ git log commit aa400858aab3927e79116941c715749780a59fc9 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 21:01:36 2020 +0530 soft reset commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 test

Теперь, используя мягкий сброс, я хочу переключиться на один из старых коммитов с SHA 0db602e085a4d59cfa9393abac41ff5fd7afcb14

Для этого я выполню следующую команду. Вам необходимо передать более 6 начальных символов SHA, полный SHA не требуется.

 $ git reset --soft 0db602e085a4

Теперь, когда я запускаю журнал git, я вижу, что HEAD сброшен до указанного мной коммита.

 $ git log commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 test

Но разница здесь в том, что файлы фиксации (aa400858aab3927e79116941c715749780a59fc9), куда я добавил 3 файла, все еще находятся в моем рабочем каталоге. Они не удалены. Вот почему вам следует использовать мягкий сброс, а не полный сброс. В мягком режиме нет риска потерять файлы.

 $ git ls-files demo dummyfile file1.txt file2.txt file3.txt newfile

Git Revert

В Git команда revert используется для выполнения операции возврата, т. Е. Для отмены некоторых изменений. Она похожа на команду сброса, но с той лишь разницей, что вы выполняете новую фиксацию, чтобы вернуться к определенной фиксации. Короче говоря, можно сказать, что команда git revert - это фиксация.

Команда Git revert не удаляет данные при выполнении операции возврата.

Допустим, я добавляю 3 файла и выполняю операцию фиксации git для примера возврата.

 $ git commit -m 'add 3 files again' [master 812335d] add 3 files again 3 files changed, 3 insertions(+) create mode 100644 file1.txt create mode 100644 file2.txt create mode 100644 file3.txt

Журнал покажет новую фиксацию.

 $ git log --oneline 812335d (HEAD -> master) add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Теперь я хотел бы вернуться к одному из моих прошлых коммитов, скажем, «59c86c9 new commit». Я бы запустил команду ниже.

 $ git revert 59c86c9

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

 Revert "new commit" This reverts commit 59c86c96a82589bad5ecba7668ad38aa684ab323. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch master # Your branch is ahead of 'origin/master' by 4 commits. # (use "git push" to publish your local commits) # # Changes to be committed: # modified: dummyfile

Это результат, который вы получите после сохранения и закрытия файла.

 $ git revert 59c86c9 [master af72b7a] Revert "new commit" 1 file changed, 1 insertion(+), 1 deletion(-)

Теперь, чтобы внести необходимые изменения, в отличие от сброса, команда revert выполнила еще одну новую фиксацию. Если вы проверите журнал еще раз, вы обнаружите новую фиксацию из-за операции возврата.

 $ git log --oneline af72b7a (HEAD -> master) Revert "new commit" 812335d add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

git revert

Журнал Git будет содержать всю историю коммитов. Если вы хотите удалить коммиты из истории, то откат - не лучший выбор, но если вы хотите сохранить изменения коммитов в истории, то подходящей командой будет команда revert вместо сброса.

Git Rebase

В Git перебазирование - это способ перемещения или объединения коммитов одной ветки по другой ветке. Как разработчик, я не стал бы создавать свои функции в основной ветке в реальном сценарии. Я бы работал над своей собственной веткой («ветвью функций»), и когда у меня есть несколько коммитов в моей ветке функций с добавленной функцией, я хотел бы переместить ее в основную ветку.

Rebase иногда может быть немного запутанным для понимания, потому что он очень похож на слияние. Цель слияния и перебазирования обоих - взять коммиты из моей функциональной ветки и поместить их в основную ветку или любую другую ветку. Подумайте, у меня есть график, который выглядит так:

git rebase

Предположим, вы работаете в команде с другими разработчиками. В этом случае вы можете представить, что это может стать действительно сложным, если у вас есть группа других разработчиков, работающих над разными ветвями функций, и они объединяют несколько изменений. Становится запутанным отслеживать.

Итак, здесь поможет перебазирование. На этот раз, вместо того, чтобы выполнять слияние git, я сделаю перебазирование, при этом я хочу взять свои две коммиты функциональной ветки и переместить их в основную ветку. Перебазирование возьмет все мои коммиты из функциональной ветки и переместит их поверх коммитов основной ветки. Итак, за кулисами git дублирует коммиты функциональной ветки в основной ветке.

git rebase 1

Такой подход даст вам чистый прямолинейный график со всеми коммитами подряд.

git revert 2

Это позволяет легко отследить, какие коммиты и куда пошли. Вы можете себе представить, что если вы работаете в команде со многими разработчиками, все коммиты по-прежнему идут подряд. Таким образом, за ним действительно легко следить, даже если над одним проектом одновременно работает много людей.

Позвольте мне показать вам это на практике.

Так сейчас выглядит моя основная ветка. Имеет 4 коммита.

 $ git log --oneline 812335d (HEAD -> master) add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Я запущу приведенную ниже команду, чтобы создать новую ветку с именем feature и переключиться на нее, и эта ветка будет создана из 2-го коммита, то есть 59c86c9.

 (master) $ git checkout -b feature 59c86c9 Switched to a new branch 'feature'

Если вы проверите журнал в функциональной ветке, там всего 2 коммита, исходящих от мастера (основная ветка).

 (feature) $ git log --oneline 59c86c9 (HEAD -> feature) new commit e2f44fc (origin/master, origin/HEAD) test

Я создам функцию 1 и передам ее в ветку функции.

 (feature) $ vi feature1.txt (feature) $ git add . The file will have its original line endings in your working directory (feature) $ git commit -m 'feature 1' [feature c639e1b] feature 1 1 file changed, 1 insertion(+) create mode 100644 feature1.txt

Я создам еще одну функцию, то есть функцию 2, в ветке функций и зафиксирую ее.

 (feature) $ vi feature2.txt (feature) $ git add . The file will have its original line endings in your working directory (feature) $ git commit -m 'feature 2' [feature 0f4db49] feature 2 1 file changed, 1 insertion(+) create mode 100644 feature2.txt

Теперь, если вы проверите журнал функциональной ветки, в нем есть два новых коммита, которые я выполнил выше.

 (feature) $ git log --oneline 0f4db49 (HEAD -> feature) feature 2 c639e1b feature 1 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Теперь я хочу добавить эти две новые функции в главную ветку. Для этого я воспользуюсь командой rebase. Из функциональной ветки я перебазируюсь на основную ветку. Это приведет к повторной привязке моей функциональной ветки к последним изменениям.

 (feature) $ git rebase master Successfully rebased and updated refs/heads/feature.

Теперь я собираюсь проверить основную ветку.

 (feature) $ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits)

И, наконец, переустановите основную ветку на мою функциональную ветку. Это займет эти два новых коммита в моей функциональной ветке и воспроизведет их поверх моей основной ветки.

 (master) $ git rebase feature Successfully rebased and updated refs/heads/master.

Теперь, если я проверю журнал в главной ветке, я вижу, что две фиксации моей ветки функций были успешно добавлены в мою главную ветку.

 (master) $ git log --oneline 766c996 (HEAD -> master, feature) feature 2 c036a11 feature 1 812335d add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test

Это все о командах reset, revert и rebase в Git.

Вывод

Это все о командах reset, revert и rebase в Git. Надеюсь, это пошаговое руководство было вам полезно. Теперь вы знаете, как поэкспериментировать со своими коммитами в соответствии с потребностями, используя команды, упомянутые в статье.