別のブランチからのすべての変更を単一のコミットとして(スカッシュで)マージします


479

Gitで、あるブランチから別のブランチにすべての変更をマージする方法はありますが、同時に単一のコミットにスカッシュする方法はありますか?

私は別のブランチで新しい機能に取り組んでいることが多く、定期的にコミット/プッシュします-主にバックアップまたは自分が作業しているものを別のマシンに転送するためです。ほとんどの場合、これらのコミットは「Feature xxx WIP」または冗長なものを言います。

その作業が完了し、WIPブランチをマージしてマスターに戻したい場合は、それらの中間コミットをすべて破棄し、単一のクリーンコミットを行います。

これを行う簡単な方法はありますか?

あるいは、ブランチされたポイント以降のブランチですべてのコミットを押しつぶすコマンドはどうでしょうか?

回答:


601

別のオプションはgit merge --squash <feature branch>、最後にを実行することgit commitです。

Gitマージから

--squash

--no-squash

実際のマージが発生したかのように(マージ情報を除いて)作業ツリーとインデックスの状態を生成しますが、実際にコミットしたり、移動したりせHEAD$GIT_DIR/MERGE_HEAD、次のgit commitコマンドでマージコミットを作成するように記録し ません 。これにより、現在のブランチの上に1つのコミットを作成できます。その効果は、別のブランチをマージするのと同じです(タコの場合はさらに多く)。


1
クールな機能!gitが大好きです。私は間違いなく将来これを使用するでしょうが、リベース-iについてあなたの方法を知ることをお勧めします。本当に1つのコミット以上のものにしたい場合に備えて、これは良いスキルです。
ウィルバック

4
注意:これは機能しますが、デフォルトのコミットメッセージには、マージされるブランチからのログが含まれます。問題は、表示されるテキスト全体が実際にはコミットメッセージの一部にならない通常の形式に似ていますが、この場合はそうなります。したがって、すべてを望まない場合は、コミットメッセージからすべてを手動で削除する必要があります。使用する前にこれをテストしておくべきだった...
still_dreaming_1 14

23
それと、ブランチはマージされたものとは見なされないことに注意してください。stackoverflow.com/questions/19308790/...
ライアン

3
私見これは呼ばれるべきだったrebase --squash
アンディ

そのため(機能ブランチは実際にはマージされないため)、コミット後に機能ブランチを削除する場合に適しています。あれは正しいですか?(私はgitの専門家ではありません)
Andrew Spencer

214

それを見つけた!マージコマンドには--squashオプションがあります

git checkout master
git merge --squash WIP

この時点ですべてがマージされ、競合する可能性がありますが、コミットされていません。だから私は今できます:

git add .
git commit -m "Merged WIP"

2
何をしgit add .ますか?
マイケル・ポッター

1
@MichaelPotterすべてのファイルと変更を追加
Daksh Shah

2
git add .無視されていないすべてのファイルを現在のディレクトリに追加します。この方法で意図しないファイルを取得することには注意が必要です。
Jake Cobb

7
代わりにgit add .、を使用git add -uして、すでにツリーに追加されているファイルのみを追加できます。
Brandon Ogle

19
「git add。」することも混乱しています。"git merge --squash WIP"を実行すると、既にインデックスにつぶされた変更があります。必要なのはそれらをコミットすることです。「git add」を実行します。たまたま作業ディレクトリにあるが機能ブランチの一部ではなかった変更を追加します。問題は、機能ブランチの変更を1つのコミットとしてコミットする方法でした。
John Pankowicz 16

30

git rebase -i master機能ブランチを試してください。その後、コミットを組み合わせるために、1つを除くすべての「ピック」を「スカッシュ」に変更できます。リベースでコミットを潰す方法を見る

最後に、masterブランチからマージを実行できます。


8
はい、動作しますが、インタラクティブなリベースの煩わしさは望みません。支店が平らになったので、私はすべてが欲しいです。
Brad Robinson

