* Re: Make ref resolution saner @ 2006-09-12 18:57 linux 0 siblings, 0 replies; 4+ messages in thread From: linux @ 2006-09-12 18:57 UTC (permalink / raw) To: git, torvalds; +Cc: linux I just noticed as part of that patch that building the path of $GIT_DIR/HEAD is no longer necessary, which is the middle hunk, and the other two jumped out at me while looking at the code. (On top of Linus' patch.) diff --git a/builtin-init-db.c b/builtin-init-db.c index 23b7714..f4a6d1f 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -203,7 +203,6 @@ static void create_default_files(const c * shared-repository settings, we would need to fix them up. */ if (shared_repository) { - path[len] = 0; adjust_shared_perm(path); strcpy(path + len, "refs"); adjust_shared_perm(path); @@ -217,7 +216,6 @@ static void create_default_files(const c * Create the default symlink from ".git/HEAD" to the "master" * branch, if it does not exist yet. */ - strcpy(path + len, "HEAD"); if (read_ref("HEAD", sha1) < 0) { if (create_symref("HEAD", "refs/heads/master") < 0) exit(1); @@ -227,7 +225,6 @@ static void create_default_files(const c sprintf(repo_version_string, "%d", GIT_REPO_VERSION); git_config_set("core.repositoryformatversion", repo_version_string); - path[len] = 0; strcpy(path + len, "config"); /* Check filemode trustability */ ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Allow multiple "git_path()" uses @ 2006-09-11 19:03 Linus Torvalds 2006-09-11 23:37 ` Start handling references internally as a sorted in-memory list Linus Torvalds 0 siblings, 1 reply; 4+ messages in thread From: Linus Torvalds @ 2006-09-11 19:03 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git Mailing List This allows you to maintain a few filesystem pathnames concurrently, by simply replacing the single static "pathname" buffer with a LRU of four buffers. We did exactly the same thing with sha1_to_hex(), for pretty much exactly the same reason. Sometimes you want to use two pathnames, and while it's easy enough to xstrdup() them, why not just do the LU buffer thing. Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- [ This actually came up when I was playing with git_path("refs-packed") when following refs, so while it doesn't hit us right now, it's for some future work.. ] diff --git a/path.c b/path.c index db8905f..bb89fb0 100644 --- a/path.c +++ b/path.c @@ -13,9 +13,15 @@ #include "cache.h" #include <pwd.h> -static char pathname[PATH_MAX]; static char bad_path[] = "/bad-path/"; +static char *get_pathname(void) +{ + static char pathname_array[4][PATH_MAX]; + static int index; + return pathname_array[3 & ++index]; +} + static char *cleanup_path(char *path) { /* Clean it up */ @@ -31,6 +37,7 @@ char *mkpath(const char *fmt, ...) { va_list args; unsigned len; + char *pathname = get_pathname(); va_start(args, fmt); len = vsnprintf(pathname, PATH_MAX, fmt, args); @@ -43,6 +50,7 @@ char *mkpath(const char *fmt, ...) char *git_path(const char *fmt, ...) { const char *git_dir = get_git_dir(); + char *pathname = get_pathname(); va_list args; unsigned len; ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Start handling references internally as a sorted in-memory list 2006-09-11 19:03 Allow multiple "git_path()" uses Linus Torvalds @ 2006-09-11 23:37 ` Linus Torvalds 2006-09-12 3:10 ` Add support for negative refs Linus Torvalds 0 siblings, 1 reply; 4+ messages in thread From: Linus Torvalds @ 2006-09-11 23:37 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git Mailing List This also adds some very rudimentary support for the notion of packed refs. HOWEVER! At this point it isn't used to actually look up a ref yet, only for listing them (ie "for_each_ref()" and friends see the packed refs, but none of the other single-ref lookup routines). Note how we keep two separate lists: one for the loose refs, and one for the packed refs we read. That's so that we can easily keep the two apart, and read only one set or the other (and still always make sure that the loose refs take precedence). [ From this, it's not actually obvious why we'd keep the two separate lists, but it's important to have the packed refs on their own list later on, when I add support for looking up a single loose one. For that case, we will want to read _just_ the packed refs in case the single-ref lookup fails, yet we may end up needing the other list at some point in the future, so keeping them separated is important ] Signed-off-by: Linus Torvalds <torvalds@osdl.org> ---- This passes all the tests, but largely because it doesn't yet actually use and test the ref-packing code. The code exists, but it doesn't remove old refs yet. It will be easy enough to do with this background code, though: I think this is all set up to be reasonably efficient. And yeah, I know that the "sorting" code is O(n**2) thanks to doing an insertion sort into a simple linked list. Tough. I didn't care enough to do it well. With "n" usually being a few hundred at most, we really don't care, and if we ever do, we _can_ fix it later on to use a heap or something. diff --git a/Makefile b/Makefile index 7b3114f..5a2e946 100644 --- a/Makefile +++ b/Makefile @@ -295,7 +295,8 @@ BUILTIN_OBJS = \ builtin-upload-tar.o \ builtin-verify-pack.o \ builtin-write-tree.o \ - builtin-zip-tree.o + builtin-zip-tree.o \ + builtin-pack-refs.o GITLIBS = $(LIB_FILE) $(XDIFF_LIB) LIBS = $(GITLIBS) -lz diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c new file mode 100644 index 0000000..0f5d827 --- /dev/null +++ b/builtin-pack-refs.c @@ -0,0 +1,41 @@ +#include "cache.h" +#include "refs.h" + +static FILE *refs_file; +static const char *result_path, *lock_path; + +static void remove_lock_file(void) +{ + if (lock_path) + unlink(lock_path); +} + +static int handle_one_ref(const char *path, const unsigned char *sha1) +{ + fprintf(refs_file, "%s %s\n", sha1_to_hex(sha1), path); + return 0; +} + +int cmd_pack_refs(int argc, const char **argv, const char *prefix) +{ + int fd; + + result_path = xstrdup(git_path("packed-refs")); + lock_path = xstrdup(mkpath("%s.lock", result_path)); + + fd = open(lock_path, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd < 0) + die("unable to create new ref-pack file (%s)", strerror(errno)); + atexit(remove_lock_file); + + refs_file = fdopen(fd, "w"); + if (!refs_file) + die("unable to create ref-pack file structure (%s)", strerror(errno)); + for_each_ref(handle_one_ref); + fsync(fd); + fclose(refs_file); + if (rename(lock_path, result_path) < 0) + die("unable to overwrite old ref-pack file (%s)", strerror(errno)); + lock_path = NULL; + return 0; +} diff --git a/builtin.h b/builtin.h index 25431d7..34ed7b9 100644 --- a/builtin.h +++ b/builtin.h @@ -61,5 +61,6 @@ extern int cmd_version(int argc, const c extern int cmd_whatchanged(int argc, const char **argv, const char *prefix); extern int cmd_write_tree(int argc, const char **argv, const char *prefix); extern int cmd_verify_pack(int argc, const char **argv, const char *prefix); +extern int cmd_pack_refs(int argc, const char **argv, const char *prefix); #endif diff --git a/git.c b/git.c index 335f405..63d1ba3 100644 --- a/git.c +++ b/git.c @@ -266,6 +266,7 @@ static void handle_internal_command(int { "whatchanged", cmd_whatchanged, RUN_SETUP | USE_PAGER }, { "write-tree", cmd_write_tree, RUN_SETUP }, { "verify-pack", cmd_verify_pack }, + { "pack-refs", cmd_pack_refs, RUN_SETUP }, }; int i; diff --git a/refs.c b/refs.c index 5e65314..5f80a68 100644 --- a/refs.c +++ b/refs.c @@ -3,6 +3,145 @@ #include "cache.h" #include <errno.h> +struct ref_list { + struct ref_list *next; + unsigned char sha1[20]; + char name[FLEX_ARRAY]; +}; + +static const char *parse_ref_line(char *line, unsigned char *sha1) +{ + /* + * 42: the answer to everything. + * + * In this case, it happens to be the answer to + * 40 (length of sha1 hex representation) + * +1 (space in between hex and name) + * +1 (newline at the end of the line) + */ + int len = strlen(line) - 42; + + if (len <= 0) + return NULL; + if (get_sha1_hex(line, sha1) < 0) + return NULL; + if (!isspace(line[40])) + return NULL; + line += 41; + if (line[len] != '\n') + return NULL; + line[len] = 0; + return line; +} + +static struct ref_list *add_ref(const char *name, const unsigned char *sha1, struct ref_list *list) +{ + int len; + struct ref_list **p = &list, *entry; + + /* Find the place to insert the ref into.. */ + while ((entry = *p) != NULL) { + int cmp = strcmp(entry->name, name); + if (cmp > 0) + break; + + /* Same as existing entry? */ + if (!cmp) + return list; + p = &entry->next; + } + + /* Allocate it and add it in.. */ + len = strlen(name) + 1; + entry = xmalloc(sizeof(struct ref_list) + len); + hashcpy(entry->sha1, sha1); + memcpy(entry->name, name, len); + entry->next = *p; + *p = entry; + return list; +} + +static struct ref_list *get_packed_refs(void) +{ + static int did_refs = 0; + static struct ref_list *refs = NULL; + + if (!did_refs) { + FILE *f = fopen(git_path("packed-refs"), "r"); + if (f) { + struct ref_list *list = NULL; + char refline[PATH_MAX]; + while (fgets(refline, sizeof(refline), f)) { + unsigned char sha1[20]; + const char *name = parse_ref_line(refline, sha1); + if (!name) + continue; + list = add_ref(name, sha1, list); + } + fclose(f); + refs = list; + } + did_refs = 1; + } + return refs; +} + +static struct ref_list *get_ref_dir(const char *base, struct ref_list *list) +{ + DIR *dir = opendir(git_path("%s", base)); + + if (dir) { + struct dirent *de; + int baselen = strlen(base); + char *path = xmalloc(baselen + 257); + + memcpy(path, base, baselen); + if (baselen && base[baselen-1] != '/') + path[baselen++] = '/'; + + while ((de = readdir(dir)) != NULL) { + unsigned char sha1[20]; + struct stat st; + int namelen; + + if (de->d_name[0] == '.') + continue; + namelen = strlen(de->d_name); + if (namelen > 255) + continue; + if (has_extension(de->d_name, ".lock")) + continue; + memcpy(path + baselen, de->d_name, namelen+1); + if (stat(git_path("%s", path), &st) < 0) + continue; + if (S_ISDIR(st.st_mode)) { + list = get_ref_dir(path, list); + continue; + } + if (read_ref(git_path("%s", path), sha1) < 0) { + error("%s points nowhere!", path); + continue; + } + list = add_ref(path, sha1, list); + } + free(path); + closedir(dir); + } + return list; +} + +static struct ref_list *get_loose_refs(void) +{ + static int did_refs = 0; + static struct ref_list *refs = NULL; + + if (!did_refs) { + refs = get_ref_dir("refs", NULL); + did_refs = 1; + } + return refs; +} + /* We allow "recursive" symbolic refs. Only within reason, though */ #define MAXDEPTH 5 @@ -121,60 +260,41 @@ int read_ref(const char *filename, unsig static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1), int trim) { - int retval = 0; - DIR *dir = opendir(git_path("%s", base)); - - if (dir) { - struct dirent *de; - int baselen = strlen(base); - char *path = xmalloc(baselen + 257); - - if (!strncmp(base, "./", 2)) { - base += 2; - baselen -= 2; + int retval; + struct ref_list *packed = get_packed_refs(); + struct ref_list *loose = get_loose_refs(); + + while (packed && loose) { + struct ref_list *entry; + int cmp = strcmp(packed->name, loose->name); + if (!cmp) { + packed = packed->next; + continue; } - memcpy(path, base, baselen); - if (baselen && base[baselen-1] != '/') - path[baselen++] = '/'; - - while ((de = readdir(dir)) != NULL) { - unsigned char sha1[20]; - struct stat st; - int namelen; + if (cmp > 0) { + entry = loose; + loose = loose->next; + } else { + entry = packed; + packed = packed->next; + } + if (strncmp(base, entry->name, trim)) + continue; + retval = fn(entry->name + trim, entry->sha1); + if (retval) + return retval; + } - if (de->d_name[0] == '.') - continue; - namelen = strlen(de->d_name); - if (namelen > 255) - continue; - if (has_extension(de->d_name, ".lock")) - continue; - memcpy(path + baselen, de->d_name, namelen+1); - if (stat(git_path("%s", path), &st) < 0) - continue; - if (S_ISDIR(st.st_mode)) { - retval = do_for_each_ref(path, fn, trim); - if (retval) - break; - continue; - } - if (read_ref(git_path("%s", path), sha1) < 0) { - error("%s points nowhere!", path); - continue; - } - if (!has_sha1_file(sha1)) { - error("%s does not point to a valid " - "commit object!", path); - continue; - } - retval = fn(path + trim, sha1); + packed = packed ? packed : loose; + while (packed) { + if (!strncmp(base, packed->name, trim)) { + retval = fn(packed->name + trim, packed->sha1); if (retval) - break; + return retval; } - free(path); - closedir(dir); + packed = packed->next; } - return retval; + return 0; } int head_ref(int (*fn)(const char *path, const unsigned char *sha1)) @@ -187,22 +307,22 @@ int head_ref(int (*fn)(const char *path, int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1)) { - return do_for_each_ref("refs", fn, 0); + return do_for_each_ref("refs/", fn, 0); } int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1)) { - return do_for_each_ref("refs/tags", fn, 10); + return do_for_each_ref("refs/tags/", fn, 10); } int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1)) { - return do_for_each_ref("refs/heads", fn, 11); + return do_for_each_ref("refs/heads/", fn, 11); } int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1)) { - return do_for_each_ref("refs/remotes", fn, 13); + return do_for_each_ref("refs/remotes/", fn, 13); } int get_ref_sha1(const char *ref, unsigned char *sha1) ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Add support for negative refs 2006-09-11 23:37 ` Start handling references internally as a sorted in-memory list Linus Torvalds @ 2006-09-12 3:10 ` Linus Torvalds 2006-09-12 3:17 ` Make ref resolution saner Linus Torvalds 0 siblings, 1 reply; 4+ messages in thread From: Linus Torvalds @ 2006-09-12 3:10 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git Mailing List You can remove a ref that is packed two different ways: either simply repack all the refs without that one, or create a loose ref that has the magic all-zero SHA1. This also adds back the test that a ref actually has the object it points to. Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- This one is trivial, and obviously depends on the previous series. I'm sending it just because I have a much bigger cleanup that I'd _really_ like to go in, and I did this trivial one before that much more interesting one. diff --git a/refs.c b/refs.c index 5f80a68..72e2283 100644 --- a/refs.c +++ b/refs.c @@ -280,6 +280,12 @@ static int do_for_each_ref(const char *b } if (strncmp(base, entry->name, trim)) continue; + if (is_null_sha1(entry->sha1)) + continue; + if (!has_sha1_file(entry->sha1)) { + error("%s does not point to a valid object!", entry->name); + continue; + } retval = fn(entry->name + trim, entry->sha1); if (retval) return retval; ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Make ref resolution saner 2006-09-12 3:10 ` Add support for negative refs Linus Torvalds @ 2006-09-12 3:17 ` Linus Torvalds 2006-09-12 5:36 ` Jeff King 0 siblings, 1 reply; 4+ messages in thread From: Linus Torvalds @ 2006-09-12 3:17 UTC (permalink / raw) To: Junio C Hamano; +Cc: Git Mailing List The old code used to totally mix up the notion of a ref-name and the path that that ref was associated with. That was not only horribly ugly (a number of users got the path, and then wanted to try to turn it back into a ref-name again), but it fundamnetally doesn't work at all once we do any setup where a ref doesn't have a 1:1 relationship with a particular pathname. This fixes things up so that we use the ref-name throughout, and only turn it into a pathname once we actually look it up in the filesystem. That makes a lot of things much clearer and more straightforward. Signed-off-by: Linus Torvalds <torvalds@osdl.org> --- This patch is a bit scary, but look at the first two hunks to builtin-fmt-merge-msg.c to get an idea of what kind of *crap* it gets rid of. There were several places where we used "resolve_ref()" to figure out what the branch it was on, but then to actually figure out what the branch-name of that branch was (rather than the cwd-relative _filename_ is), it then did strange things with the string length of the original ref compared with the string length of the _filename_ of the original ref etc etc. Making all the ref-related functions just use the ref-name itself throughout just gets rid of the crap, but more importantly, it's absolutely required for just about _any_ ref-packing scheme. That said, it _is_ a scary patch. It removes more lines that it adds: builtin-fmt-merge-msg.c | 7 +---- builtin-init-db.c | 4 +-- builtin-show-branch.c | 46 +++++++++++++------------------ builtin-symbolic-ref.c | 14 +++------- cache.h | 4 +-- refs.c | 69 +++++++++++++++++++++++++---------------------- sha1_name.c | 14 +++++----- 7 files changed, 74 insertions(+), 84 deletions(-) but if I missed some place where we used a ref as a pathname, or added one "git_path()" translation too many, it results in problems. The good news is that our test-suite for this seems to be reasonably complete. It sure caught a lot of places I had missed the first time around. So this should be ok. I'd _really_ like for this to go in, even regardless of the other patches I have sent (although I think it depends on them in mostly fairly trivial ways, since the previous patches changed how we do the recursive readdir() on the refs/ directory). It's really needed. diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c index c407c03..b93c17c 100644 --- a/builtin-fmt-merge-msg.c +++ b/builtin-fmt-merge-msg.c @@ -249,7 +249,7 @@ int cmd_fmt_merge_msg(int argc, const ch FILE *in = stdin; const char *sep = ""; unsigned char head_sha1[20]; - const char *head, *current_branch; + const char *current_branch; git_config(fmt_merge_msg_config); @@ -277,10 +277,7 @@ int cmd_fmt_merge_msg(int argc, const ch usage(fmt_merge_msg_usage); /* get current branch */ - head = xstrdup(git_path("HEAD")); - current_branch = resolve_ref(head, head_sha1, 1); - current_branch += strlen(head) - 4; - free((char *)head); + current_branch = resolve_ref("HEAD", head_sha1, 1); if (!strncmp(current_branch, "refs/heads/", 11)) current_branch += 11; diff --git a/builtin-init-db.c b/builtin-init-db.c index 5085018..23b7714 100644 --- a/builtin-init-db.c +++ b/builtin-init-db.c @@ -218,8 +218,8 @@ static void create_default_files(const c * branch, if it does not exist yet. */ strcpy(path + len, "HEAD"); - if (read_ref(path, sha1) < 0) { - if (create_symref(path, "refs/heads/master") < 0) + if (read_ref("HEAD", sha1) < 0) { + if (create_symref("HEAD", "refs/heads/master") < 0) exit(1); } diff --git a/builtin-show-branch.c b/builtin-show-branch.c index 578c9fa..4d8db0c 100644 --- a/builtin-show-branch.c +++ b/builtin-show-branch.c @@ -437,21 +437,13 @@ static void snarf_refs(int head, int tag } } -static int rev_is_head(char *head_path, int headlen, char *name, +static int rev_is_head(char *head, int headlen, char *name, unsigned char *head_sha1, unsigned char *sha1) { - int namelen; - if ((!head_path[0]) || + if ((!head[0]) || (head_sha1 && sha1 && hashcmp(head_sha1, sha1))) return 0; - namelen = strlen(name); - if ((headlen < namelen) || - memcmp(head_path + headlen - namelen, name, namelen)) - return 0; - if (headlen == namelen || - head_path[headlen - namelen - 1] == '/') - return 1; - return 0; + return !strcmp(head, name); } static int show_merge_base(struct commit_list *seen, int num_rev) @@ -559,9 +551,9 @@ int cmd_show_branch(int ac, const char * int all_heads = 0, all_tags = 0; int all_mask, all_revs; int lifo = 1; - char head_path[128]; - const char *head_path_p; - int head_path_len; + char head[128]; + const char *head_p; + int head_len; unsigned char head_sha1[20]; int merge_base = 0; int independent = 0; @@ -638,31 +630,31 @@ int cmd_show_branch(int ac, const char * ac--; av++; } - head_path_p = resolve_ref(git_path("HEAD"), head_sha1, 1); - if (head_path_p) { - head_path_len = strlen(head_path_p); - memcpy(head_path, head_path_p, head_path_len + 1); + head_p = resolve_ref("HEAD", head_sha1, 1); + if (head_p) { + head_len = strlen(head_p); + memcpy(head, head_p, head_len + 1); } else { - head_path_len = 0; - head_path[0] = 0; + head_len = 0; + head[0] = 0; } - if (with_current_branch && head_path_p) { + if (with_current_branch && head_p) { int has_head = 0; for (i = 0; !has_head && i < ref_name_cnt; i++) { /* We are only interested in adding the branch * HEAD points at. */ - if (rev_is_head(head_path, - head_path_len, + if (rev_is_head(head, + head_len, ref_name[i], head_sha1, NULL)) has_head++; } if (!has_head) { - int pfxlen = strlen(git_path("refs/heads/")); - append_one_rev(head_path + pfxlen); + int pfxlen = strlen("refs/heads/"); + append_one_rev(head + pfxlen); } } @@ -713,8 +705,8 @@ int cmd_show_branch(int ac, const char * if (1 < num_rev || extra < 0) { for (i = 0; i < num_rev; i++) { int j; - int is_head = rev_is_head(head_path, - head_path_len, + int is_head = rev_is_head(head, + head_len, ref_name[i], head_sha1, rev[i]->object.sha1); diff --git a/builtin-symbolic-ref.c b/builtin-symbolic-ref.c index 1d3a5e2..6f18db8 100644 --- a/builtin-symbolic-ref.c +++ b/builtin-symbolic-ref.c @@ -7,15 +7,11 @@ static const char git_symbolic_ref_usage static void check_symref(const char *HEAD) { unsigned char sha1[20]; - const char *git_HEAD = xstrdup(git_path("%s", HEAD)); - const char *git_refs_heads_master = resolve_ref(git_HEAD, sha1, 0); - if (git_refs_heads_master) { - /* we want to strip the .git/ part */ - int pfxlen = strlen(git_HEAD) - strlen(HEAD); - puts(git_refs_heads_master + pfxlen); - } - else + const char *refs_heads_master = resolve_ref("HEAD", sha1, 0); + + if (!refs_heads_master) die("No such ref: %s", HEAD); + puts(refs_heads_master); } int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) @@ -26,7 +22,7 @@ int cmd_symbolic_ref(int argc, const cha check_symref(argv[1]); break; case 3: - create_symref(xstrdup(git_path("%s", argv[1])), argv[2]); + create_symref(argv[1], argv[2]); break; default: usage(git_symbolic_ref_usage); diff --git a/cache.h b/cache.h index a53204f..5d6c7ee 100644 --- a/cache.h +++ b/cache.h @@ -287,8 +287,8 @@ extern int get_sha1_hex(const char *hex, extern char *sha1_to_hex(const unsigned char *sha1); /* static buffer result! */ extern int read_ref(const char *filename, unsigned char *sha1); extern const char *resolve_ref(const char *path, unsigned char *sha1, int); -extern int create_symref(const char *git_HEAD, const char *refs_heads_master); -extern int validate_symref(const char *git_HEAD); +extern int create_symref(const char *ref, const char *refs_heads_master); +extern int validate_symref(const char *ref); extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2); extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2); diff --git a/refs.c b/refs.c index 72e2283..50c25d3 100644 --- a/refs.c +++ b/refs.c @@ -93,11 +93,11 @@ static struct ref_list *get_ref_dir(cons if (dir) { struct dirent *de; int baselen = strlen(base); - char *path = xmalloc(baselen + 257); + char *ref = xmalloc(baselen + 257); - memcpy(path, base, baselen); + memcpy(ref, base, baselen); if (baselen && base[baselen-1] != '/') - path[baselen++] = '/'; + ref[baselen++] = '/'; while ((de = readdir(dir)) != NULL) { unsigned char sha1[20]; @@ -111,20 +111,20 @@ static struct ref_list *get_ref_dir(cons continue; if (has_extension(de->d_name, ".lock")) continue; - memcpy(path + baselen, de->d_name, namelen+1); - if (stat(git_path("%s", path), &st) < 0) + memcpy(ref + baselen, de->d_name, namelen+1); + if (stat(git_path("%s", ref), &st) < 0) continue; if (S_ISDIR(st.st_mode)) { - list = get_ref_dir(path, list); + list = get_ref_dir(ref, list); continue; } - if (read_ref(git_path("%s", path), sha1) < 0) { - error("%s points nowhere!", path); + if (read_ref(ref, sha1) < 0) { + error("%s points nowhere!", ref); continue; } - list = add_ref(path, sha1, list); + list = add_ref(ref, sha1, list); } - free(path); + free(ref); closedir(dir); } return list; @@ -145,12 +145,14 @@ static struct ref_list *get_loose_refs(v /* We allow "recursive" symbolic refs. Only within reason, though */ #define MAXDEPTH 5 -const char *resolve_ref(const char *path, unsigned char *sha1, int reading) +const char *resolve_ref(const char *ref, unsigned char *sha1, int reading) { int depth = MAXDEPTH, len; char buffer[256]; + static char ref_buffer[256]; for (;;) { + const char *path = git_path("%s", ref); struct stat st; char *buf; int fd; @@ -169,14 +171,16 @@ const char *resolve_ref(const char *path if (reading || errno != ENOENT) return NULL; hashclr(sha1); - return path; + return ref; } /* Follow "normalized" - ie "refs/.." symlinks by hand */ if (S_ISLNK(st.st_mode)) { len = readlink(path, buffer, sizeof(buffer)-1); if (len >= 5 && !memcmp("refs/", buffer, 5)) { - path = git_path("%.*s", len, buffer); + buffer[len] = 0; + strcpy(ref_buffer, buffer); + ref = ref_buffer; continue; } } @@ -201,19 +205,22 @@ const char *resolve_ref(const char *path while (len && isspace(*buf)) buf++, len--; while (len && isspace(buf[len-1])) - buf[--len] = 0; - path = git_path("%.*s", len, buf); + len--; + buf[len] = 0; + memcpy(ref_buffer, buf, len + 1); + ref = ref_buffer; } if (len < 40 || get_sha1_hex(buffer, sha1)) return NULL; - return path; + return ref; } -int create_symref(const char *git_HEAD, const char *refs_heads_master) +int create_symref(const char *ref_target, const char *refs_heads_master) { const char *lockpath; char ref[1000]; int fd, len, written; + const char *git_HEAD = git_path("%s", ref_target); #ifndef NO_SYMLINK_HEAD if (prefer_symlink_refs) { @@ -251,9 +258,9 @@ #endif return 0; } -int read_ref(const char *filename, unsigned char *sha1) +int read_ref(const char *ref, unsigned char *sha1) { - if (resolve_ref(filename, sha1, 1)) + if (resolve_ref(ref, sha1, 1)) return 0; return -1; } @@ -306,7 +313,7 @@ static int do_for_each_ref(const char *b int head_ref(int (*fn)(const char *path, const unsigned char *sha1)) { unsigned char sha1[20]; - if (!read_ref(git_path("HEAD"), sha1)) + if (!read_ref("HEAD", sha1)) return fn("HEAD", sha1); return 0; } @@ -335,7 +342,7 @@ int get_ref_sha1(const char *ref, unsign { if (check_ref_format(ref)) return -1; - return read_ref(git_path("refs/%s", ref), sha1); + return read_ref(mkpath("refs/%s", ref), sha1); } /* @@ -416,31 +423,30 @@ static struct ref_lock *verify_lock(stru return lock; } -static struct ref_lock *lock_ref_sha1_basic(const char *path, +static struct ref_lock *lock_ref_sha1_basic(const char *ref, int plen, const unsigned char *old_sha1, int mustexist) { - const char *orig_path = path; + const char *orig_ref = ref; struct ref_lock *lock; struct stat st; lock = xcalloc(1, sizeof(struct ref_lock)); lock->lock_fd = -1; - plen = strlen(path) - plen; - path = resolve_ref(path, lock->old_sha1, mustexist); - if (!path) { + ref = resolve_ref(ref, lock->old_sha1, mustexist); + if (!ref) { int last_errno = errno; error("unable to resolve reference %s: %s", - orig_path, strerror(errno)); + orig_ref, strerror(errno)); unlock_ref(lock); errno = last_errno; return NULL; } lock->lk = xcalloc(1, sizeof(struct lock_file)); - lock->ref_file = xstrdup(path); - lock->log_file = xstrdup(git_path("logs/%s", lock->ref_file + plen)); + lock->ref_file = xstrdup(git_path("%s", ref)); + lock->log_file = xstrdup(git_path("logs/%s", ref)); lock->force_write = lstat(lock->ref_file, &st) && errno == ENOENT; if (safe_create_leading_directories(lock->ref_file)) @@ -455,15 +461,14 @@ struct ref_lock *lock_ref_sha1(const cha { if (check_ref_format(ref)) return NULL; - return lock_ref_sha1_basic(git_path("refs/%s", ref), + return lock_ref_sha1_basic(mkpath("refs/%s", ref), 5 + strlen(ref), old_sha1, mustexist); } struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1, int mustexist) { - return lock_ref_sha1_basic(git_path("%s", ref), - strlen(ref), old_sha1, mustexist); + return lock_ref_sha1_basic(ref, strlen(ref), old_sha1, mustexist); } void unlock_ref(struct ref_lock *lock) diff --git a/sha1_name.c b/sha1_name.c index 1fbc443..b497528 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -247,8 +247,8 @@ static int get_sha1_basic(const char *st NULL }; static const char *warning = "warning: refname '%.*s' is ambiguous.\n"; - const char **p, *pathname; - char *real_path = NULL; + const char **p, *ref; + char *real_ref = NULL; int refs_found = 0, am; unsigned long at_time = (unsigned long)-1; unsigned char *this_result; @@ -276,10 +276,10 @@ static int get_sha1_basic(const char *st for (p = fmt; *p; p++) { this_result = refs_found ? sha1_from_ref : sha1; - pathname = resolve_ref(git_path(*p, len, str), this_result, 1); - if (pathname) { + ref = resolve_ref(mkpath(*p, len, str), this_result, 1); + if (ref) { if (!refs_found++) - real_path = xstrdup(pathname); + real_ref = xstrdup(ref); if (!warn_ambiguous_refs) break; } @@ -293,12 +293,12 @@ static int get_sha1_basic(const char *st if (at_time != (unsigned long)-1) { read_ref_at( - real_path + strlen(git_path(".")) - 1, + real_ref, at_time, sha1); } - free(real_path); + free(real_ref); return 0; } ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: Make ref resolution saner 2006-09-12 3:17 ` Make ref resolution saner Linus Torvalds @ 2006-09-12 5:36 ` Jeff King 2006-09-12 14:41 ` Linus Torvalds 0 siblings, 1 reply; 4+ messages in thread From: Jeff King @ 2006-09-12 5:36 UTC (permalink / raw) To: Linus Torvalds; +Cc: Junio C Hamano, Git Mailing List On Mon, Sep 11, 2006 at 08:17:35PM -0700, Linus Torvalds wrote: > The old code used to totally mix up the notion of a ref-name and the path > that that ref was associated with. That was not only horribly ugly (a I assume your patch is against master; it looks like there's exactly one call to resolve_ref that's in next but not master. One-liner fix below. -Peff -- >8 -- wt-status: use simplified resolve_ref to find current branch --- wt-status.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/wt-status.c b/wt-status.c index ec2c728..e2f49c7 100644 --- a/wt-status.c +++ b/wt-status.c @@ -41,7 +41,7 @@ void wt_status_prepare(struct wt_status s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0; - head = resolve_ref(git_path("HEAD"), sha1, 0); + head = resolve_ref("HEAD", sha1, 0); s->branch = head ? strdup(head + strlen(get_git_dir()) + 1) : NULL; -- 1.4.2.g39f1 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: Make ref resolution saner 2006-09-12 5:36 ` Jeff King @ 2006-09-12 14:41 ` Linus Torvalds 0 siblings, 0 replies; 4+ messages in thread From: Linus Torvalds @ 2006-09-12 14:41 UTC (permalink / raw) To: Jeff King; +Cc: Junio C Hamano, Git Mailing List On Tue, 12 Sep 2006, Jeff King wrote: > > I assume your patch is against master; Yeah. Well, master plus my previous patches. > it looks like there's exactly one call to resolve_ref that's in next but > not master. One-liner fix below. Not quite enough. It's the same thing: wt-status.c plays games with the return value (which _used_ to be a path) in order to turn it back into a ref. But now that it's all about refs, the games are unnecessary: > diff --git a/wt-status.c b/wt-status.c > index ec2c728..e2f49c7 100644 > --- a/wt-status.c > +++ b/wt-status.c > @@ -41,7 +41,7 @@ void wt_status_prepare(struct wt_status > > s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0; > > - head = resolve_ref(git_path("HEAD"), sha1, 0); > + head = resolve_ref("HEAD", sha1, 0); > s->branch = head ? > strdup(head + strlen(get_git_dir()) + 1) : > NULL; So that "strdup(head + strlen(get_git_dir()) + 1)" should now be just "strdup(head)". Linus ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2006-09-12 18:57 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-09-12 18:57 Make ref resolution saner linux -- strict thread matches above, loose matches on Subject: below -- 2006-09-11 19:03 Allow multiple "git_path()" uses Linus Torvalds 2006-09-11 23:37 ` Start handling references internally as a sorted in-memory list Linus Torvalds 2006-09-12 3:10 ` Add support for negative refs Linus Torvalds 2006-09-12 3:17 ` Make ref resolution saner Linus Torvalds 2006-09-12 5:36 ` Jeff King 2006-09-12 14:41 ` Linus Torvalds
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).