Git:特定のコミットにリベースする方法は?


154

他のブランチのHEADではなく、特定のコミットにリベースしたいのですが。

A --- B --- C          master
 \
  \-- D                topic

A --- B --- C          master
       \
        \-- D          topic

の代わりに

A --- B --- C          master
             \
              \-- D    topic

どうすればそれを達成できますか?


4
git checkout B走る前にやってみましたgit rebaseか?
Peter-Paul van Gemerden、2011年

いいえ、それは役に立ちますか?rebase重要なのは、コマンドの参照だけです。
OndraŽižka'13年

回答:


98

--ontoパラメーターの使用を回避するには、好きなコミットで一時ブランチを作成し、シンプルな形式でリベースを使用します。

git branch temp master^
git checkout topic
git rebase temp
git branch -d temp

5
私はこのRISCのようなアプローチがもっと好きです:)試みます。ありがとう。
OndraŽižka

10
少し違うシナリオで、なぜうまくいかないのでしょうか。私はグループpep8をスキップしてマスターに基づいていることを望みます。 git rebase tempグループの場合)は、「現在のブランチグループは最新です。」とあきらめます。
Alois Mahdal 2014年

4
このソリューションは、トピックがマスターに既にリベースされているシナリオでは機能しませんが、祖先をマスターにリベースする必要があります。その場合はgit rebase --onto <target> <from> <to>、<from>コミットを指定できるように使用する必要があります。
mirzmaster 2018

これは、ブランチのベースになっているのと同じコミットにリベースしたい場合、はるかに簡単なオプションです。
アッシュ

1
私は働いているようですが、GitLabは別のことを言っています。私が10コミット遅れ、5コミット遅れている場合、私の期待は、8コミット遅れ、2コミット取得後に5コミット遅れることでした。しかし、これに代えて、それはそれらの5に多くのコミットを追加
ROMANIA_engineer

67

あなたは直接的なアプローチを取ることさえできます:

git checkout topic
git rebase <commitB>

6
私にとって、これは実際には意図したことを行いません。私の知る限り、それは「最後の共通の祖先」の上にリベースしようtopiccommitB
Dan Lenski、2015年

2
works.Quotingリベース方法ではありません@DanLenski、ドキュメントはIt works by going to the common ancestor of the two branches (the one you’re on and the one you’re rebasing onto), getting the diff introduced by each commit of the branch you’re on, saving those diffs to temporary files, resetting the current branch to the same commit as the branch you are rebasing onto, and finally applying each change in turn. 私が今、再びそれを試してみましたが、うまく動作するように見えました。
r0hitsharma 2015年

1
超簡単で動作します!私は今持っています:commitB_from_master-> topicCommit1-> topicCommit2。
Martin Konicek 2016年

それは私にはうまくいきませんでした。この前に、GitLabは「nコミット先」と述べました。そして今、それは「m先にコミットする」と言いm > nます。
ROMANIA_engineer

48

「onto」オプションを使用します。

git rebase --onto master^ D^ D

2
DそしてD^、「トピック」の最後と最後から2番目のコミットのハッシュでしょうか?
OndraŽižka'13年

39
構文は似ていgit rebase --onto <new-parent> <old-parent>ます。git parent pointer to a different parentを参照してください。A.お使いの場合には、<新しい親が> B、および<古い親>である
jszは

7
私は常に3つの引数を使用します。それは、リベースするためのコミットメントの開始と終了です。
Adam Dymitruk、

14
これは私のために働きました:git rebase --onto <commit-ID> master

4
@jszのコメントは正しいです。SimonSouthのコメントとは逆に、それはその逆です:git rebase --onto master <commit-ID-of-old-parent>OPの場合git rebase --onto B A
過激な2016

19

上記のjszによるコメントは私に多くの苦痛を与えたので、ここに私が他のコミットの上に任意のコミットをリベース/移動するために使用してきたそれに基づくステップバイステップのレシピがあります:

  1. リベース(移動)するブランチの前のブランチポイントを見つけます-それを古い親と呼びます。上記の例ではAです
  2. ブランチの移動先のコミットを見つけます-新しい親と呼びます。例ではそれはBです
  3. あなたはあなたのブランチ(あなたが移動するもの)にいる必要があります:
  4. リベースを適用します。 git rebase --onto <new parent> <old parent>

上記の例では、次のように簡単です。

   git checkout topic
   git rebase --onto B A

6
これが正解です。私が使用することを除いて、より完全な説明についてgit rebase --onto B master私の回答を参照しください。
ザックモリス

それは私にはうまくいきませんでした。私は2つの連続したコミットを選択しました(現在のブランチにあったマスターからの最後のコミットと、現在のブランチになかったマスターからの最初のコミット)。私は100の後ろ-10の前で開始し、99の後ろ-10の前ではなく、105の後ろ-13の前を持っています。
ROMANIA_engineer

それがうまくいかなかったと聞いてごめんなさい。あなたのブランチはかなり分岐しているように聞こえます-私は、この多くの違いがあるブランチをリベースする前に、最初につぶすことをお勧めします。
Nestor Milyaev

11

トピックソリューション

投稿された質問に答えるための正しいコマンドは、次のいずれかです(ブランチtopicが既にチェックアウトされていると想定)。

git rebase --onto B master
git rebase --onto master~1 master
git rebase --onto B A
git rebase --onto B C
git rebase --onto B

topicがチェックアウトされていない場合は、次のtopicようにコマンドに追加します(最後のコマンドを除く)。

git rebase --onto B master topic

