简体   繁体   中英

Ahead of origin/master, how to put commits onto a new branch?

I'm in a state where I'm Your branch is ahead of 'origin/master' by 2 commits. because I forgot to make a new branch before editing and committing.

How do I make a new branch that is comprised of these two commits?

You can branch out from your current master :

$ git branch my_new_branch

and then reset your master back to origin/master :

$ git reset origin/master --hard

Mureinik's answer is right (and upvoted) but it might help to have a little visual illustration of what's going on here.

In Git, branch names don't really mean all that much, in a sense. What they do is "point to" (contain the raw commit-hash-ID of) one particular commit . It's the commits themselves that are important. Commits are (mostly) permanent and (entirely) unchangeable: once made, the commit whose hash is deadc0ffee... or whatever, is that commit forever. But a name like master or branch : those can change.

Each commit, meanwhile, "points back to" (stores the big ugly hash ID of) its previous commit. So if you're on master and have some series of commits—instead of writing out big ugly hash IDs, we'll use single letters here—they look a bit like this:

... <--E <--F <--G   <-- master

Since the internal arrows cannot be changed, and always point backwards, we can just draw them like this instead:

...--E--F--G   <-- master

Now if you add a new commit, it will point back to the previous tip of master , and master will point to it:

...--E--F--G--H   <-- master

Then you make the second one:

...--E--F--G--H--I   <-- master

Note that master just keeps advancing, as we add more commits. But origin/master pointed to G before, and still does, so we really should draw this instead:

...--E--F--G   <-- origin/master
            \
             H--I   <-- master

What you want to do at this point is make a new name newbranch or feature or whatever, pointing to commit I :

...--E--F--G   <-- origin/master
            \
             H--I   <-- master, newbranch

and then "re-set" master so that it points back to G :

...--E--F--G   <-- master, origin/master
            \
             H--I   <-- mewbranch

You can do this with git reset .

A side note on git reset --hard

Now, these drawing are fine—they're great ways to remember what's going on with commits —but they don't take into account the index and the work-tree . Git's index is a complicated little thing, which sits between your current commit and your work-tree; it's perhaps best described as "the place you build your next commit". The work-tree, meanwhile, is simply "where you do your work": you need this because Git's storage—including that for Git's index—is in Git's own, special, compressed Gitty format, that few if any other commands on your machine can deal with.

When you use git reset , you have Git do up to three things:

  1. re-set the current branch: eg, move master so that it points to some arbitrary other commit;
  2. re-set the index;
  3. re-set the work-tree.

Step 1 is very safe, because commits are (mostly) permanent and (entirely) read-only: moving a branch name around won't harm the commits themselves in any way. You can just move it back and there they are again.

It's steps 2 and 3 that are not so safe. A --hard reset wipes away your work-tree, changing it to match the commit you re-set to. Any work you did that you have not committed, may be lost at this point. (If you have committed it, of course, Git has saved it, permanently. Well, mostly permanently. Reachable commits are permanent, but that's for another topic.)

Likewise, a --hard or even --mixed reset re-sets the index. Until you start doing advanced tricks with the index, this doesn't really matter much, since what's in the index will either be what's in a commit—this is what it starts with—or what you copied into the index from your work-tree, using git add . So it's the work-tree, and hence the --hard , that are the big concerns here.

The short version of this, if it's not too late, :-) is: be sure your work is either committed, or unwanted, before using git reset --hard . (If you don't really want to commit it on a branch, but don't want to lose it either, you can use git stash to save it. This makes a commit—well, really, at least two commits—but the commits that git stash makes are on no branch, which is a little odd.)

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