非対話的に多くのコミットを押しつぶす方法はありますか?


回答:


146

作業ツリーがきれいであることを確認してから、

git reset --soft HEAD~3
git commit -m 'new commit message'

@wilhelmtell:すばらしい!これで、たとえば「mysquash 3 'some message'」などのgitエイリアスを作成して、これを1行に削減できますか?
Phillip

5
行数のみの場合:git reset --soft HEAD~3 && git commit -m "my message"
KingCrunch

7
@Phillip:gitエイリアスにシェル関数を埋め込むことができます。git config alias.mysquash '!f(){ git reset --soft HEAD~$1 && git commit ${2:+-m "$2"}; };f'git mysquash 3 'some message'動作しますが、私はそれを微調整したためgit musquash 3、-mフラグを完全に省略してgit commit、その場合はインタラクティブなUIを取得します。
リリーバラード2011

3
明確にするために:スカッシュと同じではありません。スカッシュはコミットメッセージもマージします。ソフトリセットを実行すると、コミットのすべてのメッセージが失われます。あなたはスカッシュのtryにしたい場合はstackoverflow.com/a/27697274/974186
ルネ・リンク

1
@sebnukem-ブランチをプッシュしようとしたときに、リモートが強制プッシュを拒否するように構成されています。
avmohan 2016

30

私はウィルヘルムテルのソリューションを個人的に気に入っています:

git reset --soft HEAD~3
git commit -m 'new commit message'

ただし、これを実行できるように、いくつかのエラーチェックでエイリアスを作成しました。

git squash 3 'my commit message'

スクリプトを実際に実行するエイリアスを設定することをお勧めします。これにより、(a)スクリプトのコーディングが簡単になり、(b)エラーチェックでより複雑な作業を行うことができます。以下はスカッシュの機能を実行するスクリプトで、次にそれはgitエイリアスを設定するためのスクリプトです。

スカッシュ用のスクリプト(squash.sh)

#!/bin/bash
#

#get number of commits to squash
squashCount=$1

#get the commit message
shift
commitMsg=$@

#regular expression to verify that squash number is an integer
regex='^[0-9]+$'

echo "---------------------------------"
echo "Will squash $squashCount commits"
echo "Commit message will be '$commitMsg'"

echo "...validating input"
if ! [[ $squashCount =~ $regex ]]
then
    echo "Squash count must be an integer."
elif [ -z "$commitMsg" ]
then
    echo "Invalid commit message.  Make sure string is not empty"
else
    echo "...input looks good"
    echo "...proceeding to squash"
    git reset --soft HEAD~$squashCount
    git commit -m "$commitMsg"
    echo "...done"
fi

echo
exit 0

次に、そのsquash.shスクリプトをgitエイリアスに接続するには、gitエイリアスを設定する別のスクリプトを作成します(create_aliases.commandまたはcreate_aliases.sh)。

#!/bin/sh
echo '-----------------------'
echo 'adding git aliases....'
echo '-----------------------'
echo
git config --global alias.squash "!bash -c 'bash <path to scripts directory>/squash.sh \$1 \$2' -"
#add your other git aliases setup here
#and here
#etc.
echo '------------------------------------'
echo 'here is your global gitconfig file:'
echo '------------------------------------'
more ~/.gitconfig
echo 
echo
echo '----------------'
echo 'end of script...'
echo '----------------'

4
$PATH名前git-squash.shを付けて置くこともでき、自動的にとしてエイリアス化されgit squashます。私が知らないcreate-aiases.shスクリプトを使用する理由がある場合に備えて、私はあなたの答えを変更しませんでした。

基本的にcreate_aliases.commandスクリプトを使用するので、PMやデザイナーでも簡単にセットアップできます。スクリプトをダブルクリックするだけで、すべてが設定されます(特に、リポジトリにセットアップスクリプトがあり、相対パスがわかっているため)。そうすれば、ターミナルを再起動する必要すらありません。
n8tr 2014年

1
私はこれを試しましたが、コミットメッセージをスカッシュカウントとして読み取り、整数ではないため失敗します。
Minthos 2014

1
解決策は、/ squash.sh \ $ 1 \ $ 2 'の後に追加することでした
Minthos

1
私は解決策のアイデアが好きですが、上のコメントは解決策ではまだ考慮されていません。一重引用符と二重引用符の間にマイナス記号が必要です。
フィジカル

10

wilhelmtellによる回答に追加するには、にソフトリセットしてからHEAD~2コミットを修正すると便利ですHEAD~3

git reset --soft HEAD~2
git commit --all --amend --no-edit    

これにより、すべてのコミットがコミットにマージされ、HEAD~3そのコミットメッセージが使用されます。クリーンな作業ツリーから始めてください。


2
これは正解です。これは、先頭に至る一連のコミットを押しつぶし、最初のコミットのメッセージを使用するためです。非インタラクティブです。
Landon Kuhn

9

私が使用した:

EDITOR="sed -i '2,/^$/s/^pick\b/s/'" git rebase -i <ref>

かなりうまくいきました。"pick"で始まる行を含むコミットログを作成しないでください:)


悲しいことに、これはWindowsでは動作しません。インタラクティブエディタを引き続き入手します。
abergmeier 2014年

3

次のコマンドを使用して、最後のコミット内の最後の4つのコミットを押しつぶします。

git squash 4

エイリアス:

squash = !"f() { NL=$1; GIT_EDITOR=\"sed -i '2,$NL s/pick/squash/;/# This is the 2nd commit message:/,$ {d}'\"; git rebase -i HEAD~$NL; }; f"
sq = !git squash $1
sqpsf = !git squash $1 && git psf 

https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfigから


ここでは、使用されているOS /シェルを指定していません。このソリューションは、おそらく人々が使用する他のすべてのデスクトップでは機能しません。
Rick-777

はい、これにはlinux / bash | zshを使用する必要があります
brauliobo

2

ここに、最後の2つのコミットを押しつぶすための1つのライナーがあります。この例では、最後の2番目のコミットのメッセージが保持されます。メッセージは自由に変更できます。

git commit -am "$(git log -1 --skip=1 --pretty=%B | xargs && git reset --soft HEAD~2)"

このコマンドは、このコマンドのエイリアスを作成し、代わりにエイリアスを使用する場合に非常に役立ちます。


1

ブランチがマスターから分岐されてからすべてをつぶすには:

git reset --soft $(git merge-base --fork-point master) \
  && git commit --verbose --reedit-message=HEAD --reset-author

--reedit-message=HEADスカッシュの一部ではない最後のコミットのメッセージを使用します。これはおそらくあなたが望むものではありません。むしろのメッセージを取得するには最初に含まれるコミットのいずれか、(1)交換するHEADあなたがのメッセージ、またはたいコミットのハッシュと(2)最初に含まれるコミットへジャンプしますgit commit --amend --reedit-message=HEAD。これが調和のとれた答えです。
Maëlan

-1

あなたはかなり近づくことができます

git rebase --on HEAD〜4 HEAD〜マスター

これは、あなたが線形履歴を持つマスターにいることを前提としています。中間のコミットを破棄するので、それはかなりスカッシュではありません。コミットメッセージを変更するには、新しいHEADを修正する必要があります。


グレッグに感謝します。「破棄」とは、これらの中間コミットがgit gcによるクリーンアップの対象となることを意味しますか?
Phillip

@Phillipはい、中間のコミットは古いHEADだけでなくガベージにもなりHEAD~4、親として持つように書き換えられます。
グレッグベーコン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.