0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Gitで変更量が多すぎるときのmerge・cherry-pick・restoreの整理

0
Posted at

概要

長期間開発を続けていると、developブランチとの差分が大きくなり、単純なマージが難しくなることがある。

調べていく中で、

  • ファイル単位で取り込めるのか
  • コミット単位で取り込めるのか
  • merge以外の選択肢はあるのか
  • 他ブランチがdevelopへ統合された単位で確認できるのか

といった疑問が出てきた。

この記事では、それぞれの方法を整理しながら、変更量が多い場合の確認方法についてまとめる。

背景

ある時点でdevelopを取り込もうとしたところ、差分がかなり大きくなっていた。

そのままマージしてもよかったが、

  • どの変更が入るのか把握できていない
  • 不要な変更まで取り込む可能性がある
  • 競合が大量発生するかもしれない

という懸念があった。

そこで、Gitが提供している複数の取り込み方法を整理した。

問題

まず疑問だったのは次の点である。

  • Gitで特定ファイルだけマージできるのか
  • restoreはマージなのか
  • restoreでは競合が発生するのか
  • cherry-pickはどういう場面で使うのか
  • developへマージされた変更をまとめて確認できるのか

調査内容

調査1: 特定ファイルだけ取り込めるのか

最初は「ファイル単位でマージできるのか」と考えた。

調べてみると、Gitのmerge自体にはファイル指定機能はない。

代わりに、別ブランチのファイルを現在のブランチへ取り込む方法がある。

git fetch origin
git restore --source origin/develop -- src/App.cs

旧形式では以下でも同様の操作が可能。

git checkout origin/develop -- src/App.cs

複数ファイルも指定できる。

git restore --source origin/develop -- src/App.cs src/Config.cs

調査2: restoreはマージなのか

最初はrestoreを「ファイル単位のマージ」だと思っていた。

しかし挙動を確認すると違った。

git restore --source origin/develop -- src/App.cs

これはマージではなく、

  • 指定ブランチのファイルを取得する
  • 現在のファイルへ反映する

という操作だった。

つまり、履歴上はマージにはならない。

原因

restoreとmergeを同じものとして考えていたことが原因だった。

実際には役割が異なる。

操作 役割
merge ブランチ統合
cherry-pick コミット単位取り込み
restore ファイル取得

調査3: restoreで競合は起きるのか

競合についても確認した。

結果として、通常の意味でのマージ競合は発生しない。

理由は単純で、自動マージをしていないからである。

git restore --source origin/develop -- src/App.cs

実行すると対象ファイルは置き換わる。

そのため、

  • コンフリクトマーカーは出ない
  • 自動マージは行われない
  • ローカル変更は失われる可能性がある

という特徴がある。

事前確認として以下を実行しておくと安全である。

git diff -- src/App.cs

調査4: コミット単位で取り込む方法

変更の一部だけ欲しい場合はcherry-pickが利用できる。

まず対象コミットを確認する。

git fetch origin
git log --oneline HEAD..origin/develop

古い順に確認する場合。

git log --oneline --reverse HEAD..origin/develop

対象コミットの内容を見る。

git show <commit-id>

取り込む場合。

git cherry-pick <commit-id>

これにより、ブランチ全体ではなく特定コミットだけを反映できる。

コミット単位とは何か

例えば以下の履歴があるとする。

develop

A
B
C
D

通常のマージ。

git merge origin/develop

結果。

A
B
C
D

すべて取り込まれる

一方、cherry-pickの場合。

git cherry-pick A
git cherry-pick C

結果。

A
C

だけ取り込まれる

ただし、依存関係のあるコミットを見落とすと問題が起きる可能性があるため、変更内容の確認は必須である。

調査5: developへマージされた単位で確認できるか

大量のコミットを個別に追うのは大変である。

そこで、ブランチ単位で確認できないか調べた。

マージコミットだけ表示する。

git log --oneline --merges HEAD..origin/develop

本流の履歴を確認する。

git log --oneline --merges --first-parent origin/develop

特定マージの内容を確認する。

git show <merge-commit-id>

マージされたブランチ側のコミット一覧を確認する。

git log --oneline <merge-commit-id>^1..<merge-commit-id>^2

個別コミットを見る前に、まずマージ単位で確認する方が状況を把握しやすいと感じた。

解決方法

変更量が多い場合は、いきなりマージする前に以下を確認する。

git fetch origin

git log --oneline --merges --first-parent origin/develop

そのうえで、

  • 全体を取り込みたい → merge
  • 特定修正だけ取り込みたい → cherry-pick
  • 特定ファイルだけ取り込みたい → restore

という使い分けを行う。

結果

各コマンドの役割を整理できた。

特に、

  • restoreはマージではない
  • restoreは通常の競合を起こさない
  • cherry-pickはコミット単位で取り込める
  • マージコミット単位で変更を確認できる

という点が理解できた。

学んだこと

  • mergeはブランチ単位の統合である
  • restoreはファイル取得でありマージではない
  • restoreはローカル変更を上書きする可能性がある
  • cherry-pickは必要なコミットだけを反映できる
  • 依存コミットの存在には注意が必要
  • git log --merges --first-parentで本流の変更を追いやすい
  • 変更量が多い場合はマージコミット単位で確認すると理解しやすい

まとめ

developとの差分が大きくなった場合でも、必ずしもmergeだけが選択肢ではない。

変更の粒度によって、

  • ブランチ単位ならmerge
  • コミット単位ならcherry-pick
  • ファイル単位ならrestore

を使い分けることができる。

また、大量の変更を把握する際は、個別コミットを見る前にマージコミット単位で確認すると整理しやすかった。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?