Open7

【Git/GitHub/Rebase Tips】Git・GitHub の merge とrebase について📝

ピン留めされたアイテム
まさぴょん🐱まさぴょん🐱

git pull --rebase

Gitでrebaseを行う際、事前にmasterブランチの最新の変更を取り込んでおくことで、コンフリクトの発生を減らすことができます!

まずは、最新 master を pullしてから事項の Rebase作業を始めましょう💪🥺🔥

Rebase作業と完了まで

# Remote の master から Rebase で pullしてくる (localブランチに取り込む)
 git pull --rebase origin master

# Conflictを解消して、git add と git commit を実行する
# Conflictなど解消したら、continueする
# まだConflictがある場合は、またConflictを解消して、git add と git commit を実行する
# すべてのConflictを解消すると、Rebaseが完了となる
 git rebase --continue

# コンフリクトを解消した後に、注意するのが、pushをする時です!
# 通常の pushができなくなるはずなので、Force Pushすることになります!
# ただし、通常の「git push --force origin ブランチ名」ではなく、
# ローカルで rebase 後にリモートにpushするときは、次のコマンドが安全
git push --force-with-lease --force-if-includes origin ブランチ名

rebaseで見るcommit量が多い場合は、git rebase --continueではなく、
VSCodeで continue操作をするのが楽💪🥺🔥

ちなみに、コンフリクトがなければ、次のようなメッセージが出るので、
その後、force pushすればOK🙆‍♂️

# Success Message
Successfully rebased and updated refs/heads/

# ローカルで rebase 後にリモートにpushするときは、次のコマンドが安全
git push --force-with-lease --force-if-includes origin ブランチ名

Gitのrebase作業を途中で中止したい場合

git rebase --abort

コミットをまとめたい場合

git rebase -i HEAD~3  # 直近3つのコミットを整理

# または、次のようにもできる
git rebase -i <commit_id>  # commit_id より後ろのコミットを整理

コンフリクトの解決選択:「現在の変更」と「入力側の変更」

「現在の変更」:Local Repository
「入力側の変更」:Remote Repository

# コンフリクトを「現在の変更」(Local に合わせる)で、すべて解決する場合
git checkout --ours .

# コンフリクトを「入力側の変更」(Remote に合わせる)で、すべて解決する場合
git checkout --theirs .

こういうやつのこと👀✨

参考・引用

https://zenn.dev/mikaneko/articles/0fe1daf2e8a987

https://zenn.dev/owayo/articles/a009820118060f

https://gist.github.com/d-kuro/08ec0964107ae4c8bc074ed8162b63cc

https://qiita.com/ucan-lab/items/0a128bb14528e4e52fd2#git-rebase-コマンドの解説

https://qiita.com/KaitoMuraoka/items/880a2022adb06dca89f0

https://qiita.com/Hashimoto-Noriaki/items/6e183f738289cf288b23

https://qiita.com/asosori2/items/bf5405978ac7409d0557

https://qiita.com/dys/items/c062b1be0d0287352e37

https://sakaishun.com/2022/09/23/git-pull-rebase/

https://kray.jp/blog/git-pull-rebase/

ピン留めされたアイテム
まさぴょん🐱まさぴょん🐱

git push --force-with-lease --force-if-includes について

git push --force-with-lease --force-if-includes origin ブランチ名 コマンドは、
Gitでブランチをリモートリポジトリに強制的にプッシュする際のオプションを組み合わせたものです。
それぞれのオプションがどのように機能するかを説明します。

コマンドの各部分

  • git push: リモートリポジトリに対して、ローカルの変更をプッシュする基本的なコマンドです。
  • --force-with-lease: このオプションは「安全な強制プッシュ」とも言われます。--forceの代わりに使うことが推奨されており、リモートにあるブランチの現在の状態を確認してからのみ強制的にプッシュします。
    • 他の人がリモートの同じブランチに変更を加えていない場合は、問題なくプッシュが実行されます。
    • 他の人がリモートブランチに変更を加えている場合、競合が発生するため、強制プッシュは行われません。
    • つまり、競合を避けつつ、必要なときには強制プッシュを行いたい場合に役立ちます。
  • --force-if-includes: このオプションは、ローカルの変更がリモートの変更も「包含」している場合にのみ強制的にプッシュします。
    • つまり、リモートに自分の変更が含まれていることを確認した上でプッシュしたい場合に便利です。
    • リモートの変更を巻き戻してしまうリスクを防ぎつつ、ローカルの変更を反映させることができます。