または、最初にブランチをチェックアウトします。

git checkout topic

コミット文字列をターゲットコミットにリベース

ドキュメントから引用した、必要なコマンドの基本的な形式は次のとおりです。

git rebase --onto <Target> [<Upstream> [<Branch>]]

<Branch>オプションであり、コマンドの残りの部分を実行する前に、指定されたブランチをチェックアウトするだけです。リベースするブランチをすでにチェックアウトしている場合は、これは必要ありません。指定<Upstream>するために指定する必要があることに注意してください。<Branch>そうしないと、gitが指定していると見なし<Upstream>ます。

<Target>コミットの文字列をアタッチするコミットです。ブランチ名を指定するときは、そのブランチのヘッドコミットを指定するだけです。<Target>移動するコミットの文字列に含まれない任意のコミットを指定できます。例えば:

A --- B --- C --- D         master
      \
       \-- X --- Y --- Z    feature

全体の機能ブランチを移動し、あなたが選択することができないためにXYZ、またはfeatureとして<Target>それらがすべて移動してグループ内のコミットされているからです。

<Upstream>これは2つの異なることを意味するため、特別です。チェックアウトされたブランチの祖先であるコミットの場合、それはカットポイントとして機能します。私は提供された例では、これがないものだろうCDまたはmaster<Upstream>チェックアウトされたブランチの先頭までのすべてのコミットが移動されます。

ただし、<Upstream>が祖先でない場合、gitは指定されたコミットからチェーンをバックアップし、チェックアウトされたブランチで共通の祖先が見つかるまで(そして、見つからない場合は中止します)。私たちの場合は、<Upstream>BCD、またはmasterすべてのコミットになりますBカット点となります。<Upstream>それ自体はオプションのコマンドであり、指定されていない場合、gitはと入力するのと同じですが、チェックアウトされたブランチの親を調べますmaster

gitが切り取り、移動するコミットを選択したので、<Target>ターゲットにすでに適用されているコミットをスキップして、に適用します。

興味深い例と結果

この開始点を使用:

A --- B --- C --- D --- E         master
            \
             \-- X --- Y --- Z    feature
  • git rebase --onto D A feature
    コミットを適用しますBCXYZコミットするDとスキップし終わるBC、彼らはすでに適用されているので。

  • git rebase --onto C X feature
    コミットYを適用してコミットしZ、コミットCを効果的に削除しますX


4

より簡単な解決策はgit rebase <SHA1 of B> topicです。これは、どこにいても機能しますHEAD

git rebase docからこの動作を確認できます

<upstream>比較する上流ブランチ。既存のブランチ名だけでなく、任意の有効なcommitにすることができます。デフォルトは、現在のブランチに設定されたアップストリームです。


topic上記のコマンドで SHA1についても言及するとどうなるでしょうか。

git rebase <SHA1 of B> <SHA1 of topic>

これも機能しますが、リベースはTopic作成された新しいブランチをポイントせずHEAD、デタッチされた状態になります。そのため、ここから手動で古いものTopicを削除し、リベースによって作成された新しいブランチに新しいブランチ参照を作成する必要があります。


3

上記のソリューションを組み合わせて使用​​しました:

$ git branch temp <specific sha1>
$ git rebase --onto temp master topic
$ git branch -d temp

読みやすく、理解しやすいと思いました。受け入れられた解決策は私にマージの競合を引き起こします(手作業で修正するには面倒です):

$ git rebase temp
First, rewinding head to replay your work on top of it...
Applying: <git comment>
Using index info to reconstruct a base tree...
M       pom.xml
.git/rebase-apply/patch:10: trailing whitespace.
    <some code>
.git/rebase-apply/patch:17: trailing whitespace.
        <some other code>
warning: 2 lines add whitespace errors.
Falling back to patching base and 3-way merge...
Auto-merging pom.xml
CONFLICT (content): Merge conflict in pom.xml
error: Failed to merge in the changes.
Patch failed at 0001 <git comment>
The copy of the patch that failed is found in: .git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".

1
ここでも同じですが、最も人気のある2つの回答(r0hitsharmaとDymitrukによる)を使用すると、いくつかのファイルで競合が発生しました
Oliver

3

リベースが非常に基本的であるため、ここにネストル・ミリャエフの答えを拡張します。組み合わせjszさんサイモン・南さんからのコメントアダムDymitrukの答えは上で動作し、このコマンドを生み出すtopicかかわらずからに分岐するかどうかのブランチmasterブランチのコミットAかをC

git checkout topic
git rebase --onto <commit-B> <pre-rebase-A-or-post-rebase-C-or-base-branch-name>

最後の引数は必須です(それ以外の場合は、ブランチを巻き戻してcommitしますB)。

例:

# if topic branches from master commit A:
git checkout topic
git rebase --onto <commit-B> <commit-A>
# if topic branches from master commit C:
git checkout topic
git rebase --onto <commit-B> <commit-C>
# regardless of whether topic branches from master commit A or C:
git checkout topic
git rebase --onto <commit-B> master

したがって、最後のコマンドは私が通常使用するものです。


-2

それを行う別の方法があります。または、1つ以上のコミットに戻りたい場合。

nコミット数に戻る例を次に示します。

git branch topic master~n

この質問のために、これも行うことができます:

git branch topic master~1

コマンドはで完全に機能しgit version 2.7.4ます。他のバージョンではテストしていません。


これを分岐に関する質問と誤解しましたか?これは実際にはリベースに関する質問です。
NetherGranite 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.