2
+1これはきれいな歴史になります。コミットを個別のパッチ、カード、ストーリーなどとして識別および管理する方がはるかに簡単です
Ryan

2

受け入れられた回答が示唆git merge --squash <feature branch>するように使用することでトリックは実行されますが、実際にマージされたブランチとしてマージされたブランチは表示されません。

したがって、さらに良い解決策は次のとおりです。

  • 最新のマスターから新しいブランチを作成する
  • <feature branch>上記を使用してマージしますgit merge --squash
  • 新しく作成したブランチをマスターにマージします

このウィキでは、手順を詳しく説明しています。


0

私はこれを正確に行うために自分のgitエイリアスを作成しました。呼んでるgit freebase!既存の乱雑でリベースできない機能ブランチを取得して再作成し、同じ名前の新しいブランチにして、コミットを1つのコミットに押しつぶし、指定したブランチ(デフォルトではマスター)にリベースします。最後に、新しく「フリーベースの」ブランチに好きなコミットメッセージを使用できるようにします。

.gitconfigに次のエイリアスを配置してインストールします。

[alias]
  freebase = "!f() { \
    TOPIC="$(git branch | grep '\\*' | cut -d ' ' -f2)"; \
    NEWBASE="${1:-master}"; \
    PREVSHA1="$(git rev-parse HEAD)"; \
    echo "Freebaseing $TOPIC onto $NEWBASE, previous sha1 was $PREVSHA1"; \
    echo "---"; \
    git reset --hard "$NEWBASE"; \
    git merge --squash "$PREVSHA1"; \
    git commit; \
  }; f"

次のコマンドを実行して、機能ブランチから使用します。 git freebase <new-base>

私はこれを数回しかテストしていないので、まずそれを読んで、実行することを確認してください。少しの安全対策として、開始sha1を出力するので、問題が発生した場合に古いブランチを復元できるはずです。

私はそれをgithub上の私のdotfilesリポジトリで維持します:https : //github.com/stevecrozz/dotfiles/blob/master/.gitconfig


至福のように働いた!あなたにも見てかかることがありますevernote.com/shard/s52/sh/7f8f4ff1-9a68-413f-9225-c49e3ee2fafd/...を
イリヤSheershoff

-1

git merge --squash <feature branch> 良いオプションです。「git commit」は、すべての機能ブランチのコミットメッセージを伝え、それを保持することを選択します。

コミットマージを減らすため。

git merge do x times --git reset HEAD ^ --soft then git commit。

リスクが削除されたファイルが戻ってくる可能性があります。


-5

「rebase」コマンドでこれを行うことができます。ブランチを「main」と「feature」と呼びましょう:

git checkout feature
git rebase main

rebaseコマンドは、「機能」のすべてのコミットを、親が「メイン」に等しい1つのコミットとして再生します。

「feature」が作成されてから(または最新のマージ後に)「main」が変更された場合は、git merge main前に実行したいgit rebase main場合があります。これにより、マージの競合が発生した場合に備えて、完全な履歴を保持できます。

リベース後、ブランチをメインにマージできます。これにより、早送りマージが行われます。

git checkout main
git merge feature

概要については、Git Conceptually理解リベースページを参照してください。


これは私にはうまくいきませんでした。WIPブランチを使用して単純なテストリポジトリを作成し、上記を試してマージの競合が発生しました(マスターに変更を加えていませんでした)。
Brad Robinson

メインから機能が作成され(git checkout -b feature main)、メインから最近マージされた場合、リベースから競合が発生しないはずです
NamshubWriter

OK、もう一度試してみました。今回は衝突しなかったが、歴史はつぶされなかった。
Brad Robinson

git-mergeのドキュメントをもう一度見てみると、そうです。一部のコミットはそのまま残ります。"main"から "feature"への以前のマージを行った場合、リベースはそれらの一部を削除しますが、すべては削除しません。
NamshubWriter

機能ブランチが以前に公開されている場合、リベースは非常に危険な場合があることを覚えておいてください。このSO質問の詳細情報。
Robert Rossmann
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.