On Wed, Aug 26, 2009 at 10:27:30AM +0100, Howard Miller wrote: > I've been working away at Gitosis and it's mostly fair enough but > there's one bit that's unclear to me... > > git push origin master:refs/heads/master > > Would somebody kindly explain (or point to docs) what > refs/heads/master means? How is this different from just 'git push > origin master' or even 'git push origin master:master'? I'll try to explain. Refs are pointers to commits. In other words, you can think of "refs/heads/master" as a key pointing to a SHA-1 commit id. The long-ish name divides up the namespace for refs. There are a few special refs that live outside of the refs/ hierarchy, like HEAD, FETCH_HEAD, MERGE_HEAD, ORIG_HEAD, etc. Normal refs are generally under refs/. The refs/heads/ hierarchy is for branches (they are the "head" of a line of development). The refs/tags hierarchy is for tags. The refs/remotes hierarchy is where we store our local idea of where remote repositories' branches point. Pushing (and fetching) take a "refspec": two refs, a source and destination, separated by a colon. So "git push foo:bar" means "look up my local ref 'foo' and update or create the remote ref 'bar' with the same commit". Every ref has a "full name" that is much longer than what we often see. We can generally abbreviate because one of the following applies: 1. We are specifying a name to look up, and there is a set of lookup rules. For example, the name "master" will be considered as a tag, and then as a branch, and then as a remote branch. The lookup rules are described in "git help rev-parse" under the section "Specifying Revisions". 2. We are using a name in a context that expects a particular type. For example, "git branch foo" knows that "foo" is a new branch name, and so will create the ref as refs/heads/foo. Similarly "git tag foo" will create refs/tags/foo. 3. We can infer the type from the other half of a refspec. For example, given a local branch "master" and a tag "v1.0" (and neither currently existing on the remote side), we can do: git push origin master:master v1.0:v1.0 and we know that the "master" we create on the remote will be a branch, because the local "master" is a branch, and similarly the "v1.0" we create on the remote will be a tag because the local "v1.0" is a tag. And finally, "git push" knows a shorthand for refspecs: a refspec without a colon is treated as having the same string on both sides. So "master" is really a shortcut for "master:master". Knowing all of that, let's look at your examples: A. git push origin master This is really a syntactic shortcut for "git push origin master:master". B. git push origin master:master The left-hand side of the refspec is looked up locally. In this case, it is probably going to be "refs/heads/master". The right-hand side is looked up on the remote. If it exists (i.e., you are updating your branch), it is probably "refs/heads/master". If it doesn't exist on the remote (i.e., you are pushing a new branch), then we can infer from the prefix of the left-hand side that the right-hand side should also be a branch (i.e., under "refs/heads/"). So assuming "master" is a branch, this is really equivalent to: git push origin refs/heads/master:refs/heads/master C. git push origin master:refs/heads/master If you understood the explanation for (B) above, you will know that this is again basically the same thing. :) However, note that in (B), if the branch is being created on the remote, we rely on the "refspec inference" rule described earlier. This behavior was adopted in git in v1.5.5.2 (commit f8aae120, 2008-04-23). So you may still see examples that pre-date this feature and recommend using the full ref-name, which should no longer be necessary. Hope that helps. Let me know if you need clarification on any of the above. -Peff -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html