Question

on my server I host my personal git remote-side projects (with gitosis), and I have built a web interface to browse the repositories (something like Github).

On the remote-side, you are not allowed to do a lot of stuff, because a working tree is missing, and this is correct: btw, for a repository explorer, with few commands I can do almost everything.

Except for git blame.

I'm not able to find out how to blame a file without a working tree, within the remote-side repository. Got you some ideas?

Was it helpful?

Solution

The following should work even in bare repositories:

git blame <rev> -- <path>

E.g.

git blame master -- README.txt

OTHER TIPS

I'm not able to find where the git docs talk about -- option, by the way this works greatly

Actually, this is necessary because "git blame" is prepared to take an ancient odd argument order "blame <path> <rev>" in addition to the usual "blame [<rev>] <path>".

That means, as Git 2.17 (Q2 2018) will explain "git blame HEAD COPYING" in a bare repository failed to run, while "git blame HEAD -- COPYING" run just fine.

But from 2.17 on, you won't need '--' anymore.

See commit 0c668f5 (05 Feb 2018) by Junio C Hamano (gitster).
(Merged by Junio C Hamano -- gitster -- in commit 0c668f5, 07 Feb 2018)

blame: tighten command line parser

An ancient odd argument order "blame <path> <rev>" in addition to the usual "blame [<rev>] <path>" has at least two negative ramifications:

  • In order to tell these two apart, it checks if the last command line argument names a path in the working tree, using file_exists().
    However, "blame <rev> <path>" is a request to explain each and every line in the contents of <path> stored in revision <rev> and does not need to have a working tree version of the file. A check with file_exists() is simply wrong.

  • To coerce that mistaken file_exists() check to work, the code calls setup_work_tree() before doing so, because the path it has is relative to the top-level of the project tree.
    However, "blame <rev> <path>" MUST be usable even in a bare repository, and there is no reason for letting setup_work_tree() complain and die with "This operation must be run in a work tree".

To correct the former, switch to check if the last token is a revision (and if so, parse arguments using "blame <path> <rev>" rule).

Correct the latter by getting rid of setup_work_tree() and file_exists() check--the only case the call to this function matters is when we are running "blame <path>" (i.e. no starting revision and asking to blame the working tree file at <path>, digging through the HEAD revision), but there is a call in setup_scoreboard() just before it calls fake_working_tree_commit().

So in short, starting Git 2.17, this will work in a bare repo:

git blame master -- README.txt

And with Git 2.22, the error message "This operation must be run in a work tree" should disappear!

"git blame -- path" in a non-bare repository starts blaming from the working tree, and the same command in a bare repository errors out because there is no working tree by definition.
The command has been taught to instead start blaming from the commit at HEAD, which is more useful.

See commit a544fb0 (07 Apr 2019) by SZEDER Gábor (szeder).
(Merged by Junio C Hamano -- gitster -- in commit d8620d3, 25 Apr 2019)

blame: default to HEAD in a bare repo when no start commit is given

When 'git blame' is invoked without specifying the commit to start blaming from, it starts from the given file's state in the work tree.
However, when invoked in a bare repository without a start commit, then there is no work tree state to start from, and it dies with the following error message:

$ git rev-parse --is-bare-repository
true
$ git blame file.c
fatal: this operation must be run in a work tree

This is misleading, because it implies that 'git blame' doesn't work in bare repositories at all, but it does, in fact, work just fine when it is given a commit to start from.

We could improve the error message, of course, but let's just default to HEAD in a bare repository instead, as most likely that is what the user wanted anyway (if they wanted to start from an other commit, then they would have specified that in the first place).

'git annotate' is just a thin wrapper around 'git blame', so in the same situation it printed the same misleading error message, and this patch fixes it, too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top