4518

Git を使用して、最後の X コミットを 1 つのコミットにまとめるにはどうすればよいですか?

4

40 に答える 40

4710

git rebaseまたはなしで、これをかなり簡単に行うことができますgit merge --squash。この例では、最後の 3 つのコミットをスカッシュします。

新しいコミットメッセージを最初から書きたい場合は、これで十分です:

git reset --soft HEAD~3 &&
git commit

既存のコミット メッセージを連結して新しいコミット メッセージの編集を開始する場合 (つまり、pick/squash/squash/…/squashgit rebase -i命令リストで開始するものと同様)、それらのメッセージを抽出して渡す必要があります。それらにgit commit:

git reset --soft HEAD~3 && 
git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"

これらの方法はどちらも、最後の 3 つのコミットを同じ方法で 1 つの新しいコミットに押しつぶします。ソフトリセットは、スカッシュしたくない最後のコミットに HEAD を再ポイントするだけです。インデックスも作業ツリーもソフト リセットの影響を受けず、インデックスは新しいコミットに必要な状態のままになります (つまり、「破棄」しようとしているコミットからのすべての変更が既に含まれています)。

于 2011-03-05T04:19:17.760 に答える
2646

マニュアルの説明に従って、2 回目以降のコミットで「pick」を使用git rebase -i <after-this-commit>し、「squash」または「fixup」に置き換えます。

この例で<after-this-commit>は、現在のブランチの HEAD からの SHA1 ハッシュまたは相対位置であり、そこから rebase コマンドのコミットが分析されます。たとえば、ユーザーが過去の現在の HEAD から 5 つのコミットを表示したい場合、コマンドはgit rebase -i HEAD~5.

于 2011-03-04T04:18:49.737 に答える
874

これはgit merge --squash、 よりもわずかにエレガントですgit rebase -i。master 上にいて、最後の 12 個のコミットを 1 つにまとめたいとします。

警告: まず、作業をコミットすることを確認してください —git statusクリーンであることを確認してください (git reset --hardステージングされた変更とステージングされていない変更を破棄するため)

それで:

# Reset the current branch to the commit just before the last 12:
git reset --hard HEAD~12

# HEAD@{1} is where the branch was just before the previous command.
# This command sets the state of the index to be as it would just
# after a merge from that commit:
git merge --squash HEAD@{1}

# Commit those squashed changes.  The commit message will be helpfully
# prepopulated with the commit messages of all the squashed commits:
git commit

ドキュメントにgit merge--squash、オプションの詳細が記載されています。


更新:git reset --soft HEAD~12 && git commit Chris Johnsenの回答で提案された単純な方法に対するこの方法の唯一の本当の利点は、押しつぶしているすべてのコミット メッセージが事前に入力されたコミット メッセージを取得することです。

于 2011-03-04T06:10:23.620 に答える
286

git reset特に Git 初心者の場合は、可能な限り避けることをお勧めします。多数のコミットに基づいてプロセスを自動化する必要が本当にない限り、あまりエキゾチックではない方法があります...

  1. 押しつぶす予定のコミットを作業ブランチに置きます (まだ作業ブランチにない場合) -- これには gitk を使用します
  2. ターゲット ブランチをチェックアウトします (例: 'master')
  3. git merge --squash (working branch name)
  4. git commit

コミット メッセージは、スカッシュに基づいて事前設定されます。

于 2014-03-14T23:24:34.343 に答える
205

この便利なブログ投稿のおかげで、このコマンドを使用して最後の 3 つのコミットをスカッシュできることがわかりました。

git rebase -i HEAD~3

これは、追跡情報やリモート リポジトリのないローカル ブランチにいる場合でも機能するので便利です。

このコマンドはインタラクティブなリベース エディターを開き、通常どおりに並べ替え、スカッシュ、リワードなどを行うことができます。


インタラクティブなリベース エディターを使用する:

インタラクティブなリベース エディターには、最後の 3 つのコミットが表示されます。この制約はHEAD~3、コマンドの実行時に決定されましたgit rebase -i HEAD~3

