Table of Contents
はじめに
フォークしたリポジトリで作業していると、上流(upstream)リポジトリの変更を取り込む必要が出てきます。
しかし、git pull upstream main
を実行すると、マージコンフリクトが発生することがよくあります。
特に複数のコミットがある場合、リベース(rebase)するとそれぞれのコミットで同じコンフリクトを何度も解決する必要があり、非常に面倒です。
この記事では、自分のコミットを一つにまとめてから(スカッシュ)リベースすることで、この問題を効率的に解決する方法を紹介します。
問題:複数コミットによるリベースの複雑さ
以下のようなエラーメッセージを見たことはありませんか?
git pull upstream main --allow-unrelated-historiesFrom https://github.com/example/repo * branch main -> FETCH_HEADAuto-merging package.jsonCONFLICT (content): Merge conflict in package.json...Could not apply abcd123... commit message
これは、上流リポジトリの変更とあなたの変更が競合している状態です。もし自分のブランチに複数のコミットがある場合、 リベースすると各コミットごとに同じコンフリクトを解決しなければならないことがあります。
解決策:スカッシュしてからリベース
この問題を解決するための効率的な方法は、
- 自分のコミットを一つにまとめる(スカッシュ)
- その後、上流リポジトリに対してリベースする
これにより、コンフリクト解決は一度だけで済みます。
手順
1. 自分のコミット数を正確に把握する
まず、上流リポジトリ(upstream)から分岐してからの自分のコミット数を確認します。
git rev-list --count HEAD ^upstream/main
しかし、この方法は常に正確とは限りません。より確実な方法は、分岐点からのコミットを確認することです。
git log --oneline upstream/main..HEAD
2. 正確なリベース範囲を指定する
マージベース(分岐点)を使ってリベースを開始します。
git rebase -i $(git merge-base upstream/main HEAD)
このコマンドは、上流リポジトリとの分岐点を自動的に見つけ、そこからのコミットをリベースの対象にします。
3. コミットをスカッシュする
エディタが開いたら、最初のコミット(一番上)は「pick」のままにし、それ以外のコミットを全て「squash」または「s」に変更します。
pick abcd123 最初のコミットs efgh456 2つ目のコミットs ijkl789 3つ目のコミット...
保存して閉じると、コミットメッセージを編集するためのエディタが開きます。ここで統合されたコミットメッセージを編集できます。
4. 上流リポジトリに対してリベースする
スカッシュが完了したら、上流リポジトリに対してリベースします:
git pull upstream main --rebase
これで、一つにまとめたコミットがupstream/mainの最新の状態の上に適用されます。コンフリクトが発生しても、一度だけ解決すれば良くなります。
5. コンフリクトを解決する
コンフリクトが発生した場合、以下の手順で解決します。
- 各コンフリクトファイルを手動で編集
- 解決したファイルを
git add <ファイル名>
で登録 git rebase --continue
で続行
なぜこの方法が効率的なのか
- 作業の削減: 複数のコミットを持つ場合、通常のリベースでは各コミットごとにコンフリクト解決が必要になることがあります。スカッシュにより、この作業を一度だけに減らせます。
- 履歴の整理: 小さな変更やフィックスを含む複数のコミットが、論理的にまとまった一つのコミットになります。
- コンフリクト解決の簡素化: 全ての変更が一つのコミットにまとまっているため、コンフリクト解決が明確になります。
注意点
- スカッシュすると個々のコミットの詳細な履歴は失われます。重要な変更履歴を保持したい場合は、慎重に行いましょう。
- 公開リポジトリの共有ブランチでは、すでにプッシュしたコミットをスカッシュすると問題が発生する可能性があります。主に個人の作業ブランチで使用しましょう。