commit - 1e37702e75053f3a6cee5414bef197b8ab26c983
commit + 29b5c21419fdbd26149d13ac87d3a09568e44f66
blob - 7a65cc39eb3b4dc33f5761f394e929bf83e2c89b
blob + 653c0773184dff988f1781ff5d73cf6524754e2d
--- lib/reference.c
+++ lib/reference.c
}
static const struct got_error *
-append_ref(struct got_reflist_head *refs, struct got_reference *ref,
+insert_ref(struct got_reflist_head *refs, struct got_reference *ref,
struct got_repository *repo)
{
const struct got_error *err;
struct got_object_id *id;
struct got_reflist_entry *entry;
+
+ /*
+ * We must de-duplicate entries on insert because packed-refs may
+ * contain redundant entries. On-disk refs take precedence.
+ * This code assumes that on-disk revs are read before packed-refs.
+ */
+ SIMPLEQ_FOREACH(entry, refs, entry) {
+ /* Check for duplicates. */
+ if (strcmp(got_ref_get_name(entry->ref),
+ got_ref_get_name(ref)) == 0) {
+ free(ref);
+ return NULL;
+ }
+ /* TODO: sort list while here */
+ }
err = got_ref_resolve(&id, repo, ref);
if (err)
}
static const struct got_error *
-gather_refs(struct got_reflist_head *refs, const char *path_refs,
+gather_on_disk_refs(struct got_reflist_head *refs, const char *path_refs,
const char *subdir, struct got_repository *repo)
{
const struct got_error *err = NULL;
if (err)
goto done;
if (ref) {
- err = append_ref(refs, ref, repo);
+ err = insert_ref(refs, ref, repo);
if (err)
goto done;
}
err = got_error_from_errno();
break;
}
- err = gather_refs(refs, path_refs, child, repo);
+ err = gather_on_disk_refs(refs, path_refs, child, repo);
free(child);
break;
default:
{
const struct got_error *err;
char *packed_refs_path, *path_refs = NULL;
- FILE *f;
+ FILE *f = NULL;
struct got_reference *ref;
+ /* HEAD ref should always exist. */
+ path_refs = get_refs_dir_path(repo, GOT_REF_HEAD);
+ if (path_refs == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ err = open_ref(&ref, path_refs, "", GOT_REF_HEAD);
+ if (err)
+ goto done;
+ err = insert_ref(refs, ref, repo);
+ if (err)
+ goto done;
+
+ /* Gather on-disk refs before parsing packed-refs. */
+ free(path_refs);
+ path_refs = get_refs_dir_path(repo, "");
+ if (path_refs == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ err = gather_on_disk_refs(refs, path_refs, "", repo);
+ if (err)
+ goto done;
+
+ /*
+ * The packed-refs file may contain redundant entries, in which
+ * case on-disk refs take precedence.
+ */
packed_refs_path = got_repo_get_path_packed_refs(repo);
- if (packed_refs_path == NULL)
- return got_error_from_errno();
+ if (packed_refs_path == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
f = fopen(packed_refs_path, "r");
free(packed_refs_path);
if (err)
goto done;
if (ref) {
- err = append_ref(refs, ref, repo);
+ err = insert_ref(refs, ref, repo);
if (err)
goto done;
}
}
}
- /* HEAD ref should always exist. */
- path_refs = get_refs_dir_path(repo, GOT_REF_HEAD);
- if (path_refs == NULL) {
- err = got_error_from_errno();
- goto done;
- }
- err = open_ref(&ref, path_refs, "", GOT_REF_HEAD);
- if (err)
- goto done;
- err = append_ref(refs, ref, repo);
- if (err)
- goto done;
-
- free(path_refs);
- path_refs = get_refs_dir_path(repo, "");
- if (path_refs == NULL) {
- err = got_error_from_errno();
- goto done;
- }
- err = gather_refs(refs, path_refs, "", repo);
done:
free(path_refs);
if (f)