12

My history looks somewhat like this but times 10:

                i - j - e'- k - h'- l - m  feature-branch
              /
    a - b - c - d - e - f - g - h  master

(the apostrophes meaning cherry picks) I want to rebase to this:

                                  i - j - k - l - m  feature-branch
                                 / 
    a - b - c - d - e - f - g - h  master

I don't mind if the feature gets squashed into 1 commit. The main problem with a regular rebase is that it tries to rebase one commit at a time, and i have to fix and re-fix similar conflicts over and over.

All I want is to take the difference between the tip of my branch and the tip of master and apply those on top of master.

ZMitton
  • 294
  • 2
  • 9
  • This would be a lot easier with a regular *merge* instead of a regular rebase. Additionally, with a merge, the history will be accurate and true instead of containing lies. – Dietrich Epp May 12 '15 at 17:58
  • Wait... have you been cherry picking commits from `master` and putting them on `feature-branch`? – Dietrich Epp May 12 '15 at 18:18
  • Is `e'` a cherry-pick of `e` and `h'` a cherry-pick of `h`? – Richard Hansen May 12 '15 at 18:18
  • 2
    @DietrichEpp: There's nothing wrong with rebasing your local history. It's public history that's the problem. Related: http://programmers.stackexchange.com/questions/255165/is-using-git-stash-as-a-workflow-an-antipattern/255174#255174 – Greg Burghardt May 12 '15 at 18:18
  • @GregBurghardt: "Nothing wrong" is incorrect, it's just that there are specific problems with rebasing public history that don't apply to private history. By no means does this mean that there are not other problems with rebasing private history, e.g., your private history could contain unit tests which now break after the rebase, sabotaging future efforts to use `git bisect`. – Dietrich Epp May 12 '15 at 18:23
  • @DietrichEpp: I agree with GregBurghardt. There are many cases where merging is worse than rebasing not-yet-pushed commits. Assuming the end result is what was intended, rebasing is just fine. – Richard Hansen May 12 '15 at 18:47
  • @DietrichEpp yes they are cherry picks. does that cause a problem when rebasing? – ZMitton May 12 '15 at 18:56
  • Usually cherry picks don't cause problems, but if the other commits on the feature branch touch the same code then you'll get conflicts when you merge or rebase. There's no way to avoid that—you just have to get good at resolving conflicts. :) – Richard Hansen May 13 '15 at 14:49
  • Also, it is unusual to cherry pick from `master` to a feature branch, so it can be confusing to others. Periodically merging `master` into the feature branch is usually preferred. – Richard Hansen May 13 '15 at 14:50

2 Answers2

11

This is actually quite easy.

  1. Merge master into feature-branch. You will solve all of your merge conflicts here at once. (I highly recommend stopping here.)

                i - j - e'- k - h'- l - m - n    feature-branch
              /                           /
    a - b - c - d - e - f - g - h --------       master
    
  2. Then, git reset --soft master. This will make it so that feature-branch points at master, but it will keep all of your changes in the index, ready to be committed.

                i - j - e'- k - h'- l - m - n    (orphaned)
              /                           /
    a - b - c - d - e - f - g - h --------       master, feature-branch
                                  \
                                    (index)
    
  3. git commit

                i - j - e'- k - h'- l - m - n    (orphaned)
              /                           /
    a - b - c - d - e - f - g - h --------       master
                                  \
                                    n'           feature-branch
    

The only purpose of #2 and #3 is to destroy the history of feature-branch. If you are certain you will never ever need that history, that's fine. But it seems like a waste to go to all this extra trouble just to delete an accurate record of what actually happened.

Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • This isn't the exact behavior I asked for but i did end up doing just step one of this. It allowed one large but manageable conflict resolution stage instead of tons of them. hopefully the fact that its not rebased to look linear doesn't cause any issues in the future. – ZMitton May 13 '15 at 23:43
3

I'm assuming e' and h' are cherry-picks of e and h, respectively. I'm also assuming that the conflicts appear when Git tries to apply e' and h', but not any of the other commits. Please correct me if I'm wrong.

You have a few options:

  • When git rebase drops to a prompt saying that it couldn't apply e' or h', run git rebase --skip to tell Git to skip that commit.

    Once the rebase is done, if you then want to squash the commits together into one:

    git reset --soft master
    git commit
    
  • Do an interactive rebase and tell Git to not apply e' and h':

    git checkout feature-branch
    git rebase -i master
    # Git will launch an editor containing an interactive rebase recipe:
    #   1. Delete the e' and h' lines.
    #   2. Optionally change the j through m lines to 'squash' if you
    #      want to squash all of those commits into one.
    #   3. Save the recipe and exit.
    
  • git rebase is an easier way to do a series of git cherry-pick commands. You can do these commands manually yourself:

    git checkout -b temp-branch master
    git cherry-pick i j k l m
    # optionally, if you want to squash i through m into a single commit:
    #   git reset --soft master
    #   git commit
    git checkout feature-branch
    git reset --hard temp-branch
    git branch -D temp-branch
    
Richard Hansen
  • 51,690
  • 20
  • 90
  • 97