git merge --squashの使用方法


1209

私はリモートGitサーバーを持っています、これが私が実行したいシナリオです:

  • バグ/機能ごとに異なるGitブランチを作成します

  • 私は非公式のGitメッセージでそのGitブランチでコードをコミットし続けます

  • 最上位のリポジトリでは、公式のGitメッセージで1つのバグに対して1つのコミットを行う必要があります

それで、ブランチをリモートブランチにマージして、すべてのチェックインに対してコミットが1つだけになるようにするにはどうすればよいですか?


1
私があなたを完全に理解したかどうかはわかりませんが、「タコのマージ」が必要かもしれません。
MatrixFrog 2011年

27
私は通常git rebase -iを使用して、すべてのコミットを1つのコミットにまとめ、コミットメッセージを書き直しています。それから私はそれを上流に送ります。
エドワードフォーク

17
git merge --squashコマンドラインですべてを一度に実行し、うまくいくことを願っています。git rebase -iエディターが表示され、リベースを微調整できます。遅いですが、何をしているのかがわかります。また、rebaseとmergeには違いがあり、少し複雑すぎてコメントで対処できません。
Edward Falk

4
これらすべての回答の問題は、ローカルでマスターブランチにいて、merge --squashコマンドを実行する必要があることです...マスターブランチではなく、機能ブランチからmerge --squashを実行したいので、完了したら、機能ブランチをリモートにプッシュしてPRを送信できますが、それは可能ですか?
Alexander Mills

2
@ AlexanderMills、2番目の機能ブランチ(マスターブランチから複製)が必要だと思います。やるmerge --squash新しいものに古いからとして、マスターに新しいブランチをマージします。古いブランチは廃止されました。
ジャイロマイト2018年

回答:


2002

バグ修正ブランチが呼び出されbugfix、それをmaster次のようにマージしたいとします。

git checkout master
git merge --squash bugfix
git commit

これにより、bugfixブランチからすべてのコミットが取得され、1つのコミットに押しつぶされ、ブランチとマージされますmaster


説明

git checkout master

masterブランチに切り替えます。

git merge --squash bugfix

bugfixブランチからすべてのコミットを取得し、現在のブランチとマージします。

git commit

マージされた変更から単一のコミットを作成します。

-mパラメーターを省略すると、コミットを完了する前に、押しつぶされたコミットからのすべてのメッセージを含むドラフトコミットメッセージを変更できます。


222
古いコミットメッセージへの参照を保持したい場合はgit commit-mparam なしで)書くことができ、押しつぶされたすべてのコミットメッセージを含むドラフトされたコミットメッセージを変更できます。
アレックスは

12
git commit --amend -m '...'後で行うことによって同じことを達成できます。
Janusz Lenar 2014

19
マージの競合が発生し、これらの競合を解決した場合、git commitは、押しつぶしたすべてのコミットメッセージを含む有用なコミットメッセージを表示しなくなります。その場合は、git commit --file .git/SQUASH_MSGstackoverflow.com/a/11230783/923560を使用して)試してください。
Abdull

23
押しつぶしはデフォルトでコミットを押しつぶしに帰することを覚えておいてください。:原作者を維持するには、明示的にそうようにそれを指定する必要がありますgit commit -a --author="Author" --message="Issue title #id"
gaborous

5
git merge --squash別のブランチをマージするのと同じ効果を持つ現在のブランチの上に単一のコミットを作成できます。ただし、マージレコードは生成されません。つまり、結果としてのプルリクエストには変更がなく、マージ済みとしてマークされません。そのため、実行するブランチを削除するだけで済みます。
am0wa 2017

129

私にとってこれを最終的に解決したのは、それ示すコメントでした:

git checkout main
git merge --squash feature

することと同じです:

git checkout feature
git diff main > feature.patch
git checkout main
patch -p1 < feature.patch
git add .

私は105(!!)コミットし、それらをすべて一つに押しつぶされていると機能ブランチをマージするとき、私はしたくないgit rebase -i origin/master、私はのために別途解決マージ競合する必要があるため、各中間のコミット(あるいは少なくとも、もののgitは自分自身を理解できません)。を使用git merge --squashすると、機能ブランチ全体をマージするための単一のコミットという、私が望む結果が得られます。そして、私はせいぜい1つの手動の競合解決を行う必要があります。


75
最初git merge masterに機能ブランチでマージを実行し、次にgit merge --squash featureマスターブランチでマージを実行することを強くお勧めします。
dotancohen 2014

8
@dotancohen古いコメントを埋めてごめんなさい:) git merge --squash featureマスターブランチから実行する前に機能ブランチにマージすることから何が得られますか?
ビットマック

57
まずマスターを機能ブランチにマージし、機能ブランチの手動修正を処理します。また、テストを実行して、機能ブランチが正しく動作することを確認することもできます。その後、機能ブランチをマスターに自動的にマージできることが保証されます。
Dan Kohn、2015年

4
@dankohn上記のコメントの説明を回答に追加することをお勧めします。
guntbert

3
@bitsmack:最初にマスターをフィーチャーにマージします。これにより、機能をマスターにマージする前に機能の競合を解決する機会が与えられます
Mike

97

スカッシュオプションとマージしたい。それは、一度に1つのブランチを実行する場合です。

git merge --squash feature1

単一のコミットと同時にすべてのブランチをマージする場合は、最初にインタラクティブにリベースし、各機能を押しつぶしてから、タコをマージします。

git checkout feature1
git rebase -i master

