From: Junio C Hamano Date: Wed, 2 May 2012 20:51:35 +0000 (-0700) Subject: Merge branch 'nd/i18n' X-Git-Tag: v1.7.11-rc0~74 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/1be65eda6a7018445ebdd9cfec4b1caab4db34ba?hp=-c Merge branch 'nd/i18n' More message strings marked for i18n. By Nguyễn Thái Ngọc Duy (10) and Jonathan Nieder (1) * nd/i18n: help: replace underlining "help -a" headers using hyphens with a blank line i18n: bundle: mark strings for translation i18n: index-pack: mark strings for translation i18n: apply: update say_patch_name to give translators complete sentence i18n: apply: mark strings for translation i18n: remote: mark strings for translation i18n: make warn_dangling_symref() automatically append \n i18n: help: mark strings for translation i18n: mark relative dates for translation strbuf: convenience format functions with \n automatically appended Makefile: feed all header files to xgettext --- 1be65eda6a7018445ebdd9cfec4b1caab4db34ba diff --combined Makefile index a14732c4cd,455446b191..7e243085da --- a/Makefile +++ b/Makefile @@@ -386,6 -386,7 +386,7 @@@ XDIFF_OBJS VCSSVN_H = VCSSVN_OBJS = VCSSVN_TEST_OBJS = + MISC_H = EXTRA_CPPFLAGS = LIB_H = LIB_OBJS = @@@ -440,7 -441,6 +441,7 @@@ SCRIPT_PERL += git-send-email.per SCRIPT_PERL += git-svn.perl SCRIPT_PYTHON += git-remote-testgit.py +SCRIPT_PYTHON += git-p4.py SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ $(patsubst %.perl,%,$(SCRIPT_PERL)) \ @@@ -481,11 -481,9 +482,11 @@@ TEST_PROGRAMS_NEED_X += test-genrando TEST_PROGRAMS_NEED_X += test-index-version TEST_PROGRAMS_NEED_X += test-line-buffer TEST_PROGRAMS_NEED_X += test-match-trees +TEST_PROGRAMS_NEED_X += test-mergesort TEST_PROGRAMS_NEED_X += test-mktemp TEST_PROGRAMS_NEED_X += test-parse-options TEST_PROGRAMS_NEED_X += test-path-utils +TEST_PROGRAMS_NEED_X += test-revision-walking TEST_PROGRAMS_NEED_X += test-run-command TEST_PROGRAMS_NEED_X += test-sha1 TEST_PROGRAMS_NEED_X += test-sigchain @@@ -546,6 -544,36 +547,36 @@@ LIB_FILE=libgit. XDIFF_LIB=xdiff/lib.a VCSSVN_LIB=vcs-svn/lib.a + XDIFF_H += xdiff/xinclude.h + XDIFF_H += xdiff/xmacros.h + XDIFF_H += xdiff/xdiff.h + XDIFF_H += xdiff/xtypes.h + XDIFF_H += xdiff/xutils.h + XDIFF_H += xdiff/xprepare.h + XDIFF_H += xdiff/xdiffi.h + XDIFF_H += xdiff/xemit.h + + VCSSVN_H += vcs-svn/line_buffer.h + VCSSVN_H += vcs-svn/sliding_window.h + VCSSVN_H += vcs-svn/repo_tree.h + VCSSVN_H += vcs-svn/fast_export.h + VCSSVN_H += vcs-svn/svndiff.h + VCSSVN_H += vcs-svn/svndump.h + + MISC_H += branch.h + MISC_H += bundle.h + MISC_H += bisect.h + MISC_H += common-cmds.h + MISC_H += fetch-pack.h + MISC_H += thread-utils.h + MISC_H += send-pack.h + MISC_H += shortlog.h + MISC_H += reachable.h + MISC_H += wt-status.h + MISC_H += tar.h + MISC_H += url.h + MISC_H += walker.h + LIB_H += advice.h LIB_H += archive.h LIB_H += argv-array.h @@@ -593,7 -621,6 +624,7 @@@ LIB_H += log-tree. LIB_H += mailmap.h LIB_H += merge-file.h LIB_H += merge-recursive.h +LIB_H += mergesort.h LIB_H += notes.h LIB_H += notes-cache.h LIB_H += notes-merge.h @@@ -631,7 -658,6 +662,7 @@@ LIB_H += tree-walk. LIB_H += unpack-trees.h LIB_H += userdiff.h LIB_H += utf8.h +LIB_H += varint.h LIB_H += xdiff-interface.h LIB_H += xdiff/xdiff.h @@@ -699,7 -725,6 +730,7 @@@ LIB_OBJS += mailmap. LIB_OBJS += match-trees.o LIB_OBJS += merge-file.o LIB_OBJS += merge-recursive.o +LIB_OBJS += mergesort.o LIB_OBJS += name-hash.o LIB_OBJS += notes.o LIB_OBJS += notes-cache.o @@@ -758,7 -783,6 +789,7 @@@ LIB_OBJS += url. LIB_OBJS += usage.o LIB_OBJS += userdiff.o LIB_OBJS += utf8.o +LIB_OBJS += varint.o LIB_OBJS += walker.o LIB_OBJS += wrapper.o LIB_OBJS += write_or_die.o @@@ -2184,24 -2208,8 +2215,8 @@@ connect.o transport.o url.o http-backen http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h - XDIFF_H += xdiff/xinclude.h - XDIFF_H += xdiff/xmacros.h - XDIFF_H += xdiff/xdiff.h - XDIFF_H += xdiff/xtypes.h - XDIFF_H += xdiff/xutils.h - XDIFF_H += xdiff/xprepare.h - XDIFF_H += xdiff/xdiffi.h - XDIFF_H += xdiff/xemit.h - xdiff-interface.o $(XDIFF_OBJS): $(XDIFF_H) - VCSSVN_H += vcs-svn/line_buffer.h - VCSSVN_H += vcs-svn/sliding_window.h - VCSSVN_H += vcs-svn/repo_tree.h - VCSSVN_H += vcs-svn/fast_export.h - VCSSVN_H += vcs-svn/svndiff.h - VCSSVN_H += vcs-svn/svndump.h - $(VCSSVN_OBJS) $(VCSSVN_TEST_OBJS): $(LIB_H) $(VCSSVN_H) endif @@@ -2272,8 -2280,6 +2287,8 @@@ $(XDIFF_LIB): $(XDIFF_OBJS $(VCSSVN_LIB): $(VCSSVN_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(VCSSVN_OBJS) +export DEFAULT_EDITOR DEFAULT_PAGER + doc: $(MAKE) -C Documentation all @@@ -2298,7 -2304,7 +2313,7 @@@ XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) -- --keyword=_ --keyword=N_ --keyword="Q_:1,2" XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl - LOCALIZED_C := $(C_OBJ:o=c) + LOCALIZED_C := $(C_OBJ:o=c) $(LIB_H) $(XDIFF_H) $(VCSSVN_H) $(MISC_H) LOCALIZED_SH := $(SCRIPT_SH) LOCALIZED_PERL := $(SCRIPT_PERL) diff --combined builtin/apply.c index 799bb5e906,c768b7fb02..725712d788 --- a/builtin/apply.c +++ b/builtin/apply.c @@@ -103,7 -103,7 +103,7 @@@ static void parse_whitespace_option(con ws_error_action = correct_ws_error; return; } - die("unrecognized whitespace option '%s'", option); + die(_("unrecognized whitespace option '%s'"), option); } static void parse_ignorewhitespace_option(const char *option) @@@ -118,7 -118,7 +118,7 @@@ ws_ignore_action = ignore_ws_change; return; } - die("unrecognized whitespace ignore option '%s'", option); + die(_("unrecognized whitespace ignore option '%s'"), option); } static void set_default_whitespace_mode(const char *whitespace_option) @@@ -152,14 -152,9 +152,14 @@@ struct fragment unsigned long leading, trailing; unsigned long oldpos, oldlines; unsigned long newpos, newlines; + /* + * 'patch' is usually borrowed from buf in apply_patch(), + * but some codepaths store an allocated buffer. + */ const char *patch; + unsigned free_patch:1, + rejected:1; int size; - int rejected; int linenr; struct fragment *next; }; @@@ -201,36 -196,6 +201,36 @@@ struct patch struct patch *next; }; +static void free_fragment_list(struct fragment *list) +{ + while (list) { + struct fragment *next = list->next; + if (list->free_patch) + free((char *)list->patch); + free(list); + list = next; + } +} + +static void free_patch(struct patch *patch) +{ + free_fragment_list(patch->fragments); + free(patch->def_name); + free(patch->old_name); + free(patch->new_name); + free(patch->result); + free(patch); +} + +static void free_patch_list(struct patch *list) +{ + while (list) { + struct patch *next = list->next; + free_patch(list); + list = next; + } +} + /* * A line in a file, len-bytes long (includes the terminating LF, * except for an incomplete line at the end if the file ends with @@@ -337,11 -302,6 +337,11 @@@ static void add_line_info(struct image img->nr++; } +/* + * "buf" has the file contents to be patched (read from various sources). + * attach it to "image" and add line-based index to it. + * "image" now owns the "buf". + */ static void prepare_image(struct image *image, char *buf, size_t len, int prepare_linetable) { @@@ -375,24 -335,28 +375,27 @@@ static void clear_image(struct image *i image->len = 0; } - static void say_patch_name(FILE *output, const char *pre, - struct patch *patch, const char *post) + /* fmt must contain _one_ %s and no other substitution */ + static void say_patch_name(FILE *output, const char *fmt, struct patch *patch) { - fputs(pre, output); + struct strbuf sb = STRBUF_INIT; + if (patch->old_name && patch->new_name && strcmp(patch->old_name, patch->new_name)) { - quote_c_style(patch->old_name, NULL, output, 0); - fputs(" => ", output); - quote_c_style(patch->new_name, NULL, output, 0); + quote_c_style(patch->old_name, &sb, NULL, 0); + strbuf_addstr(&sb, " => "); + quote_c_style(patch->new_name, &sb, NULL, 0); } else { const char *n = patch->new_name; if (!n) n = patch->old_name; - quote_c_style(n, NULL, output, 0); + quote_c_style(n, &sb, NULL, 0); } - fputs(post, output); + fprintf(output, fmt, sb.buf); + fputc('\n', output); + strbuf_release(&sb); } -#define CHUNKSIZE (8192) #define SLOP (16) static void read_patch_file(struct strbuf *sb, int fd) @@@ -455,7 -419,7 +458,7 @@@ static char *squash_slash(char *name return name; } -static char *find_name_gnu(const char *line, char *def, int p_value) +static char *find_name_gnu(const char *line, const char *def, int p_value) { struct strbuf name = STRBUF_INIT; char *cp; @@@ -478,7 -442,11 +481,7 @@@ cp++; } - /* name can later be freed, so we need - * to memmove, not just return cp - */ strbuf_remove(&name, 0, cp - name.buf); - free(def); if (root) strbuf_insert(&name, 0, root, root_len); return squash_slash(strbuf_detach(&name, NULL)); @@@ -643,13 -611,8 +646,13 @@@ static size_t diff_timestamp_len(const return line + len - end; } -static char *find_name_common(const char *line, char *def, int p_value, - const char *end, int terminate) +static char *null_strdup(const char *s) +{ + return s ? xstrdup(s) : NULL; +} + +static char *find_name_common(const char *line, const char *def, + int p_value, const char *end, int terminate) { int len; const char *start = NULL; @@@ -670,10 -633,10 +673,10 @@@ start = line; } if (!start) - return squash_slash(def); + return squash_slash(null_strdup(def)); len = line - start; if (!len) - return squash_slash(def); + return squash_slash(null_strdup(def)); /* * Generally we prefer the shorter name, especially @@@ -684,7 -647,8 +687,7 @@@ if (def) { int deflen = strlen(def); if (deflen < len && !strncmp(start, def, deflen)) - return squash_slash(def); - free(def); + return squash_slash(xstrdup(def)); } if (root) { @@@ -809,7 -773,7 +812,7 @@@ static int has_epoch_timestamp(const ch if (!stamp) { stamp = xmalloc(sizeof(*stamp)); if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) { - warning("Cannot prepare timestamp regexp %s", + warning(_("Cannot prepare timestamp regexp %s"), stamp_regexp); return 0; } @@@ -818,7 -782,7 +821,7 @@@ status = regexec(stamp, timestamp, ARRAY_SIZE(m), m, 0); if (status) { if (status != REG_NOMATCH) - warning("regexec returned %d for input: %s", + warning(_("regexec returned %d for input: %s"), status, timestamp); return 0; } @@@ -881,10 -845,8 +884,10 @@@ static void parse_traditional_patch(con name = find_name_traditional(first, NULL, p_value); patch->old_name = name; } else { - name = find_name_traditional(first, NULL, p_value); - name = find_name_traditional(second, name, p_value); + char *first_name; + first_name = find_name_traditional(first, NULL, p_value); + name = find_name_traditional(second, first_name, p_value); + free(first_name); if (has_epoch_timestamp(first)) { patch->is_new = 1; patch->is_delete = 0; @@@ -894,12 -856,11 +897,12 @@@ patch->is_delete = 1; patch->old_name = name; } else { - patch->old_name = patch->new_name = name; + patch->old_name = name; + patch->new_name = xstrdup(name); } } if (!name) - die("unable to find filename in patch at line %d", linenr); + die(_("unable to find filename in patch at line %d"), linenr); } static int gitdiff_hdrend(const char *line, struct patch *patch) @@@ -928,36 -889,30 +931,36 @@@ static char *gitdiff_verify_name(const name = orig_name; len = strlen(name); if (isnull) - die("git apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr); + die(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"), name, linenr); another = find_name(line, NULL, p_value, TERM_TAB); if (!another || memcmp(another, name, len + 1)) - die("git apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr); + die(_("git apply: bad git-diff - inconsistent %s filename on line %d"), oldnew, linenr); free(another); return orig_name; } else { /* expect "/dev/null" */ if (memcmp("/dev/null", line, 9) || line[9] != '\n') - die("git apply: bad git-diff - expected /dev/null on line %d", linenr); + die(_("git apply: bad git-diff - expected /dev/null on line %d"), linenr); return NULL; } } static int gitdiff_oldname(const char *line, struct patch *patch) { + char *orig = patch->old_name; patch->old_name = gitdiff_verify_name(line, patch->is_new, patch->old_name, "old"); + if (orig != patch->old_name) + free(orig); return 0; } static int gitdiff_newname(const char *line, struct patch *patch) { + char *orig = patch->new_name; patch->new_name = gitdiff_verify_name(line, patch->is_delete, patch->new_name, "new"); + if (orig != patch->new_name) + free(orig); return 0; } @@@ -976,23 -931,20 +979,23 @@@ static int gitdiff_newmode(const char * static int gitdiff_delete(const char *line, struct patch *patch) { patch->is_delete = 1; - patch->old_name = patch->def_name; + free(patch->old_name); + patch->old_name = null_strdup(patch->def_name); return gitdiff_oldmode(line, patch); } static int gitdiff_newfile(const char *line, struct patch *patch) { patch->is_new = 1; - patch->new_name = patch->def_name; + free(patch->new_name); + patch->new_name = null_strdup(patch->def_name); return gitdiff_newmode(line, patch); } static int gitdiff_copysrc(const char *line, struct patch *patch) { patch->is_copy = 1; + free(patch->old_name); patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0); return 0; } @@@ -1000,7 -952,6 +1003,7 @@@ static int gitdiff_copydst(const char *line, struct patch *patch) { patch->is_copy = 1; + free(patch->new_name); patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0); return 0; } @@@ -1008,7 -959,6 +1011,7 @@@ static int gitdiff_renamesrc(const char *line, struct patch *patch) { patch->is_rename = 1; + free(patch->old_name); patch->old_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0); return 0; } @@@ -1016,7 -966,6 +1019,7 @@@ static int gitdiff_renamedst(const char *line, struct patch *patch) { patch->is_rename = 1; + free(patch->new_name); patch->new_name = find_name(line, NULL, p_value ? p_value - 1 : 0, 0); return 0; } @@@ -1098,7 -1047,7 +1101,7 @@@ static const char *stop_at_slash(const * creation or deletion of an empty file. In any of these cases, * both sides are the same name under a/ and b/ respectively. */ -static char *git_header_name(char *line, int llen) +static char *git_header_name(const char *line, int llen) { const char *name; const char *second = NULL; @@@ -1225,7 -1174,7 +1228,7 @@@ } /* Verify that we recognize the lines following a git header */ -static int parse_git_header(char *line, int len, unsigned int size, struct patch *patch) +static int parse_git_header(const char *line, int len, unsigned int size, struct patch *patch) { unsigned long offset; @@@ -1341,7 -1290,7 +1344,7 @@@ static int parse_range(const char *line return offset + ex; } -static void recount_diff(char *line, int size, struct fragment *fragment) +static void recount_diff(const char *line, int size, struct fragment *fragment) { int oldlines = 0, newlines = 0, ret = 0; @@@ -1381,7 -1330,7 +1384,7 @@@ break; } if (ret) { - warning("recount: unexpected line: %.*s", + warning(_("recount: unexpected line: %.*s"), (int)linelen(line, size), line); return; } @@@ -1395,7 -1344,7 +1398,7 @@@ * Parse a unified diff fragment header of the * form "@@ -a,b +c,d @@" */ -static int parse_fragment_header(char *line, int len, struct fragment *fragment) +static int parse_fragment_header(const char *line, int len, struct fragment *fragment) { int offset; @@@ -1409,7 -1358,7 +1412,7 @@@ return offset; } -static int find_header(char *line, unsigned long size, int *hdrsize, struct patch *patch) +static int find_header(const char *line, unsigned long size, int *hdrsize, struct patch *patch) { unsigned long offset, len; @@@ -1438,7 -1387,7 +1441,7 @@@ struct fragment dummy; if (parse_fragment_header(line, len, &dummy) < 0) continue; - die("patch fragment without header at line %d: %.*s", + die(_("patch fragment without header at line %d: %.*s"), linenr, (int)len-1, line); } @@@ -1455,10 -1404,13 +1458,14 @@@ continue; if (!patch->old_name && !patch->new_name) { if (!patch->def_name) - die("git diff header lacks filename information when removing " - "%d leading pathname components (line %d)" , p_value, linenr); + die(Q_("git diff header lacks filename information when removing " + "%d leading pathname component (line %d)", + "git diff header lacks filename information when removing " + "%d leading pathname components (line %d)", + p_value), + p_value, linenr); - patch->old_name = patch->new_name = patch->def_name; + patch->old_name = xstrdup(patch->def_name); + patch->new_name = xstrdup(patch->def_name); } if (!patch->is_delete && !patch->new_name) die("git diff header lacks filename information " @@@ -1521,7 -1473,7 +1528,7 @@@ static void check_whitespace(const cha * between a "---" that is part of a patch, and a "---" that starts * the next patch is to look at the line counts.. */ -static int parse_fragment(char *line, unsigned long size, +static int parse_fragment(const char *line, unsigned long size, struct patch *patch, struct fragment *fragment) { int added, deleted; @@@ -1611,21 -1563,13 +1618,21 @@@ patch->lines_deleted += deleted; if (0 < patch->is_new && oldlines) - return error("new file depends on old contents"); + return error(_("new file depends on old contents")); if (0 < patch->is_delete && newlines) - return error("deleted file still has contents"); + return error(_("deleted file still has contents")); return offset; } -static int parse_single_patch(char *line, unsigned long size, struct patch *patch) +/* + * We have seen "diff --git a/... b/..." header (or a traditional patch + * header). Read hunks that belong to this patch into fragments and hang + * them to the given patch structure. + * + * The (fragment->patch, fragment->size) pair points into the memory given + * by the caller, not a copy, when we return. + */ +static int parse_single_patch(const char *line, unsigned long size, struct patch *patch) { unsigned long offset = 0; unsigned long oldlines = 0, newlines = 0, context = 0; @@@ -1639,7 -1583,7 +1646,7 @@@ fragment->linenr = linenr; len = parse_fragment(line, size, patch, fragment); if (len <= 0) - die("corrupt patch at line %d", linenr); + die(_("corrupt patch at line %d"), linenr); fragment->patch = line; fragment->size = len; oldlines += fragment->oldlines; @@@ -1675,12 -1619,14 +1682,14 @@@ patch->is_delete = 0; if (0 < patch->is_new && oldlines) - die("new file %s depends on old contents", patch->new_name); + die(_("new file %s depends on old contents"), patch->new_name); if (0 < patch->is_delete && newlines) - die("deleted file %s still has contents", patch->old_name); + die(_("deleted file %s still has contents"), patch->old_name); if (!patch->is_delete && !newlines && context) - fprintf(stderr, "** warning: file %s becomes empty but " - "is not deleted\n", patch->new_name); + fprintf_ln(stderr, + _("** warning: " + "file %s becomes empty but is not deleted"), + patch->new_name); return offset; } @@@ -1718,11 -1664,6 +1727,11 @@@ static char *inflate_it(const void *dat return out; } +/* + * Read a binary hunk and return a new fragment; fragment->patch + * points at an allocated memory that the caller must free, so + * it is marked as "->free_patch = 1". + */ static struct fragment *parse_binary_hunk(char **buf_p, unsigned long *sz_p, int *status_p, @@@ -1810,7 -1751,6 +1819,7 @@@ frag = xcalloc(1, sizeof(*frag)); frag->patch = inflate_it(data, hunk_size, origlen); + frag->free_patch = 1; if (!frag->patch) goto corrupt; free(data); @@@ -1824,7 -1764,7 +1833,7 @@@ corrupt: free(data); *status_p = -1; - error("corrupt binary patch at line %d: %.*s", + error(_("corrupt binary patch at line %d: %.*s"), linenr-1, llen-1, buffer); return NULL; } @@@ -1853,7 -1793,7 +1862,7 @@@ static int parse_binary(char *buffer, u forward = parse_binary_hunk(&buffer, &size, &status, &used); if (!forward && !status) /* there has to be one hunk (forward hunk) */ - return error("unrecognized binary patch at line %d", linenr-1); + return error(_("unrecognized binary patch at line %d"), linenr-1); if (status) /* otherwise we already gave an error message */ return status; @@@ -1876,13 -1816,6 +1885,13 @@@ return used; } +/* + * Read the patch text in "buffer" taht extends for "size" bytes; stop + * reading after seeing a single patch (i.e. changes to a single file). + * Create fragments (i.e. patch hunks) and hang them to the given patch. + * Return the number of bytes consumed, so that the caller can call us + * again for the next patch. + */ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch) { int hdrsize, patchsize; @@@ -1939,7 -1872,7 +1948,7 @@@ */ if ((apply || check) && (!patch->is_binary && !metadata_changes(patch))) - die("patch with only garbage at line %d", linenr); + die(_("patch with only garbage at line %d"), linenr); } return offset + hdrsize + patchsize; @@@ -2029,11 -1962,11 +2038,11 @@@ static int read_old_data(struct stat *s switch (st->st_mode & S_IFMT) { case S_IFLNK: if (strbuf_readlink(buf, path, st->st_size) < 0) - return error("unable to read symlink %s", path); + return error(_("unable to read symlink %s"), path); return 0; case S_IFREG: if (strbuf_read_file(buf, path, st->st_size) != st->st_size) - return error("unable to open or read %s", path); + return error(_("unable to open or read %s"), path); convert_to_git(path, buf->buf, buf->len, buf, 0); return 0; default: @@@ -2104,7 -2037,7 +2113,7 @@@ static void update_pre_post_images(stru ctx++; } if (preimage->nr <= ctx) - die("oops"); + die(_("oops")); /* and copy it in, while fixing the line length */ len = preimage->line[ctx].len; @@@ -2443,11 -2376,6 +2452,11 @@@ static void remove_last_line(struct ima img->len -= img->line[--img->nr].len; } +/* + * The change from "preimage" and "postimage" has been found to + * apply at applied_pos (counts in line numbers) in "img". + * Update "img" to remove "preimage" and replace it with "postimage". + */ static void update_image(struct image *img, int applied_pos, struct image *preimage, @@@ -2519,11 -2447,6 +2528,11 @@@ img->nr = nr; } +/* + * Use the patch-hunk text in "frag" to prepare two images (preimage and + * postimage) for the hunk. Find lines that match "preimage" in "img" and + * replace the part of "img" with "postimage" text. + */ static int apply_one_fragment(struct image *img, struct fragment *frag, int inaccurate_eof, unsigned ws_rule, int nth_fragment) @@@ -2626,7 -2549,7 +2635,7 @@@ break; default: if (apply_verbosely) - error("invalid start of line: '%c'", first); + error(_("invalid start of line: '%c'"), first); return -1; } if (added_blank_line) { @@@ -2743,9 -2666,11 +2752,11 @@@ int offset = applied_pos - pos; if (apply_in_reverse) offset = 0 - offset; - fprintf(stderr, - "Hunk #%d succeeded at %d (offset %d lines).\n", - nth_fragment, applied_pos + 1, offset); + fprintf_ln(stderr, + Q_("Hunk #%d succeeded at %d (offset %d line).", + "Hunk #%d succeeded at %d (offset %d lines).", + offset), + nth_fragment, applied_pos + 1, offset); } /* @@@ -2754,13 -2679,13 +2765,13 @@@ */ if ((leading != frag->leading) || (trailing != frag->trailing)) - fprintf(stderr, "Context reduced to (%ld/%ld)" - " to apply fragment at %d\n", - leading, trailing, applied_pos+1); + fprintf_ln(stderr, _("Context reduced to (%ld/%ld)" + " to apply fragment at %d"), + leading, trailing, applied_pos+1); update_image(img, applied_pos, &preimage, &postimage); } else { if (apply_verbosely) - error("while searching for:\n%.*s", + error(_("while searching for:\n%.*s"), (int)(old - oldlines), oldlines); } @@@ -2779,7 -2704,7 +2790,7 @@@ static int apply_binary_fragment(struc void *dst; if (!fragment) - return error("missing binary patch data for '%s'", + return error(_("missing binary patch data for '%s'"), patch->new_name ? patch->new_name : patch->old_name); @@@ -2814,12 -2739,6 +2825,12 @@@ return -1; } +/* + * Replace "img" with the result of applying the binary patch. + * The binary patch data itself in patch->fragment is still kept + * but the preimage prepared by the caller in "img" is freed here + * or in the helper function apply_binary_fragment() this calls. + */ static int apply_binary(struct image *img, struct patch *patch) { const char *name = patch->old_name ? patch->old_name : patch->new_name; @@@ -2882,13 -2801,13 +2893,13 @@@ * in the patch->fragments->{patch,size}. */ if (apply_binary_fragment(img, patch)) - return error("binary patch does not apply to '%s'", + return error(_("binary patch does not apply to '%s'"), name); /* verify that the result matches */ hash_sha1_file(img->buf, img->len, blob_type, sha1); if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix)) - return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)", + return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"), name, patch->new_sha1_prefix, sha1_to_hex(sha1)); } @@@ -2909,7 -2828,7 +2920,7 @@@ static int apply_fragments(struct imag while (frag) { nth++; if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule, nth)) { - error("patch failed: %s:%ld", name, frag->oldpos); + error(_("patch failed: %s:%ld"), name, frag->oldpos); if (!apply_with_reject) return -1; frag->rejected = 1; @@@ -3024,14 -2943,14 +3035,14 @@@ static int apply_data(struct patch *pat if (!(patch->is_copy || patch->is_rename) && (tpatch = in_fn_table(patch->old_name)) != NULL && !to_be_deleted(tpatch)) { if (was_deleted(tpatch)) { - return error("patch %s has been renamed/deleted", + return error(_("patch %s has been renamed/deleted"), patch->old_name); } - /* We have a patched copy in memory use that */ + /* We have a patched copy in memory; use that. */ strbuf_add(&buf, tpatch->result, tpatch->resultsize); } else if (cached) { if (read_file_or_gitlink(ce, &buf)) - return error("read of %s failed", patch->old_name); + return error(_("read of %s failed"), patch->old_name); } else if (patch->old_name) { if (S_ISGITLINK(patch->old_mode)) { if (ce) { @@@ -3040,15 -2959,12 +3051,15 @@@ /* * There is no way to apply subproject * patch without looking at the index. + * NEEDSWORK: shouldn't this be flagged + * as an error??? */ + free_fragment_list(patch->fragments); patch->fragments = NULL; } } else { if (read_old_data(st, patch->old_name, &buf)) - return error("read of %s failed", patch->old_name); + return error(_("read of %s failed"), patch->old_name); } } @@@ -3063,7 -2979,7 +3074,7 @@@ free(image.line_allocated); if (0 < patch->is_delete && patch->resultsize) - return error("removal patch leaves file contents"); + return error(_("removal patch leaves file contents")); return 0; } @@@ -3084,7 -3000,7 +3095,7 @@@ static int check_to_create_blob(const c if (has_symlink_leading_path(new_name, strlen(new_name))) return 0; - return error("%s: already exists in working directory", new_name); + return error(_("%s: already exists in working directory"), new_name); } else if ((errno != ENOENT) && (errno != ENOTDIR)) return error("%s: %s", new_name, strerror(errno)); @@@ -3122,12 -3038,12 +3133,12 @@@ static int check_preimage(struct patch if (!(patch->is_copy || patch->is_rename) && (tpatch = in_fn_table(old_name)) != NULL && !to_be_deleted(tpatch)) { if (was_deleted(tpatch)) - return error("%s: has been deleted/renamed", old_name); + return error(_("%s: has been deleted/renamed"), old_name); st_mode = tpatch->new_mode; } else if (!cached) { stat_ret = lstat(old_name, st); if (stat_ret && errno != ENOENT) - return error("%s: %s", old_name, strerror(errno)); + return error(_("%s: %s"), old_name, strerror(errno)); } if (to_be_deleted(tpatch)) @@@ -3138,7 -3054,7 +3149,7 @@@ if (pos < 0) { if (patch->is_new < 0) goto is_new; - return error("%s: does not exist in index", old_name); + return error(_("%s: does not exist in index"), old_name); } *ce = active_cache[pos]; if (stat_ret < 0) { @@@ -3152,13 -3068,13 +3163,13 @@@ return -1; } if (!cached && verify_index_match(*ce, st)) - return error("%s: does not match index", old_name); + return error(_("%s: does not match index"), old_name); if (cached) st_mode = (*ce)->ce_mode; } else if (stat_ret < 0) { if (patch->is_new < 0) goto is_new; - return error("%s: %s", old_name, strerror(errno)); + return error(_("%s: %s"), old_name, strerror(errno)); } if (!cached && !tpatch) @@@ -3169,9 -3085,9 +3180,9 @@@ if (!patch->old_mode) patch->old_mode = st_mode; if ((st_mode ^ patch->old_mode) & S_IFMT) - return error("%s: wrong type", old_name); + return error(_("%s: wrong type"), old_name); if (st_mode != patch->old_mode) - warning("%s has type %o, expected %o", + warning(_("%s has type %o, expected %o"), old_name, st_mode, patch->old_mode); if (!patch->new_mode && !patch->is_delete) patch->new_mode = st_mode; @@@ -3180,15 -3096,10 +3191,15 @@@ is_new: patch->is_new = 1; patch->is_delete = 0; + free(patch->old_name); patch->old_name = NULL; return 0; } +/* + * Check and apply the patch in-core; leave the result in patch->result + * for the caller to write it out to the final destination. + */ static int check_patch(struct patch *patch) { struct stat st; @@@ -3226,7 -3137,7 +3237,7 @@@ if (check_index && cache_name_pos(new_name, strlen(new_name)) >= 0 && !ok_if_exists) - return error("%s: already exists in index", new_name); + return error(_("%s: already exists in index"), new_name); if (!cached) { int err = check_to_create_blob(new_name, ok_if_exists); if (err) @@@ -3245,13 -3156,13 +3256,13 @@@ if (!patch->new_mode) patch->new_mode = patch->old_mode; if ((patch->old_mode ^ patch->new_mode) & S_IFMT) - return error("new mode (%o) of %s does not match old mode (%o)%s%s", + return error(_("new mode (%o) of %s does not match old mode (%o)%s%s"), patch->new_mode, new_name, patch->old_mode, same ? "" : " of ", same ? "" : old_name); } if (apply_data(patch, &st, ce) < 0) - return error("%s: patch does not apply", name); + return error(_("%s: patch does not apply"), name); patch->rejected = 0; return 0; } @@@ -3264,7 -3175,7 +3275,7 @@@ static int check_patch_list(struct patc while (patch) { if (apply_verbosely) say_patch_name(stderr, - "Checking patch ", patch, "...\n"); + _("Checking patch %s..."), patch); err |= check_patch(patch); patch = patch->next; } @@@ -3319,7 -3230,7 +3330,7 @@@ static void build_fake_ancestor(struct ce = make_cache_entry(patch->old_mode, sha1_ptr, name, 0, 0); if (!ce) - die("make_cache_entry failed for path '%s'", name); + die(_("make_cache_entry failed for path '%s'"), name); if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) die ("Could not add %s to temporary index", name); } @@@ -3462,7 -3373,7 +3473,7 @@@ static void remove_file(struct patch *p { if (update_index) { if (remove_file_from_cache(patch->old_name) < 0) - die("unable to remove %s from index", patch->old_name); + die(_("unable to remove %s from index"), patch->old_name); } if (!cached) { if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) { @@@ -3489,19 -3400,19 +3500,19 @@@ static void add_index_file(const char * const char *s = buf; if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1)) - die("corrupt patch for subproject %s", path); + die(_("corrupt patch for subproject %s"), path); } else { if (!cached) { if (lstat(path, &st) < 0) - die_errno("unable to stat newly created file '%s'", + die_errno(_("unable to stat newly created file '%s'"), path); fill_stat_cache_info(ce, &st); } if (write_sha1_file(buf, size, blob_type, ce->sha1) < 0) - die("unable to create backing store for newly created file %s", path); + die(_("unable to create backing store for newly created file %s"), path); } if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) - die("unable to add cache entry for %s", path); + die(_("unable to add cache entry for %s"), path); } static int try_create_file(const char *path, unsigned int mode, const char *buf, unsigned long size) @@@ -3534,7 -3445,7 +3545,7 @@@ strbuf_release(&nbuf); if (close(fd) < 0) - die_errno("closing file '%s'", path); + die_errno(_("closing file '%s'"), path); return 0; } @@@ -3583,7 -3494,7 +3594,7 @@@ static void create_one_file(char *path ++nr; } } - die_errno("unable to write file '%s' mode %o", path, mode); + die_errno(_("unable to write file '%s' mode %o"), path, mode); } static void create_file(struct patch *patch) @@@ -3628,6 -3539,7 +3639,7 @@@ static int write_out_one_reject(struct char namebuf[PATH_MAX]; struct fragment *frag; int cnt = 0; + struct strbuf sb = STRBUF_INIT; for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) { if (!frag->rejected) @@@ -3638,7 -3550,7 +3650,7 @@@ if (!cnt) { if (apply_verbosely) say_patch_name(stderr, - "Applied patch ", patch, " cleanly.\n"); + _("Applied patch %s cleanly."), patch); return 0; } @@@ -3646,16 -3558,20 +3658,20 @@@ * contents are marked "rejected" at the patch level. */ if (!patch->new_name) - die("internal error"); + die(_("internal error")); /* Say this even without --verbose */ - say_patch_name(stderr, "Applying patch ", patch, " with"); - fprintf(stderr, " %d rejects...\n", cnt); + strbuf_addf(&sb, Q_("Applying patch %%s with %d reject...", + "Applying patch %%s with %d rejects...", + cnt), + cnt); + say_patch_name(stderr, sb.buf, patch); + strbuf_release(&sb); cnt = strlen(patch->new_name); if (ARRAY_SIZE(namebuf) <= cnt + 5) { cnt = ARRAY_SIZE(namebuf) - 5; - warning("truncating .rej filename to %.*s.rej", + warning(_("truncating .rej filename to %.*s.rej"), cnt - 1, patch->new_name); } memcpy(namebuf, patch->new_name, cnt); @@@ -3663,7 -3579,7 +3679,7 @@@ rej = fopen(namebuf, "w"); if (!rej) - return error("cannot open %s: %s", namebuf, strerror(errno)); + return error(_("cannot open %s: %s"), namebuf, strerror(errno)); /* Normal git tools never deal with .rej, so do not pretend * this is a git patch by saying --git nor give extended @@@ -3676,10 -3592,10 +3692,10 @@@ frag; cnt++, frag = frag->next) { if (!frag->rejected) { - fprintf(stderr, "Hunk #%d applied cleanly.\n", cnt); + fprintf_ln(stderr, _("Hunk #%d applied cleanly."), cnt); continue; } - fprintf(stderr, "Rejected hunk #%d.\n", cnt); + fprintf_ln(stderr, _("Rejected hunk #%d."), cnt); fprintf(rej, "%.*s", frag->size, frag->patch); if (frag->patch[frag->size-1] != '\n') fputc('\n', rej); @@@ -3765,8 -3681,15 +3781,8 @@@ static void prefix_patches(struct patc if (!prefix || p->is_toplevel_relative) return; for ( ; p; p = p->next) { - if (p->new_name == p->old_name) { - char *prefixed = p->new_name; - prefix_one(&prefixed); - p->new_name = p->old_name = prefixed; - } - else { - prefix_one(&p->new_name); - prefix_one(&p->old_name); - } + prefix_one(&p->new_name); + prefix_one(&p->old_name); } } @@@ -3776,10 -3699,12 +3792,10 @@@ static int apply_patch(int fd, const char *filename, int options) { size_t offset; - struct strbuf buf = STRBUF_INIT; + struct strbuf buf = STRBUF_INIT; /* owns the patch text */ struct patch *list = NULL, **listp = &list; int skipped_patch = 0; - /* FIXME - memory leak when using multiple patch files as inputs */ - memset(&fn_table, 0, sizeof(struct string_list)); patch_input_file = filename; read_patch_file(&buf, fd); offset = 0; @@@ -3803,14 -3728,15 +3819,14 @@@ listp = &patch->next; } else { - /* perhaps free it a bit better? */ - free(patch); + free_patch(patch); skipped_patch++; } offset += nr; } if (!list && !skipped_patch) - die("unrecognized input"); + die(_("unrecognized input")); if (whitespace_error && (ws_error_action == die_on_ws_error)) apply = 0; @@@ -3821,7 -3747,7 +3837,7 @@@ if (check_index) { if (read_cache() < 0) - die("unable to read index file"); + die(_("unable to read index file")); } if ((check || apply) && @@@ -3844,9 -3770,7 +3860,9 @@@ if (summary) summary_patch_list(list); + free_patch_list(list); strbuf_release(&buf); + string_list_clear(&fn_table, 0); return 0; } @@@ -4016,10 -3940,10 +4032,10 @@@ int cmd_apply(int argc, const char **ar if (!force_apply && (diffstat || numstat || summary || check || fake_ancestor)) apply = 0; if (check_index && is_not_gitdir) - die("--index outside a repository"); + die(_("--index outside a repository")); if (cached) { if (is_not_gitdir) - die("--cached outside a repository"); + die(_("--cached outside a repository")); check_index = 1; } for (i = 0; i < argc; i++) { @@@ -4035,7 -3959,7 +4051,7 @@@ fd = open(arg, O_RDONLY); if (fd < 0) - die_errno("can't open patch '%s'", arg); + die_errno(_("can't open patch '%s'"), arg); read_stdin = 0; set_default_whitespace_mode(whitespace_option); errs |= apply_patch(fd, arg, options); @@@ -4049,32 -3973,32 +4065,32 @@@ squelch_whitespace_errors < whitespace_error) { int squelched = whitespace_error - squelch_whitespace_errors; - warning("squelched %d " - "whitespace error%s", - squelched, - squelched == 1 ? "" : "s"); + warning(Q_("squelched %d whitespace error", + "squelched %d whitespace errors", + squelched), + squelched); } if (ws_error_action == die_on_ws_error) - die("%d line%s add%s whitespace errors.", - whitespace_error, - whitespace_error == 1 ? "" : "s", - whitespace_error == 1 ? "s" : ""); + die(Q_("%d line adds whitespace errors.", + "%d lines add whitespace errors.", + whitespace_error), + whitespace_error); if (applied_after_fixing_ws && apply) warning("%d line%s applied after" " fixing whitespace errors.", applied_after_fixing_ws, applied_after_fixing_ws == 1 ? "" : "s"); else if (whitespace_error) - warning("%d line%s add%s whitespace errors.", - whitespace_error, - whitespace_error == 1 ? "" : "s", - whitespace_error == 1 ? "s" : ""); + warning(Q_("%d line adds whitespace errors.", + "%d lines add whitespace errors.", + whitespace_error), + whitespace_error); } if (update_index) { if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) - die("Unable to write new index file"); + die(_("Unable to write new index file")); } return !!errs; diff --combined builtin/fetch.c index 1c8cb62445,a8c3e4ceb8..bb9a0743ff --- a/builtin/fetch.c +++ b/builtin/fetch.c @@@ -240,7 -240,6 +240,7 @@@ static int s_update_ref(const char *act static int update_local_ref(struct ref *ref, const char *remote, + const struct ref *remote_ref, struct strbuf *display) { struct commit *current = NULL, *updated; @@@ -294,26 -293,18 +294,26 @@@ const char *msg; const char *what; int r; - if (!strncmp(ref->name, "refs/tags/", 10)) { + /* + * Nicely describe the new ref we're fetching. + * Base this on the remote's ref name, as it's + * more likely to follow a standard layout. + */ + const char *name = remote_ref ? remote_ref->name : ""; + if (!prefixcmp(name, "refs/tags/")) { msg = "storing tag"; what = _("[new tag]"); - } - else { + } else if (!prefixcmp(name, "refs/heads/")) { msg = "storing head"; what = _("[new branch]"); - if ((recurse_submodules != RECURSE_SUBMODULES_OFF) && - (recurse_submodules != RECURSE_SUBMODULES_ON)) - check_for_new_submodule_commits(ref->new_sha1); + } else { + msg = "storing ref"; + what = _("[new ref]"); } + if ((recurse_submodules != RECURSE_SUBMODULES_OFF) && + (recurse_submodules != RECURSE_SUBMODULES_ON)) + check_for_new_submodule_commits(ref->new_sha1); r = s_update_ref(msg, ref, 0); strbuf_addf(display, "%c %-*s %-*s -> %s%s", r ? '!' : '*', @@@ -475,7 -466,7 +475,7 @@@ static int store_updated_refs(const cha strbuf_reset(¬e); if (ref) { - rc |= update_local_ref(ref, what, ¬e); + rc |= update_local_ref(ref, what, rm, ¬e); free(ref); } else strbuf_addf(¬e, "* %-*s %-*s -> FETCH_HEAD", @@@ -546,8 -537,8 +546,8 @@@ static int prune_refs(struct refspec *r int result = 0; struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map); const char *dangling_msg = dry_run - ? _(" (%s will become dangling)\n") - : _(" (%s has become dangling)\n"); + ? _(" (%s will become dangling)") + : _(" (%s has become dangling)"); for (ref = stale_refs; ref; ref = ref->next) { if (!dry_run) diff --combined builtin/remote.c index b5645fe0ae,51434fa5f3..0f0c594b2f --- a/builtin/remote.c +++ b/builtin/remote.c @@@ -9,7 -9,7 +9,7 @@@ static const char * const builtin_remote_usage[] = { "git remote [-v | --verbose]", - "git remote add [-t ] [-m ] [-f] [--mirror=] ", + "git remote add [-t ] [-m ] [-f] [--tags|--no-tags] [--mirror=] ", "git remote rename ", "git remote rm ", "git remote set-head (-a | -d | )", @@@ -17,7 -17,7 +17,7 @@@ "git remote prune [-n | --dry-run] ", "git remote [-v | --verbose] update [-p | --prune] [( | )...]", "git remote set-branches [--add] ...", - "git remote set-url []", + "git remote set-url [--push] []", "git remote set-url --add ", "git remote set-url --delete ", NULL @@@ -95,9 -95,9 +95,9 @@@ static int fetch_remote(const char *nam argv[1] = "-v"; argv[2] = name; } - printf("Updating %s\n", name); + printf_ln(_("Updating %s"), name); if (run_command_v_opt(argv, RUN_GIT_CMD)) - return error("Could not fetch %s", name); + return error(_("Could not fetch %s"), name); return 0; } @@@ -127,8 -127,8 +127,8 @@@ static int add_branch(const char *key, } static const char mirror_advice[] = - "--mirror is dangerous and deprecated; please\n" - "\t use --mirror=fetch or --mirror=push instead"; + N_("--mirror is dangerous and deprecated; please\n" + "\t use --mirror=fetch or --mirror=push instead"); static int parse_mirror_opt(const struct option *opt, const char *arg, int not) { @@@ -136,7 -136,7 +136,7 @@@ if (not) *mirror = MIRROR_NONE; else if (!arg) { - warning("%s", mirror_advice); + warning("%s", _(mirror_advice)); *mirror = MIRROR_BOTH; } else if (!strcmp(arg, "fetch")) @@@ -144,7 -144,7 +144,7 @@@ else if (!strcmp(arg, "push")) *mirror = MIRROR_PUSH; else - return error("unknown mirror argument: %s", arg); + return error(_("unknown mirror argument: %s"), arg); return 0; } @@@ -182,9 -182,9 +182,9 @@@ static int add(int argc, const char **a usage_with_options(builtin_remote_add_usage, options); if (mirror && master) - die("specifying a master branch makes no sense with --mirror"); + die(_("specifying a master branch makes no sense with --mirror")); if (mirror && !(mirror & MIRROR_FETCH) && track.nr) - die("specifying branches to track makes sense only with fetch mirrors"); + die(_("specifying branches to track makes sense only with fetch mirrors")); name = argv[0]; url = argv[1]; @@@ -192,11 -192,11 +192,11 @@@ remote = remote_get(name); if (remote && (remote->url_nr > 1 || strcmp(name, remote->url[0]) || remote->fetch_refspec_nr)) - die("remote %s already exists.", name); + die(_("remote %s already exists."), name); strbuf_addf(&buf2, "refs/heads/test:refs/remotes/%s/test", name); if (!valid_fetch_refspec(buf2.buf)) - die("'%s' is not a valid remote name", name); + die(_("'%s' is not a valid remote name"), name); strbuf_addf(&buf, "remote.%s.url", name); if (git_config_set(buf.buf, url)) @@@ -240,7 -240,7 +240,7 @@@ strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master); if (create_symref(buf.buf, buf2.buf, "remote add")) - return error("Could not setup master '%s'", master); + return error(_("Could not setup master '%s'"), master); } strbuf_release(&buf); @@@ -296,7 -296,7 +296,7 @@@ static int config_read_branches(const c info = item->util; if (type == REMOTE) { if (info->remote_name) - warning("more than one %s", orig_key); + warning(_("more than one %s"), orig_key); info->remote_name = xstrdup(value); } else if (type == MERGE) { char *space = strchr(value, ' '); @@@ -336,7 -336,7 +336,7 @@@ static int get_ref_states(const struct for (i = 0; i < states->remote->fetch_refspec_nr; i++) if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1)) - die("Could not get fetch map for refspec %s", + die(_("Could not get fetch map for refspec %s"), states->remote->fetch_refspec[i]); states->new.strdup_strings = 1; @@@ -437,7 -437,7 +437,7 @@@ static int get_push_ref_states_noquery( states->push.strdup_strings = 1; if (!remote->push_refspec_nr) { - item = string_list_append(&states->push, "(matching)"); + item = string_list_append(&states->push, _("(matching)")); info = item->util = xcalloc(sizeof(struct push_info), 1); info->status = PUSH_STATUS_NOTQUERIED; info->dest = xstrdup(item->string); @@@ -445,11 -445,11 +445,11 @@@ for (i = 0; i < remote->push_refspec_nr; i++) { struct refspec *spec = remote->push + i; if (spec->matching) - item = string_list_append(&states->push, "(matching)"); + item = string_list_append(&states->push, _("(matching)")); else if (strlen(spec->src)) item = string_list_append(&states->push, spec->src); else - item = string_list_append(&states->push, "(delete)"); + item = string_list_append(&states->push, _("(delete)")); info = item->util = xcalloc(sizeof(struct push_info), 1); info->forced = spec->force; @@@ -592,19 -592,19 +592,19 @@@ static int migrate_file(struct remote * strbuf_addf(&buf, "remote.%s.url", remote->name); for (i = 0; i < remote->url_nr; i++) if (git_config_set_multivar(buf.buf, remote->url[i], "^$", 0)) - return error("Could not append '%s' to '%s'", + return error(_("Could not append '%s' to '%s'"), remote->url[i], buf.buf); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.push", remote->name); for (i = 0; i < remote->push_refspec_nr; i++) if (git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0)) - return error("Could not append '%s' to '%s'", + return error(_("Could not append '%s' to '%s'"), remote->push_refspec[i], buf.buf); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.fetch", remote->name); for (i = 0; i < remote->fetch_refspec_nr; i++) if (git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0)) - return error("Could not append '%s' to '%s'", + return error(_("Could not append '%s' to '%s'"), remote->fetch_refspec[i], buf.buf); if (remote->origin == REMOTE_REMOTES) path = git_path("remotes/%s", remote->name); @@@ -636,30 -636,30 +636,30 @@@ static int mv(int argc, const char **ar oldremote = remote_get(rename.old); if (!oldremote) - die("No such remote: %s", rename.old); + die(_("No such remote: %s"), rename.old); if (!strcmp(rename.old, rename.new) && oldremote->origin != REMOTE_CONFIG) return migrate_file(oldremote); newremote = remote_get(rename.new); if (newremote && (newremote->url_nr > 1 || newremote->fetch_refspec_nr)) - die("remote %s already exists.", rename.new); + die(_("remote %s already exists."), rename.new); strbuf_addf(&buf, "refs/heads/test:refs/remotes/%s/test", rename.new); if (!valid_fetch_refspec(buf.buf)) - die("'%s' is not a valid remote name", rename.new); + die(_("'%s' is not a valid remote name"), rename.new); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s", rename.old); strbuf_addf(&buf2, "remote.%s", rename.new); if (git_config_rename_section(buf.buf, buf2.buf) < 1) - return error("Could not rename config section '%s' to '%s'", + return error(_("Could not rename config section '%s' to '%s'"), buf.buf, buf2.buf); strbuf_reset(&buf); strbuf_addf(&buf, "remote.%s.fetch", rename.new); if (git_config_set_multivar(buf.buf, NULL, NULL, 1)) - return error("Could not remove config section '%s'", buf.buf); + return error(_("Could not remove config section '%s'"), buf.buf); strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old); for (i = 0; i < oldremote->fetch_refspec_nr; i++) { char *ptr; @@@ -674,13 -674,13 +674,13 @@@ strlen(rename.old), rename.new, strlen(rename.new)); } else - warning("Not updating non-default fetch respec\n" - "\t%s\n" - "\tPlease update the configuration manually if necessary.", + warning(_("Not updating non-default fetch respec\n" + "\t%s\n" + "\tPlease update the configuration manually if necessary."), buf2.buf); if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0)) - return error("Could not append '%s'", buf.buf); + return error(_("Could not append '%s'"), buf.buf); } read_branches(); @@@ -691,7 -691,7 +691,7 @@@ strbuf_reset(&buf); strbuf_addf(&buf, "branch.%s.remote", item->string); if (git_config_set(buf.buf, rename.new)) { - return error("Could not set '%s'", buf.buf); + return error(_("Could not set '%s'"), buf.buf); } } } @@@ -713,7 -713,7 +713,7 @@@ if (!(flag & REF_ISSYMREF)) continue; if (delete_ref(item->string, NULL, REF_NODEREF)) - die("deleting '%s' failed", item->string); + die(_("deleting '%s' failed"), item->string); } for (i = 0; i < remote_branches.nr; i++) { struct string_list_item *item = remote_branches.items + i; @@@ -728,7 -728,7 +728,7 @@@ strbuf_addf(&buf2, "remote: renamed %s to %s", item->string, buf.buf); if (rename_ref(item->string, buf.buf, buf2.buf)) - die("renaming '%s' failed", item->string); + die(_("renaming '%s' failed"), item->string); } for (i = 0; i < remote_branches.nr; i++) { struct string_list_item *item = remote_branches.items + i; @@@ -747,7 -747,7 +747,7 @@@ strbuf_addf(&buf3, "remote: renamed %s to %s", item->string, buf.buf); if (create_symref(buf.buf, buf2.buf, buf3.buf)) - die("creating '%s' failed", buf.buf); + die(_("creating '%s' failed"), buf.buf); } return 0; } @@@ -761,7 -761,7 +761,7 @@@ static int remove_branches(struct strin unsigned char *sha1 = item->util; if (delete_ref(refname, sha1, 0)) - result |= error("Could not remove branch %s", refname); + result |= error(_("Could not remove branch %s"), refname); } return result; } @@@ -789,14 -789,14 +789,14 @@@ static int rm(int argc, const char **ar remote = remote_get(argv[1]); if (!remote) - die("No such remote: %s", argv[1]); + die(_("No such remote: %s"), argv[1]); known_remotes.to_delete = remote; for_each_remote(add_known_remote, &known_remotes); strbuf_addf(&buf, "remote.%s", remote->name); if (git_config_rename_section(buf.buf, NULL) < 1) - return error("Could not remove config section '%s'", buf.buf); + return error(_("Could not remove config section '%s'"), buf.buf); read_branches(); for (i = 0; i < branch_list.nr; i++) { @@@ -830,11 -830,12 +830,12 @@@ string_list_clear(&branches, 1); if (skipped.nr) { - fprintf(stderr, skipped.nr == 1 ? - "Note: A branch outside the refs/remotes/ hierarchy was not removed;\n" - "to delete it, use:\n" : - "Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n" - "to delete them, use:\n"); + fprintf_ln(stderr, + Q_("Note: A branch outside the refs/remotes/ hierarchy was not removed;\n" + "to delete it, use:", + "Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n" + "to delete them, use:", + skipped.nr)); for (i = 0; i < skipped.nr; i++) fprintf(stderr, " git branch -d %s\n", skipped.items[i].string); @@@ -886,7 -887,7 +887,7 @@@ static int get_remote_ref_states(const states->remote = remote_get(name); if (!states->remote) - return error("No such remote: %s", name); + return error(_("No such remote: %s"), name); read_branches(); @@@ -939,14 -940,14 +940,14 @@@ static int show_remote_info_item(struc const char *fmt = "%s"; const char *arg = ""; if (string_list_has_string(&states->new, name)) { - fmt = " new (next fetch will store in remotes/%s)"; + fmt = _(" new (next fetch will store in remotes/%s)"); arg = states->remote->name; } else if (string_list_has_string(&states->tracked, name)) - arg = " tracked"; + arg = _(" tracked"); else if (string_list_has_string(&states->stale, name)) - arg = " stale (use 'git remote prune' to remove)"; + arg = _(" stale (use 'git remote prune' to remove)"); else - arg = " ???"; + arg = _(" ???"); printf(" %-*s", info->width, name); printf(fmt, arg); printf("\n"); @@@ -987,21 -988,21 +988,21 @@@ static int show_local_info_item(struct int i; if (branch_info->rebase && branch_info->merge.nr > 1) { - error("invalid branch.%s.merge; cannot rebase onto > 1 branch", + error(_("invalid branch.%s.merge; cannot rebase onto > 1 branch"), item->string); return 0; } printf(" %-*s ", show_info->width, item->string); if (branch_info->rebase) { - printf("rebases onto remote %s\n", merge->items[0].string); + printf_ln(_("rebases onto remote %s"), merge->items[0].string); return 0; } else if (show_info->any_rebase) { - printf(" merges with remote %s\n", merge->items[0].string); - also = " and with remote"; + printf_ln(_(" merges with remote %s"), merge->items[0].string); + also = _(" and with remote"); } else { - printf("merges with remote %s\n", merge->items[0].string); - also = " and with remote"; + printf_ln(_("merges with remote %s"), merge->items[0].string); + also = _(" and with remote"); } for (i = 1; i < merge->nr; i++) printf(" %-*s %s %s\n", show_info->width, "", also, @@@ -1043,36 -1044,43 +1044,43 @@@ static int show_push_info_item(struct s { struct show_info *show_info = cb_data; struct push_info *push_info = item->util; - char *src = item->string, *status = NULL; + const char *src = item->string, *status = NULL; switch (push_info->status) { case PUSH_STATUS_CREATE: - status = "create"; + status = _("create"); break; case PUSH_STATUS_DELETE: - status = "delete"; - src = "(none)"; + status = _("delete"); + src = _("(none)"); break; case PUSH_STATUS_UPTODATE: - status = "up to date"; + status = _("up to date"); break; case PUSH_STATUS_FASTFORWARD: - status = "fast-forwardable"; + status = _("fast-forwardable"); break; case PUSH_STATUS_OUTOFDATE: - status = "local out of date"; + status = _("local out of date"); break; case PUSH_STATUS_NOTQUERIED: break; } - if (status) - printf(" %-*s %s to %-*s (%s)\n", show_info->width, src, - push_info->forced ? "forces" : "pushes", - show_info->width2, push_info->dest, status); - else - printf(" %-*s %s to %s\n", show_info->width, src, - push_info->forced ? "forces" : "pushes", - push_info->dest); + if (status) { + if (push_info->forced) + printf_ln(_(" %-*s forces to %-*s (%s)"), show_info->width, src, + show_info->width2, push_info->dest, status); + else + printf_ln(_(" %-*s pushes to %-*s (%s)"), show_info->width, src, + show_info->width2, push_info->dest, status); + } else { + if (push_info->forced) + printf_ln(_(" %-*s forces to %s"), show_info->width, src, + push_info->dest); + else + printf_ln(_(" %-*s pushes to %s"), show_info->width, src, + push_info->dest); + } return 0; } @@@ -1107,9 -1115,9 +1115,9 @@@ static int show(int argc, const char ** get_remote_ref_states(*argv, &states, query_flag); - printf("* remote %s\n", *argv); - printf(" Fetch URL: %s\n", states.remote->url_nr > 0 ? - states.remote->url[0] : "(no URL)"); + printf_ln(_("* remote %s"), *argv); + printf_ln(_(" Fetch URL: %s"), states.remote->url_nr > 0 ? + states.remote->url[0] : _("(no URL)")); if (states.remote->pushurl_nr) { url = states.remote->pushurl; url_nr = states.remote->pushurl_nr; @@@ -1118,18 -1126,18 +1126,18 @@@ url_nr = states.remote->url_nr; } for (i = 0; i < url_nr; i++) - printf(" Push URL: %s\n", url[i]); + printf_ln(_(" Push URL: %s"), url[i]); if (!i) - printf(" Push URL: %s\n", "(no URL)"); + printf_ln(_(" Push URL: %s"), "(no URL)"); if (no_query) - printf(" HEAD branch: (not queried)\n"); + printf_ln(_(" HEAD branch: %s"), "(not queried)"); else if (!states.heads.nr) - printf(" HEAD branch: (unknown)\n"); + printf_ln(_(" HEAD branch: %s"), "(unknown)"); else if (states.heads.nr == 1) - printf(" HEAD branch: %s\n", states.heads.items[0].string); + printf_ln(_(" HEAD branch: %s"), states.heads.items[0].string); else { - printf(" HEAD branch (remote HEAD is ambiguous," - " may be one of the following):\n"); + printf(_(" HEAD branch (remote HEAD is ambiguous," + " may be one of the following):\n")); for (i = 0; i < states.heads.nr; i++) printf(" %s\n", states.heads.items[i].string); } @@@ -1140,9 -1148,10 +1148,10 @@@ for_each_string_list(&states.tracked, add_remote_to_show_info, &info); for_each_string_list(&states.stale, add_remote_to_show_info, &info); if (info.list->nr) - printf(" Remote branch%s:%s\n", - info.list->nr > 1 ? "es" : "", - no_query ? " (status not queried)" : ""); + printf_ln(Q_(" Remote branch:%s", + " Remote branches:%s", + info.list->nr), + no_query ? _(" (status not queried)") : ""); for_each_string_list(info.list, show_remote_info_item, &info); string_list_clear(info.list, 0); @@@ -1151,23 -1160,25 +1160,25 @@@ info.any_rebase = 0; for_each_string_list(&branch_list, add_local_to_show_info, &info); if (info.list->nr) - printf(" Local branch%s configured for 'git pull':\n", - info.list->nr > 1 ? "es" : ""); + printf_ln(Q_(" Local branch configured for 'git pull':", + " Local branches configured for 'git pull':", + info.list->nr)); for_each_string_list(info.list, show_local_info_item, &info); string_list_clear(info.list, 0); /* git push info */ if (states.remote->mirror) - printf(" Local refs will be mirrored by 'git push'\n"); + printf_ln(_(" Local refs will be mirrored by 'git push'")); info.width = info.width2 = 0; for_each_string_list(&states.push, add_push_to_show_info, &info); qsort(info.list->items, info.list->nr, sizeof(*info.list->items), cmp_string_with_push); if (info.list->nr) - printf(" Local ref%s configured for 'git push'%s:\n", - info.list->nr > 1 ? "s" : "", - no_query ? " (status not queried)" : ""); + printf_ln(Q_(" Local ref configured for 'git push'%s:", + " Local refs configured for 'git push'%s:", + info.list->nr), + no_query ? _(" (status not queried)") : ""); for_each_string_list(info.list, show_push_info_item, &info); string_list_clear(info.list, 0); @@@ -1202,10 -1213,10 +1213,10 @@@ static int set_head(int argc, const cha memset(&states, 0, sizeof(states)); get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES); if (!states.heads.nr) - result |= error("Cannot determine remote HEAD"); + result |= error(_("Cannot determine remote HEAD")); else if (states.heads.nr > 1) { - result |= error("Multiple remote HEAD branches. " - "Please choose one explicitly with:"); + result |= error(_("Multiple remote HEAD branches. " + "Please choose one explicitly with:")); for (i = 0; i < states.heads.nr; i++) fprintf(stderr, " git remote set-head %s %s\n", argv[0], states.heads.items[i].string); @@@ -1214,7 -1225,7 +1225,7 @@@ free_remote_ref_states(&states); } else if (opt_d && !opt_a && argc == 1) { if (delete_ref(buf.buf, NULL, REF_NODEREF)) - result |= error("Could not delete %s", buf.buf); + result |= error(_("Could not delete %s"), buf.buf); } else usage_with_options(builtin_remote_sethead_usage, options); @@@ -1222,9 -1233,9 +1233,9 @@@ strbuf_addf(&buf2, "refs/remotes/%s/%s", argv[0], head_name); /* make sure it's valid */ if (!ref_exists(buf2.buf)) - result |= error("Not a valid ref: %s", buf2.buf); + result |= error(_("Not a valid ref: %s"), buf2.buf); else if (create_symref(buf.buf, buf2.buf, "remote set-head")) - result |= error("Could not setup %s", buf.buf); + result |= error(_("Could not setup %s"), buf.buf); if (opt_a) printf("%s/HEAD set to %s\n", argv[0], head_name); free(head_name); @@@ -1260,18 -1271,18 +1271,18 @@@ static int prune_remote(const char *rem int result = 0, i; struct ref_states states; const char *dangling_msg = dry_run - ? " %s will become dangling!\n" - : " %s has become dangling!\n"; + ? _(" %s will become dangling!") + : _(" %s has become dangling!"); memset(&states, 0, sizeof(states)); get_remote_ref_states(remote, &states, GET_REF_STATES); if (states.stale.nr) { - printf("Pruning %s\n", remote); - printf("URL: %s\n", + printf_ln(_("Pruning %s"), remote); + printf_ln(_("URL: %s"), states.remote->url_nr ? states.remote->url[0] - : "(no URL)"); + : _("(no URL)")); } for (i = 0; i < states.stale.nr; i++) { @@@ -1280,8 -1291,12 +1291,12 @@@ if (!dry_run) result |= delete_ref(refname, NULL, 0); - printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned", - abbrev_ref(refname, "refs/remotes/")); + if (dry_run) + printf_ln(_(" * [would prune] %s"), + abbrev_ref(refname, "refs/remotes/")); + else + printf_ln(_(" * [pruned] %s"), + abbrev_ref(refname, "refs/remotes/")); warn_dangling_symref(stdout, dangling_msg, refname); } @@@ -1369,7 -1384,7 +1384,7 @@@ static int set_remote_branches(const ch strbuf_addf(&key, "remote.%s.fetch", remotename); if (!remote_is_configured(remotename)) - die("No such remote '%s'", remotename); + die(_("No such remote '%s'"), remotename); remote = remote_get(remotename); if (!add_mode && remove_all_fetch_refspecs(remotename, key.buf)) { @@@ -1396,7 -1411,7 +1411,7 @@@ static int set_branches(int argc, cons argc = parse_options(argc, argv, NULL, options, builtin_remote_setbranches_usage, 0); if (argc == 0) { - error("no remote specified"); + error(_("no remote specified")); usage_with_options(builtin_remote_setbranches_usage, options); } argv[argc] = NULL; @@@ -1429,7 -1444,7 +1444,7 @@@ static int set_url(int argc, const cha PARSE_OPT_KEEP_ARGV0); if (add_mode && delete_mode) - die("--add --delete doesn't make sense"); + die(_("--add --delete doesn't make sense")); if (argc < 3 || argc > 4 || ((add_mode || delete_mode) && argc != 3)) usage_with_options(builtin_remote_seturl_usage, options); @@@ -1443,7 -1458,7 +1458,7 @@@ oldurl = newurl; if (!remote_is_configured(remotename)) - die("No such remote '%s'", remotename); + die(_("No such remote '%s'"), remotename); remote = remote_get(remotename); if (push_mode) { @@@ -1469,7 -1484,7 +1484,7 @@@ /* Old URL specified. Demand that one matches. */ if (regcomp(&old_regex, oldurl, REG_EXTENDED)) - die("Invalid old URL pattern: %s", oldurl); + die(_("Invalid old URL pattern: %s"), oldurl); for (i = 0; i < urlset_nr; i++) if (!regexec(&old_regex, urlset[i], 0, NULL, 0)) @@@ -1477,9 -1492,9 +1492,9 @@@ else negative_matches++; if (!delete_mode && !matches) - die("No such URL found: %s", oldurl); + die(_("No such URL found: %s"), oldurl); if (delete_mode && !negative_matches && !push_mode) - die("Will not delete all non-push URLs"); + die(_("Will not delete all non-push URLs")); regfree(&old_regex); @@@ -1580,7 -1595,7 +1595,7 @@@ int cmd_remote(int argc, const char **a else if (!strcmp(argv[0], "update")) result = update(argc, argv); else { - error("Unknown subcommand: %s", argv[0]); + error(_("Unknown subcommand: %s"), argv[0]); usage_with_options(builtin_remote_usage, options); } diff --combined bundle.c index 27ab32e431,6d21c77421..8d31b98f58 --- a/bundle.c +++ b/bundle.c @@@ -33,7 -33,7 +33,7 @@@ static int parse_bundle_header(int fd, if (strbuf_getwholeline_fd(&buf, fd, '\n') || strcmp(buf.buf, bundle_signature)) { if (report_path) - error("'%s' does not look like a v2 bundle file", + error(_("'%s' does not look like a v2 bundle file"), report_path); status = -1; goto abort; @@@ -60,7 -60,7 +60,7 @@@ (40 <= buf.len && !isspace(buf.buf[40])) || (!is_prereq && buf.len <= 40)) { if (report_path) - error("unrecognized header: %s%s (%d)", + error(_("unrecognized header: %s%s (%d)"), (is_prereq ? "-" : ""), buf.buf, (int)buf.len); status = -1; break; @@@ -86,7 -86,7 +86,7 @@@ int read_bundle_header(const char *path int fd = open(path, O_RDONLY); if (fd < 0) - return error("could not open '%s'", path); + return error(_("could not open '%s'"), path); return parse_bundle_header(fd, header, path); } @@@ -137,7 -137,7 +137,7 @@@ int verify_bundle(struct bundle_header struct object_array refs; struct commit *commit; int i, ret = 0, req_nr; - const char *message = "Repository lacks these prerequisite commits:"; + const char *message = _("Repository lacks these prerequisite commits:"); init_revisions(&revs, NULL); for (i = 0; i < p->nr; i++) { @@@ -161,7 -161,7 +161,7 @@@ revs.leak_pending = 1; if (prepare_revision_walk(&revs)) - die("revision walk setup failed"); + die(_("revision walk setup failed")); i = req_nr; while (i && (commit = get_revision(&revs))) @@@ -183,12 -183,16 +183,16 @@@ struct ref_list *r; r = &header->references; - printf("The bundle contains %d ref%s\n", - r->nr, (1 < r->nr) ? "s" : ""); + printf_ln(Q_("The bundle contains %d ref", + "The bundle contains %d refs", + r->nr), + r->nr); list_refs(r, 0, NULL); r = &header->prerequisites; - printf("The bundle requires these %d ref%s\n", - r->nr, (1 < r->nr) ? "s" : ""); + printf_ln(Q_("The bundle requires this ref", + "The bundle requires these %d refs", + r->nr), + r->nr); list_refs(r, 0, NULL); } return ret; @@@ -283,13 -287,13 +287,13 @@@ int create_bundle(struct bundle_header strbuf_release(&buf); fclose(rls_fout); if (finish_command(&rls)) - return error("rev-list died"); + return error(_("rev-list died")); /* write references */ argc = setup_revisions(argc, argv, &revs, NULL); if (argc > 1) - return error("unrecognized argument: %s", argv[1]); - return error(_("unrecognized argument: %s'"), argv[1]); ++ return error(_("unrecognized argument: %s"), argv[1]); object_array_remove_duplicates(&revs.pending); @@@ -324,7 -328,7 +328,7 @@@ * constraints. */ if (!(e->item->flags & SHOWN) && e->item->type == OBJ_COMMIT) { - warning("ref '%s' is excluded by the rev-list options", + warning(_("ref '%s' is excluded by the rev-list options"), e->name); free(ref); continue; @@@ -369,7 -373,7 +373,7 @@@ free(ref); } if (!ref_count) - die ("Refusing to create empty bundle."); + die(_("Refusing to create empty bundle.")); /* end header */ write_or_die(bundle_fd, "\n", 1); @@@ -387,7 -391,7 +391,7 @@@ rls.out = bundle_fd; rls.git_cmd = 1; if (start_command(&rls)) - return error("Could not spawn pack-objects"); + return error(_("Could not spawn pack-objects")); /* * start_command closed bundle_fd if it was > 1 @@@ -405,10 -409,10 +409,10 @@@ } close(rls.in); if (finish_command(&rls)) - return error ("pack-objects died"); + return error(_("pack-objects died")); if (!bundle_to_stdout) { if (commit_lock_file(&lock)) - die_errno("cannot create '%s'", path); + die_errno(_("cannot create '%s'"), path); } return 0; } @@@ -430,6 -434,6 +434,6 @@@ int unbundle(struct bundle_header *head ip.no_stdout = 1; ip.git_cmd = 1; if (run_command(&ip)) - return error("index-pack died"); + return error(_("index-pack died")); return 0; } diff --combined cache.h index 5e419a11cc,5bfa94996d..e14ffcd914 --- a/cache.h +++ b/cache.h @@@ -105,9 -105,6 +105,9 @@@ struct cache_header unsigned int hdr_entries; }; +#define INDEX_FORMAT_LB 2 +#define INDEX_FORMAT_UB 4 + /* * The "cache_time" is just the low 32 bits of the * time. It doesn't matter if it overflows - we only @@@ -118,6 -115,48 +118,6 @@@ struct cache_time unsigned int nsec; }; -/* - * dev/ino/uid/gid/size are also just tracked to the low 32 bits - * Again - this is just a (very strong in practice) heuristic that - * the inode hasn't changed. - * - * We save the fields in big-endian order to allow using the - * index file over NFS transparently. - */ -struct ondisk_cache_entry { - struct cache_time ctime; - struct cache_time mtime; - unsigned int dev; - unsigned int ino; - unsigned int mode; - unsigned int uid; - unsigned int gid; - unsigned int size; - unsigned char sha1[20]; - unsigned short flags; - char name[FLEX_ARRAY]; /* more */ -}; - -/* - * This struct is used when CE_EXTENDED bit is 1 - * The struct must match ondisk_cache_entry exactly from - * ctime till flags - */ -struct ondisk_cache_entry_extended { - struct cache_time ctime; - struct cache_time mtime; - unsigned int dev; - unsigned int ino; - unsigned int mode; - unsigned int uid; - unsigned int gid; - unsigned int size; - unsigned char sha1[20]; - unsigned short flags; - unsigned short flags2; - char name[FLEX_ARRAY]; /* more */ -}; - struct cache_entry { struct cache_time ce_ctime; struct cache_time ce_mtime; @@@ -214,6 -253,9 +214,6 @@@ static inline size_t ce_namelen(const s } #define ce_size(ce) cache_entry_size(ce_namelen(ce)) -#define ondisk_ce_size(ce) (((ce)->ce_flags & CE_EXTENDED) ? \ - ondisk_cache_entry_extended_size(ce_namelen(ce)) : \ - ondisk_cache_entry_size(ce_namelen(ce))) #define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT) #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE) #define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE) @@@ -264,11 -306,13 +264,11 @@@ static inline unsigned int canon_mode(u return S_IFGITLINK; } -#define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7) #define cache_entry_size(len) (offsetof(struct cache_entry,name) + (len) + 1) -#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len) -#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len) struct index_state { struct cache_entry **cache; + unsigned int version; unsigned int cache_nr, cache_alloc, cache_changed; struct string_list *resolve_undo; struct cache_tree *cache_tree; @@@ -580,7 -624,6 +580,7 @@@ enum rebase_setup_type enum push_default_type { PUSH_DEFAULT_NOTHING = 0, PUSH_DEFAULT_MATCHING, + PUSH_DEFAULT_SIMPLE, PUSH_DEFAULT_UPSTREAM, PUSH_DEFAULT_CURRENT, PUSH_DEFAULT_UNSPECIFIED @@@ -877,10 -920,8 +877,8 @@@ enum date_mode }; const char *show_date(unsigned long time, int timezone, enum date_mode mode); - const char *show_date_relative(unsigned long time, int tz, - const struct timeval *now, - char *timebuf, - size_t timebuf_size); + void show_date_relative(unsigned long time, int tz, const struct timeval *now, + struct strbuf *timebuf); int parse_date(const char *date, char *buf, int bufsize); int parse_date_basic(const char *date, unsigned long *timestamp, int *offset); void datestamp(char *buf, int bufsize); diff --combined refs.c index 09322fede0,052c2f6058..a5802e1902 --- a/refs.c +++ b/refs.c @@@ -4,109 -4,18 +4,109 @@@ #include "tag.h" #include "dir.h" -/* ISSYMREF=0x01, ISPACKED=0x02 and ISBROKEN=0x04 are public interfaces */ -#define REF_KNOWS_PEELED 0x10 +/* + * Make sure "ref" is something reasonable to have under ".git/refs/"; + * We do not like it if: + * + * - any path component of it begins with ".", or + * - it has double dots "..", or + * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or + * - it ends with a "/". + * - it ends with ".lock" + * - it contains a "\" (backslash) + */ -struct ref_entry { - unsigned char flag; /* ISSYMREF? ISPACKED? */ +/* Return true iff ch is not allowed in reference names. */ +static inline int bad_ref_char(int ch) +{ + if (((unsigned) ch) <= ' ' || ch == 0x7f || + ch == '~' || ch == '^' || ch == ':' || ch == '\\') + return 1; + /* 2.13 Pattern Matching Notation */ + if (ch == '*' || ch == '?' || ch == '[') /* Unsupported */ + return 1; + return 0; +} + +/* + * Try to read one refname component from the front of refname. Return + * the length of the component found, or -1 if the component is not + * legal. + */ +static int check_refname_component(const char *refname, int flags) +{ + const char *cp; + char last = '\0'; + + for (cp = refname; ; cp++) { + char ch = *cp; + if (ch == '\0' || ch == '/') + break; + if (bad_ref_char(ch)) + return -1; /* Illegal character in refname. */ + if (last == '.' && ch == '.') + return -1; /* Refname contains "..". */ + if (last == '@' && ch == '{') + return -1; /* Refname contains "@{". */ + last = ch; + } + if (cp == refname) + return 0; /* Component has zero length. */ + if (refname[0] == '.') { + if (!(flags & REFNAME_DOT_COMPONENT)) + return -1; /* Component starts with '.'. */ + /* + * Even if leading dots are allowed, don't allow "." + * as a component (".." is prevented by a rule above). + */ + if (refname[1] == '\0') + return -1; /* Component equals ".". */ + } + if (cp - refname >= 5 && !memcmp(cp - 5, ".lock", 5)) + return -1; /* Refname ends with ".lock". */ + return cp - refname; +} + +int check_refname_format(const char *refname, int flags) +{ + int component_len, component_count = 0; + + while (1) { + /* We are at the start of a path component. */ + component_len = check_refname_component(refname, flags); + if (component_len <= 0) { + if ((flags & REFNAME_REFSPEC_PATTERN) && + refname[0] == '*' && + (refname[1] == '\0' || refname[1] == '/')) { + /* Accept one wildcard as a full refname component. */ + flags &= ~REFNAME_REFSPEC_PATTERN; + component_len = 1; + } else { + return -1; + } + } + component_count++; + if (refname[component_len] == '\0') + break; + /* Skip to next component. */ + refname += component_len + 1; + } + + if (refname[component_len - 1] == '.') + return -1; /* Refname ends with '.'. */ + if (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2) + return -1; /* Refname has only one component. */ + return 0; +} + +struct ref_entry; + +struct ref_value { unsigned char sha1[20]; unsigned char peeled[20]; - /* The full name of the reference (e.g., "refs/heads/master"): */ - char name[FLEX_ARRAY]; }; -struct ref_array { +struct ref_dir { int nr, alloc; /* @@@ -117,59 -26,41 +117,59 @@@ */ int sorted; - struct ref_entry **refs; + struct ref_entry **entries; }; +/* ISSYMREF=0x01, ISPACKED=0x02, and ISBROKEN=0x04 are public interfaces */ +#define REF_KNOWS_PEELED 0x08 +#define REF_DIR 0x10 + /* - * Parse one line from a packed-refs file. Write the SHA1 to sha1. - * Return a pointer to the refname within the line (null-terminated), - * or NULL if there was a problem. + * A ref_entry represents either a reference or a "subdirectory" of + * references. Each directory in the reference namespace is + * represented by a ref_entry with (flags & REF_DIR) set and + * containing a subdir member that holds the entries in that + * directory. References are represented by a ref_entry with (flags & + * REF_DIR) unset and a value member that describes the reference's + * value. The flag member is at the ref_entry level, but it is also + * needed to interpret the contents of the value field (in other + * words, a ref_value object is not very much use without the + * enclosing ref_entry). + * + * Reference names cannot end with slash and directories' names are + * always stored with a trailing slash (except for the top-level + * directory, which is always denoted by ""). This has two nice + * consequences: (1) when the entries in each subdir are sorted + * lexicographically by name (as they usually are), the references in + * a whole tree can be generated in lexicographic order by traversing + * the tree in left-to-right, depth-first order; (2) the names of + * references and subdirectories cannot conflict, and therefore the + * presence of an empty subdirectory does not block the creation of a + * similarly-named reference. (The fact that reference names with the + * same leading components can conflict *with each other* is a + * separate issue that is regulated by is_refname_available().) + * + * Please note that the name field contains the fully-qualified + * reference (or subdirectory) name. Space could be saved by only + * storing the relative names. But that would require the full names + * to be generated on the fly when iterating in do_for_each_ref(), and + * would break callback functions, who have always been able to assume + * that the name strings that they are passed will not be freed during + * the iteration. */ -static const char *parse_ref_line(char *line, unsigned char *sha1) -{ +struct ref_entry { + unsigned char flag; /* ISSYMREF? ISPACKED? */ + union { + struct ref_value value; /* if not (flags&REF_DIR) */ + struct ref_dir subdir; /* if (flags&REF_DIR) */ + } u; /* - * 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) + * The full name of the reference (e.g., "refs/heads/master") + * or the full name of the directory with a trailing slash + * (e.g., "refs/heads/"): */ - 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 (isspace(*line)) - return NULL; - if (line[len] != '\n') - return NULL; - line[len] = 0; - - return line; -} + char name[FLEX_ARRAY]; +}; static struct ref_entry *create_ref_entry(const char *refname, const unsigned char *sha1, int flag, @@@ -183,59 -74,18 +183,59 @@@ die("Reference has invalid format: '%s'", refname); len = strlen(refname) + 1; ref = xmalloc(sizeof(struct ref_entry) + len); - hashcpy(ref->sha1, sha1); - hashclr(ref->peeled); + hashcpy(ref->u.value.sha1, sha1); + hashclr(ref->u.value.peeled); memcpy(ref->name, refname, len); ref->flag = flag; return ref; } -/* Add a ref_entry to the end of the ref_array (unsorted). */ -static void add_ref(struct ref_array *refs, struct ref_entry *ref) +static void clear_ref_dir(struct ref_dir *dir); + +static void free_ref_entry(struct ref_entry *entry) +{ + if (entry->flag & REF_DIR) + clear_ref_dir(&entry->u.subdir); + free(entry); +} + +/* + * Add a ref_entry to the end of dir (unsorted). Entry is always + * stored directly in dir; no recursion into subdirectories is + * done. + */ +static void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry) { - ALLOC_GROW(refs->refs, refs->nr + 1, refs->alloc); - refs->refs[refs->nr++] = ref; + ALLOC_GROW(dir->entries, dir->nr + 1, dir->alloc); + dir->entries[dir->nr++] = entry; +} + +/* + * Clear and free all entries in dir, recursively. + */ +static void clear_ref_dir(struct ref_dir *dir) +{ + int i; + for (i = 0; i < dir->nr; i++) + free_ref_entry(dir->entries[i]); + free(dir->entries); + dir->sorted = dir->nr = dir->alloc = 0; + dir->entries = NULL; +} + +/* + * Create a struct ref_entry object for the specified dirname. + * dirname is the name of the directory with a trailing slash (e.g., + * "refs/heads/") or "" for the top-level directory. + */ +static struct ref_entry *create_dir_entry(const char *dirname) +{ + struct ref_entry *direntry; + int len = strlen(dirname); + direntry = xcalloc(1, sizeof(struct ref_entry) + len + 1); + memcpy(direntry->name, dirname, len + 1); + direntry->flag = REF_DIR; + return direntry; } static int ref_entry_cmp(const void *a, const void *b) @@@ -245,102 -95,6 +245,102 @@@ return strcmp(one->name, two->name); } +static void sort_ref_dir(struct ref_dir *dir); + +/* + * Return the entry with the given refname from the ref_dir + * (non-recursively), sorting dir if necessary. Return NULL if no + * such entry is found. + */ +static struct ref_entry *search_ref_dir(struct ref_dir *dir, const char *refname) +{ + struct ref_entry *e, **r; + int len; + + if (refname == NULL || !dir->nr) + return NULL; + + sort_ref_dir(dir); + + len = strlen(refname) + 1; + e = xmalloc(sizeof(struct ref_entry) + len); + memcpy(e->name, refname, len); + + r = bsearch(&e, dir->entries, dir->nr, sizeof(*dir->entries), ref_entry_cmp); + + free(e); + + if (r == NULL) + return NULL; + + return *r; +} + +/* + * If refname is a reference name, find the ref_dir within the dir + * tree that should hold refname. If refname is a directory name + * (i.e., ends in '/'), then return that ref_dir itself. dir must + * represent the top-level directory. Sort ref_dirs and recurse into + * subdirectories as necessary. If mkdir is set, then create any + * missing directories; otherwise, return NULL if the desired + * directory cannot be found. + */ +static struct ref_dir *find_containing_dir(struct ref_dir *dir, + const char *refname, int mkdir) +{ + char *refname_copy = xstrdup(refname); + char *slash; + struct ref_entry *entry; + for (slash = strchr(refname_copy, '/'); slash; slash = strchr(slash + 1, '/')) { + char tmp = slash[1]; + slash[1] = '\0'; + entry = search_ref_dir(dir, refname_copy); + if (!entry) { + if (!mkdir) { + dir = NULL; + break; + } + entry = create_dir_entry(refname_copy); + add_entry_to_dir(dir, entry); + } + slash[1] = tmp; + assert(entry->flag & REF_DIR); + dir = &entry->u.subdir; + } + + free(refname_copy); + return dir; +} + +/* + * Find the value entry with the given name in dir, sorting ref_dirs + * and recursing into subdirectories as necessary. If the name is not + * found or it corresponds to a directory entry, return NULL. + */ +static struct ref_entry *find_ref(struct ref_dir *dir, const char *refname) +{ + struct ref_entry *entry; + dir = find_containing_dir(dir, refname, 0); + if (!dir) + return NULL; + entry = search_ref_dir(dir, refname); + return (entry && !(entry->flag & REF_DIR)) ? entry : NULL; +} + +/* + * Add a ref_entry to the ref_dir (unsorted), recursing into + * subdirectories as necessary. dir must represent the top-level + * directory. Return 0 on success. + */ +static int add_ref(struct ref_dir *dir, struct ref_entry *ref) +{ + dir = find_containing_dir(dir, ref->name, 1); + if (!dir) + return -1; + add_entry_to_dir(dir, ref); + return 0; +} + /* * Emit a warning and return true iff ref1 and ref2 have the same name * and the same sha1. Die if they have the same name but different @@@ -348,242 -102,69 +348,242 @@@ */ static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2) { - if (!strcmp(ref1->name, ref2->name)) { - /* Duplicate name; make sure that the SHA1s match: */ - if (hashcmp(ref1->sha1, ref2->sha1)) - die("Duplicated ref, and SHA1s don't match: %s", - ref1->name); - warning("Duplicated ref: %s", ref1->name); - return 1; - } else { + if (strcmp(ref1->name, ref2->name)) return 0; - } + + /* Duplicate name; make sure that they don't conflict: */ + + if ((ref1->flag & REF_DIR) || (ref2->flag & REF_DIR)) + /* This is impossible by construction */ + die("Reference directory conflict: %s", ref1->name); + + if (hashcmp(ref1->u.value.sha1, ref2->u.value.sha1)) + die("Duplicated ref, and SHA1s don't match: %s", ref1->name); + + warning("Duplicated ref: %s", ref1->name); + return 1; } /* - * Sort the entries in array (if they are not already sorted). + * Sort the entries in dir non-recursively (if they are not already + * sorted) and remove any duplicate entries. */ -static void sort_ref_array(struct ref_array *array) +static void sort_ref_dir(struct ref_dir *dir) { int i, j; + struct ref_entry *last = NULL; /* * This check also prevents passing a zero-length array to qsort(), * which is a problem on some platforms. */ - if (array->sorted == array->nr) + if (dir->sorted == dir->nr) return; - qsort(array->refs, array->nr, sizeof(*array->refs), ref_entry_cmp); + qsort(dir->entries, dir->nr, sizeof(*dir->entries), ref_entry_cmp); - /* Remove any duplicates from the ref_array */ - i = 0; - for (j = 1; j < array->nr; j++) { - if (is_dup_ref(array->refs[i], array->refs[j])) { - free(array->refs[j]); - continue; + /* Remove any duplicates: */ + for (i = 0, j = 0; j < dir->nr; j++) { + struct ref_entry *entry = dir->entries[j]; + if (last && is_dup_ref(last, entry)) + free_ref_entry(entry); + else + last = dir->entries[i++] = entry; + } + dir->sorted = dir->nr = i; +} + +#define DO_FOR_EACH_INCLUDE_BROKEN 01 + +static struct ref_entry *current_ref; + +static int do_one_ref(const char *base, each_ref_fn fn, int trim, + int flags, void *cb_data, struct ref_entry *entry) +{ + int retval; + if (prefixcmp(entry->name, base)) + return 0; + + if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) { + if (entry->flag & REF_ISBROKEN) + return 0; /* ignore broken refs e.g. dangling symref */ + if (!has_sha1_file(entry->u.value.sha1)) { + error("%s does not point to a valid object!", entry->name); + return 0; } - array->refs[++i] = array->refs[j]; } - array->sorted = array->nr = i + 1; + current_ref = entry; + retval = fn(entry->name + trim, entry->u.value.sha1, entry->flag, cb_data); + current_ref = NULL; + return retval; } -static struct ref_entry *search_ref_array(struct ref_array *array, const char *refname) +/* + * Call fn for each reference in dir that has index in the range + * offset <= index < dir->nr. Recurse into subdirectories that are in + * that index range, sorting them before iterating. This function + * does not sort dir itself; it should be sorted beforehand. + */ +static int do_for_each_ref_in_dir(struct ref_dir *dir, int offset, + const char *base, + each_ref_fn fn, int trim, int flags, void *cb_data) { - struct ref_entry *e, **r; - int len; + int i; + assert(dir->sorted == dir->nr); + for (i = offset; i < dir->nr; i++) { + struct ref_entry *entry = dir->entries[i]; + int retval; + if (entry->flag & REF_DIR) { + sort_ref_dir(&entry->u.subdir); + retval = do_for_each_ref_in_dir(&entry->u.subdir, 0, + base, fn, trim, flags, cb_data); + } else { + retval = do_one_ref(base, fn, trim, flags, cb_data, entry); + } + if (retval) + return retval; + } + return 0; +} - if (refname == NULL) - return NULL; +/* + * Call fn for each reference in the union of dir1 and dir2, in order + * by refname. Recurse into subdirectories. If a value entry appears + * in both dir1 and dir2, then only process the version that is in + * dir2. The input dirs must already be sorted, but subdirs will be + * sorted as needed. + */ +static int do_for_each_ref_in_dirs(struct ref_dir *dir1, + struct ref_dir *dir2, + const char *base, each_ref_fn fn, int trim, + int flags, void *cb_data) +{ + int retval; + int i1 = 0, i2 = 0; - if (!array->nr) - return NULL; - sort_ref_array(array); - len = strlen(refname) + 1; - e = xmalloc(sizeof(struct ref_entry) + len); - memcpy(e->name, refname, len); + assert(dir1->sorted == dir1->nr); + assert(dir2->sorted == dir2->nr); + while (1) { + struct ref_entry *e1, *e2; + int cmp; + if (i1 == dir1->nr) { + return do_for_each_ref_in_dir(dir2, i2, + base, fn, trim, flags, cb_data); + } + if (i2 == dir2->nr) { + return do_for_each_ref_in_dir(dir1, i1, + base, fn, trim, flags, cb_data); + } + e1 = dir1->entries[i1]; + e2 = dir2->entries[i2]; + cmp = strcmp(e1->name, e2->name); + if (cmp == 0) { + if ((e1->flag & REF_DIR) && (e2->flag & REF_DIR)) { + /* Both are directories; descend them in parallel. */ + sort_ref_dir(&e1->u.subdir); + sort_ref_dir(&e2->u.subdir); + retval = do_for_each_ref_in_dirs( + &e1->u.subdir, &e2->u.subdir, + base, fn, trim, flags, cb_data); + i1++; + i2++; + } else if (!(e1->flag & REF_DIR) && !(e2->flag & REF_DIR)) { + /* Both are references; ignore the one from dir1. */ + retval = do_one_ref(base, fn, trim, flags, cb_data, e2); + i1++; + i2++; + } else { + die("conflict between reference and directory: %s", + e1->name); + } + } else { + struct ref_entry *e; + if (cmp < 0) { + e = e1; + i1++; + } else { + e = e2; + i2++; + } + if (e->flag & REF_DIR) { + sort_ref_dir(&e->u.subdir); + retval = do_for_each_ref_in_dir( + &e->u.subdir, 0, + base, fn, trim, flags, cb_data); + } else { + retval = do_one_ref(base, fn, trim, flags, cb_data, e); + } + } + if (retval) + return retval; + } + if (i1 < dir1->nr) + return do_for_each_ref_in_dir(dir1, i1, + base, fn, trim, flags, cb_data); + if (i2 < dir2->nr) + return do_for_each_ref_in_dir(dir2, i2, + base, fn, trim, flags, cb_data); + return 0; +} - r = bsearch(&e, array->refs, array->nr, sizeof(*array->refs), ref_entry_cmp); +/* + * Return true iff refname1 and refname2 conflict with each other. + * Two reference names conflict if one of them exactly matches the + * leading components of the other; e.g., "foo/bar" conflicts with + * both "foo" and with "foo/bar/baz" but not with "foo/bar" or + * "foo/barbados". + */ +static int names_conflict(const char *refname1, const char *refname2) +{ + for (; *refname1 && *refname1 == *refname2; refname1++, refname2++) + ; + return (*refname1 == '\0' && *refname2 == '/') + || (*refname1 == '/' && *refname2 == '\0'); +} - free(e); +struct name_conflict_cb { + const char *refname; + const char *oldrefname; + const char *conflicting_refname; +}; - if (r == NULL) - return NULL; +static int name_conflict_fn(const char *existingrefname, const unsigned char *sha1, + int flags, void *cb_data) +{ + struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data; + if (data->oldrefname && !strcmp(data->oldrefname, existingrefname)) + return 0; + if (names_conflict(data->refname, existingrefname)) { + data->conflicting_refname = existingrefname; + return 1; + } + return 0; +} - return *r; +/* + * Return true iff a reference named refname could be created without + * conflicting with the name of an existing reference in array. If + * oldrefname is non-NULL, ignore potential conflicts with oldrefname + * (e.g., because oldrefname is scheduled for deletion in the same + * operation). + */ +static int is_refname_available(const char *refname, const char *oldrefname, + struct ref_dir *dir) +{ + struct name_conflict_cb data; + data.refname = refname; + data.oldrefname = oldrefname; + data.conflicting_refname = NULL; + + sort_ref_dir(dir); + if (do_for_each_ref_in_dir(dir, 0, "", name_conflict_fn, + 0, DO_FOR_EACH_INCLUDE_BROKEN, + &data)) { + error("'%s' exists; cannot create '%s'", + data.conflicting_refname, refname); + return 0; + } + return 1; } /* @@@ -594,23 -175,35 +594,23 @@@ static struct ref_cache struct ref_cache *next; char did_loose; char did_packed; - struct ref_array loose; - struct ref_array packed; + struct ref_dir loose; + struct ref_dir packed; /* The submodule name, or "" for the main repo. */ char name[FLEX_ARRAY]; } *ref_cache; -static struct ref_entry *current_ref; - -static void clear_ref_array(struct ref_array *array) -{ - int i; - for (i = 0; i < array->nr; i++) - free(array->refs[i]); - free(array->refs); - array->sorted = array->nr = array->alloc = 0; - array->refs = NULL; -} - static void clear_packed_ref_cache(struct ref_cache *refs) { if (refs->did_packed) - clear_ref_array(&refs->packed); + clear_ref_dir(&refs->packed); refs->did_packed = 0; } static void clear_loose_ref_cache(struct ref_cache *refs) { if (refs->did_loose) - clear_ref_array(&refs->loose); + clear_ref_dir(&refs->loose); refs->did_loose = 0; } @@@ -643,53 -236,20 +643,53 @@@ static struct ref_cache *get_ref_cache( refs = refs->next; } - refs = create_ref_cache(submodule); - refs->next = ref_cache; - ref_cache = refs; - return refs; -} + refs = create_ref_cache(submodule); + refs->next = ref_cache; + ref_cache = refs; + return refs; +} + +void invalidate_ref_cache(const char *submodule) +{ + struct ref_cache *refs = get_ref_cache(submodule); + clear_packed_ref_cache(refs); + clear_loose_ref_cache(refs); +} + +/* + * Parse one line from a packed-refs file. Write the SHA1 to sha1. + * Return a pointer to the refname within the line (null-terminated), + * or NULL if there was a problem. + */ +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 (isspace(*line)) + return NULL; + if (line[len] != '\n') + return NULL; + line[len] = 0; -void invalidate_ref_cache(const char *submodule) -{ - struct ref_cache *refs = get_ref_cache(submodule); - clear_packed_ref_cache(refs); - clear_loose_ref_cache(refs); + return line; } -static void read_packed_refs(FILE *f, struct ref_array *array) +static void read_packed_refs(FILE *f, struct ref_dir *dir) { struct ref_entry *last = NULL; char refline[PATH_MAX]; @@@ -711,7 -271,7 +711,7 @@@ refname = parse_ref_line(refline, sha1); if (refname) { last = create_ref_entry(refname, sha1, flag, 1); - add_ref(array, last); + add_ref(dir, last); continue; } if (last && @@@ -719,11 -279,11 +719,11 @@@ strlen(refline) == 42 && refline[41] == '\n' && !get_sha1_hex(refline + 1, sha1)) - hashcpy(last->peeled, sha1); + hashcpy(last->u.value.peeled, sha1); } } -static struct ref_array *get_packed_refs(struct ref_cache *refs) +static struct ref_dir *get_packed_refs(struct ref_cache *refs) { if (!refs->did_packed) { const char *packed_refs_file; @@@ -750,9 -310,9 +750,9 @@@ void add_packed_ref(const char *refname } static void get_ref_dir(struct ref_cache *refs, const char *base, - struct ref_array *array) + struct ref_dir *dir) { - DIR *dir; + DIR *d; const char *path; if (*refs->name) @@@ -760,8 -320,10 +760,8 @@@ else path = git_path("%s", base); - - dir = opendir(path); - - if (dir) { + d = opendir(path); + if (d) { struct dirent *de; int baselen = strlen(base); char *refname = xmalloc(baselen + 257); @@@ -770,7 -332,7 +770,7 @@@ if (baselen && base[baselen-1] != '/') refname[baselen++] = '/'; - while ((de = readdir(dir)) != NULL) { + while ((de = readdir(d)) != NULL) { unsigned char sha1[20]; struct stat st; int flag; @@@ -791,7 -353,7 +791,7 @@@ if (stat(refdir, &st) < 0) continue; if (S_ISDIR(st.st_mode)) { - get_ref_dir(refs, refname, array); + get_ref_dir(refs, refname, dir); continue; } if (*refs->name) { @@@ -805,14 -367,49 +805,14 @@@ hashclr(sha1); flag |= REF_ISBROKEN; } - add_ref(array, create_ref_entry(refname, sha1, flag, 1)); + add_ref(dir, create_ref_entry(refname, sha1, flag, 1)); } free(refname); - closedir(dir); + closedir(d); } } -struct warn_if_dangling_data { - FILE *fp; - const char *refname; - const char *msg_fmt; -}; - -static int warn_if_dangling_symref(const char *refname, const unsigned char *sha1, - int flags, void *cb_data) -{ - struct warn_if_dangling_data *d = cb_data; - const char *resolves_to; - unsigned char junk[20]; - - if (!(flags & REF_ISSYMREF)) - return 0; - - resolves_to = resolve_ref_unsafe(refname, junk, 0, NULL); - if (!resolves_to || strcmp(resolves_to, d->refname)) - return 0; - - fprintf(d->fp, d->msg_fmt, refname); - fputc('\n', d->fp); - return 0; -} - -void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname) -{ - struct warn_if_dangling_data data; - - data.fp = fp; - data.refname = refname; - data.msg_fmt = msg_fmt; - for_each_rawref(warn_if_dangling_symref, &data); -} - -static struct ref_array *get_loose_refs(struct ref_cache *refs) +static struct ref_dir *get_loose_refs(struct ref_cache *refs) { if (!refs->did_loose) { get_ref_dir(refs, "refs", &refs->loose); @@@ -834,13 -431,13 +834,13 @@@ static int resolve_gitlink_packed_ref(s const char *refname, unsigned char *sha1) { struct ref_entry *ref; - struct ref_array *array = get_packed_refs(refs); + struct ref_dir *dir = get_packed_refs(refs); - ref = search_ref_array(array, refname); + ref = find_ref(dir, refname); if (ref == NULL) return -1; - memcpy(sha1, ref->sha1, 20); + memcpy(sha1, ref->u.value.sha1, 20); return 0; } @@@ -907,10 -504,10 +907,10 @@@ int resolve_gitlink_ref(const char *pat */ static int get_packed_ref(const char *refname, unsigned char *sha1) { - struct ref_array *packed = get_packed_refs(get_ref_cache(NULL)); - struct ref_entry *entry = search_ref_array(packed, refname); + struct ref_dir *packed = get_packed_refs(get_ref_cache(NULL)); + struct ref_entry *entry = find_ref(packed, refname); if (entry) { - hashcpy(sha1, entry->sha1); + hashcpy(sha1, entry->u.value.sha1); return 0; } return -1; @@@ -1049,10 -646,23 +1049,10 @@@ int read_ref(const char *refname, unsig return read_ref_full(refname, sha1, 1, NULL); } -#define DO_FOR_EACH_INCLUDE_BROKEN 01 -static int do_one_ref(const char *base, each_ref_fn fn, int trim, - int flags, void *cb_data, struct ref_entry *entry) +int ref_exists(const char *refname) { - if (prefixcmp(entry->name, base)) - return 0; - - if (!(flags & DO_FOR_EACH_INCLUDE_BROKEN)) { - if (entry->flag & REF_ISBROKEN) - return 0; /* ignore broken refs e.g. dangling symref */ - if (!has_sha1_file(entry->sha1)) { - error("%s does not point to a valid object!", entry->name); - return 0; - } - } - current_ref = entry; - return fn(entry->name + trim, entry->sha1, entry->flag, cb_data); + unsigned char sha1[20]; + return !!resolve_ref_unsafe(refname, sha1, 1, NULL); } static int filter_refs(const char *refname, const unsigned char *sha1, int flags, @@@ -1073,10 -683,10 +1073,10 @@@ int peel_ref(const char *refname, unsig if (current_ref && (current_ref->name == refname || !strcmp(current_ref->name, refname))) { if (current_ref->flag & REF_KNOWS_PEELED) { - hashcpy(sha1, current_ref->peeled); + hashcpy(sha1, current_ref->u.value.peeled); return 0; } - hashcpy(base, current_ref->sha1); + hashcpy(base, current_ref->u.value.sha1); goto fallback; } @@@ -1084,11 -694,11 +1084,11 @@@ return -1; if ((flag & REF_ISPACKED)) { - struct ref_array *array = get_packed_refs(get_ref_cache(NULL)); - struct ref_entry *r = search_ref_array(array, refname); + struct ref_dir *dir = get_packed_refs(get_ref_cache(NULL)); + struct ref_entry *r = find_ref(dir, refname); if (r != NULL && r->flag & REF_KNOWS_PEELED) { - hashcpy(sha1, r->peeled); + hashcpy(sha1, r->u.value.peeled); return 0; } } @@@ -1105,74 -715,50 +1105,75 @@@ fallback return -1; } +struct warn_if_dangling_data { + FILE *fp; + const char *refname; + const char *msg_fmt; +}; + +static int warn_if_dangling_symref(const char *refname, const unsigned char *sha1, + int flags, void *cb_data) +{ + struct warn_if_dangling_data *d = cb_data; + const char *resolves_to; + unsigned char junk[20]; + + if (!(flags & REF_ISSYMREF)) + return 0; + + resolves_to = resolve_ref_unsafe(refname, junk, 0, NULL); + if (!resolves_to || strcmp(resolves_to, d->refname)) + return 0; + + fprintf(d->fp, d->msg_fmt, refname); ++ fputc('\n', d->fp); + return 0; +} + +void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname) +{ + struct warn_if_dangling_data data; + + data.fp = fp; + data.refname = refname; + data.msg_fmt = msg_fmt; + for_each_rawref(warn_if_dangling_symref, &data); +} + static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn fn, int trim, int flags, void *cb_data) { - int retval = 0, p = 0, l = 0; struct ref_cache *refs = get_ref_cache(submodule); - struct ref_array *packed = get_packed_refs(refs); - struct ref_array *loose = get_loose_refs(refs); - - sort_ref_array(packed); - sort_ref_array(loose); - while (p < packed->nr && l < loose->nr) { - struct ref_entry *entry; - int cmp = strcmp(packed->refs[p]->name, loose->refs[l]->name); - if (!cmp) { - p++; - continue; - } - if (cmp > 0) { - entry = loose->refs[l++]; - } else { - entry = packed->refs[p++]; - } - retval = do_one_ref(base, fn, trim, flags, cb_data, entry); - if (retval) - goto end_each; - } - - if (l < loose->nr) { - p = l; - packed = loose; - } + struct ref_dir *packed_dir = get_packed_refs(refs); + struct ref_dir *loose_dir = get_loose_refs(refs); + int retval = 0; - for (; p < packed->nr; p++) { - retval = do_one_ref(base, fn, trim, flags, cb_data, packed->refs[p]); - if (retval) - goto end_each; + if (base && *base) { + packed_dir = find_containing_dir(packed_dir, base, 0); + loose_dir = find_containing_dir(loose_dir, base, 0); + } + + if (packed_dir && loose_dir) { + sort_ref_dir(packed_dir); + sort_ref_dir(loose_dir); + retval = do_for_each_ref_in_dirs( + packed_dir, loose_dir, + base, fn, trim, flags, cb_data); + } else if (packed_dir) { + sort_ref_dir(packed_dir); + retval = do_for_each_ref_in_dir( + packed_dir, 0, + base, fn, trim, flags, cb_data); + } else if (loose_dir) { + sort_ref_dir(loose_dir); + retval = do_for_each_ref_in_dir( + loose_dir, 0, + base, fn, trim, flags, cb_data); } -end_each: - current_ref = NULL; return retval; } - static int do_head_ref(const char *submodule, each_ref_fn fn, void *cb_data) { unsigned char sha1[20]; @@@ -1323,6 -909,101 +1324,6 @@@ int for_each_rawref(each_ref_fn fn, voi DO_FOR_EACH_INCLUDE_BROKEN, cb_data); } -/* - * Make sure "ref" is something reasonable to have under ".git/refs/"; - * We do not like it if: - * - * - any path component of it begins with ".", or - * - it has double dots "..", or - * - it has ASCII control character, "~", "^", ":" or SP, anywhere, or - * - it ends with a "/". - * - it ends with ".lock" - * - it contains a "\" (backslash) - */ - -/* Return true iff ch is not allowed in reference names. */ -static inline int bad_ref_char(int ch) -{ - if (((unsigned) ch) <= ' ' || ch == 0x7f || - ch == '~' || ch == '^' || ch == ':' || ch == '\\') - return 1; - /* 2.13 Pattern Matching Notation */ - if (ch == '*' || ch == '?' || ch == '[') /* Unsupported */ - return 1; - return 0; -} - -/* - * Try to read one refname component from the front of refname. Return - * the length of the component found, or -1 if the component is not - * legal. - */ -static int check_refname_component(const char *refname, int flags) -{ - const char *cp; - char last = '\0'; - - for (cp = refname; ; cp++) { - char ch = *cp; - if (ch == '\0' || ch == '/') - break; - if (bad_ref_char(ch)) - return -1; /* Illegal character in refname. */ - if (last == '.' && ch == '.') - return -1; /* Refname contains "..". */ - if (last == '@' && ch == '{') - return -1; /* Refname contains "@{". */ - last = ch; - } - if (cp == refname) - return -1; /* Component has zero length. */ - if (refname[0] == '.') { - if (!(flags & REFNAME_DOT_COMPONENT)) - return -1; /* Component starts with '.'. */ - /* - * Even if leading dots are allowed, don't allow "." - * as a component (".." is prevented by a rule above). - */ - if (refname[1] == '\0') - return -1; /* Component equals ".". */ - } - if (cp - refname >= 5 && !memcmp(cp - 5, ".lock", 5)) - return -1; /* Refname ends with ".lock". */ - return cp - refname; -} - -int check_refname_format(const char *refname, int flags) -{ - int component_len, component_count = 0; - - while (1) { - /* We are at the start of a path component. */ - component_len = check_refname_component(refname, flags); - if (component_len < 0) { - if ((flags & REFNAME_REFSPEC_PATTERN) && - refname[0] == '*' && - (refname[1] == '\0' || refname[1] == '/')) { - /* Accept one wildcard as a full refname component. */ - flags &= ~REFNAME_REFSPEC_PATTERN; - component_len = 1; - } else { - return -1; - } - } - component_count++; - if (refname[component_len] == '\0') - break; - /* Skip to next component. */ - refname += component_len + 1; - } - - if (refname[component_len - 1] == '.') - return -1; /* Refname ends with '.'. */ - if (!(flags & REFNAME_ALLOW_ONELEVEL) && component_count < 2) - return -1; /* Refname has only one component. */ - return 0; -} - const char *prettify_refname(const char *name) { return name + ( @@@ -1392,6 -1073,35 +1393,6 @@@ static int remove_empty_directories(con return result; } -/* - * Return true iff a reference named refname could be created without - * conflicting with the name of an existing reference. If oldrefname - * is non-NULL, ignore potential conflicts with oldrefname (e.g., - * because oldrefname is scheduled for deletion in the same - * operation). - */ -static int is_refname_available(const char *refname, const char *oldrefname, - struct ref_array *array) -{ - int i, namlen = strlen(refname); /* e.g. 'foo/bar' */ - for (i = 0; i < array->nr; i++ ) { - struct ref_entry *entry = array->refs[i]; - /* entry->name could be 'foo' or 'foo/bar/baz' */ - if (!oldrefname || strcmp(oldrefname, entry->name)) { - int len = strlen(entry->name); - int cmplen = (namlen < len) ? namlen : len; - const char *lead = (namlen < len) ? entry->name : refname; - if (!strncmp(refname, entry->name, cmplen) && - lead[cmplen] == '/') { - error("'%s' exists; cannot create '%s'", - entry->name, refname); - return 0; - } - } - } - return 1; -} - /* * *string and *len will only be substituted, and *string returned (for * later free()ing) if the string passed in is a magic short-hand form @@@ -1577,44 -1287,36 +1578,44 @@@ struct ref_lock *lock_any_ref_for_updat return lock_ref_sha1_basic(refname, old_sha1, flags, NULL); } +struct repack_without_ref_sb { + const char *refname; + int fd; +}; + +static int repack_without_ref_fn(const char *refname, const unsigned char *sha1, + int flags, void *cb_data) +{ + struct repack_without_ref_sb *data = cb_data; + char line[PATH_MAX + 100]; + int len; + + if (!strcmp(data->refname, refname)) + return 0; + len = snprintf(line, sizeof(line), "%s %s\n", + sha1_to_hex(sha1), refname); + /* this should not happen but just being defensive */ + if (len > sizeof(line)) + die("too long a refname '%s'", refname); + write_or_die(data->fd, line, len); + return 0; +} + static struct lock_file packlock; static int repack_without_ref(const char *refname) { - struct ref_array *packed; - int fd, i; - - packed = get_packed_refs(get_ref_cache(NULL)); - if (search_ref_array(packed, refname) == NULL) + struct repack_without_ref_sb data; + struct ref_dir *packed = get_packed_refs(get_ref_cache(NULL)); + if (find_ref(packed, refname) == NULL) return 0; - fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0); - if (fd < 0) { + data.refname = refname; + data.fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0); + if (data.fd < 0) { unable_to_lock_error(git_path("packed-refs"), errno); return error("cannot delete '%s' from packed refs", refname); } - - for (i = 0; i < packed->nr; i++) { - char line[PATH_MAX + 100]; - int len; - struct ref_entry *ref = packed->refs[i]; - - if (!strcmp(refname, ref->name)) - continue; - len = snprintf(line, sizeof(line), "%s %s\n", - sha1_to_hex(ref->sha1), ref->name); - /* this should not happen but just being defensive */ - if (len > sizeof(line)) - die("too long a refname '%s'", ref->name); - write_or_die(fd, line, len); - } + do_for_each_ref_in_dir(packed, 0, "", repack_without_ref_fn, 0, 0, &data); return commit_lock_file(&packlock); } @@@ -2225,10 -1927,10 +2226,10 @@@ int for_each_reflog_ent(const char *ref static int do_for_each_reflog(const char *base, each_ref_fn fn, void *cb_data) { - DIR *dir = opendir(git_path("logs/%s", base)); + DIR *d = opendir(git_path("logs/%s", base)); int retval = 0; - if (dir) { + if (d) { struct dirent *de; int baselen = strlen(base); char *log = xmalloc(baselen + 257); @@@ -2237,7 -1939,7 +2238,7 @@@ if (baselen && base[baselen-1] != '/') log[baselen++] = '/'; - while ((de = readdir(dir)) != NULL) { + while ((de = readdir(d)) != NULL) { struct stat st; int namelen; @@@ -2264,7 -1966,7 +2265,7 @@@ break; } free(log); - closedir(dir); + closedir(d); } else if (*base) return errno; @@@ -2303,6 -2005,12 +2304,6 @@@ int update_ref(const char *action, cons return 0; } -int ref_exists(const char *refname) -{ - unsigned char sha1[20]; - return !!resolve_ref_unsafe(refname, sha1, 1, NULL); -} - struct ref *find_ref_by_name(const struct ref *list, const char *name) { for ( ; list; list = list->next)