git rebase basics

GitGit Rebase

Git Problem Overview


I have started using git rebase recently and am not 100% certain I'm doing it right. For the sake of the question, there are two branches in origin, master and next, which was branched from master.

Since last sync between the two, master had 2 commits and next 6:

$ git log --oneline origin/next..origin/master
59b5552 master commit #2
485a811 master commit #1

$ git log --oneline origin/master..origin/next
4ebf401 next commit #6
e9b6586 next commit #5
197ada0 next commit #4
4a2c3c6 next commit #3
040a055 next commit #2
84537bf next commit #1

When I checkout next and execute git rebase -i origin/master, I get the following:

$ git status
# On branch next
# Your branch and 'origin/next' have diverged,
# and have 8 and 6 different commits each, respectively.

And finally after doing git pull --rebase, the two commits from master are in next:

$ git log --oneline origin/next..next 
8741d09 master commit #2
485a811 master commit #1

Questions:

  1. Is this correct approach?
  2. Why are there 8 and 6 different commits until pull --rebase is run?
  3. Is it possible to simplify the flow?

Much obliged :)

Git Solutions


Solution 1 - Git

Let's start from the beginning. Here's a diagram of your original state:

A-B-C  (master, origin/master)

D-E-F-G-H-I (next, origin/next)

When you checked out next and rebased next onto origin/master, it created 6 new commits after the two that are already on origin/master. These new commits have "master commit #2" (C in my diagram) as their ancestor, not their original ancestor where origin/master and origin/next diverged (A in my diagram), so their hashes will be different. I believe this is why you'll see that next has 8 different commits from origin/next: the 2 from origin/master and the 6 "rehashed" commits that were on origin/next.

After git checkout next ; git rebase -i origin/master, you should have this:

A-B-C  (master, origin/master)
\   
\ D'-E'-F'-G'-H'-I' (next)
D-E-F-G-H-I (origin/next)

You can see that next does have 8 commits that aren't on origin/next, and origin/next does have 6 commits that aren't on next. Granted this is just according to the SHA-1 hashes of the commits. The actual content should match very closely if you git diff origin/next next -- the diff should just show the changes from B and C (as labeled in the diagram).

When you do git pull --rebase while still on next, it fetches changes from the source (the remote origin/next) and rebases the current branch (next) onto that remote. This causes the changes that were in the next but not in origin/next to appear after origin/next on the new next branch. It should look like this:

A-B-C  (master, origin/master)

D-E-F-G-H-I (origin/next)
B'-C' (next)

If this is what you wanted the history graph to look like, then you've succeeded.

However, I suspect you really wanted things to look like the middle diagram, especially if next is a feature branch where you're working on the next piece of the project and master is for stable code and small bug fixes. If so, then you should have done git push instead of git pull --rebase to make the remote reflect your version of history instead of the other way around.

Solution 2 - Git

Start with the very simple steps for rebasing your branch with the master; Name;

git-rebase

Synopsis;

git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
        [<upstream>] [<branch>]
git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>]
        --root [<branch>]
git rebase --continue | --skip | --abort | --edit-todo

Description; Assume the following history exists and the current branch is "sample":

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

From this point, the result of either of the following commands:

git rebase master
git rebase master sample

would be:

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

NOTE: The latter form is just a short-hand of git checkout sample followed by git rebase master. When rebase exits sample will remain the checked-out branch.

If the upstream branch already contains a change you have made (e.g., because you mailed a patch which was applied upstream), then that commit will be skipped. For example, running ‘git rebase master` on the following history (in which A’ and A introduce the same set of changes, but have different committer information):

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

will result in:

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

All these were the diagramatic understanding of the rebase process. Once you resolve the conflicts being found after typing git rebase master resolve the conflicts and type git add -u to add the changed codes to the repository. after that perform the command git rebase --continue and continue resolving the conflicts and and repeating the command ;

git add -u 

and

git rebase --continue 

until no conflicts being found. At last the final command will be ,

git push --force origin sample(your branch name)

Solution 3 - Git

I don't always do git rebase, but when I do, I use this "hammer":

o---o---o---o---o  A
     \
      o---o---o---o---o  B
                       \
                        o---o---o  C

git rebase -r B C --onto A    # C should be branch, not hash

o---o---o---o---o  A
    |            \
    |             o'--o'--o'  C
     \
      o---o---o---o---o  B

No more stressing about what is the best way to do git rebase for each case ("Should I use rebase -i? Should I use cherry-pick?") and spending time looking them up.

Of course this is not for everyone, like for example, in a case where we want to split a commit, some people don't like "doing a bunch of funky work on a new branch". But some people, like me, "have a phobia of interactive approaches".

> Fear not the man who does 1000 ways of rebase once, but fear the man who does one way of rebase 1000 times. ~Not Bruce Lee

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDavid KuridžaView Question on Stackoverflow
Solution 1 - GitMike SeplowitzView Answer on Stackoverflow
Solution 2 - GitSamView Answer on Stackoverflow
Solution 3 - GitM Imam PratamaView Answer on Stackoverflow