Gitでよく使用するコマンドをGIFアニメで解説
Post on:2020年4月21日
Gitでよく使用するコマンドが何を行っているかをGIFアニメで解説した記事を紹介します。
Gitのマージ、リベース、リセット、チェリーピック、フェッチ、プル、リフログなど、コマンドを実行した時にブランチはどのように相互作用し、履歴にどのような影響を与えるのか視覚的に学べます。
🌳🚀 CS Visualized: Useful Git Commands
by Lydia Hallie
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- Gitのマージ(fast-forward, no-fast-forward)
- Gitのリベース(rebase)
- Gitのリセット(reset, revert)
- Gitのチェリーピック(cherry-pick)
- Gitのフェッチ(fetch)
- Gitのプル(pull)
- Gitのリフログ(reflog)
はじめに
Gitは非常にパワフルなツールです、ほとんどの人が同意すると思います😐
私はGitを使用している時に何が起こっているのかを視覚化すると非常に便利だといつも感じていました。コマンドを実行した時にブランチはどのように相互作用し、履歴にどのような影響を与えるのでしょう?
Gitでよく使用するコマンドを可視化することは、役に立つと思いました🥳 ここで紹介するコマンドは、オプションの引数で動作を変更できます。私の例では構成オプションを追加せずに、コマンドのデフォルト動作をカバーしています!😄
Gitのマージ(fast-forward, no-fast-forward)
複数のブランチを持つことは、新しい変更を互いに分離して管理し、承認されていない変更や壊れた変更を誤って本番環境にプッシュしてしまわないようにするのに非常に便利です。変更が承認されたら、これらの変更を本番用ブランチに反映させたいですよね!
あるブランチから別のブランチに変更を加える1つの方法は、git mergeを実行することです。Gitが実行できるマージには、fast-forwardとno-fast-forwardの2種類があります。この2つの違いを見てみましょう。
fast-forward (--ff)
fast-forwardマージは、現在のブランチがマージするブランチに比べて余分なコミットがない場合に発生します。Gitは怠け者なので、、、最初に最も簡単なオプションであるfast-forwardを実行しようとします。このタイプのマージでは新しいコミットは作成されませんが、現在のブランチでマージしているブランチのコミットがマージされます🥳
マージ(fast-forward)
これでdevブランチで行われたすべての変更がmasterブランチで利用できるようになりました。では、no-fast-forwardではどうなるでしょうか?
no-fast-foward (--no-ff)
現在のブランチにマージしたいブランチと比較して余分なコミットがない場合はいいのですが、残念ながらそれはまれなケースです。マージしたブランチが持っていない変更を現在のブランチにコミットした場合は、gitはno-fast-forwardマージを実行します。
no-fast-forwardマージでは、Gitはアクティブなブランチに新しいマージコミットを作成します。コミットの親コミットはアクティブなブランチとマージしたいブランチの両方を指します!
マージ(no-fast-foward)
完璧なマージです!🎉
masterブランチには、devブランチで行ったすべての変更が含まれています。
マージの競合(コンフリクト)
Gitはブランチをマージしてファイルに変更を追加する方法を決めるのは得意ですが、常にこの判断をGit自身で行うことはできません🙂 これはマージしようとしている2つのブランチが同じファイルの同一行に変更があったり、一方のブランチがもう一方のブランチが変更したファイルを削除してしまった場合などに起こります。
そういった場合、Gitは2つの選択肢のうちどちらを残すか決めるのを手伝ってくれるように頼みます! 両方のブランチで、README.mdの最初の行を変更したとしましょう。
最初の行を変更
devをmasterにマージしたい場合、マージの競合が発生することになります。Hello!にしますか? それともHey!にしますか?
ブランチをマージしようとすると、Gitは競合が発生したところを表示します。残したくない変更を手動で削除して、変更を保存し、変更したファイルを再度追加して、変更をコミットします🥳
マージの競合
マージの競合にはイライラさせられますが、これは非常に理にかなっています。Gitはどの変更を保持したいかを想定するだけではいけません。
Gitのリベース(rebase)
git mergeを実行して、あるブランチから別のブランチに変更を適用する方法を確認しました。あるブランチから別のブランチに変更を適用する別の方法は、git rebaseを実行することです。
git rebaseは現在のブランチのコミットをコピーし、そのコピーしたコミットを指定したブランチの上に置きます。
Gitのリベース
これでmasterブランチで行われたすべての変更がdevブランチで利用できるようになります🎊
マージとの大きな違いは、Gitが保持するファイルと保持しないファイルを見つけようとしないことです。リベースしているブランチには常に最新の変更点が残っています。マージの競合に遭遇することもなく、Gitの履歴を直線的に維持できます。
この例ではmasterブランチをリベースすることを示しています。ただし、大規模なプロジェクトでは通常、このようなことを行う必要はありません。git rebaseを実行すると、コピーされたコミットに対して新しいハッシュが作成されるので、プロジェクトの履歴が変更されます!
リベースはfeatureブランチで作業をしていて、masterブランチが更新されたときにとても便利です。ブランチの変更をすべて取得できるので、将来的にマージの競合を防ぐことができます😄
インタラクティブリベース
コミットをリベースする前に、変更できます!😃 インタラクティブリベースを使えば可能です。現在作業中のブランチでコミットを変更したい場合にも役立ちます。
リベースするコミットに対して実行できるアクションは6つあります。
- reword: コミットメッセージを変更
- edit: コミットを修正
- squash: コミットを前のコミットに統合
- fixup: コミットのログメッセージを保持せずに、前のコミットに統合
- exec: リベースするコミットごとにコマンドを実行
- drop: コミットを削除
便利ですね! これでコミットを完全にコントロールできるようになります。コミットを削除したい場合は、dropするだけです。
インタラクティブリベース
また、複数のコミットをまとめて潰して履歴を綺麗にしたい場合も問題ありません。
コミットを前のコミットに統合
インタラクティブリベースでは、リベースしようとしているコミットを現在アクティブなブランチであっても制御することができます。
Gitのリセット(reset, revert)
後で必要のない変更をコミットしてしまったということもあります。もしかしたら、それはWIP(途中)コミットかもしれませんし、バグが発生したコミットかもしれません🐛 その場合は、git resetを実行します。
git resetは現在のステージファイルをすべて削除し、HEADが示す場所をコントロールできるようにします。
ソフトリセット
ソフトリセットはHEADを指定されたコミット(またはHEADと比較したコミットのインデックス)に移動します。その後のコミットで導入された変更を取り除かずにです!
例えば、style.cssを追加したコミット9e78iを残したくない、index.jsを追加したコミット035ccを残したくない、ただし、新しく追加したstyle.cssとindex.jsファイルは残しておきたい、そんな場合にソフトリセットは最適です。
ソフトリセット
git statusと入力すると、前回のコミットで行われたすべての変更に引き続きアクセスできることが分かります。これは素晴らしいことです。これでこれらのファイルの内容を修正して、後で再度コミットできることを意味します。
ハードリセット
特定のコミットで導入された変更をそのままにしておきたくない場合があります。ソフトリセットとは異なり、これらにアクセスする必要はありません。Gitは指定されたコミット時の状態に戻すだけです。これには作業ディレクトリとステージングされたファイルの変更も含まれます💣
ハードリセット
Gitは9e78iと035ccで導入された変更を破棄し、その状態をコミットec5beの状態にリセットしました。
リバート
変更を元に戻すもうひとつの方法は、git revertです。特定のコミットを元に戻すことで、元に戻した変更を含む新しいコミットを作成します。
ec5beでindex.jsファイルを追加したとしましょう。後になって、このコミットによって変更された箇所がいらないと気がつきました。コミットec5beを元に戻します。
リバート
コミット9e78iは、コミットec5beで導入された変更を元に戻しました。git revertを実行すると、ブランチの履歴を変更せずに特定のコミットを元に戻すことができ、非常に便利です。
Gitのチェリーピック(cherry-pick)
特定のブランチにアクティブなブランチに必要な変更をしたコミットがある場合、そのコミットをcherry-pickすることができます。コミットをcherry-pickすることで、cherry-pickされたコミットで適用した変更を含む新しいコミットをアクティブなブランチに作成します。
devブランチの76d12でindex.jsに変更を加えたとします。全体ではなく、この1つのコミットだけを対象としています。
Gitのチェリーピック
masterブランチには、76d12で導入された変更が含まれています。
Gitのフェッチ(fetch)
リモートのGitブランチ、例えばGitHub上のブランチがある場合、リモートブランチには現在のブランチにはないコミットがあるかもしれません。おそらく、別のブランチがマージされたとか、同僚がクリックフィックスをプッシュしたとか、そんなことがあるかもしれません。
リモートブランチでgit fetchを実行することで、これらの変更をローカルで取得することができます。ローカルブランチに影響を与えることはありません、fetchは新しいデータをダウンロードするだけです。
Gitのフェッチ
これで最後にプッシュしてから行われた変更をすべて確認することができます。新しいデータをローカルにあるので、新しいデータをどうするか決めることができます。
Gitのプル(pull)
git fetchはブランチのリモート情報を取得するのにとても便利ですが、git pullを実行することもできます。git pullは実際にはgit fetchとgit mergeの2つをまとめたコマンドです。originから変更点をプルするときは、最初にgit fetchで行ったようにすべてのデータをフェッチしてから、最新の変更点をローカルブランチに自動的にマージしていきます。
Gitのプル
これでリモートブランチと完全に同期し、すべての最新の変更点が適用されました🤩
Gitのリフログ(reflog)
誰もが間違いを犯すものですが、全く問題ありません。時には自分のgitリポジトリをめちゃくちゃにしてしまったと思い完全に削除したくなることもあるかもしれません。
git reflogは、実行されたすべてのアクションのログを表示するための非常に便利なコマンドです。これにはマージ、リセット、リバートが含まれ、基本的には自分のブランチに変更を加えることはありません。
Gitのリフログ
間違えてしまった場合は、reflogが教えてくれる情報を元に、HEADをリセットすることで簡単にやり直すことができます!
実際にはoriginブランチをマージしたくなかったとしましょう。git reflogを実行すると、マージ前のリポジトリの状態がHEAD@{1}にあることが分かります。git resetでHEADをHEAD@{1}の状態に戻しましょう!
Gitのリフログ
最新のアクションがreflogにプッシュされていることが分かります!
Gitにはたくさんの便利な機能やコマンドがあります、それらすべてをカバーできたらと思います😄 他にもたくさんのコマンドがありますが、今回は時間がなくて取り上げることができませんでした。あなたがお気に入りのコマンドや役立つコマンドを教えてください。次の機会にそれを取り上げるかもしれません。
気軽に、@lydiahallieまで連絡してください!😊
sponsors