コミットの並べ替え


104

私は現在ブランチに取り組んでおり、いくつかのコミットを他のブランチにマージしたいです:

    a-b-c-d-e-f-g (branchA)
   /
--o-x-x-x-x-x-x-x-x-x-x (master)
   \
    x-x-x-x-x (branchB)

(文字はコミットを示し、「x」は関係のないコミットです。)

しかし、いくつかのコミットをプールすることは良い考えであることに気づきました。a、d、e、gを1つのパッチに「連結」して、マスターにコミットしたい。コミットbとfは、branchBへの1つのコミットとして実行する必要があります。それを達成するための良い「git」っぽい方法はありますか?


4
すでに与えられた2つの答えは正しいコマンドについて言及していますが、私はこのコマンドと同じくらい基本的なタスクであると思うので、ここStackOverflowで実際の手順を説明する価値があるので、いくつか投稿しました。(リンクする前の良い質問が見つからないことに驚いています。)
Cascabel

回答:


125

あなたが探しているコマンドはgit rebase、特に-i/--interactiveオプションです。

ブランチAにコミットcを残し、他のコミットをマージするのではなく他のブランチに移動したいということを想定します。マージは単純なのでです。ブランチAを操作することから始めましょう。

git rebase -i <SHA1 of commit a>^ branchA

これ^は前のコミットを意味するため、このコマンドは、「a」の前のコミットをベースとしてブランチAをリベースすることを示しています。Gitはこの範囲のコミットのリストを表示します。それらを並べ替えて、適切なものを押しつぶすようにgitに指示します。

pick c ...
pick a ...
squash d ...
squash e ...
squash g ...
pick b
squash f

これで、履歴は次のようになります。

    c - [a+d+e+g] - [b+f] (branchA)
   /
--o-x-x-x-x-x-x-x-x-x-x (master)

ここで、ブランチBの新しく押しつぶされたコミットb + fを取得します。

git checkout branchB
git cherry-pick branchA  # cherry-pick one commit, the tip of branchA

マスターのa + d + e + gの場合も同じです。

git checkout master
git cherry-pick branchA^

最後に、branchAを更新してcを指すようにします。

git branch -f branchA branchA^^

これで次のようになります。

    c (branch A) - [a+d+e+g] - [b+f] (dangling commits)
   /
--o-x-x-x-x-x-x-x-x-x-x-[a+d+e+g] (master)
   \
    x-x-x-x-x-[b+f] (branchB)

ブランチ間を移動したい複数のコミットがある場合は、再度(非対話的に)rebaseを使用できます。

# create a temporary branch
git branch fromAtoB branchA
# move branchA back two commits
git branch -f branchA branchA~2
# rebase those two commits onto branchB
git rebase --onto branchB branchA fromAtoB
# merge (fast-forward) these into branchB
git checkout branchB
git merge fromAtoB
# clean up
git branch -d fromAtoB

最後に、免責事項:一部がクリーンに適用されなくなるような方法でコミットを並べ替えることはかなり可能です。これは、不適切な順序を選択したことが原因である可能性があります(パッチを適用した機能を導入するコミットの前にパッチを適用)。その場合、リベースを中止する必要があります(git rebase --abort)。それ以外の場合は、(マージの競合の場合と同じように)競合をインテリジェントに修正し、修正を追加して、実行git rebase --continueして次に進む必要があります。これらの指示は、競合が発生したときに出力されるエラーメッセージによっても提供されます。


図はgit branch -f branchA branchA^^間違っていますか?つまり、branchAはこの時点でcを指しているべきではないので、ダイアグラムの最初の行はであり、そうではc (branchA)ありませんc - [a+d+e+g] - [b+f] (branchA)か?
ntc2

@enoksrd:はい、間違いがありますが、編集に誤りがありました。ここで機会があったら直します。
Cascabel

代わりにやってgit branch -f branchA branchA^^、なぜあなただけで行うことはできませんgit reset --hard <sha1 of c>分岐Aには?
ミハイルヴァシリーエフ

17
git rebase -i HEAD~3

3並べ替えが必要なコミットの数はどこですか(source)。

これによりviが開き、最も古い(上)から最も新しい(下)までのコミットがリストされます。
次に、行を並べ替え、を保存して、エディターを終了します。

ddp現在の行を
ddkPに移動します現在の行を上に移動しますソース


9

git rebase --interactive 必要なコマンドです。

例:

現在のステータスはこれです:

bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git status
On branch master
nothing to commit, working tree clean
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git log --oneline
a6e3c6a (HEAD -> master) Fourth commit
9a24b81 Third commit
7bdfb68 Second commit
186d1e0 First commit

コミット9a24b81(3番目のコミット)と7bdfb68(2 番目のコミット)を並べ替えたい。これを行うには、変更する最初のコミットの前に、まずコミットを見つけます。これはコミット186d1e0(最初のコミット)です。

実行するコマンドはgit rebase --interactive COMMIT-BEFORE-FIRST-COMMIT-WE-WANT-TO-CHANGE、この場合はです。

bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git rebase --interactive 186d1e0

これにより、デフォルトのエディターで次の内容のファイルが開きます。

pick 7bdfb68 Second commit
pick 9a24b81 Third commit
pick a6e3c6a Fourth commit

# Rebase 186d1e0..a6e3c6a onto 186d1e0 (3 commands)
#
# 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
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#

ファイル内のコミットの順序は、git logで使用される順序とは逆であることに注意してください。gitログでは、最新のコミットが一番上にあります。このファイルでは、最新のコミットが一番下にあります。

ファイルの下部にあるコメントで説明されているように、コミットのスカッシュ、ドロップ、並べ替えなど、さまざまなことができます。コミットを並べ替えるには、ファイルを次のように編集します(下部のコメントは表示されません)。

pick 9a24b81 Third commit
pick 7bdfb68 Second commit
pick a6e3c6a Fourth commit

pick各行の先頭のコマンドは「このコミットを使用(つまり、含める)」を意味し、リベースコマンドで一時ファイルを保存してエディターを終了すると、gitがコマンドを実行してリポジトリと作業ディレクトリを更新します。

$ git rebase --interactive 186d1e0
Successfully rebased and updated refs/heads/master.
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git log --oneline
ba48fc9 (HEAD -> master) Fourth commit
119639c Second commit
9716581 Third commit
186d1e0 First commit

書き換えられたコミット履歴に注意してください。

リンク:


1
リンクから関連する詳細を追加して、完全な自己完結型の回答を提供してください。そのため、「リンクのみの回答」については眉をひそめています。具体的には、git rebase --interactiveOPの目標を達成するためにどのように使用しますか?
SherylHohman 2018

2番目のリンクは現在存在しません。
devsaw

回答を完全かつ自己完結型にするためのコンテンツを追加しました。2番目のリンクを削除しました。
codeape


-1

git rebaseが必要です。--interactiveオプションを確認してください。


4
リンクから関連する詳細を追加して、完全な自己完結型の回答を提供してください。そのため、「リンクのみの回答」については眉をひそめています。
SherylHohman 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.