Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does git update-ref accepts non /refs references?

Tags:

git

reference

While commands like "git log" will happily accept different expressions for the same ref, e.g.

refs/heads/master
heads/master
master

this is not true for "git update-ref". For example

git update-ref master HEAD^

is not the same as

git update-ref refs/heads/master HEAD^

The first command creates a new ref .git/master (and in turn introduces an ambiguity regarding refs/heads/master). Only the second command really updates master's head. (.git/refs/heads/master)

Why does git update-ref accepts references without "refs/" prefix? Shouldn't there be at least a warning or a command line option to force creation of such references?

It took me quite a long time to figure out why

git update-ref master HEAD^

did not work as expected.

like image 760
Henning Avatar asked Mar 15 '16 08:03

Henning


1 Answers

tl;dr

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.

Porcelain vs. Plumbing

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.

git-update-ref

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 <value> 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 <value> it will write <value> to the .git/HEAD file.

like image 71
Enrico Campidoglio Avatar answered Oct 26 '22 14:10

Enrico Campidoglio