連続しない2つのコミットをどのように押しつぶすのですか?


183

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

A -> B -> C -> D

その後、にD追加されたいくつかの新しいコードに依存する修正が含まれていることA、およびこれらのコミットが一緒に属していることに気付きました。どのように私はつぶすんAD一緒に休暇BC一人で?

回答:


258

git rebase --interactiveD を実行してBの前に並べ替え、DをAにスカッシュできます。

Gitがエディターを開き、次のようなファイルが表示されます。 git rebase --interactive HEAD~4

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ではなく、Dのコミットメッセージを保持したくないsquash場合は、fixupキーワードを使用します。詳細fixupについては、git rebaseドキュメントを参照するか、いくつかの良い答えがあるこの質問をチェックしてください。


5
最初は「DをAに​​リベースし、DをAにスカッシュし、次にBをDAにリベース」と読みました。これは、テキストエディタで行を並べ替えることによって実行できることは、回答から明らかではありません。
ビクターセルギエンコ

3
ブランチがローカルの場合、There is no tracking information for the current branchリベース時にエラーが発生します。この場合、次のように、処理するコミットの数を指定する必要がありますgit rebase -i HEAD~4この回答を参照してください。
johndodo 2018年

1
私は何年も対話モード(gitのリベース-i)を使用し、私はちょうどそれがすることができます実現並べ替え。おかげ🤟🏻
CalvinChe

43

注:結果がわかっていない限り、別のリポジトリにプッシュされたコミットを変更しないでください

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

新しいコミットメッセージをどのように表示するかをテキストに変更します。私は、このコミットの変更の説明であることをお勧めしますAD

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ローカルの変更は破棄されます!)。


3

SourceTreeを使用している場合

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

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

1

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

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を取得しました。

PSは、自動モードでこの手順を実行するためのbash スクリプトです。


その記事の最初のソリューションは、リンクのおかげで本当にいいです
パーカー

-1

$ gitチェックアウトマスター

$ git log --oneline

D
C
B
A

$ git rebase --onto HEAD ^^^ HEAD ^

$ git log --oneline

D
A

と思います--onelineか?そして、あなたが落としたように見えます、CそしてB、それはOPが意図していたものではありません。
bstpierre 10/10/13

私のために働いていませんでした。それは私のヘッドとマスターの両方をAに移動しましたが、DをA(git show A)にマージせず、D、C、Bは私の参照ログで失われました。しなければならなかったgit rebase D取り戻すために。
2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.