git, reorder commits in messed up branches

I’ve got a git repo that I would like to restructure completely.

All in all I’ve got three features, let’s call them feature A, B, C, that I’ve been working on for the past few weeks. Unfortunately I’ve been a bit unthoughtful regarding how to use branches to split my working on the features correctly, and I somehow also jumped from feature to feature even between commits.

  • How do you release a bugfix to a previous version and tag it?
  • Where are logs of git-daemon saved? (Git on windows using Cygwin)
  • Newly created branch on github not showing in Xcode “switch to branch” option
  • Merge codes from different authors on github
  • git gui branch management
  • Git: how to merge a commit into a branch via an update githook
  • So now I’ve got three branches A_devel, B_devel, C_devel and in each branch a bunch of commits that belong to each of the three features. Some commits of feature A also containing some changes for feature B in B_devel, some of B with changes for A in C_devel and so on. Some commits are even in the master branch, containing changes for any of the features. And all the commits are also already pushed to origin.

    It’s a complete chaos…

    … that I would like to clean up now.

    At least I can see from the commit messages and in some cases just from the code diffs what I’ve been working on in every particular commit. So I know which commit belongs to which feature. I just need to know how to actually move the commits to the corresponding correct branch.

    //edit: by the way, I have to mention that I’m the only one working on this repo, locally as well as on origin. So most likely no one would have problems with a changed history… just in case that’s going to be necessary.

  • How to make a GitHub mirror to Bitbucket?
  • Why is the size of a copied git folder on exFAT bigger than its original on ext4?
  • How save or safately avoid the key of Social Networks like Facebook or LinkedIn in GitHub
  • Git SSH setup Permission denied (publickey)
  • git commit not showing up in github
  • Git - ignore on push/pull but not clone
  • 2 Solutions collect form web for “git, reorder commits in messed up branches”

    Please note the following before reading the rest of the answer:

    1. git reset or rebase both do history rewriting, so they should not be used if the history was published. This shouldn’t be a problem in your case, since you are the only one using the repo.
    2. cherry-pick, as of v1.7.1, can cherry-pick multiple commits, so you can use this to “yank” more than one commit out.

    So my suggested strategy would be something as follows. Consider the following structure which has a mish-mash of changes related to features A and B on two branches:

          A1--A2--B1--B2--A3 (A_Devel HEAD)
         /
    o-o-X (master HEAD)
         \ 
          B3--B4--A4--B5 (B_Devel HEAD)
    

    what we want is:

          A1--A2--A3--A4 (A_Devel HEAD)
         /
    o-o-X (master HEAD)
         \ 
          B1--B2--B3--B4--B5 (B_Devel HEAD)
    

    Make sure that all feature branches have all relevant commits + some unneeded ones

    Copy all commit related to feature A to A_Devel from B_Devel:

    1. git checkout A_Devel
    2. git cherry-pick A4

    giving

          A1--A2--B1--B2--A3--A4 (A_Devel HEAD)
         /
    o-o-X (master HEAD)
         \ 
          B3--B4--A4--B5 (B_Devel HEAD)
    

    1. git checkout B_Devel
    2. git cherry-pick B1 B2

    giving

          A1--A2--B1--B2--A3--A4 (A_Devel HEAD)
         /
    o-o-X (master HEAD)
         \ 
          B3--B4--A4--B5--B1--B2 (B_Devel HEAD)
    


    Now remove the irrelevant commits

    1. git checkout A_Devel
    2. git rebase -i HEAD~~~~ (we wanna remove B1, B2)
    3. Editor opens up with:

      pick B1
      pick B2
      pick A3
      pick A4

    Delete the first two lines and save and exit from editor. Wait for rebase to finish.

    Now we’ll have:

          A1--A2--A3--A4 (A_Devel HEAD)
         /
    o-o-X (master HEAD)
         \ 
          B3--B4--A4--B5--B1--B2 (B_Devel HEAD)
    

    Similarly, for branch B_Devel:

    1. git checkout B_Devel
    2. git rebase -i HEAD~~~~~~ (we wanna change stuff in the last 6 commits)
    3. Editor opens up with:

      pick B3
      pick B4
      pick A4
      pick B5
      pick B1
      pick B2

    delete the line with A1 and reorder the remaining ‘B’ changes so that they look like:

     pick B1
     pick B2
     pick B3
     pick B4
     pick B5
    

    Save, exit, wait for rebase to finish which will finally give us:

          A1--A2--A3--A4 (A_Devel HEAD)
         /
    o-o-X (master HEAD)
         \ 
          B1--B2--B3--B4--B5 (B_Devel HEAD)
    

    Definitely not a nice solution, but if you’re going through the whole log, you could theoretically use a combination of git cherry-pick <commithash> to get one commit from one branch to another one, and git rebase -i (interactive rebase) to reorder commits in your branch.

    Read more on this here.

    Git Baby is a git and github fan, let's start git clone.