From cf0adba7885342e1bbcf0689fece9d13e39784b4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 19 Nov 2006 13:22:44 -0800 Subject: Store peeled refs in packed-refs file. This would speed up "show-ref -d" in a repository with mostly packed tags. Signed-off-by: Junio C Hamano --- refs.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 7 deletions(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index 0e156c5dee..75cbc0e7ef 100644 --- a/refs.c +++ b/refs.c @@ -1,16 +1,18 @@ #include "refs.h" #include "cache.h" +#include "object.h" +#include "tag.h" #include struct ref_list { struct ref_list *next; - unsigned char flag; /* ISSYMREF? ISPACKED? */ + unsigned char flag; /* ISSYMREF? ISPACKED? ISPEELED? */ unsigned char sha1[20]; char name[FLEX_ARRAY]; }; -static const char *parse_ref_line(char *line, unsigned char *sha1) +static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag) { /* * 42: the answer to everything. @@ -21,6 +23,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1) * +1 (newline at the end of the line) */ int len = strlen(line) - 42; + int peeled = 0; if (len <= 0) return NULL; @@ -29,11 +32,24 @@ static const char *parse_ref_line(char *line, unsigned char *sha1) if (!isspace(line[40])) return NULL; line += 41; - if (isspace(*line)) - return NULL; + + if (isspace(*line)) { + /* "SHA-1 SP SP refs/tags/tagname^{} LF"? */ + line++; + len--; + peeled = 1; + } 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; } @@ -108,10 +124,12 @@ static struct ref_list *get_packed_refs(void) char refline[PATH_MAX]; while (fgets(refline, sizeof(refline), f)) { unsigned char sha1[20]; - const char *name = parse_ref_line(refline, sha1); + int flag = REF_ISPACKED; + const char *name = + parse_ref_line(refline, sha1, &flag); if (!name) continue; - list = add_ref(name, sha1, REF_ISPACKED, list); + list = add_ref(name, sha1, flag, list); } fclose(f); refs = list; @@ -207,7 +225,8 @@ 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 (!strcmp(ref, list->name)) { + if (!(list->flag & REF_ISPEELED) && + !strcmp(ref, list->name)) { hashcpy(sha1, list->sha1); if (flag) *flag |= REF_ISPACKED; @@ -329,6 +348,8 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim, 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; @@ -336,6 +357,44 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim, return fn(entry->name + trim, entry->sha1, entry->flag, cb_data); } +int peel_ref(const char *ref, unsigned char *sha1) +{ + int flag; + unsigned char base[20]; + struct object *o; + + if (!resolve_ref(ref, base, 1, &flag)) + return -1; + + 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; + } + list = list->next; + } + /* older pack-refs did not leave peeled ones in */ + } + + /* otherwise ... */ + o = parse_object(base); + if (o->type == OBJ_TAG) { + o = deref_tag(o, ref, 0); + if (o) { + hashcpy(sha1, o->sha1); + return 0; + } + } + return -1; +} + static int do_for_each_ref(const char *base, each_ref_fn fn, int trim, void *cb_data) { -- cgit v1.2.1 From f4204ab9f6a192cdb9a68150e031d7183688bfeb Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 21 Nov 2006 23:36:35 -0800 Subject: Store peeled refs in packed-refs (take 2). 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 "^". 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 --- refs.c | 111 +++++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 64 insertions(+), 47 deletions(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index 75cbc0e7ef..96ea8b6907 100644 --- a/refs.c +++ b/refs.c @@ -5,14 +5,18 @@ #include +/* 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. @@ -23,7 +27,6 @@ static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag) * +1 (newline at the end of the line) */ int len = strlen(line) - 42; - int peeled = 0; if (len <= 0) return NULL; @@ -32,29 +35,18 @@ static const char *parse_ref_line(char *line, unsigned char *sha1, int *flag) 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; @@ -66,8 +58,11 @@ static struct ref_list *add_ref(const char *name, const unsigned char *sha1, break; /* Same as existing entry? */ - if (!cmp) + if (!cmp) { + if (new_entry) + *new_entry = entry; return list; + } p = &entry->next; } @@ -75,10 +70,13 @@ static struct ref_list *add_ref(const char *name, const unsigned char *sha1, 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; } @@ -114,27 +112,50 @@ static void invalidate_cached_refs(void) 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; @@ -177,7 +198,7 @@ static struct ref_list *get_ref_dir(const char *base, struct ref_list *list) 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; @@ -348,8 +368,6 @@ static int do_one_ref(const char *base, each_ref_fn fn, int trim, 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; @@ -368,22 +386,21 @@ int peel_ref(const char *ref, unsigned char *sha1) 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); -- cgit v1.2.1 From c976d415e5352886f0650f8e2edba81866c38587 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Tue, 28 Nov 2006 15:47:40 +0100 Subject: git-branch: add options and tests for branch renaming Extend git-branch with the following options: git-branch -m|-M [] newbranch The -M variation is required to force renaming over an exsisting branchname. This also indroduces $GIT_DIR/RENAME_REF which is a "metabranch" used when renaming branches. It will always hold the original sha1 for the latest renamed branch. Additionally, if $GIT_DIR/logs/RENAME_REF exists, all branch rename events are logged there. Finally, some testcases are added to verify the new options. Signed-off-by: Lars Hjemli Signed-off-by: Junio C Hamano --- refs.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 146 insertions(+), 23 deletions(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index 96ea8b6907..cdedb45f00 100644 --- a/refs.c +++ b/refs.c @@ -610,6 +610,29 @@ static int remove_empty_directories(char *file) return remove_empty_dir_recursive(path, len); } +static int is_refname_available(const char *ref, const char *oldref, + struct ref_list *list, int quiet) +{ + int namlen = strlen(ref); /* e.g. 'foo/bar' */ + while (list) { + /* list->name could be 'foo' or 'foo/bar/baz' */ + if (!oldref || strcmp(oldref, list->name)) { + int len = strlen(list->name); + int cmplen = (namlen < len) ? namlen : len; + const char *lead = (namlen < len) ? list->name : ref; + if (!strncmp(ref, list->name, cmplen) && + lead[cmplen] == '/') { + if (!quiet) + error("'%s' exists; cannot create '%s'", + list->name, ref); + return 0; + } + } + list = list->next; + } + return 1; +} + static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char *old_sha1, int *flag) { char *ref_file; @@ -643,29 +666,14 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char orig_ref, strerror(errno)); goto error_return; } - if (is_null_sha1(lock->old_sha1)) { - /* The ref did not exist and we are creating it. - * Make sure there is no existing ref that is packed - * whose name begins with our refname, nor a ref whose - * name is a proper prefix of our refname. - */ - int namlen = strlen(ref); /* e.g. 'foo/bar' */ - struct ref_list *list = get_packed_refs(); - while (list) { - /* list->name could be 'foo' or 'foo/bar/baz' */ - int len = strlen(list->name); - int cmplen = (namlen < len) ? namlen : len; - const char *lead = (namlen < len) ? list->name : ref; - - if (!strncmp(ref, list->name, cmplen) && - lead[cmplen] == '/') { - error("'%s' exists; cannot create '%s'", - list->name, ref); - goto error_return; - } - list = list->next; - } - } + /* When the ref did not exist and we are creating it, + * make sure there is no existing ref that is packed + * whose name begins with our refname, nor a ref whose + * name is a proper prefix of our refname. + */ + if (is_null_sha1(lock->old_sha1) && + !is_refname_available(ref, NULL, get_packed_refs(), 0)) + goto error_return; lock->lk = xcalloc(1, sizeof(struct lock_file)); @@ -776,6 +784,121 @@ int delete_ref(const char *refname, unsigned char *sha1) return ret; } +int rename_ref(const char *oldref, const char *newref) +{ + static const char renamed_ref[] = "RENAMED-REF"; + unsigned char sha1[20], orig_sha1[20]; + int flag = 0, logmoved = 0; + struct ref_lock *lock; + char msg[PATH_MAX*2 + 100]; + struct stat loginfo; + int log = !stat(git_path("logs/%s", oldref), &loginfo); + + if (S_ISLNK(loginfo.st_mode)) + return error("reflog for %s is a symlink", oldref); + + if (!resolve_ref(oldref, orig_sha1, 1, &flag)) + return error("refname %s not found", oldref); + + if (!is_refname_available(newref, oldref, get_packed_refs(), 0)) + return 1; + + if (!is_refname_available(newref, oldref, get_loose_refs(), 0)) + return 1; + + if (snprintf(msg, sizeof(msg), "renamed %s to %s", oldref, newref) > sizeof(msg)) + return error("Refnames to long"); + + lock = lock_ref_sha1_basic(renamed_ref, NULL, NULL); + if (!lock) + return error("unable to lock %s", renamed_ref); + lock->force_write = 1; + if (write_ref_sha1(lock, orig_sha1, msg)) + return error("unable to save current sha1 in %s", renamed_ref); + + if (log && rename(git_path("logs/%s", oldref), git_path("tmp-renamed-log"))) + return error("unable to move logfile logs/%s to tmp-renamed-log: %s", + oldref, strerror(errno)); + + if (delete_ref(oldref, orig_sha1)) { + error("unable to delete old %s", oldref); + goto rollback; + } + + if (resolve_ref(newref, sha1, 1, &flag) && delete_ref(newref, sha1)) { + if (errno==EISDIR) { + if (remove_empty_directories(git_path("%s", newref))) { + error("Directory not empty: %s", newref); + goto rollback; + } + } else { + error("unable to delete existing %s", newref); + goto rollback; + } + } + + if (log && safe_create_leading_directories(git_path("logs/%s", newref))) { + error("unable to create directory for %s", newref); + goto rollback; + } + + retry: + if (log && rename(git_path("tmp-renamed-log"), git_path("logs/%s", newref))) { + if (errno==EISDIR) { + if (remove_empty_directories(git_path("logs/%s", newref))) { + error("Directory not empty: logs/%s", newref); + goto rollback; + } + goto retry; + } else { + error("unable to move logfile tmp-renamed-log to logs/%s: %s", + newref, strerror(errno)); + goto rollback; + } + } + logmoved = log; + + lock = lock_ref_sha1_basic(newref, NULL, NULL); + if (!lock) { + error("unable to lock %s for update", newref); + goto rollback; + } + + lock->force_write = 1; + hashcpy(lock->old_sha1, orig_sha1); + if (write_ref_sha1(lock, orig_sha1, msg)) { + error("unable to write current sha1 into %s", newref); + goto rollback; + } + + return 0; + + rollback: + lock = lock_ref_sha1_basic(oldref, NULL, NULL); + if (!lock) { + error("unable to lock %s for rollback", oldref); + goto rollbacklog; + } + + lock->force_write = 1; + flag = log_all_ref_updates; + log_all_ref_updates = 0; + if (write_ref_sha1(lock, orig_sha1, NULL)) + error("unable to write current sha1 into %s", oldref); + log_all_ref_updates = flag; + + rollbacklog: + if (logmoved && rename(git_path("logs/%s", newref), git_path("logs/%s", oldref))) + error("unable to restore logfile %s from %s: %s", + oldref, newref, strerror(errno)); + if (!logmoved && log && + rename(git_path("tmp-renamed-log"), git_path("logs/%s", oldref))) + error("unable to restore logfile %s from tmp-renamed-log: %s", + oldref, strerror(errno)); + + return 1; +} + void unlock_ref(struct ref_lock *lock) { if (lock->lock_fd >= 0) { -- cgit v1.2.1 From 16c2bfbb449a90db00a46984d7dd7f735caa1d56 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Wed, 29 Nov 2006 21:44:56 +0100 Subject: rename_ref: use lstat(2) when testing for symlink The current check for symlinked reflogs was based on stat(2), which is utterly embarrassing. Fix it, and add a matching testcase. Signed-off-by: Lars Hjemli Signed-off-by: Junio C Hamano --- refs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index cdedb45f00..c23561e158 100644 --- a/refs.c +++ b/refs.c @@ -792,7 +792,7 @@ int rename_ref(const char *oldref, const char *newref) struct ref_lock *lock; char msg[PATH_MAX*2 + 100]; struct stat loginfo; - int log = !stat(git_path("logs/%s", oldref), &loginfo); + int log = !lstat(git_path("logs/%s", oldref), &loginfo); if (S_ISLNK(loginfo.st_mode)) return error("reflog for %s is a symlink", oldref); -- cgit v1.2.1 From 678d0f4cbfa7a3b529c6e894f2977bef6a2d3e4c Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Thu, 30 Nov 2006 03:16:56 +0100 Subject: git-branch: let caller specify logmsg This changes the signature of rename_ref() in refs.[hc] to include a logmessage for the reflogs. Also, builtin-branch.c is modified to provide a proper logmessage + call setup_ident() before any logmessages are written. Signed-off-by: Lars Hjemli Signed-off-by: Junio C Hamano --- refs.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index c23561e158..2ac8273ea4 100644 --- a/refs.c +++ b/refs.c @@ -784,13 +784,12 @@ int delete_ref(const char *refname, unsigned char *sha1) return ret; } -int rename_ref(const char *oldref, const char *newref) +int rename_ref(const char *oldref, const char *newref, const char *logmsg) { static const char renamed_ref[] = "RENAMED-REF"; unsigned char sha1[20], orig_sha1[20]; int flag = 0, logmoved = 0; struct ref_lock *lock; - char msg[PATH_MAX*2 + 100]; struct stat loginfo; int log = !lstat(git_path("logs/%s", oldref), &loginfo); @@ -806,14 +805,11 @@ int rename_ref(const char *oldref, const char *newref) if (!is_refname_available(newref, oldref, get_loose_refs(), 0)) return 1; - if (snprintf(msg, sizeof(msg), "renamed %s to %s", oldref, newref) > sizeof(msg)) - return error("Refnames to long"); - lock = lock_ref_sha1_basic(renamed_ref, NULL, NULL); if (!lock) return error("unable to lock %s", renamed_ref); lock->force_write = 1; - if (write_ref_sha1(lock, orig_sha1, msg)) + if (write_ref_sha1(lock, orig_sha1, logmsg)) return error("unable to save current sha1 in %s", renamed_ref); if (log && rename(git_path("logs/%s", oldref), git_path("tmp-renamed-log"))) @@ -866,7 +862,7 @@ int rename_ref(const char *oldref, const char *newref) lock->force_write = 1; hashcpy(lock->old_sha1, orig_sha1); - if (write_ref_sha1(lock, orig_sha1, msg)) { + if (write_ref_sha1(lock, orig_sha1, logmsg)) { error("unable to write current sha1 into %s", newref); goto rollback; } -- cgit v1.2.1 From 37adac765a469f8f8495e2befe7afeda65a2b272 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 13 Dec 2006 10:30:11 -0800 Subject: send-pack: tighten checks for remote names "git push $URL HEAD~6" created a bogus ref HEAD~6 immediately under $GIT_DIR of the remote repository. While we should keep refspecs that have arbitrary extended SHA-1 expression on the source side working (e.g. "HEAD~6:refs/tags/yesterday"), we should not create bogus ref on the other end. Signed-off-by: Junio C Hamano --- refs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index 96ea8b6907..e56abb8585 100644 --- a/refs.c +++ b/refs.c @@ -534,7 +534,7 @@ int check_ref_format(const char *ref) level++; if (!ch) { if (level < 2) - return -1; /* at least of form "heads/blah" */ + return -2; /* at least of form "heads/blah" */ return 0; } } -- cgit v1.2.1 From dc81c58cd6b791a3db23f1d1acb5f7d38d1ff086 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 16 Dec 2006 15:15:02 +0100 Subject: git-branch: rename config vars branch..*, too When renaming a branch, the corresponding config section should be renamed, too. Signed-off-by: Johannes Schindelin Signed-off-by: Junio C Hamano --- refs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'refs.c') diff --git a/refs.c b/refs.c index a02957c399..d911b9e860 100644 --- a/refs.c +++ b/refs.c @@ -867,6 +867,16 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg) goto rollback; } + if (!strncmp(oldref, "refs/heads/", 11) && + !strncmp(newref, "refs/heads/", 11)) { + char oldsection[1024], newsection[1024]; + + snprintf(oldsection, 1024, "branch.%s", oldref + 11); + snprintf(newsection, 1024, "branch.%s", newref + 11); + if (git_config_rename_section(oldsection, newsection) < 0) + return 1; + } + return 0; rollback: -- cgit v1.2.1 From 85023577a8f4b540aa64aa37f6f44578c0c305a3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 19 Dec 2006 14:34:12 -0800 Subject: simplify inclusion of system header files. This is a mechanical clean-up of the way *.c files include system header files. (1) sources under compat/, platform sha-1 implementations, and xdelta code are exempt from the following rules; (2) the first #include must be "git-compat-util.h" or one of our own header file that includes it first (e.g. config.h, builtin.h, pkt-line.h); (3) system headers that are included in "git-compat-util.h" need not be included in individual C source files. (4) "git-compat-util.h" does not have to include subsystem specific header files (e.g. expat.h). Signed-off-by: Junio C Hamano --- refs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index d911b9e860..a101ff3bf8 100644 --- a/refs.c +++ b/refs.c @@ -1,10 +1,8 @@ -#include "refs.h" #include "cache.h" +#include "refs.h" #include "object.h" #include "tag.h" -#include - /* ISSYMREF=01 and ISPACKED=02 are public interfaces */ #define REF_KNOWS_PEELED 04 -- cgit v1.2.1 From 2ff81662c2fb2679f841c09a28bd80c0a63011ac Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 18 Dec 2006 01:18:16 -0800 Subject: add for_each_reflog_ent() iterator Signed-off-by: Junio C Hamano --- refs.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'refs.c') diff --git a/refs.c b/refs.c index a101ff3bf8..b67b1f011f 100644 --- a/refs.c +++ b/refs.c @@ -1091,3 +1091,28 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char * logfile, show_rfc2822_date(date, tz)); return 0; } + +void for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data) +{ + const char *logfile; + FILE *logfp; + char buf[1024]; + + logfile = git_path("logs/%s", ref); + logfp = fopen(logfile, "r"); + if (!logfp) + return; + while (fgets(buf, sizeof(buf), logfp)) { + unsigned char osha1[20], nsha1[20]; + int len; + + /* old SP new SP name SP time TAB msg LF */ + len = strlen(buf); + if (len < 83 || buf[len-1] != '\n' || + get_sha1_hex(buf, osha1) || buf[40] != ' ' || + get_sha1_hex(buf + 41, nsha1) || buf[81] != ' ') + continue; /* corrupt? */ + fn(osha1, nsha1, buf+82, cb_data); + } + fclose(logfp); +} -- cgit v1.2.1 From e29cb53a8b6aa1256221207b14a1c8ef72f69d9f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 18 Dec 2006 22:07:45 -0800 Subject: reflog: fix warning message. When ref@{N} is specified on a ref that has only M entries (M < N), instead of saying the initial timestamp the reflog has, warn that there is only M entries. Signed-off-by: Junio C Hamano --- refs.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'refs.c') diff --git a/refs.c b/refs.c index b67b1f011f..8b2a3c1378 100644 --- a/refs.c +++ b/refs.c @@ -1013,7 +1013,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char * { const char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec; char *tz_c; - int logfd, tz; + int logfd, tz, reccnt = 0; struct stat st; unsigned long date; unsigned char logged_sha1[20]; @@ -1031,6 +1031,7 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char * lastrec = NULL; rec = logend = logdata + st.st_size; while (logdata < rec) { + reccnt++; if (logdata < rec && *(rec-1) == '\n') rec--; lastgt = NULL; @@ -1087,8 +1088,12 @@ int read_ref_at(const char *ref, unsigned long at_time, int cnt, unsigned char * if (get_sha1_hex(logdata, sha1)) die("Log %s is corrupt.", logfile); munmap((void*)logdata, st.st_size); - fprintf(stderr, "warning: Log %s only goes back to %s.\n", - logfile, show_rfc2822_date(date, tz)); + if (at_time) + fprintf(stderr, "warning: Log %s only goes back to %s.\n", + logfile, show_rfc2822_date(date, tz)); + else + fprintf(stderr, "warning: Log %s only has %d entries.\n", + logfile, reccnt); return 0; } @@ -1116,3 +1121,4 @@ void for_each_reflog_ent(const char *ref, each_reflog_ent_fn fn, void *cb_data) } fclose(logfp); } + -- cgit v1.2.1