組み合わせて使う目的

  • **--force-with-lease--force-if-includes**を同時に使用することで、より安全に強制プッシュができます。
  • 他の開発者の変更をリモートに保持しつつ、自分の変更を適用する際に使用されます。

:

git push --force-with-lease --force-if-includes origin ブランチ名

このコマンドを使うと、他の人の作業を上書きせずに、リモートブランチに対して自分の変更を反映できるので、チームでの作業の安全性を高めるのに役立ちます。

https://zenn.dev/mary_pp/articles/eaac544eaf600a

ピン留めされたアイテム
まさぴょん🐱まさぴょん🐱

rebaseで整理する必要があるパターン📝

画像の状態

スクリーンショットでは Merge branch 'main' of github.com:… というマージコミットが何度も並び、履歴が「ジグザグ」になっています。

  • 自分の作業ブランチ ←→ main を何度も git merge で取り込んだ
  • あるいは git pull の既定が --no-rebase になっていて、毎回 “引き込みマージ” が発生している

という典型的なパターンです。

リベースは有効か?

✔ こんなときはリベースがおすすめ

シチュエーション 理由 コマンド例
1. まだ自分しか触っていないブランチ 履歴を書き換えても他人に影響しない git rebase -i main で不要コミットを squash / fixup
2. git pull 時のマージコミットを無くしたい 毎回の「引き込みマージ」を避けて直線的な履歴に git pull --rebase(設定例: git config --global pull.rebase true
3. PR を作る直前にまとめたい レビューしやすい“意味単位”のコミットに整理 git rebase -i main で順序やメッセージを整理

⚠ リベースを避けた方がいい場合

  • そのブランチ すでに複数人が push / fetch 済み
    → 強制 push (--force-with-lease) が必要になるため、チームと合意が無いと衝突しやすい
  • 公式履歴として残したい分岐点(リリースタグ直前など)
    → マージコミットがあった方が意図が明確なこともある

推奨ワークフロー(例)

  1. feature ブランチを main から作成

    git switch -c feat/awesome
    
  2. 作業中は

    git pull --rebase  # or git fetch && git rebase origin/main
    

    で “引き込みマージ” を作らない

  3. プッシュ前に意味の薄いコミットを squash

    git rebase -i origin/main
    
  4. PR を作成し、マージ方法を

    • GitHub の「Squash and merge
    • もしくは --ff-only(fast-forward マージ)
      に統一する
  5. 本番ブランチ(main/production など)は マージコミットの無い直線的履歴 が保たれる


既にマージコミットだらけのブランチを整理したいとき

# 最新 main を取得
git fetch origin

# 自分の作業ブランチで main を付け替え
git rebase -i origin/main

# 問題なければ強制 push(他の人が触っていないことを確認)
git push --force-with-lease

まとめ

  • 可読性・トラブルシュートのしやすさ を重視するなら、日常的に rebase(pull --rebase)+ squash/ff マージ を採用すると履歴は一直線で綺麗になります。
  • ただし 公開済み履歴の強制書き換えは慎重に — チームでポリシーを決め、--force-with-lease を必ず使うなどの運用ルールを整えてください。
まさぴょん🐱まさぴょん🐱

Git Merge

# 1. masterブランチへ移動
git checkout master

# 2. git pullでmasterを最新に
git pull origin master

# 3. 開発用ブランチへ移動
git checkout 開発用ブランチ

# 4. mergeコマンドでmaserの内容を取り込む
git merge master

# 5. 取り込んだものをリモートにpush
git push origin 開発用ブランチ

https://qiita.com/ksygu/items/7ca1e72c6c079d3a25c1

https://qiita.com/kuramoto30/items/6924a92b512dc073f058

https://qiita.com/chihiro/items/5dd671aa6f1c332986a7

https://zenn.dev/tana0102/articles/475d8952933af6

https://www-creators.com/archives/2111

https://qiita.com/chihiro/items/2fa827d0eac98109e7ee

https://codelikes.com/git-merge/

まさぴょん🐱まさぴょん🐱

git rebase でError

git rebase development

# [ Error内容 ]
It seems that I cannot create a rebase-apply directory, and
I wonder if you are in the middle of patch application or another
rebase.  If that is not the case, please
        rm -fr ".git/rebase-merge" and run me again. 
and run me again.  I am stopping in case you still have something
valuable there.

https://haayaaa.hatenablog.com/entry/2019/10/07/221537

https://kanonji.hatenadiary.com/entry/20110722/1311314486

まさぴょん🐱まさぴょん🐱

「ours」と「theirs」を理解する

Git では、マージまたはリベース中に競合が発生した場合、「ours」と「theirs」のいずれかを選択して競合を解決することができます。
「ours」と「theirs」が何を指すかを理解することは、競合を効果的に解決するために重要です。

  • ours: 現在のブランチ (マージまたはリベースを開始する前にチェックアウトしたブランチ) を指します。これは、ローカルの変更を表します。

  • theirs: 現在のブランチにマージされるブランチを指します。これは、別のブランチ (多くの場合、リモート リポジトリ) から受信した変更を表します。

コマンドの説明

1. ローカルの変更 (ours) を維持して競合を解決する

git checkout --ours .

説明:

  • 目的: このコマンドは、現在のブランチからの変更 (ローカルの変更) を保持することで、現在のすべての競合を解決します。

  • 実行内容:

  • 作業ディレクトリ内の競合ファイルを、現在のブランチのバージョンに置き換えます。

  • 競合を解決済みとしてマークします。

  • 使用例: ローカルの変更を信頼し、他のブランチから受信した変更を破棄したい場合に使用します。

2. 受信した変更 (theirs) を受け入れて競合を解決する

git checkout --theirs .

説明:

  • 目的: このコマンドは、マージ先のブランチからの変更 (多くの場合、リモート リポジトリからの受信した変更) を受け入れて、現在のすべての競合を解決します。

  • 機能:

  • 作業ディレクトリ内の競合ファイルを、マージされるブランチのバージョンに置き換えます。

  • 競合を解決済みとしてマークします。

  • 使用例: ローカルの変更を破棄して、他のブランチから受信した変更を優先する場合に使用します。

用語に関する重要な注意

提供されたコメントに誤解があるようです:

  • コメント:

  • **「現在の変更」(リモート) の場合: git checkout --ours .

  • **「受信した変更」(ローカル) の場合: git checkout --theirs .

  • 説明:

  • 「現在の変更」(ours) は、実際には ローカル ブランチ を指し、リモート ブランチを指しません。

  • 「受信した変更」(theirs) は、マージされるブランチ を指し、多くの場合、リモート ブランチを指します。

視覚的な表現

master にいて、featuremaster にマージしていると仮定します:

  • master: 現在のブランチ (ours)。

  • feature: マージされるブランチ (theirs)。

競合を解決する手順

  1. 競合するファイルを識別する:
git status
  1. 解決戦略を選択する:
  • ローカルの変更を保持する:
git checkout --ours .
  • 受信した変更を受け入れる:
git checkout --theirs .
  1. 解決されたファイルを追加する:
git add .
  1. マージを確定する:
git commit -m "マージ競合を解決しました"

要約

  • git checkout --ours .: ローカルの変更 (現在のブランチ) を保持し、他のブランチから受信した変更を破棄します。

  • git checkout --theirs .: 他のブランチから受信した変更を受け入れ、競合ファイル内のローカルの変更を破棄します。

この違いを理解することで、マージ競合時に情報に基づいた決定を下すことができ、プロジェクトに組み込む変更を制御できるようになります。