From 89df9c84e478b7e6055a93cf45cf37027d25b3e4 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Sun, 14 Apr 2013 14:54:16 +0200 Subject: refs: document flags constants REF_* Document the bits that can appear in the "flags" parameter passed to an each_ref_function and/or in the ref_entry::flag field. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- refs.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'refs.h') diff --git a/refs.h b/refs.h index d6c2fe2dfb..f111024a18 100644 --- a/refs.h +++ b/refs.h @@ -10,8 +10,21 @@ struct ref_lock { int force_write; }; +/* + * Bit values set in the flags argument passed to each_ref_fn(): + */ + +/* Reference is a symbolic reference. */ #define REF_ISSYMREF 0x01 + +/* Reference is a packed reference. */ #define REF_ISPACKED 0x02 + +/* + * Reference cannot be resolved to an object name: dangling symbolic + * reference (directly or indirectly), corrupt reference file, or + * symbolic reference refers to ill-formatted reference name. + */ #define REF_ISBROKEN 0x04 /* -- cgit 1.2.3-korg From 2312a7932080f17c2847ec3ce5dddbc65c2e0b41 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Mon, 22 Apr 2013 21:52:21 +0200 Subject: peel_ref(): fix return value for non-peelable, not-current reference The old version was inconsistent: when a reference was REF_KNOWS_PEELED but with a null peeled value, it returned non-zero for the current reference but zero for other references. Change the behavior for non-current references to match that of current_ref, which is what callers expect. Document the behavior. Current callers only call peel_ref() from within a for_each_ref-style iteration and only for the current ref; therefore, the buggy code path was never reached. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- refs.c | 5 ++++- refs.h | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'refs.h') diff --git a/refs.c b/refs.c index 7405d1c962..787db21dfc 100644 --- a/refs.c +++ b/refs.c @@ -119,7 +119,8 @@ struct ref_value { /* * If REF_KNOWS_PEELED, then this field holds the peeled value * of this reference, or null if the reference is known not to - * be peelable. + * be peelable. See the documentation for peel_ref() for an + * exact definition of "peelable". */ unsigned char peeled[20]; }; @@ -1340,6 +1341,8 @@ int peel_ref(const char *refname, unsigned char *sha1) struct ref_entry *r = get_packed_ref(refname); if (r && (r->flag & REF_KNOWS_PEELED)) { + if (is_null_sha1(r->u.value.peeled)) + return -1; hashcpy(sha1, r->u.value.peeled); return 0; } diff --git a/refs.h b/refs.h index f111024a18..3fc97a2e4a 100644 --- a/refs.h +++ b/refs.h @@ -74,6 +74,14 @@ extern void add_packed_ref(const char *refname, const unsigned char *sha1); extern int ref_exists(const char *); +/* + * If refname is a non-symbolic reference that refers to a tag object, + * and the tag can be (recursively) dereferenced to a non-tag object, + * store the SHA1 of the referred-to object to sha1 and return 0. If + * any of these conditions are not met, return a non-zero value. + * Symbolic references are considered unpeelable, even if they + * ultimately resolve to a peelable tag. + */ extern int peel_ref(const char *refname, unsigned char *sha1); /** Locks a "refs/" ref returning the lock on success and NULL on failure. **/ -- cgit 1.2.3-korg From 32d462cea80cd52b2c3fa0d538aba7fcf079ba77 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Mon, 22 Apr 2013 21:52:32 +0200 Subject: pack-refs: merge code from pack-refs.{c,h} into refs.{c,h} pack-refs.c doesn't contain much code, and the code it does contain is closely related to reference handling. Moreover, there is some duplication between pack_refs() and repack_without_ref(). Therefore, merge pack-refs.c into refs.c and pack-refs.h into refs.h. The code duplication will be addressed in future commits. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- Makefile | 2 - builtin/clone.c | 1 - builtin/pack-refs.c | 2 +- pack-refs.c | 148 ---------------------------------------------------- pack-refs.h | 18 ------- refs.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++ refs.h | 14 +++++ 7 files changed, 159 insertions(+), 170 deletions(-) delete mode 100644 pack-refs.c delete mode 100644 pack-refs.h (limited to 'refs.h') diff --git a/Makefile b/Makefile index 5be54584b7..d2e93779b1 100644 --- a/Makefile +++ b/Makefile @@ -644,7 +644,6 @@ LIB_H += notes-cache.h LIB_H += notes-merge.h LIB_H += notes.h LIB_H += object.h -LIB_H += pack-refs.h LIB_H += pack-revindex.h LIB_H += pack.h LIB_H += parse-options.h @@ -775,7 +774,6 @@ LIB_OBJS += notes-cache.o LIB_OBJS += notes-merge.o LIB_OBJS += object.o LIB_OBJS += pack-check.o -LIB_OBJS += pack-refs.o LIB_OBJS += pack-revindex.o LIB_OBJS += pack-write.o LIB_OBJS += pager.o diff --git a/builtin/clone.c b/builtin/clone.c index 36ec99db3f..a0f5bb9f45 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -18,7 +18,6 @@ #include "transport.h" #include "strbuf.h" #include "dir.h" -#include "pack-refs.h" #include "sigchain.h" #include "branch.h" #include "remote.h" diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c index b5a0f88eb8..b20b1ec4c1 100644 --- a/builtin/pack-refs.c +++ b/builtin/pack-refs.c @@ -1,6 +1,6 @@ #include "builtin.h" #include "parse-options.h" -#include "pack-refs.h" +#include "refs.h" static char const * const pack_refs_usage[] = { N_("git pack-refs [options]"), diff --git a/pack-refs.c b/pack-refs.c deleted file mode 100644 index d840055121..0000000000 --- a/pack-refs.c +++ /dev/null @@ -1,148 +0,0 @@ -#include "cache.h" -#include "refs.h" -#include "tag.h" -#include "pack-refs.h" - -struct ref_to_prune { - struct ref_to_prune *next; - unsigned char sha1[20]; - char name[FLEX_ARRAY]; -}; - -struct pack_refs_cb_data { - unsigned int flags; - struct ref_to_prune *ref_to_prune; - FILE *refs_file; -}; - -static int do_not_prune(int flags) -{ - /* If it is already packed or if it is a symref, - * do not prune it. - */ - return (flags & (REF_ISSYMREF|REF_ISPACKED)); -} - -static int pack_one_ref(const char *path, const unsigned char *sha1, - int flags, void *cb_data) -{ - struct pack_refs_cb_data *cb = cb_data; - struct object *o; - int is_tag_ref; - - /* Do not pack the symbolic refs */ - if ((flags & REF_ISSYMREF)) - return 0; - is_tag_ref = !prefixcmp(path, "refs/tags/"); - - /* ALWAYS pack refs that were already packed or are tags */ - if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref && !(flags & REF_ISPACKED)) - return 0; - - fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path); - - o = parse_object_or_die(sha1, path); - if (o->type == OBJ_TAG) { - o = deref_tag(o, path, 0); - if (o) - fprintf(cb->refs_file, "^%s\n", - sha1_to_hex(o->sha1)); - } - - if ((cb->flags & PACK_REFS_PRUNE) && !do_not_prune(flags)) { - int namelen = strlen(path) + 1; - struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen); - hashcpy(n->sha1, sha1); - strcpy(n->name, path); - n->next = cb->ref_to_prune; - cb->ref_to_prune = n; - } - return 0; -} - -/* - * Remove empty parents, but spare refs/ and immediate subdirs. - * Note: munges *name. - */ -static void try_remove_empty_parents(char *name) -{ - char *p, *q; - int i; - p = name; - for (i = 0; i < 2; i++) { /* refs/{heads,tags,...}/ */ - while (*p && *p != '/') - p++; - /* tolerate duplicate slashes; see check_refname_format() */ - while (*p == '/') - p++; - } - for (q = p; *q; q++) - ; - while (1) { - while (q > p && *q != '/') - q--; - while (q > p && *(q-1) == '/') - q--; - if (q == p) - break; - *q = '\0'; - if (rmdir(git_path("%s", name))) - break; - } -} - -/* make sure nobody touched the ref, and unlink */ -static void prune_ref(struct ref_to_prune *r) -{ - struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1); - - if (lock) { - unlink_or_warn(git_path("%s", r->name)); - unlock_ref(lock); - try_remove_empty_parents(r->name); - } -} - -static void prune_refs(struct ref_to_prune *r) -{ - while (r) { - prune_ref(r); - r = r->next; - } -} - -static struct lock_file packed; - -int pack_refs(unsigned int flags) -{ - int fd; - struct pack_refs_cb_data cbdata; - - memset(&cbdata, 0, sizeof(cbdata)); - cbdata.flags = flags; - - fd = hold_lock_file_for_update(&packed, git_path("packed-refs"), - LOCK_DIE_ON_ERROR); - cbdata.refs_file = fdopen(fd, "w"); - if (!cbdata.refs_file) - die_errno("unable to create ref-pack file structure"); - - /* perhaps other traits later as well */ - fprintf(cbdata.refs_file, "# pack-refs with: peeled fully-peeled \n"); - - for_each_ref(pack_one_ref, &cbdata); - if (ferror(cbdata.refs_file)) - die("failed to write ref-pack file"); - if (fflush(cbdata.refs_file) || fsync(fd) || fclose(cbdata.refs_file)) - die_errno("failed to write ref-pack file"); - /* - * Since the lock file was fdopen()'ed and then fclose()'ed above, - * assign -1 to the lock file descriptor so that commit_lock_file() - * won't try to close() it. - */ - packed.fd = -1; - if (commit_lock_file(&packed) < 0) - die_errno("unable to overwrite old ref-pack file"); - prune_refs(cbdata.ref_to_prune); - return 0; -} diff --git a/pack-refs.h b/pack-refs.h deleted file mode 100644 index 518acfb370..0000000000 --- a/pack-refs.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef PACK_REFS_H -#define PACK_REFS_H - -/* - * Flags for controlling behaviour of pack_refs() - * PACK_REFS_PRUNE: Prune loose refs after packing - * PACK_REFS_ALL: Pack _all_ refs, not just tags and already packed refs - */ -#define PACK_REFS_PRUNE 0x0001 -#define PACK_REFS_ALL 0x0002 - -/* - * Write a packed-refs file for the current repository. - * flags: Combination of the above PACK_REFS_* flags. - */ -int pack_refs(unsigned int flags); - -#endif /* PACK_REFS_H */ diff --git a/refs.c b/refs.c index e09c0457af..fcd7163581 100644 --- a/refs.c +++ b/refs.c @@ -1984,6 +1984,150 @@ static void write_packed_entry(int fd, char *refname, unsigned char *sha1, } } +struct ref_to_prune { + struct ref_to_prune *next; + unsigned char sha1[20]; + char name[FLEX_ARRAY]; +}; + +struct pack_refs_cb_data { + unsigned int flags; + struct ref_to_prune *ref_to_prune; + FILE *refs_file; +}; + +static int do_not_prune(int flags) +{ + /* If it is already packed or if it is a symref, + * do not prune it. + */ + return (flags & (REF_ISSYMREF|REF_ISPACKED)); +} + +static int pack_one_ref(const char *path, const unsigned char *sha1, + int flags, void *cb_data) +{ + struct pack_refs_cb_data *cb = cb_data; + struct object *o; + int is_tag_ref; + + /* Do not pack the symbolic refs */ + if ((flags & REF_ISSYMREF)) + return 0; + is_tag_ref = !prefixcmp(path, "refs/tags/"); + + /* ALWAYS pack refs that were already packed or are tags */ + if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref && !(flags & REF_ISPACKED)) + return 0; + + fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path); + + o = parse_object_or_die(sha1, path); + if (o->type == OBJ_TAG) { + o = deref_tag(o, path, 0); + if (o) + fprintf(cb->refs_file, "^%s\n", + sha1_to_hex(o->sha1)); + } + + if ((cb->flags & PACK_REFS_PRUNE) && !do_not_prune(flags)) { + int namelen = strlen(path) + 1; + struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen); + hashcpy(n->sha1, sha1); + strcpy(n->name, path); + n->next = cb->ref_to_prune; + cb->ref_to_prune = n; + } + return 0; +} + +/* + * Remove empty parents, but spare refs/ and immediate subdirs. + * Note: munges *name. + */ +static void try_remove_empty_parents(char *name) +{ + char *p, *q; + int i; + p = name; + for (i = 0; i < 2; i++) { /* refs/{heads,tags,...}/ */ + while (*p && *p != '/') + p++; + /* tolerate duplicate slashes; see check_refname_format() */ + while (*p == '/') + p++; + } + for (q = p; *q; q++) + ; + while (1) { + while (q > p && *q != '/') + q--; + while (q > p && *(q-1) == '/') + q--; + if (q == p) + break; + *q = '\0'; + if (rmdir(git_path("%s", name))) + break; + } +} + +/* make sure nobody touched the ref, and unlink */ +static void prune_ref(struct ref_to_prune *r) +{ + struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1); + + if (lock) { + unlink_or_warn(git_path("%s", r->name)); + unlock_ref(lock); + try_remove_empty_parents(r->name); + } +} + +static void prune_refs(struct ref_to_prune *r) +{ + while (r) { + prune_ref(r); + r = r->next; + } +} + +static struct lock_file packed; + +int pack_refs(unsigned int flags) +{ + int fd; + struct pack_refs_cb_data cbdata; + + memset(&cbdata, 0, sizeof(cbdata)); + cbdata.flags = flags; + + fd = hold_lock_file_for_update(&packed, git_path("packed-refs"), + LOCK_DIE_ON_ERROR); + cbdata.refs_file = fdopen(fd, "w"); + if (!cbdata.refs_file) + die_errno("unable to create ref-pack file structure"); + + /* perhaps other traits later as well */ + fprintf(cbdata.refs_file, "# pack-refs with: peeled fully-peeled \n"); + + for_each_ref(pack_one_ref, &cbdata); + if (ferror(cbdata.refs_file)) + die("failed to write ref-pack file"); + if (fflush(cbdata.refs_file) || fsync(fd) || fclose(cbdata.refs_file)) + die_errno("failed to write ref-pack file"); + /* + * Since the lock file was fdopen()'ed and then fclose()'ed above, + * assign -1 to the lock file descriptor so that commit_lock_file() + * won't try to close() it. + */ + packed.fd = -1; + if (commit_lock_file(&packed) < 0) + die_errno("unable to overwrite old ref-pack file"); + prune_refs(cbdata.ref_to_prune); + return 0; +} + static int repack_ref_fn(struct ref_entry *entry, void *cb_data) { int *fd = cb_data; diff --git a/refs.h b/refs.h index 3fc97a2e4a..175b7a92d1 100644 --- a/refs.h +++ b/refs.h @@ -72,6 +72,20 @@ extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refn */ extern void add_packed_ref(const char *refname, const unsigned char *sha1); +/* + * Flags for controlling behaviour of pack_refs() + * PACK_REFS_PRUNE: Prune loose refs after packing + * PACK_REFS_ALL: Pack _all_ refs, not just tags and already packed refs + */ +#define PACK_REFS_PRUNE 0x0001 +#define PACK_REFS_ALL 0x0002 + +/* + * Write a packed-refs file for the current repository. + * flags: Combination of the above PACK_REFS_* flags. + */ +int pack_refs(unsigned int flags); + extern int ref_exists(const char *); /* -- cgit 1.2.3-korg