Commit 48cae60d0ae734495d85aa8a8d9409e71cfe7d76

Stefan Sperling 2020-09-22T00:03:02

make dangling symbolic references show up in 'got ref -l' Storing a resolved ID for each reference list item was a bad idea. This ID cannot be resolved if a symbolic references points to a reference which does not exist. Such symrefs were skipped by got ref -l as a result. Just let users of reference lists resolve the IDs as needed.

diff --git a/got/got.c b/got/got.c
index e8c441e..2abb631 100644
--- a/got/got.c
+++ b/got/got.c
@@ -3202,6 +3202,7 @@ print_commit(struct got_commit_object *commit, struct got_object_id *id,
 		char *s;
 		const char *name;
 		struct got_tag_object *tag = NULL;
+		struct got_object_id *ref_id;
 		int cmp;
 
 		name = got_ref_get_name(re->ref);
@@ -3219,18 +3220,24 @@ print_commit(struct got_commit_object *commit, struct got_object_id *id,
 			if (s != NULL && s[strlen(s)] == '\0')
 				continue;
 		}
+		err = got_ref_resolve(&ref_id, repo, re->ref);
+		if (err)
+			return err;
 		if (strncmp(name, "tags/", 5) == 0) {
-			err = got_object_open_as_tag(&tag, repo, re->id);
+			err = got_object_open_as_tag(&tag, repo, ref_id);
 			if (err) {
-				if (err->code != GOT_ERR_OBJ_TYPE)
+				if (err->code != GOT_ERR_OBJ_TYPE) {
+					free(ref_id);
 					return err;
+				}
 				/* Ref points at something other than a tag. */
 				err = NULL;
 				tag = NULL;
 			}
 		}
 		cmp = got_object_id_cmp(tag ?
-		    got_object_tag_get_object_id(tag) : re->id, id);
+		    got_object_tag_get_object_id(tag) : ref_id, id);
+		free(ref_id);
 		if (tag)
 			got_object_tag_close(tag);
 		if (cmp != 0)
diff --git a/include/got_reference.h b/include/got_reference.h
index 5286f89..5f2594f 100644
--- a/include/got_reference.h
+++ b/include/got_reference.h
@@ -75,11 +75,10 @@ const struct got_error *got_ref_resolve(struct got_object_id **,
  */
 char *got_ref_to_str(struct got_reference *);
 
-/* A list of references and the object ID which they resolve to. */
+/* List of references. */
 struct got_reflist_entry {
 	SIMPLEQ_ENTRY(got_reflist_entry) entry;
 	struct got_reference *ref;
-	struct got_object_id *id;
 };
 SIMPLEQ_HEAD(got_reflist_head, got_reflist_entry);
 
diff --git a/lib/reference.c b/lib/reference.c
index 1e9c232..0106f4d 100644
--- a/lib/reference.c
+++ b/lib/reference.c
@@ -566,14 +566,6 @@ got_reflist_entry_dup(struct got_reflist_entry **newp,
 		return err;
 	}
 
-	new->id = got_object_id_dup(re->id);
-	if (new->id == NULL) {
-		err = got_error_from_errno("got_ref_dup");
-		free(new->id);
-		free(new);
-		return err;
-	}
-
 	*newp = new;
 	return NULL;
 }
@@ -752,23 +744,15 @@ insert_ref(struct got_reflist_entry **newp, struct got_reflist_head *refs,
     got_ref_cmp_cb cmp_cb, void *cmp_arg)
 {
 	const struct got_error *err;
-	struct got_object_id *id;
 	struct got_reflist_entry *new, *re, *prev = NULL;
 	int cmp;
 
 	*newp = NULL;
 
-	err = got_ref_resolve(&id, repo, ref);
-	if (err)
-		return err;
-
 	new = malloc(sizeof(*new));
-	if (new == NULL) {
-		free(id);
+	if (new == NULL)
 		return got_error_from_errno("malloc");
-	}
 	new->ref = ref;
-	new->id = id;
 	*newp = new;
 
 	/*
@@ -784,7 +768,6 @@ insert_ref(struct got_reflist_entry **newp, struct got_reflist_head *refs,
 			return err;
 		if (cmp == 0) {
 			/* duplicate */
-			free(new->id);
 			free(new);
 			*newp = NULL;
 			return NULL;
@@ -1031,7 +1014,6 @@ got_ref_list_free(struct got_reflist_head *refs)
 		re = SIMPLEQ_FIRST(refs);
 		SIMPLEQ_REMOVE_HEAD(refs, entry);
 		got_ref_close(re->ref);
-		free(re->id);
 		free(re);
 	}
 
diff --git a/regress/cmdline/ref.sh b/regress/cmdline/ref.sh
index 5a2b0f6..e3bb018 100755
--- a/regress/cmdline/ref.sh
+++ b/regress/cmdline/ref.sh
@@ -266,7 +266,8 @@ test_ref_delete() {
 	got ref -r $testroot/repo -d master
 
 	got ref -l -r $testroot/repo > $testroot/stdout
-	echo "refs/heads/ref1: $commit_id" > $testroot/stdout.expected
+	echo "HEAD: refs/heads/master" > $testroot/stdout.expected
+	echo "refs/heads/ref1: $commit_id" >> $testroot/stdout.expected
 	echo "refs/heads/ref3: $commit_id" >> $testroot/stdout.expected
 	cmp -s $testroot/stdout $testroot/stdout.expected
 	ret="$?"
diff --git a/tog/tog.c b/tog/tog.c
index d46c6ec..c85b72c 100644
--- a/tog/tog.c
+++ b/tog/tog.c
@@ -1163,6 +1163,7 @@ build_refs_str(char **refs_str, struct got_reflist_head *refs,
 
 	SIMPLEQ_FOREACH(re, refs, entry) {
 		struct got_tag_object *tag = NULL;
+		struct got_object_id *ref_id;
 		int cmp;
 
 		name = got_ref_get_name(re->ref);
@@ -1180,18 +1181,24 @@ build_refs_str(char **refs_str, struct got_reflist_head *refs,
 			if (s != NULL && s[strlen(s)] == '\0')
 				continue;
 		}
+		err = got_ref_resolve(&ref_id, repo, re->ref);
+		if (err)
+			break;
 		if (strncmp(name, "tags/", 5) == 0) {
-			err = got_object_open_as_tag(&tag, repo, re->id);
+			err = got_object_open_as_tag(&tag, repo, ref_id);
 			if (err) {
-				if (err->code != GOT_ERR_OBJ_TYPE)
+				if (err->code != GOT_ERR_OBJ_TYPE) {
+					free(ref_id);
 					break;
+				}
 				/* Ref points at something other than a tag. */
 				err = NULL;
 				tag = NULL;
 			}
 		}
 		cmp = got_object_id_cmp(tag ?
-		    got_object_tag_get_object_id(tag) : re->id, id);
+		    got_object_tag_get_object_id(tag) : ref_id, id);
+		free(ref_id);
 		if (tag)
 			got_object_tag_close(tag);
 		if (cmp != 0)