最新のコミットHEADが最初に 1 行目に表示されます。a で始まる行#はコメント/ドキュメントです。

表示されるドキュメントは非常に明確です。任意の行で、コマンドを からpick選択したコマンドに変更できます。

fixupこのコマンドは、コミットの変更を上記の行のコミットに「押しつぶし」、コミットのメッセージを破棄するため、このコマンドを使用することを好みます。

1 行目のコミットは であるHEADため、ほとんどの場合、これをそのままにしておきますpick。コミットを押しつぶす他のコミットがないためsquash、 orを使用することはできません。fixup

コミットの順序を変更することもできます。これにより、時系列的に隣接していないコミットをスカッシュまたは修正できます。

対話型リベース エディター


実用的な日常の例

最近、新しい機能をコミットしました。それ以来、2 つのバグ修正をコミットしました。しかし今、コミットした新機能にバグ (または単なるスペルミス) を発見しました。うっとうしい!コミット履歴を汚染する新しいコミットはしたくありません!

私が最初にすることは、間違いを修正し、コメントで新しいコミットを作成することsquash this into my new feature!です。

次にgit logorgitkを実行して、新しい機能のコミット SHA を取得します (この場合は1ff9460)。

次に、インタラクティブなリベース エディターを立ち上げgit rebase -i 1ff9460~ます。コミット後、SHA はエディターにその~コミットをエディターに含めるように指示します。

次に、修正を含むコミット ( fe7f1e0) を機能コミットの下に移動し、 に変更pickfixupます。

エディターを閉じると、修正が機能のコミットに押しつぶされ、コミット履歴がきれいに表示されます。

これは、すべてのコミットがローカルの場合はうまく機能しますが、既にリモートにプッシュされているコミットを変更しようとすると、同じブランチをチェックアウトした他の開発者に問題が発生する可能性があります!

ここに画像の説明を入力

于 2016-05-17T06:19:48.900 に答える
62

TortoiseGit を使用すると、次の機能を実行できますCombine to one commit

  1. TortoiseGit コンテキスト メニューを開く
  2. 選択するShow Log
  3. ログビューで関連するコミットをマークします
  4. Combine to one commitコンテキストメニューから選択

コミットを組み合わせる

この関数は、必要な単一の git ステップをすべて自動的に実行します。残念ながら、Windows でのみ利用可能です。

于 2015-11-06T12:51:23.070 に答える
58

この記事に基づいて、この方法が私のユースケースにとってより簡単であることがわかりました。

私の 'dev' ブランチは 'origin/dev' よりも 96 コミット進んでいました (したがって、これらのコミットはまだリモートにプッシュされていません)。

変更をプッシュする前に、これらのコミットを 1 つにまとめたかったのです。ブランチを「origin/dev」の状態にリセットし (これにより、96 個のコミットからのすべての変更がステージングされないままになります)、変更を一度にコミットすることをお勧めします。

git reset origin/dev
git add --all
git commit -m 'my commit message'
于 2014-05-22T00:41:28.123 に答える
35

feature-branchGolden Repository( ) から複製されたリモート ブランチ ( と呼ばれる) を使用している場合golden_repo_name、コミットを 1 つにまとめる方法は次のとおりです。

  1. ゴールデンレポをチェックアウト

    git checkout golden_repo_name
    
  2. 次のように、それ(ゴールデンレポ)から新しいブランチを作成します

    git checkout -b dev-branch
    
  3. 既に持っているローカル ブランチとのマージをスカッシュします。

    git merge --squash feature-branch
    
  4. 変更をコミットします (これが dev-branch に入る唯一のコミットになります)

    git commit -m "My feature complete"
    
  5. ブランチをローカル リポジトリにプッシュする

    git push origin dev-branch
    
于 2015-09-09T15:58:27.320 に答える
18

すべてのコミットを 1 つのコミットにまとめたい場合(たとえば、プロジェクトを初めて公開する場合)、次のことを試してください。

git checkout --orphan <new-branch>
git commit
于 2016-08-20T20:39:00.160 に答える
17

