3

I think we develop our project in a branch and when finished, we rebase it to master branch and then we can push it to repository server.

If I think wrong, tell me, and explain when we rebase to origin/master

*update:thank for ur answers, but u are misunderstood, I need to know difference of

git rebase master

and

git rebase origin/master

arianpress
  • 456
  • 1
  • 6
  • 16
  • It will be helpful for you to read some Git manual: [Git Basics - Working with Remotes](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) and [Merging vs. Rebasing](https://www.atlassian.com/git/tutorials/merging-vs-rebasing). – Mohammad Dehghan Aug 28 '17 at 14:10

4 Answers4

15

You want to compare git rebase master with git rebase origin/master.

The argument you give to git rebase is what the git rebase documentation calls the upstream. This is not a very good name (the documentation is, in this case, not so great) but the answer is in there.

What git rebase does is to copy some set of commits. Git needs two pieces of information: which commits should it copy? and where should it copy them to? This one argument, this upstream as the documentation calls it, provides the answer to both questions.

To understand this copying process, you need to draw at least some part of the commit graph so that you can see which commits get copied and what happens afterward.

Drawing commit graphs is a little bit tricky, although if you practice it for a while you can get quite good at it. To draw the graph, you need to view the commits with their parent linkages. You can use git log --all --decorate --oneline --graph, which will do its own graph drawing, or use a graphical viewer like gitk or some Git GUIs. (You cannot use GitHub's graphs as they contain the wrong information.) If you draw them manually, it's helpful to have a whiteboard or similar.

Let's draw a quick sample graph here. Your own graph may be different.

                C4   <-- feature
               /
...--C1--C2--C3   <-- master
               \
                C5--C6   <-- origin/master

These Cns represent commits. We say that each commit "points back" to its parent (previous) commit. Note that the parent of a commit always comes earlier, but "earlier" doesn't always mean a lot. Here, probably made your branch feature from your branch master, then made one commit on it. Since then, you also ran git fetch, which has obtained two commits from what Git calls a remote named origin. These two commits are now on your origin/master, but not on your master.

What to copy and where to copy

If at this point you run git checkout feature and then git rebase master, Git will tell you that there is nothing to do (Current branch feature is up to date). If you run git rebase origin/master, though, it will do something.

The key as to why is, again, in the documentation. Rebase starts out by selecting which commits to copy using the two-dot notation described in the gitrevisions documentation:

master..feature

(the name feature comes from your current branch, the one you have checked out; the name master comes from your argument to git rebase).

This two-dot notation means: On the commit graph, start at feature and work backwards through its parents, and mark all these commits green. Then, on the same graph, start at master and work backwards through its parents and mark all these commits red.

When we do this with the graph I've drawn, we mark C4 green, then mark C3 green, then mark C2 green, and so on. Commits C5 and C6 don't get marked at all. Then, we mark C3 red—this overrides its green—and mark C2 red, and so on. What we're left with is just C4 in green.

This means that what git rebase master will do is copy commit C4.

Now, the next step is to figure out where to copy. The answer is: right after whichever commit the upstream points to. So this says: Copy commit C4 to where it is right now. Which is pointless, so git rebase says there is nothing to do.

If you run git rebase origin/master right now, Git will mark C4 green, and then C3 green, and so on as before; then it will mark C6 red, C5 red, C3 red, and so on. This gives us the list of commits to copy, which once again is just commit C4. We marked more commits, but the end result for what to copy turned out to be the same. And then the next step is to figure out where to copy, and this time, it's different.

We're supposed to copy all the commits—all one of them—to come right after the one origin/master points-to, which is C6. So we must copy commit C4 there.

How Git copies commits

The main command that copies commits is git cherry-pick. So, internally, git rebase often uses git cherry-pick to do the copying. Some kinds of rebase use different commands internally, but the end result is intended to be the same. We can just view this as a cherry-pick, anyway.

To do the copying, Git first checks out the "after" commit, C6. It does so without checking out any branch—it checks out the raw commit instead, using what Git calls "detached HEAD" mode. If something goes wrong during the rebase, you are left in this "detached HEAD" mode. That's not a big deal, and if everything goes right, Git gets right back out of this mode, but it's worth remembering.

Anyway, so Git "detaches HEAD" and makes it point to commit C6:

                C4   <-- feature
               /
...--C1--C2--C3   <-- master
               \
                C5--C6   <-- origin/master, HEAD (detached)

and then cherry-picks C4 to copy it. Read the git cherry-pick documentation for details, but essentially, this copies the changes you made, by comparing C4 vs C3, then makes a new commit with a copy of the commit message as well. The new copy comes after the HEAD commit, which is C6, so it looks like this:

                C4   <-- feature
               /
...--C1--C2--C3   <-- master
               \
                C5--C6   <-- origin/master
                      \
                       C4A   <-- HEAD (detached)

The new commit is a lot like C4, but has a different parent commit: it points back to existing commit C6, not to C3.

After the copying

We've now finished copying all the commits we had to copy, so for its final trick, git rebase makes the branch name that we were on, i.e., feature, point to this last commit it copied. In other words, it reattaches your HEAD, but at the new graph location:

                C4   [abandoned]
               /
...--C1--C2--C3   <-- master
               \
                C5--C6   <-- origin/master
                      \
                       C4A   <-- feature (HEAD)

What happens to the original, pre-copy, commit C4?

Git secretly hangs on to it for a while, but it's "gone invisible". It has no name by which you can find it. It's not on any of your branches any more! Eventually, the things that keep it around—what Git calls reflog entries—expire, and Git removes it entirely through what Git calls garbage collection. For a short while, though, you can "undo" a git rebase if you need to.

Branch names change—well, move, over time. Commits don't.

Let's go back to the original graph, i.e., back before we ran git rebase origin/master:

                C4   <-- feature
               /
...--C1--C2--C3   <-- master
               \
                C5--C6   <-- origin/master

If, at this point, you run git checkout master and then git merge origin/master—or git checkout master and then git pull, which runs git merge for you—Git will move your name master in a "fast-forward" operation:

                C4   <-- feature
               /
...--C1--C2--C3
               \
                C5--C6   <-- master (HEAD), origin/master

There was no need to do anything else, so Git did the least work it could get away with. It made the name master point to commit C6, too, just like origin/master does. (I've marked master with HEAD since we did a git checkout master to get here.)

If you now do the same kind of rebase you were going to do earlier, now both names, master and origin/master, point to the same commit. So now, after git checkout feature to attach your HEAD to feature, git rebase master and git rebase origin/master will do the same thing.

Remember, the rebase operation uses the upstream argument to find out what to copy and where to put the copies. That's all it uses this argument for, so if two different names point to the same commit, the "what to copy" and "where to copy" answers will be the same for both names.

It's when two different names point to different commits that you get different results. The green-vs-red trick may (or may not—try this with other graphs) mean that you get the same commits copied, but the "where to copy" part is different, by definition.

torek
  • 448,244
  • 59
  • 642
  • 775
4

Rebase could be needed when your branch is behind and you need the changes from master. You could also use merging, but rebase is preferred by some. (Including myself)

I need to know difference of

git rebase master

and

git rebase origin/master

The different is to rebase on your local master, or the one of origin. It's likely that your local master is behind origin/master, but it could be also forward or even has different histories (not recommend)

If your master is the same as origin/master, it doesn't matter which one to use.

We rebase (and branch) from origin/master so we don't have to update our local master. (no need to do git pull on the local master branch).

If you rebase on local master, you could do:

git checkout master
git pull
git checkout myBranch
git rebase master

if you rebase on origin/master, you could do

git fetch
git rebase origin/master

so a lot shorter.

Shorter syntax

For even shorter, you could also use "pulled rebase", that one is nicely to combine with the "origin rebase":

git pull origin master --rebase

No need to fetch then.

If you're even more lazy, you could set the rebase on by default when pulling.

Set git config --global pull.rebase true, only once needed.

Then for the pulled rebase, just use

git pull origin/master

PS: Unfortunately of the inconsistent syntax (origin/master vs origin master)

Community
  • 1
  • 1
Julian
  • 33,915
  • 22
  • 119
  • 174
1

Edit: I had forgotten to add why fast forward merges are preferred by some, it is because there are no merge conflicts, as the branch pointer is just moved forward, instead of having to merge 2 separate copies of the code

Rebase merge does this:

First, you have commits on your branch

First image

Merging would just move master to C1, and everything would be ok

But if someone adds a commit then it would look like this: Second image

And the merge is no longer a fast forward merge.

Rebasing your branch off C2 changes it to this: Third image

Which means the merge can be done as a fast forward, making sure there are no conflicts.

jrtapsell
  • 6,719
  • 1
  • 26
  • 49
1

I usually prefer rebase for small-medium changes and merge for large, long-standing branches.

rebase has the advantage of giving you a very clean commit history.

merge has the advantage of giving you an explicit merge commit, which means the changes to resolve merge conflicts are sectioned off by themselves. With merge, if you later find a bug with the branch or you realize that you fixed a conflict in the wrong way, it is much easier to revert the merge commit and apply the necessary fixes.

0x5453
  • 12,753
  • 1
  • 32
  • 61