11

A hard git reset is often used after a force push or forced update to copy all remote changes of a branch. For example after a rebase and a force push with

git push --force origin my_branch

your team member can use

git reset --hard origin/my_branch

to get the updated branch. The question is why do you have to specify a slash / for git reset, but not for git push ?

3 Answers 3

8

This is more of a long comment rather then a proper answer.

I suppose generic answer to this would be something like:

"it has been programmed that way"

On a more serious note, perhaps it has something to do with the resources and their location. What I mean by resources here is local or remote.

Let's look at the two commands you've mentioned in your original post.

git push -f <remote> <branch>

So what does push actually do? Simplistically it takes whatever you've got on your local repository and pushes it upstream to the remote repository. How would we do that? From design perspective, if you think about it, it makes a perfect sense to pass two parameters in this case a remote a place where you will send your changes and branch from your local system which you will be preserving long-term.

Next, let's look at

git reset --hard <remote>/<branch>

This instruction basically resets your working directory to whichever index you specify. Also, note this is all done from your local file system and this is the difference between the two commands you've brought up in your OP.

4
  • 1
    This is, in fact, the right answer: the last argument to git push is not a branch name, but rather a refspec, consisting in this case of a pair of branch names: some sort of commit specifier in your repository, then a colon, then the name in their (origin's) repository that you want them to change. The last argument to git reset, on the other hand, is simply any suitable commit specifier. A branch name (regular local branch like foo, or remote-tracking branch like origin/foo) works fine as a commit-specifier, but so does a hash like a1234567. (continued)
    – torek
    Commented Aug 5, 2016 at 14:54
  • 1
    On the other hand, the final part of the refspec argument to git push must be a name, never a raw commit hash. Plus, it's their name, rather than yours! Hence it's never origin/foo. The funny thing about git push refspecs is that you can omit their name (and the colon) if you use a name on your side. The precise details vary but usually that means "same name on both sides". That is, foo:foo can be shortened to just foo.
    – torek
    Commented Aug 5, 2016 at 14:56
  • 1
    @torek would you mind making appropriate modifications to my answer above to reflect on what you've just said in the comment section. I totally agree with it and its technically better defined. Or if you don't mind, I could integrate appropriate changes myself with your approval Commented Aug 5, 2016 at 15:11
  • 2
    I'll leave it to you. :-)
    – torek
    Commented Aug 5, 2016 at 16:58
2

The git push command first takes a remote parameter, where you specify the repo you're pushing to followed by the local branch ref to update the corresponding remote branch with.

git reset, however, takes a single path parameter where you are specifying the branch of the remote repo (via a path) to reset the local copy to.

To answer your question directly, the reason you need a slash for git reset is because it takes one parameter which is a path rather than git push which takes two separate parameters: a remote and a branch.

You may wish to refer to git push and git reset official documentation for Git.

2

Why the / ?

In git push <remote> <branch> you are giving two parameters: the remote name and the branch name. Hence no reason to add a /. The remote is an essential part here; after all, push will communicate with it.

In git reset ... origin/my_branch you are giving one parameter: the name of a branch. In this context, origin/my_branch is the name of the branch, fully specified. You could also give the name of a local branch here (in which case you would leave off the .../ part. So if there were a space in between (instead of using the fully qualified branch name), it would become quite confusing and error prone. reset does not care about or even know about remotes.

Careful

git reset --hard origin/my_branch

This needs a git checkout my_branch first or you will reset whatever other branch you are currently on. You might want to edit your question so people who stumble across it don't get the wrong impression.

Keep their changes

More importantly, there is no need to do a hard reset (i.e. to throw away all locally committed changes on the branch) after a rebase was force-pushed. Your colleagues can simply do the same rebase operation on their end, and then everything is fine again (well, not in pathologigal cases with lots and lots of conflicts, of course). The "rerere cache" can help here (see git help rerere).

So, if you did:

git checkout my_branch
git rebase abc12345
git push --force

Then they can do:

git fetch   # in case they do not have abc12345 yet
git checkout my_branch
git rebase abc12345
git pull

The rebase operation is repeatable, so this should work well, usually. This will let the other developers keep all their local changes and get yours on top (remember that the pull is basically a merge).

3
  • 2
    The bad thing about deleting, then re-creating, the branch (git branch -D my_branch followed by git checkout my_branch) is that this discards your reflog for my_branch. Well, that, and, accidentally using the wrong name (for a private branch that has no upstream) could be even worse. :-)
    – torek
    Commented Aug 5, 2016 at 14:49
  • 1
    I like the git branch -f method too, except for one other problem: if you're actually on that branch at the time, it moves the label without altering your index and work-tree. This leaves you with a whole lot of "changes to be committed" if you had a clean index and work-tree before. (Which you can then fix with git reset --hard, but you need to know to check, and to understand why that just happened.) It does show that there is no need to leave the current branch, if the upstream rebase you need to deal with affected some other branch.
    – torek
    Commented Aug 5, 2016 at 15:01
  • 1
    Gah, you're completely right. I've removed that part of my answer, hard to get right without stepping into difficulties; and it is not the important part anyways. ;)
    – AnoE
    Commented Aug 5, 2016 at 15:03

Not the answer you're looking for? Browse other questions tagged or ask your own question.