PotatoBoy
PotatoBoy

Reputation: 45

Moving commits branched from master onto a previous commit in master

I'm attempting to move commits from branch "feature" to a new branch, which is forked from an earlier commit than "feature".

Suppose my tree looks like this:

master   A - B - C
                  \
feature            D - E

I'd like to move my feature commits D and E to a new branch derived from commit A, so that my tree looks like this:

desired    D - E
          /
master   A - B - C
                  \
feature             D - E

I created branch "desired" from A and attempted to rebase commits in "feature" onto the tip of "desired", but doing so pulled in commits B and C. Why didn't this rebase work, and how can I move these commits?

Upvotes: 1

Views: 40

Answers (2)

Mark Adelsberger
Mark Adelsberger

Reputation: 45659

Let's redraw the commit graph in a way that better represents git's data structures. You have

A - B - C <--(master)
         \
          D - E <--(feature)

Then you go back to A and create the desired branch, which gives you

A <--(desired)
 \
  B - C <--(master)
       \
        D - E <--(feature)

Now I assume you said

git rebsae desired feature

thinking that the feature branch means "commits D and E". But a branch isn't a set of commits; it's a pointer to one commit (hence my rearrangement of the graph). In git commits are "reachable from refs"; there isn't a real concept of a commit being "on a branch" or "not on a branch" beyond that.

So what makes B and C different from D and E? They're all reachable from feature; but B and C are also reachable from master (which is why you don't think of them as being "on the feature branch").

Which brings us to your first question: the rebase command didn't do what you want, because the rebase command as you issued it doesn't know or care about the master ref. The upstream is desired (from which A is reachable) and the source branch is feature (from which A, B, C, D, and E are reachable). So the rebase rewrites desired..feature - i.e. everything reachable from feature but not reachable from desired - and that includes B and C.

What you want is to make master your upstream, so that the command will rewrite master..feature (i.e. D and E only). That in turn means you want the new base to be something other than the upstream, which calls for the --onto option

git rebase --onto desired master feature

yielding

  D' - E' <--(feature)
 /
A <--(desired)
 \
  B - C <--(master)
       \
        D - E

(I kept D and E in the picture to emphasize the reason for calling the new commits D' and E'. The original commits are not deleted; if they're reachable from refs other than feature, those refs will still "see" the original commits. The feature branch now reaches two new commits with identity distinct from the original D and E.)

Upvotes: 2

&#212;rel
&#212;rel

Reputation: 7622

You should do something like

git rebase --onto A C E

Upvotes: 0

Related Questions