Commit d1f2edc95ce19d76654b6ac6616fa33a9086540c

Stefan Sperling 2018-06-13T19:19:55

make 'got log -c' accept a branch name

diff --git a/got/got.1 b/got/got.1
index 8ead4c5..9e3a090 100644
--- a/got/got.1
+++ b/got/got.1
@@ -106,7 +106,8 @@ Display the patch of modifications made in each commit.
 .It Fl c Ar commit
 Start traversing history at the specified
 .Ar commit .
-The expected argument is the SHA1 hash which corresponds to the commit object.
+The expected argument is the name of a branch or a SHA1 hash which corresponds
+to the commit object.
 .It Fl l Ar N
 Limit history traversal to a given number of commits.
 .It Fl f
diff --git a/got/got.c b/got/got.c
index 61a7b2a..6319c20 100644
--- a/got/got.c
+++ b/got/got.c
@@ -438,7 +438,7 @@ cmd_log(int argc, char *argv[])
 	const struct got_error *error;
 	struct got_repository *repo;
 	struct got_object_id *id = NULL;
-	struct got_object *obj;
+	struct got_object *obj = NULL;
 	char *repo_path = NULL;
 	char *start_commit = NULL;
 	int ch;
@@ -502,8 +502,22 @@ cmd_log(int argc, char *argv[])
 			return error;
 		error = got_object_open(&obj, repo, id);
 	} else {
-		error = got_object_open_by_id_str(&obj, repo, start_commit);
+		struct got_reference *ref;
+		error = got_ref_open(&ref, repo, start_commit);
 		if (error == NULL) {
+			error = got_ref_resolve(&id, repo, ref);
+			got_ref_close(ref);
+			if (error != NULL)
+				return error;
+			error = got_object_open(&obj, repo, id);
+			if (error != NULL)
+				return error;
+		}
+		if (obj == NULL) {
+			error = got_object_open_by_id_str(&obj, repo,
+			    start_commit);
+			if (error != NULL)
+				return error;
 			id = got_object_get_id(obj);
 			if (id == NULL)
 				error = got_error_from_errno();
diff --git a/lib/reference.c b/lib/reference.c
index 90e79b5..8336d48 100644
--- a/lib/reference.c
+++ b/lib/reference.c
@@ -35,6 +35,10 @@
 #include "got_lib_zbuf.h"
 #include "got_lib_object.h"
 
+#define GOT_REF_HEADS	"heads"
+#define GOT_REF_TAGS	"tags"
+#define GOT_REF_REMOTES	"remotes"
+
 /* A symbolic reference. */
 struct got_symref {
 	char *name;
@@ -153,13 +157,35 @@ get_refs_dir_path(struct got_repository *repo, const char *refname)
 	return got_repo_get_path_refs(repo);
 }
 
+static const struct got_error *
+open_ref(struct got_reference **ref, const char *path_refs, const char *subdir,
+    const char *refname)
+{
+	const struct got_error *err = NULL;
+	char *path_ref;
+	char *normpath;
+
+	if (asprintf(&path_ref, "%s/%s/%s", path_refs, subdir, refname) == -1)
+		return got_error_from_errno();
+
+	normpath = got_path_normalize(path_ref);
+	if (normpath == NULL) {
+		err = got_error(GOT_ERR_NOT_REF);
+		goto done;
+	}
+
+	err = parse_ref_file(ref, refname, normpath);
+done:
+	free(path_ref);
+	free(normpath);
+	return err;
+}
+
 const struct got_error *
 got_ref_open(struct got_reference **ref, struct got_repository *repo,
    const char *refname)
 {
 	const struct got_error *err = NULL;
-	char *path_ref = NULL;
-	char *normpath = NULL;
 	char *path_refs = get_refs_dir_path(repo, refname);
 
 	if (path_refs == NULL) {
@@ -169,21 +195,14 @@ got_ref_open(struct got_reference **ref, struct got_repository *repo,
 	
 	/* XXX For now, this assumes that refs exist in the filesystem. */
 
-	if (asprintf(&path_ref, "%s/%s", path_refs, refname) == -1) {
-		err = got_error_from_errno();
-		goto done;
-	}
-
-	normpath = got_path_normalize(path_ref);
-	if (normpath == NULL) {
-		err = got_error(GOT_ERR_NOT_REF);
-		goto done;
-	}
-
-	err = parse_ref_file(ref, refname, normpath);
+	err = open_ref(ref, path_refs, GOT_REF_HEADS, refname);
+	if (err != NULL)
+		err = open_ref(ref, path_refs, GOT_REF_TAGS, refname);
+	if (err != NULL)
+		err = open_ref(ref, path_refs, GOT_REF_REMOTES, refname);
+	if (err != NULL)
+		err = open_ref(ref, path_refs, "", refname);
 done:
-	free(normpath);
-	free(path_ref);
 	free(path_refs);
 	return err;
 }