I'm looking for a command that can be run without having a local repo at all, just as we can execute git ls-remote without having a local copy of the repo.
You'd have to run a command on the remote—i.e., have shell access there, or have someone on the inside there who gives you a backdoor way to run the command. For instance, if the remote is host2.example.com
, you might do:
ssh host2.example.com 'git -C /path/to/repo rev-parse ...'
This, of course, requires that you be able to log in to that host. If you can't log in to that host, then no, you'll need to clone the repository first.
Meanwhile, back to the rev-parse
command. In your case this seems to be sufficient, but just in general:
git rev-parse HEAD:path/to/subdir
is very different from the command shown in Latest commit hash of subdirectory (this was linked at some point, so now it is via this answer):
git log -n 1 --format="%h %aN %s %ad" -- $directory
What git rev-parse HEAD:path/to/subdir
prints is the hash ID of the internal Git tree object that stores path/to/subdir
within the current commit. But what git log -n 1 ... $directory
prints is the hash ID of some commit. This is never the hash ID of any Git internal tree object.
The commit that this git log
finds is the first commit that satisfies some constraint, within in the sequence of commits formed by enumerating commits the way git log
usually does, one at a time starting from HEAD
and working backwards. The constraint in question is that, by comparing (as with git diff
) the (single) parent commit of some non-merge commit to the commit itself, in that pair of commits, some file(s) within path/to/subdir
changed.
That is, suppose we have the following partial commit graph:
...--F--G--H <-- master (HEAD)
where H
is some commit hash ID, G
is the parent of H
, and F
is the parent of G
. (Note that there are no merge commits in this graph-fragment.)
Suppose further that if we compare the snapshot in G
vs the snapshot in H
, the only file changed is README.md
. Hence git log -p
would show that in H
we changed README.md
. However, when comparing the snapshot in F
vs the snapshot in G
, file path/to/subdir/foo.cc
has changed. So git log -p
would show that in G
, we changed a file within path/to/subdir
.
Since git log
starts by looking at H
(and thus compares G
-vs-H
), but then goes on to look at G
(and thus compares F
-vs-G
), the command:
git log -n 1 --format="%h %aN %s %ad" -- $directory
will print the abbreviated hash (%h
) of commit G
, the author name (after applying .mailmap
, %aN
) from commit G
, the subject line (%s
) from commit G
, and the author date (%ad
) from commit G.
But running:
git rev-parse HEAD:path/to/subdir
prints the full hash ID of the tree object in commit H
that holds information about any sub-trees and blobs that are required for the snapshot that is part of commit H
.
If you want to enumerate (potentially many) commit hash IDs, with or without applying various constraints, you use git log
or git rev-list
to follow the commit graph. That's what the git log
command does, after all: walk the commit graph, starting at the starting-points you request (or at HEAD
if you don't request any particular starting-points) and showing commits.
If you want one particular commit hash ID and you know enough about that commit, you can use git rev-parse
. In some cases, git rev-parse
can also walk the commit graph: in particular it can find commits whose commit log message contains some string or regular expression. But it is not smart enough to examine the diffs from one commit's parent(s) to that commit; for that, you need git log
or its plumbing sister command, git rev-list
.
(Note also that by default, git log
ignores the diffs of any merge commits. That's because the diff of a merge is complicated by the fact that there are two or more parent snapshots: Which parent should Git use when making a diff? To avoid answering that question, git log
just doesn't bother to make a diff at all, by default.)