I have 2 branches (both locally and remotely on github). I will call them BranchA and BranchB. I have BranchA with commits c1, c2 and c3. I have BranchB only with commit c1. Both branches are totally updated with github, and I can check that BranchA has c1,c2 and c3 and BranchB has only c1.
I want to push from local BranchA to remote BranchB. To do this I try:
git push origin refs/heads/BranchA:refs/remotes/origin/BranchB
When I do this, I get a strange output:
Total 0 (delta 0), reused 0 (delta 0)
To https://github.com/<username>/<repo>.git
<hash> BranchA -> origin/BranchB
When I go to github I see that BranchB is not updated and still only has c1. Then, if I run the command again, it returns that everything is up to date.
This was confusing me, but it got worse since when I try to do the command without the full ref, like this:
git push origin BranchA:BranchB
...it worked.
I am very confused by this. I searched for it and I thought that using the full ref (/refs/heads/ for example) would never do any harm.
Why is this happening? Shouldn't it work when I specify the full branch name?
As prahlad venkata commented, the reference on the remote is
refs/heads/BranchB, notrefs/heads/remotes/BranchB.Remember that when using
git pushor its counterpart,git fetch, there are two Gits, and two repositories, involved in the process. Let's call these yours (matovski's) and GitHub's.Your Git has a branch named
BranchAwhose full name isrefs/heads/BranchA. This name stores a (single) hash ID.Their Git has a branch named
BranchBwhose full name isrefs/heads/BranchB. Their Git probably also has a branch namedBranchA. These names also store hash IDs (one each).When your Git talks to GitHub's Git, your Git sees their
refs/heads/BranchAand theirrefs/heads/BranchB. Your Git would like to remember those two name-and-ID pairs, but if your Git stored them asrefs/heads/BranchAandrefs/heads/BranchB, your Git would overwrite your own branches. So your Git renames their branch names, replacingrefs/heads/withrefs/remotes/origin/.In other words,
refs/remotes/origin/BranchBis your Git's memory of their Git'srefs/heads/BranchB. But when your Git talks to their Git, your Git has to tell their Git:Please set yourrefs/heads/BranchB. If your Git asks their Git to set theirrefs/heads/origin/BranchB, that would set their Git's memory of some third Git'srefs/heads/BranchB(which, as you just saw, is sometimes allowed!—it just has no useful effect in this case, since GitHub's Git repos don't use these on their own).When you use the short-hand syntax
git push origin BranchA:BranchB, your Git sends their Git a request to setBranchB. Their Git figures out, based on this request, that you probably meant to set theirrefs/heads/BranchB, and does what (it thinks) you meant, rather than what you asked. This particular trick works only when they already have arefs/heads/BranchBsince their Git won't attempt this same guess if they don't have one yet.