これは非常に不器用ですが、一種のクールな方法なので、リングに放り込みます。

GIT_EDITOR='f() { if [ "$(basename $1)" = "git-rebase-todo" ]; then sed -i "2,\$s/pick/squash/" $1; else vim $1; fi }; f' git rebase -i foo~5 foo

翻訳:編集するファイル名がgit-rebase-todo(インタラクティブなリベースプロンプト)である場合、最初の「ピック」以外のすべてを「スカッシュ」に変更し、そうでない場合はvimを生成する新しい「エディター」をgitに提供します-プロンプトが表示されたときに押しつぶされたコミット メッセージを編集するには、vim を取得します。(そして明らかに、私はブランチ foo の最後の 5 つのコミットを押しつぶしていましたが、好きなように変更できます。)

私はおそらくマーク・ロングエアが提案したことをするだろう.

于 2011-03-04T16:12:39.307 に答える
15

IntelliJ IDEA UIで行うのがいかに簡単かについて誰かが言及しましたか?

  • gitウィンドウに移動
  • 1 つにマージするすべてのコミットを手動で選択します。
  • 右クリック > Squash Commits> 押しつぶされたコミット メッセージを編集
  • 左側のブランチ名をクリック > 右クリック > プッシュ >Force Push

ここに画像の説明を入力

于 2021-07-28T03:32:52.453 に答える
6

より一般的な解決策は、「N」コミットを指定するのではなく、スカッシュしたいブランチ/コミット ID を指定することです。これは、特定のコミットまでのコミットをカウントするよりもエラーが発生しにくくなります。タグを直接指定するか、本当にカウントしたい場合は、HEAD~N を指定できます。

私のワークフローでは、ブランチを開始し、そのブランチでの最初のコミットで目標が要約されます (つまり、これは通常、機能の「最終」メッセージとしてパブリック リポジトリにプッシュするものです)。私がやりたいことはgit squash master、最初のメッセージに戻って、プッシュする準備ができたことです。

私はエイリアスを使用します:

squash = !EDITOR="\"_() { sed -n 's/^pick //p' \"\\$1\"; sed -i .tmp '2,\\$s/^pick/f/' \"\\$1\"; }; _\"" git rebase -i

これにより、押しつぶされた履歴がダンプされる前にダンプされます。これにより、元に戻したい場合に、コンソールから古いコミット ID を取得して復元する機会が得られます。(Solaris ユーザーは、GNU sed-iオプションを使用していることに注意してください。Mac および Linux ユーザーはこれで問題ないはずです。)

于 2014-11-04T20:40:26.913 に答える
2

同じブランチのコミットにリベースするときにマージの競合を解決する必要がないようにするには、次のコマンドを使用できます。

git rebase -i <last commit id before your changes start> -s recursive -X ours

すべてのコミットを 1 つにまとめるには、マージするコミットを編集するように求められたら (-i フラグ)、他の回答でも推奨されているように、最初のアクションを除くすべてを更新しますpicksquash

ここでは、マージ戦略 (-s フラグ)recursiveと戦略オプション (-X)oursを使用して、履歴内の後のコミットがマージ競合に勝つようにします。

git rebase -s ours: これを他の何かを行うものと混同しないでください。

参照: git rebase 再帰マージ戦略

于 2020-01-10T17:31:56.800 に答える
2

まず、フィーチャー ブランチと現在のマスター ブランチの間のコミット数を確認します。

git checkout master
git rev-list master.. --count

次に、my-feature ブランチに基づいて別のブランチを作成し、ブランチはそのままにしmy-featureます。

最後に、私は走ります

git checkout my-feature
git checkout -b my-rebased-feature
git checkout master
git checkout my-rebased-feature
git rebase master
git rebase head^x -i
// fixup/pick/rewrite
git push origin my-rebased-feature -f // force, if my-rebased-feature was ever pushed, otherwise no need for -f flag
// make a PR with clean history, delete both my-feature and my-rebased-feature after merge

役に立てば幸いです、ありがとう。

于 2018-08-29T06:37:40.020 に答える