简体   繁体   中英

How to rebase to master instead of git pull origin master?

I have a old branch foo , and wanna make it up to the latest master .

If I execute $ git rebase origin master on the foo branch, somewhy the changes made in foo branch disappears and foo gets just same as the HEAD of master .

Why does this happen? And How to rebase my foo branch to the master?

Here is my git reflog . foo is equal to komoto/crop_image .

fd8d9c1d (HEAD -> komoto/crop_image, origin/master, origin/HEAD, master) HEAD@{0}: rebase finished: returning to refs/heads/komoto/crop_image
fd8d9c1d (HEAD -> komoto/crop_image, origin/master, origin/HEAD, master) HEAD@{1}: rebase: checkout master
92284980 (tag: beta-test, origin/komoto/crop_image) HEAD@{2}: checkout: moving from master to komoto/crop_image

Beware: git rebase origin master means git checkout master; git rebase origin git checkout master; git rebase origin (and then return to the original branch). That's why your reflog shows:

HEAD@{1}: rebase: checkout master

(and then HEAD@{0}: rebase finished: returning to refs/heads/komoto/crop_image : obviously you were on komoto/crop_image when you started).

What you did actually run

When you write origin by itself in this positional argument , your Git follows the six-step process outlined in the gitrevisions documentation . Step 6 reads:

  1. otherwise, refs/remotes/<refname>/HEAD if it exists.

So if git rev-parse origin/HEAD succeeds (and the five preceding steps fail), the sequence of commands:

git checkout master
git rebase origin

is equivalent to the sequence:

git checkout master
git rebase origin/master

If there are no commits on your master that are not already reachable from origin/master , this does nothing. For a good introduction to reachability, see Think Like (a) Git .

What you should have run

I have a old branch foo , and wanna make it up to the latest master .

In general, I prefer to do this as:

git checkout foo
git rebase master

but you can—because of the shortcut that I think people should avoid (it has bad failure modes in older versions of Git)—run:

git rebase master foo

Remember that rebase works by copying commits, so this will first enumerate all non-merge commits reachable from foo that are not reachable from master , in a topologically-sorted order, 1 saving their hash IDs somewhere. 2 It will then use the equivalent of git cherry-pick 3 to copy each such commit, with the copy landing after the previously-copied commit. The first-copied commit lands right after the tip of master :

...--A--B--C--...--N--O   <-- master
         \
          G--H--I   <-- foo

becomes:

                        G'-H'-I'  <-- foo
                       /
...--A--B--C--...--N--O   <-- master
         \
          G--H--I   [abandoned, but still findable as foo@{1}]

where G'-H'-I' is the sequence of cherry-picked, ie, copied, commits that correspond to the original commits GHI .


1 For a simple chain of commits with no branching and merging, the only correct topological sort is: in order from first to last . If there are branch-and-merge sequences in the chain of commits you are rebasing, rebase picks some valid topological sort, linearizing the commits in the process and omitting merge commits. This is actually sometimes a good idea and what you want, but more often, it's not. Git is growing a new kind of rebase that will be able to handle this better; currently there is an option called --preserve-merges that attempts to do the job, but is not really adequate and should be avoided except in emergencies.

2 This somewhere is literally in the file full of pick directives when you use git rebase -i . Each pick hash directive tells Git to do a cherry-pick of that particular commit, listing its true name: its hash ID. for some other kinds of rebases, the IDs are not as easily visible—but they are still saved somewhere, with the ability to stop the copying process when a copy step fails, then resume from the point where it stopped after you have manually fixed things up.

3 An interactive rebase, or a rebase run with -m or -s flags, literally uses git cherry-pick . All rebases probably should default to this, but currently, non -interactive rebases that do not use -m or -s use an older method that combines git format-patch with git am --3way . See also What is the difference between git cherry-pick and git format-patch | git am?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM