Anonymous committed af13cdf

Be more careful about reference parsing

This does two things:

- we don't allow "." and ".." as components of a refname. Thus get_sha1()
will not accept "./refname" as being the same as "refname" any more.

- git-rev-parse stops doing revision translation after seeing a pathname,
to match the brhaviour of all the tools (once we see a pathname,
everything else will also be parsed as a pathname).

Basically, if you did

git log *

and "gitk" was somewhere in the "*", we don't want to replace the filename
"gitk" with the SHA1 of the branch with the same name.

Of course, if there is any change of ambiguity, you should always use "--"
to make it explicit what are filenames and what are revisions, but this
makes the normal cases sane. The refname rule also means that instead of
the "--", you can do the same thing we're used to doing with filenames
that start with a slash: use "./filename" instead, and now it's a
filename, not an option (and not a revision).

So "git log ./*.c" is now actually a perfectly valid thing to do, even if
the first C-file might have the same name as a branch.

Trivial test:

git-rev-parse gitk ./gitk gitk

should output something like


where the "./gitk" isn't seen as a revision, and the second "gitk" is a
filename simply because we've seen filenames already, and thus stopped
doing revision parsing.

Signed-off-by: Linus Torvalds <>
Signed-off-by: Junio C Hamano <>

  • Participants
  • Parent commits 41f222e

Comments (0)

Files changed (2)

 		if (verify)
 			die("Needed a single revision");
+		as_is = 1;
 	return NULL;
+static int ambiguous_path(const char *path)
+	int slash = 1;
+	for (;;) {
+		switch (*path++) {
+		case '\0':
+			break;
+		case '/':
+			if (slash)
+				break;
+			slash = 1;
+			continue;
+		case '.':
+			continue;
+		default:
+			slash = 0;
+			continue;
+		}
+		return slash;
+	}
 static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
 	static const char *prefix[] = {
 	if (len == 40 && !get_sha1_hex(str, sha1))
 		return 0;
+	/* Accept only unambiguous ref paths. */
+	if (ambiguous_path(str))
+		return -1;
 	for (p = prefix; *p; p++) {
 		char *pathname = git_path("%s/%.*s", *p, len, str);
 		if (!read_ref(pathname, sha1))