Reputation: 8091
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?
Upvotes: 1
Views: 33
Reputation: 488163
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
.
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:
master
so that it points to some arbitrary other commit;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.)
Upvotes: 2
Reputation: 311198
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
Upvotes: 2