Gitを使って最後のX個のコミットをまとめて1つのコミットにまとめるにはどうすればいいですか?
git rebase -i <after-this-commit>
を使用し、 マニュアル で説明されているように、2回目以降のコミットの "pick"を "squash"または "fixup"に置き換えます。
この例では、<after-this-commit>
はSHA1ハッシュか、rebaseコマンドでコミットが分析される現在のブランチのHEADからの相対位置です。たとえば、過去に現在のHEADから5コミットを表示したい場合、コマンドはgit rebase -i HEAD~5
です。
git rebase
やgit merge --squash
がなくても、これはかなり簡単にできます。この例では、最後の3つのコミットを潰します。
新しいコミットメッセージを一から書きたいのであれば、これで十分です。
git reset --soft HEAD~3 &&
git commit
既存のコミットメッセージを連結して新しいコミットメッセージの編集を開始したい場合(つまり、pick/squash/squash /…/ squash git rebase -i
命令リストから始まるのと同じように)、それらのメッセージを抽出する必要があります。それらをgit commit
に渡します。
git reset --soft HEAD~3 &&
git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"
どちらの方法も、最後の3つのコミットを同じ方法で1つの新しいコミットに圧縮します。ソフトリセットはHEADをスカッシュしたくない最後のコミットに再設定するだけです。インデックスも作業ツリーもソフトリセットで触れられず、インデックスは新しいコミットに望ましい状態になります(つまり、「破棄」しようとしているコミットからのすべての変更が既にあります)。
これにはgit merge --squash
を使用できます。これはgit rebase -i
よりも少しエレガントです。あなたがマスターしていて、最後の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
オプションをより詳細に説明しています。
更新: Chris Johnsenによって 彼の答え で提案されている単純なgit reset --soft HEAD~12 && git commit
に対するこの方法の唯一の本当の利点は、あなたが押しつぶしているすべてのコミットメッセージでコミットメッセージを事前入力することです。
可能であればgit reset
を避けることをお勧めします。 - - のコミット数に基づいてプロセスを自動化する必要が本当にない限り、それほど珍しい方法はありません...
git merge --squash (working branch name)
git commit
コミットメッセージはスカッシュに基づいて事前入力されます。
Bash:からグローバルな "squash"エイリアスを追加します(またはWindowsではGit Bash)。
git config --global alias.squash '!f(){ git reset --soft HEAD~${1} && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"; };f'
...またはWindowsのコマンドプロンプトを使用する
git config --global alias.squash "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"
あなたの~/.gitconfig
はこのエイリアスを含むはずです:
[alias]
squash = "!f(){ git reset --soft HEAD~${1} && git commit --edit -m\"$(git log --format=%B --reverse HEAD..HEAD@{1})\"; };f"
使用法:
git squash N
...これは自動的に最後のN
コミットをまとめます。
注:結果として得られるコミットメッセージは、順番にすべての潰されたコミットの組み合わせです。あなたがそれに不満を抱いているなら、手動でそれを修正するためにいつでもgit commit --amend
を使うことができます。 (または、あなたの好みに合うようにエイリアスを編集してください。)
おかげで この便利なブログ記事 私はあなたが最後の3つのコミットを潰すためにこのコマンドを使うことができるとわかりました:
git rebase -i HEAD~3
あなたが追跡情報/リモートレポのないローカルブランチにいる時でさえもそれが働くのでこれは便利です。
このコマンドは対話式リベースエディタを開きます。これにより、通常どおりに並べ替え、スカッシュ、書き換えなどを行うことができます。
対話式リベースエディタを使用します。
対話式リベースエディタは、最後の3つのコミットを表示します。この制約は、コマンドHEAD~3
の実行時にgit rebase -i HEAD~3
によって決定されました。
最新のコミットHEAD
が1行目の最初に表示されます。#
で始まる行はコメント/ドキュメンテーションです。
表示される文書はかなり明確です。どの行でも、コマンドをpick
から選択したコマンドに変更できます。
上の行でコミットの変更をコミットに「押し潰し」、コミットのメッセージを破棄するので、コマンドfixup
を使用することを好みます。
1行目のコミットはHEAD
なので、ほとんどの場合、これはpick
のままにします。 コミットを潰すためのコミットが他にないため、squash
またはfixup
を使用することはできません。
に基づいて この記事 私は私のユースケースのためにこのメソッドが簡単だとわかりました。
私の 'dev'ブランチは 'Origin/dev'より96コミット進んでいました(だからこれらのコミットはまだリモートにプッシュされていません)。
変更を進める前に、これらのコミットを1つにまとめたいと思いました。私はブランチを 'Origin/dev'の状態にリセットすることを好み(これは96のコミットからの全ての変更をステージングされないままにしておくでしょう)それから一度に変更をコミットします:
git reset Origin/dev
git add --all
git commit -m 'my commit message'
これを行うには、次のgitコマンドを使用します。
git rebase -i HEAD~n
n(ここでは4)は最後のコミットの数です。それからあなたは以下のオプションを得ました、
pick 01d1124 Message....
pick 6340aaa Message....
pick ebfd367 Message....
pick 30e0ccb Message....
次のように更新
p 01d1124 Message....
s 6340aaa Message....
s ebfd367 Message....
s 30e0ccb Message....
詳細については リンクをクリックしてください
がんばろう!!
1)コミットショートハッシュを識別する
# git log --pretty=oneline --abbrev-commit
abcd1234 Update to Fix for issue B
cdababcd Fix issue B
deab3412 Fix issue A
....
ここでもgit log --oneline
で短いハッシュを取得するのに使用することができます。
2)最後の2つのコミットをスカッシュ(マージ)したい場合
# git rebase -i deab3412
3)これはマージのためのnano
エディタを開きます。そしてそれは以下のようになります
....
pick cdababcd Fix issue B
pick abcd1234 Update to Fix for issue B
....
4)Wordのpick
をabcd1234
の前にあるsquash
に名前変更します。名前を変更した後は、次のようになります。
....
pick cdababcd Fix issue B
squash abcd1234 Update to Fix for issue B
....
5)nano
エディタを保存して閉じます。 ctrl + o
を押し、Enter
を押して保存します。そしてctrl + x
を押してエディタを終了します。
6)それからコメントを更新するためにnano
エディタが再び開き、必要ならそれを更新します。
7)これで正常に圧縮されました。ログを確認して確認できます。
# git log --pretty=oneline --abbrev-commit
1122abcd Fix issue B
deab3412 Fix issue A
....
8)今リポジトリにプッシュします。ブランチ名の前に+
記号を追加することに注意してください。これは強制プッシュを意味します。
# git Push Origin +master
注:これはubuntu
シェルでのgitの使用に基づいています。異なるos(Windows
またはMac
)を使用している場合、上記のコマンドはエディタ以外は同じです。あなたは別のエディタを手に入れるかもしれません。
Anomies answer は良いですが、これについて不安を感じたので、スクリーンショットをいくつか追加することにしました。
git log
で現在地を確認してください。最も重要なのは、スカッシュするしてはいけない最初のコミットのコミットハッシュを見つけることです。だから:
実行 git rebase -i [your hash]
、私の場合:
$ git rebase -i 2d23ea524936e612fae1ac63c95b705db44d937d
私の場合、時間内に最初に行ったコミットですべてをつぶします。順序は最初から最後までなので、git log
の場合とまったく同じです。私の場合、私は欲しい:
コミットを1つだけ選択し、残りをつぶした場合は、1つのコミットメッセージを調整できます。
それでおしまい。これを保存したら(:wq
)完了です。 git log
でご覧ください。
ゴールデンリポジトリ(feature-branch
)から複製されたリモートブランチ(golden_repo_name
)にいる場合は、コミットを1つにまとめる手法は次のとおりです。
ゴールデンレポをチェックアウト
git checkout golden_repo_name
次のようにして、そこから新しいブランチを作成します(ゴールデンレポ)。
git checkout -b dev-branch
あなたが既に持っているあなたのローカルブランチとのスカッシュマージ
git merge --squash feature-branch
変更をコミットします(これがdev-branchで行われる唯一のコミットになります)。
git commit -m "My feature complete"
ブランチをあなたのローカルリポジトリにプッシュする
git Push Origin dev-branch
これは非常におしゃべりですが、ちょっとクールな方法ですので、それをリングに投げます。
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
(インタラクティブリベースプロンプト)の場合、最初の "pick"以外はすべて "squash"に変更し、それ以外の場合はvimを生成するように、gitに新しい "editor"を提供押しつぶされたコミットメッセージを編集するよう促されて、あなたはvimを得ます。 (そして明らかに私はブランチfooでの最後の5つのコミットを潰していましたが、あなたはそれを好きなように変更することができます。)
ブランチで、コミットを結合したい場合は、次のように実行します。
git rebase -i HEAD~(n number of commits back to review)
これによりテキストエディタが開きます。これらのコミットをマージしたい場合は、各コミットの前にある 'pick'を 'squash'に切り替える必要があります。たとえば、すべてのコミットを1つにマージしようとしている場合は、 'pick'が最初のコミットであり、それ以降のすべてのコミットは 'squash'に設定する必要があります。 vimを使用している場合は、挿入モードで :x を使用してエディタを保存して終了します。
その後、リベースを続行します。
git rebase --continue
これやあなたのコミット履歴を書き換える他の方法についての詳細は この役に立つ投稿 を参照してください。
本当に便利なことがあります。d43e15
のように、つぶしたいコミットハッシュを見つけます。
今すぐ使用
git reset d43e15
git commit -am 'new commit name'
every commitを1つのコミットにまとめたい場合(たとえば、初めてプロジェクトを公開したとき)、次のことを試してください。
git checkout --Orphan <new-branch>
git commit
これを行うための最も簡単な方法は、masterから新しいブランチを作成し、マージすることです - featureブランチのスカッシュ。
git checkout master
git checkout -b feature_branch_squashed
git merge --squash feature_branch
これで、すべての変更をコミットする準備が整いました。
最後の10個のコミットを1つのシングルコミットに圧縮するには
git reset --soft HEAD~10 && git commit -m "squashed commit"
潰されたコミットでリモートブランチを更新したい場合は、
git Push -f
git rebase -i HEAD^^
^の数はXです
(この場合、最後の2つのコミットを潰します)
もっと一般的な解決策は 'N'コミットを指定するのではなく、むしろあなたが一番上に押しつぶしたいbranch/commit-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ユーザーはこれで問題ないはずです。)
問題となるのは、「最後の」の意味が曖昧なことです。
たとえば、git log --graph
は次のように出力します(簡略化)。
* commit H0
|
* merge
|\
| * commit B0
| |
| * commit B1
| |
* | commit H1
| |
* | commit H2
|/
|
それから時間による最後のコミットはH0、マージ、B0です。それらを潰すには、マージしたブランチをコミットH1でリベースする必要があります。
問題は、H0にH1とH2が含まれていること(そしてマージ前と分岐後のコミット数が多いこと)ですが、B0には含まれていないことです。そのため、少なくともH0、マージ、H1、H2、B0からの変更を管理する必要があります。
リベースを使用することは可能ですが、他の方法で答えを述べたのとは異なる方法で使用します。
rebase -i HEAD~2
これはあなたに選択の選択肢を示すでしょう(他の答えで述べたように):
pick B1
pick B0
pick H0
ピックの代わりにスカッシュをH0に置きます。
pick B1
pick B0
s H0
保存および終了後、リベースはH1の後に順番にコミットを適用します。つまり、競合を再度解決するように求められます(最初にHEADがH1になり、適用されるたびにコミットが累積されます)。
リベースが完了したら、つぶしたH0とB0のメッセージを選択できます。
* commit squashed H0 and B0
|
* commit B1
|
* commit H1
|
* commit H2
|
P.S単にBO:にリセットするだけの場合(たとえば、ここで詳しく説明されているreset --mixed
を使用する https://stackoverflow.com/a/18690845/2405850 ):
git reset --mixed hash_of_commit_B0
git add .
git commit -m 'some commit message'
それからB0のH0、H1、H2の変更に潰します(分岐の後でマージの前に完全に変更をコミットします)。
他の優れた答えに加えて、私はgit rebase -i
が常にコミット順と私を混同していることを付け加えたいと思います - 古いものから新しいもの、またはその逆でしょうか。これが私のワークフローです。
git rebase -i HEAD~[N]
、ここでNは参加したいコミットの数です 最新のものから始めて 。そのためgit rebase -i HEAD~5
は「最後の5つのコミットを新しいものに変更する」という意味です。中間コミットのコミットメッセージを気にしない場合は、次を使用できます。
git reset --mixed <commit-hash-into-which-you-want-to-squash>
git commit -a --amend
(MASTER)
Fleetwood Mac Fritz
║ ║
Add Danny Lindsey Stevie
Kirwan Buckingham Nicks
║ ╚═══╦══════╝
Add Christine ║
Perfect Buckingham
║ Nicks
LA1974══════════╝
║
║
Bill <══════ YOU ARE EDITING HERE
Clinton (CHECKED OUT, CURRENT WORKING DIRECTORY)
https://github.com/fleetwood-mac/band-history リポジトリの非常に簡略化された歴史の中で、Bill Clintonコミットを元の(MASTER
)Fleetwood Macコミットにマージするためのpull requestを開きました。 。
プルリクエストを開くと、GitHubでこれがわかります。
4つのコミット
だれもリポジトリの全履歴を読んでも構わないと考える人はいません。 (実際にはリポジトリがあります。上のリンクをクリックしてください!)これらのコミットを潰すことにしました。 git reset --soft HEAD~4 && git commit
を実行してください。それからあなたのPRをクリーンアップするためにGitHubにそれをgit Push --force
します。
そして何が起こりますか? FritzからBill Clintonへのシングルコミットを完了しました。昨日あなたがこのプロジェクトのバッキンガムニックス版に取り組んでいたことを忘れたので。そしてgit log
はGitHubで見たものと一致しません。
git checkout
git reset --soft
git commit
を作るこのようなワークフローに関する質問に対する回答はどうですか。
merge --squash
を入力するほうが簡単ですが、チームはプロセスを遅くすると考えました。)このページではそのようなワークフローは見たことがありません。 (それは私の目かもしれません。)もし私がrebase
を正しく理解するならば、複数のマージは 複数の衝突解決を必要とするでしょう 。私はそれについても考えたくありません!
だから、これは私たちのために働くようだ。
git pull master
git checkout -b new-branch
git checkout -b new-branch-temp
git checkout new-branch
git merge --squash new-branch-temp
//全ての変更をステージに入れるgit commit 'one message to rule them all'
git Push
まず、私の機能ブランチと現在のマスターブランチの間のコミット数を調べます。
git checkout master
git rev-list master.. --count
それから、私は自分の機能のブランチに基づいて別のブランチを作成し、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
お役に立てば幸いです。
あなたが現在あなたが潰したいブランチにいて、masterがそれが由来するブランチであり、そして最新のコミットがあなたが使いたいコミットメッセージと作者を含んでいるならば、いつもうまくいく単純なワンライナー
git reset --soft $(git merge-base HEAD master) && git commit --reuse-message=HEAD@{1}
GitUp を使用している場合は、親とマージしたいコミットを選択して _ s _ を押します。コミットごとに1回実行する必要がありますが、正しいコマンドラインの呪文を思いつくよりもずっと簡単です。特にそれがあなたがたまにしかしないものであるならば。
たとえば、最後の3つのコミットをブランチ(リモートリポジトリ)内の1つのコミットにまとめたい場合は、次のようにします。 https://bitbucket.org
私がしたことは
このbash関数をbashの.zshrcファイルに追加するだけです。
# Squash last X commits with a Commit message.
# Usage: squash X 'COMMIT_MSG'
# where X= Number of last commits.
# where COMMIT_MSG= New commit msg.
function squash() {
if [ -z "${1}" -o -z "${2}" ]; then
echo "Usage: \`squash X COMMIT_MSG\`"
echo "X= Number of last commits."
echo "COMMIT_MSG= New commit msg."
return 1
fi
git reset --soft HEAD~"$1"
git add . && git ci -m "$2" # With 100 emoji
git Push --force
}
それから走りなさい
squash X 'New Commit Message'
そして、これで終わりです。