git pull
git pull
コマンドは、リモートリポジトリから最新の変更を取得し、現在のローカルブランチに統合するための重要な操作です。--rebase
オプションを付けるかどうかで統合方法が異なります。
概要
git pull origin master
git pull
は、次の2つのステップで構成されます。
- フェッチ (fetch):リモートリポジトリから最新のコミットをローカルに取得します。
- 統合 (merge/rebase):フェッチしたコミットを現在のローカルブランチに統合します。
git pull
を引数なしで実行すると、現在のブランチに設定されている追跡リモートブランチからフェッチし、マージします。
git pull
マージ (merge) とリベース (rebase)
git pull
の統合方法は、マージ (merge) とリベース (rebase) の2種類があります。
マージ (デフォルト)
リモートの変更をフェッチし、ローカルブランチにマージします。また、新たにマージコミットが生成されます。
git pull --no-rebase
# --no-rebase オプションは省略可能
- 履歴にマージコミットが残る:マージによって新しいマージコミットが作成されるため、履歴に「マージした」という記録が残ります。
- 履歴の複雑化:マージコミットが多くなると、履歴が複雑に見えることがあります。特に、複数人での共同開発ではこの傾向が強まります。
- コンフリクト解決:マージ中にコンフリクトが発生した場合、手動で解決する必要があります。
リベース
リモートの変更をフェッチし、ローカルの変更をリモートの最新の変更の上にリベースします。また、履歴が直線的になります。
git pull --rebase
- 直線的な履歴:リベースによってコミット履歴が直線的になり、読みやすくなります。
- 履歴の書き換え:リベースは履歴を書き換えるため、公開済みのブランチでの使用は注意が必要です。
- コンフリクト解決:リベース中にコンフリクトが発生した場合も手動で解決する必要があります。コンフリクトは各コミットごとに発生します。
どちらを使うべきか
マージを選ぶ理由
- 履歴をそのまま残したい:誰がどの時点で変更をマージしたかを記録しておきたい場合に有効です。
- チームでの共同開発:マージによって履歴がそのまま残るため、複数人が同時に開発しているプロジェクトでは、変更履歴が明確になります。
リベースを選ぶ理由
- 直線的な履歴を好む場合:履歴が直線的で、シンプルな方が望ましい場合に有効です。特に個人の作業ブランチで役立ちます。
- 公開されていないブランチでの使用:履歴が書き換わるため、個人の作業ブランチや一時的なブランチでの使用に向いています。
git merge
git merge
git merge
コマンドは、2つのブランチを統合します。基本的には、現在のブランチに指定したブランチの変更を統合します。
特徴
- マージが完了すると、新しい「マージコミット」が作成され、統合された内容が記録されます。
- Gitが自動的に競合を解決できる場合もあります。
ユースケース
- 開発が完了した
feature
ブランチをmain
ブランチやmaster
ブランチに統合する場合。 - 複数の開発ブランチを統合する際に使用。
コマンド
git checkout main
git merge feature-branch
git merge --no-ff
--no-ff
オプションを使用すると、Fast-Forwardマージを無効にし、必ずマージコミットを作成します。
特徴
- Fast-Forwardマージを防ぎ、必ずマージコミットが作成されます。
- マージの履歴を明示的に記録できます。
ユースケース
- 開発履歴を分かりやすく保つために、マージコミットを残したい場合。
- 大規模な変更や機能追加を行った場合に、マージの際にその変更を明確にするため。
コマンド
git checkout main
git merge --no-ff feature-branch
git merge --squash
--squash
オプションを使用すると、マージ対象のブランチの変更を1つのコミットとして現在のブランチに統合します。
特徴
- マージ対象のブランチのすべてのコミットを1つのコミットにまとめることができます。
- スクワッシュコミットによって、履歴がシンプルに保たれます。
ユースケース
feature
ブランチで多くの小さなコミットを行ったが、main
ブランチには1つのまとまったコミットとして統合したい場合。- レビューやデプロイの際に、履歴をシンプルに保ちたい場合。
コマンド
git checkout main
git merge --squash feature-branch
git commit -m "Merged feature-branch"
git merge --strategy
--strategy
オプションを使用すると、マージ時の戦略を指定できます。recursive
,ours
,theirs
などの戦略が用意されています。
特徴
- 競合解決の方法をカスタマイズできます。
- 特定の状況に応じて、どのようにマージを行うかを指定できます。
ユースケース
- 特定の戦略を使って競合を解決したい場合。
- 特定のマージ戦略が必要な状況で使用します。
コマンド
git checkout main
git merge --strategy=ours feature-branch
git merge --no-commit
--no-commit
オプションを使用すると、マージを行っても自動的にコミットはされません。手動でコミットする必要があります。
特徴
- マージの内容を確認し、手動でコミットできます。
- マージ後の変更を確認し、調整が可能です。
ユースケース
- マージ後に変更内容を確認し、手動でコミットしたい場合。
- マージの結果に対してさらに変更を加えたい場合。
コマンド
git checkout main
git merge --no-commit feature-branch
# 変更を確認し、調整
git commit -m "Manually merged feature-branch"
まとめ
git merge
: 標準のマージ方法、履歴を保つ。--no-ff
: マージコミットを必ず作成、履歴を明示化。--squash
: 変更を1つのコミットにまとめる、履歴をシンプルに。--strategy
: マージ戦略を指定、競合解決のカスタマイズ。--no-commit
: マージ後に自動コミットを行わない、手動で確認。
ブランチの切り替え
別のブランチに切り替える際に使うコマンドは、git switch
とgit checkout
の2つがあります。
git switch
このコマンドは、ブランチを切り替えるためのシンプルで直感的な方法です。
既存のブランチに切り替え
git switch <ブランチ名>
新しいブランチを作成してそのブランチに切り替え
git switch -c <新しいブランチ名>
git checkout
git checkout
もブランチを切り替えるために使えますが、それに加えてファイルのチェックアウト(ファイルを特定のコミットの状態に戻す)も行えます。
既存のブランチに切り替え
git checkout <ブランチ名>
新しいブランチを作成してそのブランチに切り替え
git checkout -b <新しいブランチ名>
補足: git switch と git checkout の違い
機能の範囲
git checkout
は、ブランチの切り替えだけでなく、ファイルを特定の状態に戻す操作にも使われます。多機能ですが、混乱を招く可能性があります。git switch
はブランチの切り替え専用で、ブランチ操作に特化しています。
新しいGitでの推奨
git switch
はGitの新しいバージョンで追加されたコマンドで、ブランチの切り替えをよりシンプルに行うために推奨されています。
ブランチ名の変更
ブランチ名を変更するには、以下の手順を行います。
現在のローカルブランチ名を変更
git branch -m <新しいブランチ名>
例えば、main
ブランチの名前をdevelop
に変更する場合は以下のコマンドを実行します。
git branch -m develop
別のローカルブランチ名を変更
git branch -m <古いブランチ名> <新しいブランチ名>
リモートブランチ名を変更
リモートにある古いブランチ名を削除し、新しいブランチ名をプッシュします。
新しいブランチ名をリモートにプッシュ
git push origin <新しいブランチ名>
古いブランチ名をリモートから削除
git push origin --delete <古いブランチ名>
トラッキングの設定(もしリモートブランチと連携している場合)
git push --set-upstream origin <新しいブランチ名>
子ブランチに親ブランチの変更を取り込む
状況
featureブランチで開発を行っている途中に親ブランチであるmasterブランチに変更が発生したので、featureブランチにmasterブランチの変更を取り込みたい状況です。
○ = Commit
◎ = HEAD
○ -- ○ -- ○ ------ ○ (master)
\
○ -- ○ -- ◎ (feature)
手順
# 親ブランチに切り替える
git switch master
# 親ブランチを最新状態にする
git pull origin master
# 子ブランチに切り替える
git switch feature
# 子ブランチに親ブランチをマージ
git merge master
コミットの取り消し
通常のコミットの取り消し
git revert
git revert
コマンドを使うと、特定のコミットを取り消す新しいコミットを作成します。履歴を保持しつつ、変更を打ち消すことができます。
git revert <コミットハッシュ>
git reset
git reset
コマンドを使うと、特定のコミットまでの状態にリセットできます。以下のオプションがあります。
--soft
コミットを取り消しても、作業ツリーとステージングエリアはそのままにします。
git reset --soft <コミットハッシュ>
--mixed (デフォルト)
コミットを取り消し、ステージングエリアを更新しますが、作業ツリーはそのままにします。
git reset --mixed <コミットハッシュ>
--hard
コミットを取り消し、作業ツリーとステージングエリアもその状態にリセットします。データが失われる可能性があるため、注意が必要です。
git reset --hard <コミットハッシュ>
git checkout
git checkout
コマンドを使って、特定のファイルや状態をコミットの状態に戻すこともできます。
git checkout <コミットハッシュ> -- <ファイル名>
マージコミットの取り消し
マージコミットの取り消しには、次の方法があります。
git revert
マージコミットを取り消す場合、-m
オプションを使ってどの親を基準にするかを指定します。通常、-m 1
を指定して、最初の親を基準にします。
git revert -m 1 <マージコミットハッシュ>
例えば、以下のようなブランチ構造の場合を考えます。
○ = Commit
◎ = HEAD
○ -- ○ -- ○ (master)
\
○ -- ◯ (develop)
\
◯ -- ◎ (feature)
feature
ブランチに最初の親ブランチであるdevelop
ブランチをマージしたコミットを取り消すには-m 1
を指定し、さらに親ブランチであるmaster
ブランチをマージしたコミットを取り消すには-m 2
を指定します。
git reset
マージコミットを含むコミットをリセットする場合もあります。リセットオプションに注意して使う必要があります。
--soft
コミットを取り消し、変更をステージングエリアに残します。
git reset --soft <マージコミットの前のコミットハッシュ>
--mixed
コミットを取り消し、ステージングエリアを更新します。
git reset --mixed <マージコミットの前のコミットハッシュ>
--hard
コミットを取り消し、作業ツリーとステージングエリアもその状態にリセットします。
git reset --hard <マージコミットの前のコミットハッシュ>
git reflog
リセット後に元の状態に戻したい場合、git reflog
で以前の操作履歴を確認し、必要な状態に戻すことができます。
git reflog
補足:revertとresetの違い
git revert
git revert
は、特定のコミットの変更を打ち消す新しいコミットを作成します。履歴はそのまま保たれ、新しいコミットが追加されます。
git revert <コミットハッシュ>
すでにリモートに公開されたコミットを取り消す場合に使用します。履歴を変更せず、新しいコミットを追加するため、安全に取り消すことができます。
例えば、ローカルで行ったコミットをリモートに公開した後に、そのコミットが不要だとわかり取り消したい場合、git revert
を使用します。
git reset
git reset
は、特定のコミットまで履歴を戻します。--soft
/--mixed
/--hard
の3つのオプションがあります。
--soft
コミットを取り消し、ステージングエリアと作業ツリーはそのままにします。
git reset --soft <コミットハッシュ>
--mixed (デフォルト)
コミットを取り消し、ステージングエリアをリセットしますが、作業ツリーはそのままにします。
git reset --mixed <コミットハッシュ>
--hard
コミットを取り消し、作業ツリーとステージングエリアもその状態にリセットします。
git reset --hard <コミットハッシュ>
ローカルでの作業中に誤ったコミットを取り消し、履歴を変更する場合に使用します。公開リポジトリに影響を与えないため、主にローカルで使います。また、複数のコミットをまとめて修正したい場合や、履歴から不要なコミットを削除したい場合に使用します。
例えば、誤って複数のコミットを行ってしまった場合、--soft
を使って最近のコミットを取り消し、変更を再調整します。大きな変更を取り消し、履歴を完全にリセットしたい場合に --hard
を使用します。
使い分けのポイント
- すでに他の人が作業しているリモートリポジトリに対しては、
git revert
を使用して、新しい変更を追加することで安全に取り消します。履歴はそのままで、新しいコミットを追加するため、チーム全体に影響を与えません。 - ローカルで作業している場合、履歴の編集や複数のコミットの修正を行うために
git reset
を使用します。特に、--hard
オプションは作業ツリーとステージングエリアを完全にリセットするため、作業中の変更が失われる可能性があります。注意して使用してください。