summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: cf0adba)
raw | patch | inline | side by side (parent: cf0adba)
author | Junio C Hamano <junkio@cox.net> | |
Wed, 22 Nov 2006 07:36:35 +0000 (23:36 -0800) | ||
committer | Junio C Hamano <junkio@cox.net> | |
Wed, 22 Nov 2006 07:37:35 +0000 (23:37 -0800) |
This fixes the previous implementation which failed to optimize
repositories with tons of lightweight tags. The updated
packed-refs format begins with "# packed-refs with:" line that
lists the kind of extended data the file records. Currently,
there is only one such extension defined, "peeled". This stores
the "peeled tag" on a line that immediately follows a line for a
tag object itself in the format "^<sha-1>".
The header line itself and any extended data are ignored by
older implementation, so packed-refs file generated with this
version can still be used by older git. packed-refs made by
older git can of course be used with this version.
Signed-off-by: Junio C Hamano <junkio@cox.net>
repositories with tons of lightweight tags. The updated
packed-refs format begins with "# packed-refs with:" line that
lists the kind of extended data the file records. Currently,
there is only one such extension defined, "peeled". This stores
the "peeled tag" on a line that immediately follows a line for a
tag object itself in the format "^<sha-1>".
The header line itself and any extended data are ignored by
older implementation, so packed-refs file generated with this
version can still be used by older git. packed-refs made by
older git can of course be used with this version.
Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-pack-refs.c | patch | blob | history | |
builtin-show-ref.c | patch | blob | history | |
refs.c | patch | blob | history | |
refs.h | patch | blob | history |
diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c
index ee5a5565af9206dcc4c75abdb7efac9896ad8a74..8dc5b9efffc3ad2cd56130155a94aa489d0d0b1b 100644 (file)
--- a/builtin-pack-refs.c
+++ b/builtin-pack-refs.c
if (o->type == OBJ_TAG) {
o = deref_tag(o, path, 0);
if (o)
- fprintf(cb->refs_file, "%s %s^{}\n",
- sha1_to_hex(o->sha1), path);
+ fprintf(cb->refs_file, "^%s\n",
+ sha1_to_hex(o->sha1));
}
}
if (!cbdata.refs_file)
die("unable to create ref-pack file structure (%s)",
strerror(errno));
+
+ /* perhaps other traits later as well */
+ fprintf(cbdata.refs_file, "# pack-refs with: peeled \n");
+
for_each_ref(handle_one_ref, &cbdata);
fflush(cbdata.refs_file);
fsync(fd);
diff --git a/builtin-show-ref.c b/builtin-show-ref.c
index 9ae3d08546c74a579e9bb13285424290b4449d4d..073979855b30b72363ed8116288b7bbbb2f0ff74 100644 (file)
--- a/builtin-show-ref.c
+++ b/builtin-show-ref.c
return 0;
if ((flag & REF_ISPACKED) && !peel_ref(refname, peeled)) {
- hex = find_unique_abbrev(peeled, abbrev);
- printf("%s %s^{}\n", hex, refname);
+ if (!is_null_sha1(peeled)) {
+ hex = find_unique_abbrev(peeled, abbrev);
+ printf("%s %s^{}\n", hex, refname);
+ }
}
else {
obj = parse_object(sha1);
index 75cbc0e7ef32c384daafb4e8b8c27f8d1fd40538..96ea8b6907b1e4be9c7b8575ff7e4a36f5a7a5f8 100644 (file)
--- a/refs.c
+++ b/refs.c
#include <errno.h>
+/* ISSYMREF=01 and ISPACKED=02 are public interfaces */
+#define REF_KNOWS_PEELED 04
+
struct ref_list {
struct ref_list *next;
- unsigned char flag; /* ISSYMREF? ISPACKED? ISPEELED? */
+ unsigned char flag; /* ISSYMREF? ISPACKED? */
unsigned char sha1[20];
+ unsigned char peeled[20];
char name[FLEX_ARRAY];
};
-static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag)
+static const char *parse_ref_line(char *line, unsigned char *sha1)
{
/*
* 42: the answer to everything.
* +1 (newline at the end of the line)
*/
int len = strlen(line) - 42;
- int peeled = 0;
if (len <= 0)
return NULL;
if (!isspace(line[40]))
return NULL;
line += 41;
-
- if (isspace(*line)) {
- /* "SHA-1 SP SP refs/tags/tagname^{} LF"? */
- line++;
- len--;
- peeled = 1;
- }
+ if (isspace(*line))
+ return NULL;
if (line[len] != '\n')
return NULL;
line[len] = 0;
- if (peeled && (len < 3 || strcmp(line + len - 3, "^{}")))
- return NULL;
-
- if (!peeled)
- *flag &= ~REF_ISPEELED;
- else
- *flag |= REF_ISPEELED;
return line;
}
static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
- int flag, struct ref_list *list)
+ int flag, struct ref_list *list,
+ struct ref_list **new_entry)
{
int len;
struct ref_list **p = &list, *entry;
break;
/* Same as existing entry? */
- if (!cmp)
+ if (!cmp) {
+ if (new_entry)
+ *new_entry = entry;
return list;
+ }
p = &entry->next;
}
len = strlen(name) + 1;
entry = xmalloc(sizeof(struct ref_list) + len);
hashcpy(entry->sha1, sha1);
+ hashclr(entry->peeled);
memcpy(entry->name, name, len);
entry->flag = flag;
entry->next = *p;
*p = entry;
+ if (new_entry)
+ *new_entry = entry;
return list;
}
ca->did_loose = ca->did_packed = 0;
}
+static void read_packed_refs(FILE *f, struct cached_refs *cached_refs)
+{
+ struct ref_list *list = NULL;
+ struct ref_list *last = NULL;
+ char refline[PATH_MAX];
+ int flag = REF_ISPACKED;
+
+ while (fgets(refline, sizeof(refline), f)) {
+ unsigned char sha1[20];
+ const char *name;
+ static const char header[] = "# pack-refs with:";
+
+ if (!strncmp(refline, header, sizeof(header)-1)) {
+ const char *traits = refline + sizeof(header) - 1;
+ if (strstr(traits, " peeled "))
+ flag |= REF_KNOWS_PEELED;
+ /* perhaps other traits later as well */
+ continue;
+ }
+
+ name = parse_ref_line(refline, sha1);
+ if (name) {
+ list = add_ref(name, sha1, flag, list, &last);
+ continue;
+ }
+ if (last &&
+ refline[0] == '^' &&
+ strlen(refline) == 42 &&
+ refline[41] == '\n' &&
+ !get_sha1_hex(refline + 1, sha1))
+ hashcpy(last->peeled, sha1);
+ }
+ cached_refs->packed = list;
+}
+
static struct ref_list *get_packed_refs(void)
{
if (!cached_refs.did_packed) {
- struct ref_list *refs = NULL;
FILE *f = fopen(git_path("packed-refs"), "r");
+ cached_refs.packed = NULL;
if (f) {
- struct ref_list *list = NULL;
- char refline[PATH_MAX];
- while (fgets(refline, sizeof(refline), f)) {
- unsigned char sha1[20];
- int flag = REF_ISPACKED;
- const char *name =
- parse_ref_line(refline, sha1, &flag);
- if (!name)
- continue;
- list = add_ref(name, sha1, flag, list);
- }
+ read_packed_refs(f, &cached_refs);
fclose(f);
- refs = list;
}
- cached_refs.packed = refs;
cached_refs.did_packed = 1;
}
return cached_refs.packed;
error("%s points nowhere!", ref);
continue;
}
- list = add_ref(ref, sha1, flag, list);
+ list = add_ref(ref, sha1, flag, list, NULL);
}
free(ref);
closedir(dir);
@@ -225,8 +246,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
if (lstat(path, &st) < 0) {
struct ref_list *list = get_packed_refs();
while (list) {
- if (!(list->flag & REF_ISPEELED) &&
- !strcmp(ref, list->name)) {
+ if (!strcmp(ref, list->name)) {
hashcpy(sha1, list->sha1);
if (flag)
*flag |= REF_ISPACKED;
return 0;
if (is_null_sha1(entry->sha1))
return 0;
- if (entry->flag & REF_ISPEELED)
- return 0;
if (!has_sha1_file(entry->sha1)) {
error("%s does not point to a valid object!", entry->name);
return 0;
if ((flag & REF_ISPACKED)) {
struct ref_list *list = get_packed_refs();
- int len = strlen(ref);
while (list) {
- if ((list->flag & REF_ISPEELED) &&
- !strncmp(list->name, ref, len) &&
- strlen(list->name) == len + 3 &&
- !strcmp(list->name + len, "^{}")) {
- hashcpy(sha1, list->sha1);
- return 0;
+ if (!strcmp(list->name, ref)) {
+ if (list->flag & REF_KNOWS_PEELED) {
+ hashcpy(sha1, list->peeled);
+ return 0;
+ }
+ /* older pack-refs did not leave peeled ones */
+ break;
}
list = list->next;
}
- /* older pack-refs did not leave peeled ones in */
}
- /* otherwise ... */
+ /* fallback - callers should not call this for unpacked refs */
o = parse_object(base);
if (o->type == OBJ_TAG) {
o = deref_tag(o, ref, 0);
index 40048a6919846acdf5ded8b6eb76bfb5d419ad0e..cd1e1d620e6513cd1542d15763ccd5c07f108e48 100644 (file)
--- a/refs.h
+++ b/refs.h
int force_write;
};
+#define REF_ISSYMREF 01
+#define REF_ISPACKED 02
+
/*
* Calls the specified function for each ref file until it returns nonzero,
* and returns the value
*/
-#define REF_ISSYMREF 01
-#define REF_ISPACKED 02
-#define REF_ISPEELED 04 /* internal use */
-
typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data);
extern int head_ref(each_ref_fn, void *);
extern int for_each_ref(each_ref_fn, void *);