Gitリセットvsリバートvsリベース

公開: 2021-05-20

この記事では、Gitでコミットを試すさまざまな方法について学習します。

開発者は、以前のコミットの1つにロールバックしたいが、その方法がわからないような状況を何度も経験することになります。 また、reset、revert、rebaseなどのGitコマンドを知っていても、それらの違いに気づいていません。 それでは、始めて、git reset、revert、rebaseとは何かを理解しましょう。

Gitリセット

Gitリセットは複雑なコマンドであり、変更を元に戻すために使用されます。

gitresetはロールバック機能と考えることができます。 git resetを使用すると、さまざまなコミット間をジャンプできます。 git resetコマンドの実行には、–soft、–mixed、および–hardの3つのモードがあります。 デフォルトでは、gitresetコマンドは混合モードを使用します。 gitリセットワークフローでは、gitの3つの内部管理メカニズム( HEADステージング領域(インデックス)、および作業ディレクトリ)が登場します。

gitリセット-geekflare

作業ディレクトリは、現在作業している場所であり、ファイルが存在する場所です。 git statusコマンドを使用すると、作業ディレクトリに存在するすべてのファイル/フォルダーを確認できます。

ステージング領域(インデックス)は、gitがファイル内のすべての変更を追跡および保存する場所です。 保存された変更は.gitディレクトリに反映されます。 git add“ filename”を使用して、ファイルをステージング領域に追加します。 以前と同様に、git statusを実行すると、ステージング領域にどのファイルが存在するかがわかります。

Gitの現在のブランチはHEADと呼ばれます。 これは、現在のチェックアウトブランチで発生した最後のコミットを指します。 これは、参照用のポインターとして扱われます。 別のブランチにチェックアウトすると、HEADも新しいブランチに移動します。

ハードモード、ソフトモード、および混合モードでgitresetがどのように機能するかを説明します。 ハードモードは、指定されたコミットに移動するために使用され、作業ディレクトリにはそのコミットのファイルが入力され、ステージング領域がリセットされます。 ソフトリセットでは、ポインタのみが指定されたコミットに変更されます。 すべてのコミットのファイルは、リセット前に作業ディレクトリとステージング領域に残ります。 混合モード(デフォルト)では、ポインターとステージング領域の両方がリセットされます。

Gitリセットハード

git hard resetの目的は、HEADを指定されたコミットに移動することです。 指定されたコミットの後に発生したすべてのコミットが削除されます。 このコマンドは、コミット履歴を変更し、指定されたコミットを指します。

この例では、3つの新しいファイルを追加し、それらをコミットしてから、ハードリセットを実行します。

以下のコマンドからわかるように、現在、コミットするものはありません。

 $ 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

コミットする前に、お見せしましょう。現在、Gitには3つのコミットのログがあります。

 $ 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

gitでlogコマンドを実行すると、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 statusを実行すると、変更がコミット用にステージングされていないというメッセージが表示されます。

 $ 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

ハードリセットの目的は、指定されたコミットをポイントし、作業ディレクトリとステージング領域を更新することです。 もう1つの例を示しましょう。 現在、私のコミットの視覚化は次のようになっています。

git hard

ここでは、HEAD ^を使用してコマンドを実行します。これは、前のコミットにリセットする(1つのコミットを戻す)ことを意味します。

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

ヘッドポインタがd69950bから0db602eに変更されたことがわかります。

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

git hard 1

ログを確認すると、d69950bのコミットがなくなり、ヘッドが0db​​602eSHAを指すようになります。

 $ 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-filesを実行すると、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

ソフトリセットを使用して、SHA0db602e085a4d59cfa9393abac41ff5fd7afcb14を使用した古いコミットの1つに切り替えたい

そのために、以下のコマンドを実行します。 SHAの開始文字を6文字以上渡す必要があります。完全な、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

ただし、ここでの違いは、3つのファイルを追加したコミット(aa400858aab3927e79116941c715749780a59fc9)のファイルがまだ作業ディレクトリにあることです。 それらは削除されていません。 そのため、ハードリセットではなくソフトリセットを使用する必要があります。 ソフトモードでファイルを失うリスクはありません。

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

Git Revert

Gitでは、revertコマンドを使用して、元に戻す操作を実行します。つまり、一部の変更を元に戻します。 これはresetコマンドに似ていますが、ここでの唯一の違いは、新しいコミットを実行して特定のコミットに戻ることです。 つまり、gitrevertコマンドはコミットであると言っても過言ではありません。

Git revertコマンドは、復帰操作の実行中にデータを削除しません。

3つのファイルを追加し、復帰の例でgitcommit操作を実行しているとしましょう。

 $ 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

ここで、過去のコミットの1つ、たとえば「59c86c9newcommit」に戻したいと思います。 以下のコマンドを実行します。

 $ 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はもう1つの新しいコミットを実行しました。 ログをもう一度確認すると、元に戻す操作のために新しいコミットが見つかります。

 $ 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ログには、コミットのすべての履歴が含まれます。 履歴からコミットを削除する場合は、元に戻すのは適切ではありませんが、履歴にコミットの変更を保持する場合は、リセットする代わりに元に戻すのが適切なコマンドです。

Git Rebase

Gitでは、リベースは、あるブランチのコミットを別のブランチに移動または結合する方法です。 開発者として、実際のシナリオではマスターブランチに機能を作成しませんでした。 私は自分のブランチ(「機能ブランチ」)で作業し、機能が追加された機能ブランチにいくつかのコミットがある場合は、それをマスターブランチに移動したいと思います。

リベースはマージに非常に似ているため、理解するのが少し難しい場合があります。 両方をマージしてリベースする目的は、機能ブランチからコミットを取得し、それらをマスターブランチまたは他のブランチに配置することです。 考えてみてください。次のようなグラフがあります。

git rebase

他の開発者とチームで作業しているとします。 その場合、他の開発者がさまざまな機能ブランチに取り組んでいて、複数の変更をマージしている場合、これは非常に複雑になる可能性があることを想像できます。 トレースするのが混乱します。

したがって、これがリベースが役立つ場所です。 今回は、gitマージを実行する代わりに、リベースを実行します。ここで、2つの機能ブランチのコミットを取得してマスターブランチに移動します。 リベースは、機能ブランチからすべてのコミットを取得し、それらをマスターブランチのコミットの上に移動します。 そのため、舞台裏では、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

機能ブランチにもう1つの機能、つまり機能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

ここで、機能ブランチのログを確認すると、上記で実行した2つの新しいコミットがあります。

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

次に、これら2つの新機能をマスターブランチに追加します。 そのために、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)

そして最後に、マスターブランチを私の機能ブランチに対してリベースします。 これにより、機能ブランチでこれら2つの新しいコミットが取得され、マスターブランチ上で再生されます。

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

マスターブランチのログを確認すると、機能ブランチの2つのコミットがマスターブランチに正常に追加されていることがわかります。

 (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のリセット、復帰、リベースコマンドに関するものでした。 このステップバイステップガイドがお役に立てば幸いです。 これで、記事に記載されているコマンドを使用して、必要に応じてコミットを試す方法がわかりました。