From: Junio C Hamano Date: Mon, 30 May 2011 07:09:55 +0000 (-0700) Subject: Merge branch 'maint' X-Git-Tag: v1.7.6-rc0~17 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/fb674d767180354d9ad3e69f1d41bee98df6bfe9?ds=inline;hp=-c Merge branch 'maint' * maint: git-submodule.sh: separate parens by a space to avoid confusing some shells Documentation/technical/api-diff.txt: correct name of diff_unmerge() read_gitfile_gently: use ssize_t to hold read result remove tests of always-false condition rerere.c: diagnose a corrupt MERGE_RR when hitting EOF between TAB and '\0' --- fb674d767180354d9ad3e69f1d41bee98df6bfe9 diff --combined git-submodule.sh index bf110e9cb7,4361ae418c..d189a24c71 --- a/git-submodule.sh +++ b/git-submodule.sh @@@ -8,7 -8,7 +8,7 @@@ dashless=$(basename "$0" | sed -e 's/- USAGE="[--quiet] add [-b branch] [-f|--force] [--reference ] [--] [] or: $dashless [--quiet] status [--cached] [--recursive] [--] [...] or: $dashless [--quiet] init [--] [...] - or: $dashless [--quiet] update [--init] [-N|--no-fetch] [--rebase] [--reference ] [--merge] [--recursive] [--] [...] + or: $dashless [--quiet] update [--init] [-N|--no-fetch] [-f|--force] [--rebase] [--reference ] [--merge] [--recursive] [--] [...] or: $dashless [--quiet] summary [--cached|--files] [--summary-limit ] [commit] [--] [...] or: $dashless [--quiet] foreach [--recursive] or: $dashless [--quiet] sync [--] [...]" @@@ -402,9 -402,6 +402,9 @@@ cmd_update( -N|--no-fetch) nofetch=1 ;; + -f|--force) + force=$1 + ;; -r|--rebase) update="rebase" ;; @@@ -483,11 -480,10 +483,11 @@@ if test "$subsha1" != "$sha1" then - force= - if test -z "$subsha1" + subforce=$force + # If we don't already have a -f flag and the submodule has never been checked out + if test -z "$subsha1" -a -z "$force" then - force="-f" + subforce="-f" fi if test -z "$nofetch" @@@ -495,7 -491,7 +495,7 @@@ # Run fetch only if $sha1 isn't present or it # is not reachable from a ref. (clear_local_git_env; cd "$path" && - ((rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) && + ( (rev=$(git rev-list -n 1 $sha1 --not --all 2>/dev/null) && test -z "$rev") || git-fetch)) || die "Unable to fetch in submodule path '$path'" fi @@@ -519,7 -515,7 +519,7 @@@ msg="merged in" ;; *) - command="git checkout $force -q" + command="git checkout $subforce -q" action="checkout" msg="checked out" ;; diff --combined rerere.c index e3407cf334,6ec452f7bc..dcb525a4d0 --- a/rerere.c +++ b/rerere.c @@@ -47,8 -47,14 +47,14 @@@ static void read_rr(struct string_list name = xstrdup(buf); if (fgetc(in) != '\t') die("corrupt MERGE_RR"); - for (i = 0; i < sizeof(buf) && (buf[i] = fgetc(in)); i++) - ; /* do nothing */ + for (i = 0; i < sizeof(buf); i++) { + int c = fgetc(in); + if (c < 0) + die("corrupt MERGE_RR"); + buf[i] = c; + if (c == 0) + break; + } if (i == sizeof(buf)) die("filename too long"); string_list_insert(rr, buf)->util = name; @@@ -671,88 -677,3 +677,88 @@@ int rerere_forget(const char **pathspec } return write_rr(&merge_rr, fd); } + +static time_t rerere_created_at(const char *name) +{ + struct stat st; + return stat(rerere_path(name, "preimage"), &st) ? (time_t) 0 : st.st_mtime; +} + +static time_t rerere_last_used_at(const char *name) +{ + struct stat st; + return stat(rerere_path(name, "postimage"), &st) ? (time_t) 0 : st.st_mtime; +} + +static void unlink_rr_item(const char *name) +{ + unlink(rerere_path(name, "thisimage")); + unlink(rerere_path(name, "preimage")); + unlink(rerere_path(name, "postimage")); + rmdir(git_path("rr-cache/%s", name)); +} + +struct rerere_gc_config_cb { + int cutoff_noresolve; + int cutoff_resolve; +}; + +static int git_rerere_gc_config(const char *var, const char *value, void *cb) +{ + struct rerere_gc_config_cb *cf = cb; + + if (!strcmp(var, "gc.rerereresolved")) + cf->cutoff_resolve = git_config_int(var, value); + else if (!strcmp(var, "gc.rerereunresolved")) + cf->cutoff_noresolve = git_config_int(var, value); + else + return git_default_config(var, value, cb); + return 0; +} + +void rerere_gc(struct string_list *rr) +{ + struct string_list to_remove = STRING_LIST_INIT_DUP; + DIR *dir; + struct dirent *e; + int i, cutoff; + time_t now = time(NULL), then; + struct rerere_gc_config_cb cf = { 15, 60 }; + + git_config(git_rerere_gc_config, &cf); + dir = opendir(git_path("rr-cache")); + if (!dir) + die_errno("unable to open rr-cache directory"); + while ((e = readdir(dir))) { + if (is_dot_or_dotdot(e->d_name)) + continue; + + then = rerere_last_used_at(e->d_name); + if (then) { + cutoff = cf.cutoff_resolve; + } else { + then = rerere_created_at(e->d_name); + if (!then) + continue; + cutoff = cf.cutoff_noresolve; + } + if (then < now - cutoff * 86400) + string_list_append(&to_remove, e->d_name); + } + closedir(dir); + for (i = 0; i < to_remove.nr; i++) + unlink_rr_item(to_remove.items[i].string); + string_list_clear(&to_remove, 0); +} + +void rerere_clear(struct string_list *merge_rr) +{ + int i; + + for (i = 0; i < merge_rr->nr; i++) { + const char *name = (const char *)merge_rr->items[i].util; + if (!has_rerere_resolution(name)) + unlink_rr_item(name); + } + unlink_or_warn(git_path("MERGE_RR")); +} diff --combined setup.c index 013ad11275,e7a37863cc..ce87900ce3 --- a/setup.c +++ b/setup.c @@@ -85,17 -85,8 +85,17 @@@ static void NORETURN die_verify_filenam { unsigned char sha1[20]; unsigned mode; - /* try a detailed diagnostic ... */ - get_sha1_with_mode_1(arg, sha1, &mode, 0, prefix); + + /* + * Saying "'(icase)foo' does not exist in the index" when the + * user gave us ":(icase)foo" is just stupid. A magic pathspec + * begins with a colon and is followed by a non-alnum; do not + * let get_sha1_with_mode_1(only_to_die=1) to even trigger. + */ + if (!(arg[0] == ':' && !isalnum(arg[1]))) + /* try a detailed diagnostic ... */ + get_sha1_with_mode_1(arg, sha1, &mode, 1, prefix); + /* ... or fall back the most general message. */ die("ambiguous argument '%s': unknown revision or path not in the working tree.\n" "Use '--' to separate paths from revisions", arg); @@@ -135,105 -126,6 +135,105 @@@ void verify_non_filename(const char *pr "Use '--' to separate filenames from revisions", arg); } +/* + * Magic pathspec + * + * NEEDSWORK: These need to be moved to dir.h or even to a new + * pathspec.h when we restructure get_pathspec() users to use the + * "struct pathspec" interface. + * + * Possible future magic semantics include stuff like: + * + * { PATHSPEC_NOGLOB, '!', "noglob" }, + * { PATHSPEC_ICASE, '\0', "icase" }, + * { PATHSPEC_RECURSIVE, '*', "recursive" }, + * { PATHSPEC_REGEXP, '\0', "regexp" }, + * + */ +#define PATHSPEC_FROMTOP (1<<0) + +static struct pathspec_magic { + unsigned bit; + char mnemonic; /* this cannot be ':'! */ + const char *name; +} pathspec_magic[] = { + { PATHSPEC_FROMTOP, '/', "top" }, +}; + +/* + * Take an element of a pathspec and check for magic signatures. + * Append the result to the prefix. + * + * For now, we only parse the syntax and throw out anything other than + * "top" magic. + * + * NEEDSWORK: This needs to be rewritten when we start migrating + * get_pathspec() users to use the "struct pathspec" interface. For + * example, a pathspec element may be marked as case-insensitive, but + * the prefix part must always match literally, and a single stupid + * string cannot express such a case. + */ +static const char *prefix_pathspec(const char *prefix, int prefixlen, const char *elt) +{ + unsigned magic = 0; + const char *copyfrom = elt; + int i; + + if (elt[0] != ':') { + ; /* nothing to do */ + } else if (elt[1] == '(') { + /* longhand */ + const char *nextat; + for (copyfrom = elt + 2; + *copyfrom && *copyfrom != ')'; + copyfrom = nextat) { + size_t len = strcspn(copyfrom, ",)"); + if (copyfrom[len] == ')') + nextat = copyfrom + len; + else + nextat = copyfrom + len + 1; + if (!len) + continue; + for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) + if (strlen(pathspec_magic[i].name) == len && + !strncmp(pathspec_magic[i].name, copyfrom, len)) { + magic |= pathspec_magic[i].bit; + break; + } + if (ARRAY_SIZE(pathspec_magic) <= i) + die("Invalid pathspec magic '%.*s' in '%s'", + (int) len, copyfrom, elt); + } + if (*copyfrom == ')') + copyfrom++; + } else { + /* shorthand */ + for (copyfrom = elt + 1; + *copyfrom && *copyfrom != ':'; + copyfrom++) { + char ch = *copyfrom; + + if (!is_pathspec_magic(ch)) + break; + for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++) + if (pathspec_magic[i].mnemonic == ch) { + magic |= pathspec_magic[i].bit; + break; + } + if (ARRAY_SIZE(pathspec_magic) <= i) + die("Unimplemented pathspec magic '%c' in '%s'", + ch, elt); + } + if (*copyfrom == ':') + copyfrom++; + } + + if (magic & PATHSPEC_FROMTOP) + return xstrdup(copyfrom); + else + return prefix_path(prefix, prefixlen, copyfrom); +} + const char **get_pathspec(const char *prefix, const char **pathspec) { const char *entry = *pathspec; @@@ -255,7 -147,8 +255,7 @@@ dst = pathspec; prefixlen = prefix ? strlen(prefix) : 0; while (*src) { - const char *p = prefix_path(prefix, prefixlen, *src); - *(dst++) = p; + *(dst++) = prefix_pathspec(prefix, prefixlen, *src); src++; } *dst = NULL; @@@ -382,7 -275,7 +382,7 @@@ const char *read_gitfile_gently(const c const char *slash; struct stat st; int fd; - size_t len; + ssize_t len; if (stat(path, &st)) return NULL; @@@ -432,7 -325,6 +432,7 @@@ static const char *setup_explicit_git_d const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT); const char *worktree; char *gitfile; + int offset; if (PATH_MAX - 40 < strlen(gitdirenv)) die("'$%s' too big", GIT_DIR_ENVIRONMENT); @@@ -498,15 -390,15 +498,15 @@@ return NULL; } - if (!prefixcmp(cwd, worktree) && - cwd[strlen(worktree)] == '/') { /* cwd inside worktree */ + offset = dir_inside_of(cwd, worktree); + if (offset >= 0) { /* cwd inside worktree? */ set_git_dir(real_path(gitdirenv)); if (chdir(worktree)) die_errno("Could not chdir to '%s'", worktree); cwd[len++] = '/'; cwd[len] = '\0'; free(gitfile); - return cwd + strlen(worktree) + 1; + return cwd + offset; } /* cwd outside worktree */ diff --combined transport.c index 1a3998ee51,69dae71103..c9c8056f9d --- a/transport.c +++ b/transport.c @@@ -156,7 -156,7 +156,7 @@@ static void set_upstreams(struct transp continue; if (!ref->peer_ref) continue; - if (!ref->new_sha1 || is_null_sha1(ref->new_sha1)) + if (is_null_sha1(ref->new_sha1)) continue; /* Follow symbolic refs (mainly for HEAD). */ @@@ -1190,20 -1190,14 +1190,20 @@@ literal_copy return xstrdup(url); } -int refs_from_alternate_cb(struct alternate_object_database *e, void *cb) +struct alternate_refs_data { + alternate_ref_fn *fn; + void *data; +}; + +static int refs_from_alternate_cb(struct alternate_object_database *e, + void *data) { char *other; size_t len; struct remote *remote; struct transport *transport; const struct ref *extra; - alternate_ref_fn *ref_fn = cb; + struct alternate_refs_data *cb = data; e->name[-1] = '\0'; other = xstrdup(real_path(e->base)); @@@ -1224,16 -1218,8 +1224,16 @@@ for (extra = transport_get_remote_refs(transport); extra; extra = extra->next) - ref_fn(extra, NULL); + cb->fn(extra, cb->data); transport_disconnect(transport); free(other); return 0; } + +void for_each_alternate_ref(alternate_ref_fn fn, void *data) +{ + struct alternate_refs_data cb; + cb.fn = fn; + cb.data = data; + foreach_alt_odb(refs_from_alternate_cb, &cb); +}