While commands like \"git log\" will happily accept different expressions for the same ref, e.g.
refs/heads/master
heads/master
master
this is
The main reason why git log
and git update-ref
behave differently is because git-log
is a high-level command – and therefore designed to be user-friendly – while git-update-ref
is a low-level command meant to be used in scripts.
In Git parlance, high-level commands are referred to as porcelain while low-level ones are collectively called plumbing.
Porcelain commands are meant to be used interactively by humans and therefore expose familiar high-level concepts such as symbolic references. Plumbing commands, on the other hand, are meant to be used programmatically – usually in scripts – and allow to directly manipulate Git's internal file system structures.
While git-log
is able to resolve references, git-update-ref
– it being a plumbing command – interprets the first argument as either a symlink or a regular file name depending on how it's specified.
From the documentation:
It follows real symlinks only if they start with "refs/": otherwise it will just try to read them and update them as a regular file.
So that's why if you say git update-ref master
it will treat master
as a file name and create it in the .git directory. By the same token, when you say git update-ref HEAD
it will write
to the .git/HEAD
file.