Git Reset против Revert против Rebase

Git Reset против Revert против Rebase

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

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

Git сброс

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

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

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

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

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

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

Git сбросить жесткий

Цель жесткого сброса git — переместить 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*

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

$ 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 ..." 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-файлы, вы увидите, что были добавлены новые файлы.

$ 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

Если я пойду и удалю файл1.tkt вручную и сделаю статус 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 ..." to update what will be committed)

(use "git restore ..." 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 
Date:
Mon May 17 19:53:31 2020 +0530

added 3 files

commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14
Author: mrgeek 
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek 
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek 
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

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

$ git log
commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master)
Author: mrgeek 
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek 
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek 
Date:
Mon May 17 00:16:33 2020 +0530

Test

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

$ 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 
Date:
Mon May 17 21:01:36 2020 +0530

soft reset

commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14
Author: mrgeek 
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek 
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek 
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 
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek 
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek 
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 Вернуть

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

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

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

$ 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 не является хорошим выбором, но если вы хотите сохранить изменения фиксации в истории, тогда revert является подходящей командой вместо reset.

Git перебазировать

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

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

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

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

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

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

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

Вот так сейчас выглядит моя основная ветка. Есть 4 коммита.

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

Я выполню приведенную ниже команду, чтобы создать и переключиться на новую ветку с именем function, и эта ветка будет создана из 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

Теперь я хочу добавить эти две новые функции в ветку master. Для этого я буду использовать команду 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

Это было все о сбросе, откате и перемещении команд в Git.

Заключение

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

Поделиться в соцсетях