Christoph S
Christoph S

Reputation: 773

How to move later created branch before first commit on master branch in git?

I have my master branch masterand a branch originalCode. The parent of the originalCode branch is master:

                  F  originalCode
                 / 
A - B - C - D - E  master

Now I want to move my originalCode branch with commit F before the commit A. I already tried around with rebasing and merging, but I could not get it to work and I could not find a similar question regarding this.

The goal is to have a common history to see exactly what changes from the original code (some scripts) have been made. When I started with checkin in, I already started with an external modified version.

Upvotes: 1

Views: 875

Answers (2)

mkrieger1
mkrieger1

Reputation: 23144

Here's how I would do it:

  1. Create and switch to a new branch reordered, which will later contain the reordered commits, to point to the same commit (F) as originalCode:

    $ git checkout -b reordered originalCode
    

    The commit graph now looks like this:

                      F  originalCode, reordered
                     / 
    A - B - C - D - E  master
    

    This is so that master and originalCode remain untouched. In case something goes wrong, you can simply delete reordered and start over.

  2. Interactively rebase reordered, positioning F before A:

    Since A is the root commit, you need to specify the --root option.

    $ git rebase -i --root reordered
    

    This will open a text editor containing something like this:

    pick d14a5dd A
    pick 57b6bd9 B
    pick de4e672 C
    pick 6fc8c1f D
    pick 453da48 E
    pick d2443c0 F
    

    Cut the line with F and paste it above the line with A. Then save and exit the editor to continue.

    Depending on the actual contents of your commits, you may need to resolve merge conflicts during the rebase.

  3. Once the rebase is done, the commit graph should look like this:

                      F  originalCode
                     / 
    A - B - C - D - E  master
    
    F'- A'- B'- C'- D'- E'  reordered
    

    Note that there are two series of commits that have no common ancestor, because of the --root rebase.

  4. Reassure yourself that there are no differences in content between reordered and master.

    $ git diff reordered master
    

    This should produce no output.

    (Edit: I suspect you want the contents of master as the "newest" version, not the contents of originalCode, so I changed the diff accordingly.)

    If there is a difference, you may have done something wrong while resolving merge conflicts.

    You may also inspect the individual commits using a graphical repository browser like gitk.

  5. Once you are satisfied with the state of the reordered branch, you can either delete originalCode and master, followed by renaming reordered to master, or you can move master to point to the same commit (E') as reordered and delete the originalCode and reordered branches.

    $ git checkout -B master reordered
    $ git branch -D reordered originalCode
    

    The end result should be a commit graph like this:

    F'- A'- B'- C'- D'- E'  master
    

To address the concerns raised by some commenters:

In case there are other people who have cloned the repository and depend on the master branch, you should not delete or move it like shown in step 5 above.

Instead (after step 4) I would propose to merge the new reordered branch into master, to provide an alternative history leading to the current state, but keeping the original history as well:

$ git checkout master
$ git merge reordered
$ git branch -d reordered

Result:

    A - B - C - D - E - G  master
                      /
F'- A'- B'- C'- D'- E'

Upvotes: 3

j6t
j6t

Reputation: 13387

You do the following:

Create a new root commit containing the original code base:

git checkout originalCode
git checkout --orphan originalCode2
git commit -m "Original code of project foo"

Now we have to transplant the history leading to master on top of this new root. For this purpose, we graft commit A on top of originalCode2:

echo $(git rev-parse A originalCode2) >> .git/info/grafts

and then rewrite the history to make the new parentship permanent:

git filter-branch master

Now you have the intended history. Note that this rewrites history and all caveats concerning published rewritten history apply.

Finally, you should remove the last line of .git/info/grafts (which was written in the above steps). It is most probably the only line, then you can just remove .git/info/grafts.

It may be possible to use git rebase --root originalCode2 master or some variation involving --root instead of filter-branch, but I have no experience with this rebase variant.

Upvotes: 0

Related Questions