web-dev-qa-db-ja.com

2つの非連続コミットをどのようにスカッシュしますか?

私はgitのリベース機能全体に少し慣れています。私が次のコミットをしたとしましょう:

A -> B -> C -> D

その後、Dに追加されたいくつかの新しいコードに依存する修正がAに含まれており、これらのコミットが一緒になっていることに気付きました。 ADをまとめてスカッシュし、BCをそのままにする方法を教えてください。

153
Nik Reiman

git rebase --interactiveを実行し、Bの前にDを並べ替え、DをAに押しつぶすことができます。

Gitはエディターを開き、次のようなファイルが表示されます。

pick aaaaaaa Commit A
pick bbbbbbb Commit B
pick ccccccc Commit C
pick ddddddd Commit D

# Rebase aaaaaaa..ddddddd onto 1234567 (4 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using Shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

ここで、ファイルを次のように変更します。

pick aaaaaaa Commit A
squash ddddddd Commit D
pick bbbbbbb Commit B
pick ccccccc Commit C

GitはAとDの変更を1つのコミットにまとめ、その後BとCをコミットします。 Dのコミットメッセージを保持したくない場合は、「fix」キーワードを使用することもできます。

204
Rudi

注意:プッシュされたコミットを変更しないでくださいは、 結果を知っている場合を除き、何らかの方法で別のリポジトリにする必要があります

git log --oneline -4

D commit_message_for_D
C commit_message_for_C
B commit_message_for_B
A commit_message_for_A

git rebase --interactive

pick D commit_message_for_D
pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A

タイプi(挿入モードでVIM)

リストを次のように変更します(コミットメッセージを削除または含める必要はありません)。 squash!のスペルを間違えないでください!

pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
squash D

タイプ Esc 次にZZ(VIMを保存して終了)

# This is a combination of 2 commits.
# The first commit's message is:

commit_message_for_D

# This is the 2nd commit message:

commit_message_for_A

タイプi

テキストを、新しいコミットメッセージの外観に変更します。これをcommit AおよびDの変更の説明にすることをお勧めします。

new_commit_message_for_A_and_D

タイプ Esc 次にZZ

git log --oneline -4

E new_commit_message_for_A_and_D
C commit_message_for_C
B commit_message_for_B

git show E

(You should see a diff showing a combination of changes from A and D)

これで、新しいコミットEが作成されました。コミットAおよびDは履歴にありませんが、消えていません。この時点でしばらくは、git rebase --hard Dgit rebase --hardはローカルの変更を破棄します!)。

41
Nate

SourceTree を使用している場合:

コミットをプッシュしていないことを確認してください。

  1. リポジトリ>インタラクティブリベース...
  2. D(新しいコミット)をドラッグして、A(古いコミット)の真上に移動します
  3. コミットDが強調表示されていることを確認してください
  4. Squash with previousをクリックします
3
Adam Johns

インタラクティブなリベースは、ブランチでコミットしている間に20-30のコミットやマスターからのマージのカップル、または競合を修正する大きな機能ブランチができるまでうまく機能します。履歴からコミットを見つけ、picksquashに置き換えても、ここでは機能しません。だから私は別の方法を探していて、これを見つけました 記事 。私はこれを別のブランチで動作するように変更しました:

git checkout master
git fetch
git pull
git merge branch-name
git reset Origin/master
git branch -D branch-name
git checkout -b branch-name
git add --all
#Do some commit
git Push -f --set-upstream Origin branch-name

この前に、マスターからの2〜3回のマージと競合の修正を含む約30のコミットでプルリクエストを受け取りました。そしてこの後、私は1回のコミットで明確なPRを得ました。

追伸自動モードでこの手順を実行するには、bash script を使用します。

1
Oleksiy Guzenko