1つのコミットに押しつぶしてから、他の機能についても繰り返します。

git checkout master
git merge feature1 feature2 feature3 ...

その最後のマージは、多数のブランチを一度にマージするため、「タコマージ」です。

お役に立てれば


3
なぜリベースするのですか?
Umair A. 2013

12
@UmairAshrafブランチ内でスカッシュを実行するオプションを提供するインタラクティブなリベースです。
andho 2013年

1
リベースは悪い考えです。すでに公開されているコミットをリベースしないでください
Sebi2020 '16

1
@ Sebi2020 git merge --squashは、インタラクティブなリベースよりも悪い方法で、すでに公開されているコミットをリベースします。(機能ブランチでの)インタラクティブなリベースは、ほとんどまたはまったく悪影響をもたらしません。
xiix

1
@xiixこれは、機能ブランチで作業している唯一のユーザーである場合にのみ当てはまります。これはあなたができる仮定ではありません。Git-SCMのリベースに関連するページを読むことをお勧めします。「リポジトリ外に存在するコミットをリベースしないでください、そして人々はそれらに基づいた作業を持っているかもしれません」そして、人々がすでに公開されたコミットに基づいて作業しているかどうか確実にわからない場合(分散のためにそれを知ることができませんgitの性質)あなたはそれをしません。
Sebi2020

23

すでにgit merge bugfixオンmainになっている場合は、マージコミットを次のコマンドで1つにまとめることができます。

git reset --soft HEAD^1
git commit

git reset --soft HEAD^1少なくともマージが早送りの場合、マージの前に実行された最後のコミットを取り消すようです。
Jesper Matthiesen、2018年

早送りの場合は@JesperMatthiesenでマージコミットを取得できないため、実行しますgit reset --soft HEAD^<number-of-commits-to-squash>
qwertzguy

これは、ダウンストリームマージ後にすべてを1つのコミットに押しつぶすのに役立ちました。
killjoy

18

カスタムコミットでnewFeatureブランチをマージしmasterます:

git merge --squash newFeature && git commit -m 'Your custom commit message';

もしそうなら、あなたは

git merge --squash newFeature && git commit

すべてを含むコミットメッセージが表示されます newFeatureカスタマイズ可能なブランチコミットされます。

ここで徹底的に説明します:https : //youtu.be/FQNAIacelT4


10

この質問は特にGithubに関するものではないことは知っていますが、Githubは非常に広く使用されており、これが私が探していた答えなので、ここで共有します。

Githubには、リポジトリで有効になっているマージオプションに応じて、スカッシュマージを実行する機能があります。

スカッシュマージが有効になっている場合、[マージ]ボタンの下のドロップダウンに[スカッシュとマージ]オプションが表示されます。

「スカッシュとマージ」のGithub機能のスクリーンショット


GitHubは、アカウントに関連付けられているデフォルトのメールを使用します。複数のメールアドレスがあり、セカンダリアドレスを使用する必要がある場合は、GH UIを使用できません。
Luca Guidi

4

複数のコミットを使用してfeature / task1で作業したとします。

  1. プロジェクトブランチに移動します(project / my_project)

    git checkout project/my_project
    
  2. 新しいブランチを作成します(feature / task1_bugfix)

    git checkout -b feature/task1_bugfix
    
  3. --squashオプションでマージ

    git merge --squash feature/task1
    
  4. 単一のコミットを作成する

    git commit -am "add single comments"
    
  5. ブランチをプッシュする

    git push --set-upstream origin feature/task1_bugfix
    

1

Gitの場合

新しいフィーチャーを作成する

ターミナル/シェル経由:

git checkout origin/feature/<featurename>
git merge --squash origin/feature/<featurename>

これはコミットせず、最初に確認できます。

次に、この新しいブランチから機能をコミットして終了し、古いもの(開発したもの)を削除/無視します。


@Melebius「SourceTree」への唯一の参照は、それがタグまたは前の質問であった場合、文の中にあります。それはもう存在しません。
ジョーダンステファネリ

1
@JordanStefanelli SourceTreeは、この回答の元のバージョンで使用されていました。修正されたことを通知してくれてありがとう!
メレビウス

1

エラーが発生した場合:マージされていないファイルがあるため、コミットできません。

git checkout master
git merge --squash bugfix
git add .
git commit -m "Message"

すべての競合ファイルを修正

git add . 

あなたも使うことができます

git add [filename]

0

プッシュする前にローカルブランチを押しつぶすには:

  1. まだチェックアウトされていない場合は、問題のブランチをチェックアウトして作業します。

  2. 保持したい最も古いコミットのshaを見つけます。

  3. そのコミットから新しいブランチ(tmp1)を作成/チェックアウトします。

    git checkout -b tmp1 <sha1-of-commit>

  4. 元のブランチを新しいものにつぶします。

    git merge --squash <original branch>

  5. マージによって作成された変更をコミットの概要メッセージでコミットします。

    git commit -m <msg>

  6. スカッシュする元のブランチをチェックアウトします。

    git checkout <branch>

  7. 保持したい元のcommit shaにリセットします。

    git reset --soft <sha1>

  8. 新しいtmp1ブランチに基づいてこのブランチをリベースします。

    git rebase tmp1

  9. それだけです-すべてが問題ないことを確認したら、一時tmp1ブランチを削除してください。


0

このプロセスを簡単にするために私が作成したツールgit-squashを使用できます。たとえば、マスターブランチからブランチされた機能ブランチのすべてのコミットをスカッシュするには、次のように記述します。

git squash master
git push --force
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.