From 2ba0572a82923fb67da21393ca7a4181ba99b0ed Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Wed, 3 Mar 2021 15:15:28 +0900 Subject: [PATCH] Imported Upstream version 2.5.2 --- Documentation/RelNotes/2.2.3.txt | 9 ++++ Documentation/RelNotes/2.3.9.txt | 9 ++++ Documentation/RelNotes/2.4.9.txt | 9 ++++ Documentation/RelNotes/2.5.2.txt | 63 ++++++++++++++++++++++++ Documentation/config.txt | 2 +- Documentation/git.txt | 12 +++-- Documentation/pretty-formats.txt | 2 + Documentation/pretty-options.txt | 2 + Documentation/rev-list-options.txt | 2 + GIT-VERSION-GEN | 2 +- Makefile | 4 +- RelNotes | 2 +- alias.c | 3 +- archive-zip.c | 99 ++++++++++++++++++++++++++++++++++++-- builtin/checkout.c | 2 +- builtin/commit.c | 4 +- builtin/fetch.c | 14 +++--- builtin/ls-files.c | 2 +- builtin/rev-list.c | 3 ++ builtin/show-branch.c | 6 ++- cache.h | 1 + config.c | 44 ++++++++++++----- generate-cmdlist.perl | 50 ------------------- generate-cmdlist.sh | 50 +++++++++++++++++++ git-compat-util.h | 2 +- notes.c | 19 ++++---- pager.c | 3 +- po/README | 19 ++++++++ revision.c | 17 ++++++- run-command.c | 17 +------ setup.c | 4 +- sha1_file.c | 14 +++--- strbuf.c | 10 ++-- t/t0090-cache-tree.sh | 10 ++++ t/t1509-root-worktree.sh | 8 +-- t/t2019-checkout-ambiguous-ref.sh | 2 +- t/t3020-ls-files-error-unmatch.sh | 2 +- t/t4202-log.sh | 14 ++++++ t/t5004-archive-corner-cases.sh | 40 +++++++++++++++ t/t7006-pager.sh | 9 ++++ t/t7300-clean.sh | 16 ++---- t/t7513-interpret-trailers.sh | 29 ++++++++++- test-dump-split-index.c | 6 ++- trailer.c | 13 ++++- unpack-trees.c | 17 ++++--- usage.c | 31 +++++++----- wt-status.c | 1 - wt-status.h | 1 + 48 files changed, 524 insertions(+), 176 deletions(-) create mode 100644 Documentation/RelNotes/2.2.3.txt create mode 100644 Documentation/RelNotes/2.3.9.txt create mode 100644 Documentation/RelNotes/2.4.9.txt create mode 100644 Documentation/RelNotes/2.5.2.txt delete mode 100755 generate-cmdlist.perl create mode 100755 generate-cmdlist.sh diff --git a/Documentation/RelNotes/2.2.3.txt b/Documentation/RelNotes/2.2.3.txt new file mode 100644 index 0000000..5bfffa4 --- /dev/null +++ b/Documentation/RelNotes/2.2.3.txt @@ -0,0 +1,9 @@ +Git v2.2.3 Release Notes +======================== + +Fixes since v2.2.2 +------------------ + + * A handful of codepaths that used to use fixed-sized arrays to hold + pathnames have been corrected to use strbuf and other mechanisms to + allow longer pathnames without fearing overflows. diff --git a/Documentation/RelNotes/2.3.9.txt b/Documentation/RelNotes/2.3.9.txt new file mode 100644 index 0000000..1a2ad32 --- /dev/null +++ b/Documentation/RelNotes/2.3.9.txt @@ -0,0 +1,9 @@ +Git v2.3.9 Release Notes +======================== + +Fixes since v2.3.8 +------------------ + + * A handful of codepaths that used to use fixed-sized arrays to hold + pathnames have been corrected to use strbuf and other mechanisms to + allow longer pathnames without fearing overflows. diff --git a/Documentation/RelNotes/2.4.9.txt b/Documentation/RelNotes/2.4.9.txt new file mode 100644 index 0000000..09af9dd --- /dev/null +++ b/Documentation/RelNotes/2.4.9.txt @@ -0,0 +1,9 @@ +Git v2.4.9 Release Notes +======================== + +Fixes since v2.4.9 +------------------ + + * A handful of codepaths that used to use fixed-sized arrays to hold + pathnames have been corrected to use strbuf and other mechanisms to + allow longer pathnames without fearing overflows. diff --git a/Documentation/RelNotes/2.5.2.txt b/Documentation/RelNotes/2.5.2.txt new file mode 100644 index 0000000..3f74939 --- /dev/null +++ b/Documentation/RelNotes/2.5.2.txt @@ -0,0 +1,63 @@ +Git v2.5.2 Release Notes +======================== + +Fixes since v2.5.1 +------------------ + + * "git init empty && git -C empty log" said "bad default revision 'HEAD'", + which was found to be a bit confusing to new users. + + * The "interpret-trailers" helper mistook a multi-paragraph title of + a commit log message with a colon in it as the end of the trailer + block. + + * When re-priming the cache-tree opportunistically while committing + the in-core index as-is, we mistakenly invalidated the in-core + index too aggressively, causing the experimental split-index code + to unnecessarily rewrite the on-disk index file(s). + + * "git archive" did not use zip64 extension when creating an archive + with more than 64k entries, which nobody should need, right ;-)? + + * The code in "multiple-worktree" support that attempted to recover + from an inconsistent state updated an incorrect file. + + * "git rev-list" does not take "--notes" option, but did not complain + when one is given. + + * Because the configuration system does not allow "alias.0foo" and + "pager.0foo" as the configuration key, the user cannot use '0foo' + as a custom command name anyway, but "git 0foo" tried to look these + keys up and emitted useless warnings before saying '0foo is not a + git command'. These warning messages have been squelched. + + * We recently rewrote one of the build scripts in Perl, which made it + necessary to have Perl to build Git. Reduced Perl dependency by + rewriting it again using sed. + + * t1509 test that requires a dedicated VM environment had some + bitrot, which has been corrected. + + * strbuf_read() used to have one extra iteration (and an unnecessary + strbuf_grow() of 8kB), which was eliminated. + + * The codepath to produce error messages had a hard-coded limit to + the size of the message, primarily to avoid memory allocation while + calling die(). + + * When trying to see that an object does not exist, a state errno + leaked from our "first try to open a packfile with O_NOATIME and + then if it fails retry without it" logic on a system that refuses + O_NOATIME. This confused us and caused us to die, saying that the + packfile is unreadable, when we should have just reported that the + object does not exist in that packfile to the caller. + + * An off-by-one error made "git remote" to mishandle a remote with a + single letter nickname. + + * A handful of codepaths that used to use fixed-sized arrays to hold + pathnames have been corrected to use strbuf and other mechanisms to + allow longer pathnames without fearing overflows. + +Also contains typofixes, documentation updates and trivial code +clean-ups. diff --git a/Documentation/config.txt b/Documentation/config.txt index 43bb53c..a65cdd4 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1298,7 +1298,7 @@ gc..reflogExpire:: the refs that match the . gc.reflogExpireUnreachable:: -gc..reflogExpireUnreachable:: +gc..reflogExpireUnreachable:: 'git reflog expire' removes reflog entries older than this time and are not reachable from the current tip; defaults to 30 days. With "" (e.g. "refs/stash") diff --git a/Documentation/git.txt b/Documentation/git.txt index 5a78d77..629e62c 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,15 +43,17 @@ unreleased) version of Git, that is available from the 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v2.5.1/git.html[documentation for release 2.5.1] +* link:v2.5.2/git.html[documentation for release 2.5.2] * release notes for + link:RelNotes/2.5.2.txt[2.5.2], link:RelNotes/2.5.1.txt[2.5.1], link:RelNotes/2.5.0.txt[2.5]. -* link:v2.4.8/git.html[documentation for release 2.4.8] +* link:v2.4.9/git.html[documentation for release 2.4.9] * release notes for + link:RelNotes/2.4.9.txt[2.4.9], link:RelNotes/2.4.8.txt[2.4.8], link:RelNotes/2.4.7.txt[2.4.7], link:RelNotes/2.4.6.txt[2.4.6], @@ -62,9 +64,10 @@ Documentation for older releases are available here: link:RelNotes/2.4.1.txt[2.4.1], link:RelNotes/2.4.0.txt[2.4]. -* link:v2.3.8/git.html[documentation for release 2.3.8] +* link:v2.3.9/git.html[documentation for release 2.3.9] * release notes for + link:RelNotes/2.3.9.txt[2.3.9], link:RelNotes/2.3.8.txt[2.3.8], link:RelNotes/2.3.7.txt[2.3.7], link:RelNotes/2.3.6.txt[2.3.6], @@ -75,9 +78,10 @@ Documentation for older releases are available here: link:RelNotes/2.3.1.txt[2.3.1], link:RelNotes/2.3.0.txt[2.3]. -* link:v2.2.2/git.html[documentation for release 2.2.2] +* link:v2.2.3/git.html[documentation for release 2.2.3] * release notes for + link:RelNotes/2.2.3.txt[2.2.3], link:RelNotes/2.2.2.txt[2.2.2], link:RelNotes/2.2.1.txt[2.2.1], link:RelNotes/2.2.0.txt[2.2]. diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index dc865cb..671cebd 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -139,7 +139,9 @@ The placeholders are: - '%f': sanitized subject line, suitable for a filename - '%b': body - '%B': raw body (unwrapped subject and body) +ifndef::git-rev-list[] - '%N': commit notes +endif::git-rev-list[] - '%GG': raw verification message from GPG for a signed commit - '%G?': show "G" for a Good signature, "B" for a Bad signature, "U" for a good, untrusted signature and "N" for no signature diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt index 642af6e..8d6c5ce 100644 --- a/Documentation/pretty-options.txt +++ b/Documentation/pretty-options.txt @@ -42,6 +42,7 @@ people using 80-column terminals. verbatim; this means that invalid sequences in the original commit may be copied to the output. +ifndef::git-rev-list[] --notes[=]:: Show the notes (see linkgit:git-notes[1]) that annotate the commit, when showing the commit log message. This is the default @@ -73,6 +74,7 @@ being displayed. Examples: "--notes=foo" will show only notes from --[no-]standard-notes:: These options are deprecated. Use the above --notes/--no-notes options instead. +endif::git-rev-list[] --show-signature:: Check the validity of a signed commit object by passing the signature diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 77ac439..31bee06 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -58,9 +58,11 @@ endif::git-rev-list[] more than one `--grep=`, commits whose message matches any of the given patterns are chosen (but see `--all-match`). +ifndef::git-rev-list[] + When `--show-notes` is in effect, the message from the notes is matched as if it were part of the log message. +endif::git-rev-list[] --all-match:: Limit the commits output to ones that match all given `--grep`, diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 5e23aba..9e3723e 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.5.1 +DEF_VER=v2.5.2 LF=' ' diff --git a/Makefile b/Makefile index 8c3c724..ce0cfe2 100644 --- a/Makefile +++ b/Makefile @@ -1696,10 +1696,10 @@ $(BUILT_INS): git$X ln -s $< $@ 2>/dev/null || \ cp $< $@ -common-cmds.h: generate-cmdlist.perl command-list.txt +common-cmds.h: generate-cmdlist.sh command-list.txt common-cmds.h: $(wildcard Documentation/git-*.txt) - $(QUIET_GEN)$(PERL_PATH) generate-cmdlist.perl command-list.txt > $@+ && mv $@+ $@ + $(QUIET_GEN)./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@ SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\ $(localedir_SQ):$(NO_CURL):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\ diff --git a/RelNotes b/RelNotes index 171969f..24f83fe 120000 --- a/RelNotes +++ b/RelNotes @@ -1 +1 @@ -Documentation/RelNotes/2.5.1.txt \ No newline at end of file +Documentation/RelNotes/2.5.2.txt \ No newline at end of file diff --git a/alias.c b/alias.c index 6aa164a..a11229d 100644 --- a/alias.c +++ b/alias.c @@ -5,7 +5,8 @@ char *alias_lookup(const char *alias) char *v = NULL; struct strbuf key = STRBUF_INIT; strbuf_addf(&key, "alias.%s", alias); - git_config_get_string(key.buf, &v); + if (git_config_key_is_valid(key.buf)) + git_config_get_string(key.buf, &v); strbuf_release(&key); return v; } diff --git a/archive-zip.c b/archive-zip.c index ae3d67f..9db4735 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -16,7 +16,9 @@ static unsigned int zip_dir_size; static unsigned int zip_offset; static unsigned int zip_dir_offset; -static unsigned int zip_dir_entries; +static uint64_t zip_dir_entries; + +static unsigned int max_creator_version; #define ZIP_DIRECTORY_MIN_SIZE (1024 * 1024) #define ZIP_STREAM (1 << 3) @@ -86,6 +88,28 @@ struct zip_extra_mtime { unsigned char _end[1]; }; +struct zip64_dir_trailer { + unsigned char magic[4]; + unsigned char record_size[8]; + unsigned char creator_version[2]; + unsigned char version[2]; + unsigned char disk[4]; + unsigned char directory_start_disk[4]; + unsigned char entries_on_this_disk[8]; + unsigned char entries[8]; + unsigned char size[8]; + unsigned char offset[8]; + unsigned char _end[1]; +}; + +struct zip64_dir_trailer_locator { + unsigned char magic[4]; + unsigned char disk[4]; + unsigned char offset[8]; + unsigned char number_of_disks[4]; + unsigned char _end[1]; +}; + /* * On ARM, padding is added at the end of the struct, so a simple * sizeof(struct ...) reports two bytes more than the payload size @@ -98,6 +122,12 @@ struct zip_extra_mtime { #define ZIP_EXTRA_MTIME_SIZE offsetof(struct zip_extra_mtime, _end) #define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \ (ZIP_EXTRA_MTIME_SIZE - offsetof(struct zip_extra_mtime, flags)) +#define ZIP64_DIR_TRAILER_SIZE offsetof(struct zip64_dir_trailer, _end) +#define ZIP64_DIR_TRAILER_RECORD_SIZE \ + (ZIP64_DIR_TRAILER_SIZE - \ + offsetof(struct zip64_dir_trailer, creator_version)) +#define ZIP64_DIR_TRAILER_LOCATOR_SIZE \ + offsetof(struct zip64_dir_trailer_locator, _end) static void copy_le16(unsigned char *dest, unsigned int n) { @@ -113,6 +143,31 @@ static void copy_le32(unsigned char *dest, unsigned int n) dest[3] = 0xff & (n >> 030); } +static void copy_le64(unsigned char *dest, uint64_t n) +{ + dest[0] = 0xff & n; + dest[1] = 0xff & (n >> 010); + dest[2] = 0xff & (n >> 020); + dest[3] = 0xff & (n >> 030); + dest[4] = 0xff & (n >> 040); + dest[5] = 0xff & (n >> 050); + dest[6] = 0xff & (n >> 060); + dest[7] = 0xff & (n >> 070); +} + +static uint64_t clamp_max(uint64_t n, uint64_t max, int *clamped) +{ + if (n <= max) + return n; + *clamped = 1; + return max; +} + +static void copy_le16_clamp(unsigned char *dest, uint64_t n, int *clamped) +{ + copy_le16(dest, clamp_max(n, 0xffff, clamped)); +} + static void *zlib_deflate_raw(void *data, unsigned long size, int compression_level, unsigned long *compressed_size) @@ -223,6 +278,7 @@ static int write_zip_entry(struct archiver_args *args, unsigned long size; int is_binary = -1; const char *path_without_prefix = path + args->baselen; + unsigned int creator_version = 0; crc = crc32(0, NULL, 0); @@ -251,6 +307,8 @@ static int write_zip_entry(struct archiver_args *args, method = 0; attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) : (mode & 0111) ? ((mode) << 16) : 0; + if (S_ISLNK(mode) || (mode & 0111)) + creator_version = 0x0317; if (S_ISREG(mode) && args->compression_level != 0 && size > 0) method = 8; @@ -279,6 +337,9 @@ static int write_zip_entry(struct archiver_args *args, sha1_to_hex(sha1)); } + if (creator_version > max_creator_version) + max_creator_version = creator_version; + if (buffer && method == 8) { out = deflated = zlib_deflate_raw(buffer, size, args->compression_level, @@ -303,8 +364,7 @@ static int write_zip_entry(struct archiver_args *args, } copy_le32(dirent.magic, 0x02014b50); - copy_le16(dirent.creator_version, - S_ISLNK(mode) || (S_ISREG(mode) && (mode & 0111)) ? 0x0317 : 0); + copy_le16(dirent.creator_version, creator_version); copy_le16(dirent.version, 10); copy_le16(dirent.flags, flags); copy_le16(dirent.compression_method, method); @@ -437,20 +497,49 @@ static int write_zip_entry(struct archiver_args *args, return 0; } +static void write_zip64_trailer(void) +{ + struct zip64_dir_trailer trailer64; + struct zip64_dir_trailer_locator locator64; + + copy_le32(trailer64.magic, 0x06064b50); + copy_le64(trailer64.record_size, ZIP64_DIR_TRAILER_RECORD_SIZE); + copy_le16(trailer64.creator_version, max_creator_version); + copy_le16(trailer64.version, 45); + copy_le32(trailer64.disk, 0); + copy_le32(trailer64.directory_start_disk, 0); + copy_le64(trailer64.entries_on_this_disk, zip_dir_entries); + copy_le64(trailer64.entries, zip_dir_entries); + copy_le64(trailer64.size, zip_dir_offset); + copy_le64(trailer64.offset, zip_offset); + + copy_le32(locator64.magic, 0x07064b50); + copy_le32(locator64.disk, 0); + copy_le64(locator64.offset, zip_offset + zip_dir_offset); + copy_le32(locator64.number_of_disks, 1); + + write_or_die(1, &trailer64, ZIP64_DIR_TRAILER_SIZE); + write_or_die(1, &locator64, ZIP64_DIR_TRAILER_LOCATOR_SIZE); +} + static void write_zip_trailer(const unsigned char *sha1) { struct zip_dir_trailer trailer; + int clamped = 0; copy_le32(trailer.magic, 0x06054b50); copy_le16(trailer.disk, 0); copy_le16(trailer.directory_start_disk, 0); - copy_le16(trailer.entries_on_this_disk, zip_dir_entries); - copy_le16(trailer.entries, zip_dir_entries); + copy_le16_clamp(trailer.entries_on_this_disk, zip_dir_entries, + &clamped); + copy_le16_clamp(trailer.entries, zip_dir_entries, &clamped); copy_le32(trailer.size, zip_dir_offset); copy_le32(trailer.offset, zip_offset); copy_le16(trailer.comment_length, sha1 ? GIT_SHA1_HEXSZ : 0); write_or_die(1, zip_dir, zip_dir_offset); + if (clamped) + write_zip64_trailer(); write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE); if (sha1) write_or_die(1, sha1_to_hex(sha1), GIT_SHA1_HEXSZ); diff --git a/builtin/checkout.c b/builtin/checkout.c index f71844a..3b6e499 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -282,7 +282,7 @@ static int checkout_paths(const struct checkout_opts *opts, if (opts->source_tree) read_tree_some(opts->source_tree, &opts->pathspec); - ps_matched = xcalloc(1, opts->pathspec.nr); + ps_matched = xcalloc(opts->pathspec.nr, 1); /* * Make sure all pathspecs participated in locating the paths diff --git a/builtin/commit.c b/builtin/commit.c index 254477f..1692620 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -404,10 +404,8 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix hold_locked_index(&index_lock, 1); refresh_cache_or_die(refresh_flags); if (active_cache_changed - || !cache_tree_fully_valid(active_cache_tree)) { + || !cache_tree_fully_valid(active_cache_tree)) update_main_cache_tree(WRITE_TREE_SILENT); - active_cache_changed = 1; - } if (active_cache_changed) { if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK)) diff --git a/builtin/fetch.c b/builtin/fetch.c index 8d5b2db..635bbdf 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -979,17 +979,15 @@ static int get_remote_group(const char *key, const char *value, void *priv) { struct remote_group_data *g = priv; - if (starts_with(key, "remotes.") && - !strcmp(key + 8, g->name)) { + if (skip_prefix(key, "remotes.", &key) && !strcmp(key, g->name)) { /* split list by white space */ - int space = strcspn(value, " \t\n"); while (*value) { - if (space > 1) { + size_t wordlen = strcspn(value, " \t\n"); + + if (wordlen >= 1) string_list_append(g->list, - xstrndup(value, space)); - } - value += space + (value[space] != '\0'); - space = strcspn(value, " \t\n"); + xstrndup(value, wordlen)); + value += wordlen + (value[wordlen] != '\0'); } } diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 6fa2205..b6a7cb0 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -516,7 +516,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) /* Treat unmatching pathspec elements as errors */ if (pathspec.nr && error_unmatch) - ps_matched = xcalloc(1, pathspec.nr); + ps_matched = xcalloc(pathspec.nr, 1); if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) die("ls-files --ignored needs some exclude pattern"); diff --git a/builtin/rev-list.c b/builtin/rev-list.c index c0b4b53..d80d1ed 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -350,6 +350,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) revs.diff) usage(rev_list_usage); + if (revs.show_notes) + die(_("rev-list does not support display of notes")); + save_commit_buffer = (revs.verbose_header || revs.grep_filter.pattern_list || revs.grep_filter.header_list); diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 323f857..344ae4c 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -730,7 +730,6 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) if (reflog) { struct object_id oid; - char nth_desc[256]; char *ref; int base = 0; unsigned int flags = 0; @@ -769,6 +768,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) for (i = 0; i < reflog; i++) { char *logmsg; + char *nth_desc; const char *msg; unsigned long timestamp; int tz; @@ -787,8 +787,10 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) show_date(timestamp, tz, 1), msg); free(logmsg); - sprintf(nth_desc, "%s@{%d}", *av, base+i); + + nth_desc = xstrfmt("%s@{%d}", *av, base+i); append_ref(nth_desc, &oid, 1); + free(nth_desc); } free(ref); } diff --git a/cache.h b/cache.h index 4f55466..c9e2f74 100644 --- a/cache.h +++ b/cache.h @@ -1446,6 +1446,7 @@ extern int git_config_pathname(const char **, const char *, const char *); extern int git_config_set_in_file(const char *, const char *, const char *); extern int git_config_set(const char *, const char *); extern int git_config_parse_key(const char *, char **, int *); +extern int git_config_key_is_valid(const char *key); extern int git_config_set_multivar(const char *, const char *, const char *, int); extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int); extern int git_config_rename_section(const char *, const char *); diff --git a/config.c b/config.c index 9fd275f..0e532b8 100644 --- a/config.c +++ b/config.c @@ -1848,7 +1848,7 @@ int git_config_set(const char *key, const char *value) * baselen - pointer to int which will hold the length of the * section + subsection part, can be NULL */ -int git_config_parse_key(const char *key, char **store_key, int *baselen_) +static int git_config_parse_key_1(const char *key, char **store_key, int *baselen_, int quiet) { int i, dot, baselen; const char *last_dot = strrchr(key, '.'); @@ -1859,12 +1859,14 @@ int git_config_parse_key(const char *key, char **store_key, int *baselen_) */ if (last_dot == NULL || last_dot == key) { - error("key does not contain a section: %s", key); + if (!quiet) + error("key does not contain a section: %s", key); return -CONFIG_NO_SECTION_OR_NAME; } if (!last_dot[1]) { - error("key does not contain variable name: %s", key); + if (!quiet) + error("key does not contain variable name: %s", key); return -CONFIG_NO_SECTION_OR_NAME; } @@ -1875,7 +1877,8 @@ int git_config_parse_key(const char *key, char **store_key, int *baselen_) /* * Validate the key and while at it, lower case it for matching. */ - *store_key = xmalloc(strlen(key) + 1); + if (store_key) + *store_key = xmalloc(strlen(key) + 1); dot = 0; for (i = 0; key[i]; i++) { @@ -1886,26 +1889,42 @@ int git_config_parse_key(const char *key, char **store_key, int *baselen_) if (!dot || i > baselen) { if (!iskeychar(c) || (i == baselen + 1 && !isalpha(c))) { - error("invalid key: %s", key); + if (!quiet) + error("invalid key: %s", key); goto out_free_ret_1; } c = tolower(c); } else if (c == '\n') { - error("invalid key (newline): %s", key); + if (!quiet) + error("invalid key (newline): %s", key); goto out_free_ret_1; } - (*store_key)[i] = c; + if (store_key) + (*store_key)[i] = c; } - (*store_key)[i] = 0; + if (store_key) + (*store_key)[i] = 0; return 0; out_free_ret_1: - free(*store_key); - *store_key = NULL; + if (store_key) { + free(*store_key); + *store_key = NULL; + } return -CONFIG_INVALID_KEY; } +int git_config_parse_key(const char *key, char **store_key, int *baselen) +{ + return git_config_parse_key_1(key, store_key, baselen, 0); +} + +int git_config_key_is_valid(const char *key) +{ + return !git_config_parse_key_1(key, NULL, NULL, 1); +} + /* * If value==NULL, unset in (remove from) config, * if value_regex!=NULL, disregard key/value pairs where value does not match. @@ -1935,7 +1954,7 @@ int git_config_set_multivar_in_file(const char *config_filename, const char *key, const char *value, const char *value_regex, int multi_replace) { - int fd = -1, in_fd; + int fd = -1, in_fd = -1; int ret; struct lock_file *lock = NULL; char *filename_buf = NULL; @@ -2065,6 +2084,7 @@ int git_config_set_multivar_in_file(const char *config_filename, goto out_free; } close(in_fd); + in_fd = -1; if (chmod(lock->filename.buf, st.st_mode & 07777) < 0) { error("chmod on %s failed: %s", @@ -2148,6 +2168,8 @@ out_free: free(filename_buf); if (contents) munmap(contents, contents_sz); + if (in_fd >= 0) + close(in_fd); return ret; write_err_out: diff --git a/generate-cmdlist.perl b/generate-cmdlist.perl deleted file mode 100755 index 31516e3..0000000 --- a/generate-cmdlist.perl +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/perl -use strict; -use warnings; - -print <<"EOT"; -/* Automatically generated by $0 */ - -struct cmdname_help { - char name[16]; - char help[80]; - unsigned char group; -}; - -static char *common_cmd_groups[] = { -EOT - -my $n = 0; -my %grp; -while (<>) { - last if /^### command list/; - next if (1../^### common groups/) || /^#/ || /^\s*$/; - chop; - my ($k, $v) = split ' ', $_, 2; - $grp{$k} = $n++; - print "\tN_(\"$v\"),\n"; -} - -print "};\n\nstatic struct cmdname_help common_cmds[] = {\n"; - -while (<>) { - next if /^#/ || /^\s*$/; - my @tags = split; - my $cmd = shift @tags; - for my $t (@tags) { - if (exists $grp{$t}) { - my $s; - open my $f, '<', "Documentation/$cmd.txt" or die; - while (<$f>) { - ($s) = /^$cmd - (.+)$/; - last if $s; - } - close $f; - $cmd =~ s/^git-//; - print "\t{\"$cmd\", N_(\"$s\"), $grp{$t}},\n"; - last; - } - } -} - -print "};\n"; diff --git a/generate-cmdlist.sh b/generate-cmdlist.sh new file mode 100755 index 0000000..ab0d1b0 --- /dev/null +++ b/generate-cmdlist.sh @@ -0,0 +1,50 @@ +#!/bin/sh + +echo "/* Automatically generated by $0 */ +struct cmdname_help { + char name[16]; + char help[80]; + unsigned char group; +}; + +static const char *common_cmd_groups[] = {" + +grps=grps$$.tmp +match=match$$.tmp +trap "rm -f '$grps' '$match'" 0 1 2 3 15 + +sed -n ' + 1,/^### common groups/b + /^### command list/q + /^#/b + /^[ ]*$/b + h;s/^[^ ][^ ]*[ ][ ]*\(.*\)/ N_("\1"),/p + g;s/^\([^ ][^ ]*\)[ ].*/\1/w '$grps' + ' "$1" +printf '};\n\n' + +n=0 +substnum= +while read grp +do + echo "^git-..*[ ]$grp" + substnum="$substnum${substnum:+;}s/[ ]$grp/$n/" + n=$(($n+1)) +done <"$grps" >"$match" + +printf 'static struct cmdname_help common_cmds[] = {\n' +grep -f "$match" "$1" | +sed 's/^git-//' | +sort | +while read cmd tags +do + tag=$(echo "$tags" | sed "$substnum; s/[^0-9]//g") + sed -n ' + /^NAME/,/git-'"$cmd"'/H + ${ + x + s/.*git-'"$cmd"' - \(.*\)/ {"'"$cmd"'", N_("\1"), '$tag'},/ + p + }' "Documentation/git-$cmd.txt" +done +echo "};" diff --git a/git-compat-util.h b/git-compat-util.h index c6d391f..076461e 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -389,7 +389,6 @@ struct strbuf; /* General helper functions */ extern void vreportf(const char *prefix, const char *err, va_list params); -extern void vwritef(int fd, const char *prefix, const char *err, va_list params); extern NORETURN void usage(const char *err); extern NORETURN void usagef(const char *err, ...) __attribute__((format (printf, 1, 2))); extern NORETURN void die(const char *err, ...) __attribute__((format (printf, 1, 2))); @@ -425,6 +424,7 @@ static inline int const_error(void) extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params)); extern void set_error_routine(void (*routine)(const char *err, va_list params)); extern void set_die_is_recursing_routine(int (*routine)(void)); +extern void set_error_handle(FILE *); extern int starts_with(const char *str, const char *prefix); diff --git a/notes.c b/notes.c index df08209..eacd2a6 100644 --- a/notes.c +++ b/notes.c @@ -362,13 +362,14 @@ static int non_note_cmp(const struct non_note *a, const struct non_note *b) return strcmp(a->path, b->path); } -static void add_non_note(struct notes_tree *t, const char *path, +/* note: takes ownership of path string */ +static void add_non_note(struct notes_tree *t, char *path, unsigned int mode, const unsigned char *sha1) { struct non_note *p = t->prev_non_note, *n; n = (struct non_note *) xmalloc(sizeof(struct non_note)); n->next = NULL; - n->path = xstrdup(path); + n->path = path; n->mode = mode; hashcpy(n->sha1, sha1); t->prev_non_note = n; @@ -482,17 +483,17 @@ handle_non_note: * component. */ { - char non_note_path[PATH_MAX]; - char *p = non_note_path; + struct strbuf non_note_path = STRBUF_INIT; const char *q = sha1_to_hex(subtree->key_sha1); int i; for (i = 0; i < prefix_len; i++) { - *p++ = *q++; - *p++ = *q++; - *p++ = '/'; + strbuf_addch(&non_note_path, *q++); + strbuf_addch(&non_note_path, *q++); + strbuf_addch(&non_note_path, '/'); } - strcpy(p, entry.path); - add_non_note(t, non_note_path, entry.mode, entry.sha1); + strbuf_addstr(&non_note_path, entry.path); + add_non_note(t, strbuf_detach(&non_note_path, NULL), + entry.mode, entry.sha1); } } free(buf); diff --git a/pager.c b/pager.c index 070dc11..27d4c8a 100644 --- a/pager.c +++ b/pager.c @@ -150,7 +150,8 @@ int check_pager_config(const char *cmd) struct strbuf key = STRBUF_INIT; const char *value = NULL; strbuf_addf(&key, "pager.%s", cmd); - if (!git_config_get_value(key.buf, &value)) { + if (git_config_key_is_valid(key.buf) && + !git_config_get_value(key.buf, &value)) { int b = git_config_maybe_bool(key.buf, value); if (b >= 0) want = b; diff --git a/po/README b/po/README index d8c9111..fef4c0f 100644 --- a/po/README +++ b/po/README @@ -10,10 +10,26 @@ coordinates our localization effort in the l10 coordinator repository: https://github.com/git-l10n/git-po/ +The two character language translation codes are defined by ISO_639-1, as +stated in the gettext(1) full manual, appendix A.1, Usual Language Codes. + + +Contributing to an existing translation +--------------------------------------- As a contributor for a language XX, you should first check TEAMS file in this directory to see whether a dedicated repository for your language XX exists. Fork the dedicated repository and start to work if it exists. +Sometime, contributors may find that the translations of their Git +distributions are quite different with the translations of the +corresponding version from Git official. This is because some Git +distributions (such as from Ubuntu, etc.) have their own l10n workflow. +For this case, wrong translations should be reported and fixed through +their workflows. + + +Creating a new language translation +----------------------------------- If you are the first contributor for the language XX, please fork this repository, prepare and/or update the translated message file po/XX.po (described later), and ask the l10n coordinator to pull your work. @@ -23,6 +39,9 @@ coordinate among yourselves and nominate the team leader for your language, so that the l10n coordinator only needs to interact with one person per language. + +Translation Process Flow +------------------------ The overall data-flow looks like this: +-------------------+ +------------------+ diff --git a/revision.c b/revision.c index ab97ffd..9b9d77d 100644 --- a/revision.c +++ b/revision.c @@ -2173,6 +2173,21 @@ static int handle_revision_pseudo_opt(const char *submodule, return 1; } +static void NORETURN diagnose_missing_default(const char *def) +{ + unsigned char sha1[20]; + int flags; + const char *refname; + + refname = resolve_ref_unsafe(def, 0, sha1, &flags); + if (!refname || !(flags & REF_ISSYMREF) || (flags & REF_ISBROKEN)) + die(_("your current branch appears to be broken")); + + skip_prefix(refname, "refs/heads/", &refname); + die(_("your current branch '%s' does not have any commits yet"), + refname); +} + /* * Parse revision information, filling in the "rev_info" structure, * and removing the used arguments from the argument list. @@ -2302,7 +2317,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s struct object *object; struct object_context oc; if (get_sha1_with_context(revs->def, 0, sha1, &oc)) - die("bad default revision '%s'", revs->def); + diagnose_missing_default(revs->def); object = get_reference(revs, revs->def, sha1, 0); add_pending_object_with_mode(revs, object, revs->def, oc.mode); } diff --git a/run-command.c b/run-command.c index 4d73e90..0d01671 100644 --- a/run-command.c +++ b/run-command.c @@ -200,7 +200,6 @@ static int execv_shell_cmd(const char **argv) #endif #ifndef GIT_WINDOWS_NATIVE -static int child_err = 2; static int child_notifier = -1; static void notify_parent(void) @@ -212,17 +211,6 @@ static void notify_parent(void) */ xwrite(child_notifier, "", 1); } - -static NORETURN void die_child(const char *err, va_list params) -{ - vwritef(child_err, "fatal: ", err, params); - exit(128); -} - -static void error_child(const char *err, va_list params) -{ - vwritef(child_err, "error: ", err, params); -} #endif static inline void set_cloexec(int fd) @@ -362,11 +350,10 @@ fail_pipe: * in subsequent call paths use the parent's stderr. */ if (cmd->no_stderr || need_err) { - child_err = dup(2); + int child_err = dup(2); set_cloexec(child_err); + set_error_handle(fdopen(child_err, "w")); } - set_die_routine(die_child); - set_error_routine(error_child); close(notify_pipe[0]); set_cloexec(notify_pipe[1]); diff --git a/setup.c b/setup.c index 82c0cc2..465b42a 100644 --- a/setup.c +++ b/setup.c @@ -402,9 +402,9 @@ static void update_linked_gitdir(const char *gitfile, const char *gitdir) struct strbuf path = STRBUF_INIT; struct stat st; - strbuf_addf(&path, "%s/gitfile", gitdir); + strbuf_addf(&path, "%s/gitdir", gitdir); if (stat(path.buf, &st) || st.st_mtime + 24 * 3600 < time(NULL)) - write_file(path.buf, 0, "%s\n", gitfile); + write_file(path.buf, 1, "%s\n", gitfile); strbuf_release(&path); } diff --git a/sha1_file.c b/sha1_file.c index 1cee438..17262e1 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -377,15 +377,12 @@ void read_info_alternates(const char * relative_base, int depth) char *map; size_t mapsz; struct stat st; - const char alt_file_name[] = "info/alternates"; - /* Given that relative_base is no longer than PATH_MAX, - ensure that "path" has enough space to append "/", the - file name, "info/alternates", and a trailing NUL. */ - char path[PATH_MAX + 1 + sizeof alt_file_name]; + char *path; int fd; - sprintf(path, "%s/%s", relative_base, alt_file_name); + path = xstrfmt("%s/info/alternates", relative_base); fd = git_open_noatime(path); + free(path); if (fd < 0) return; if (fstat(fd, &st) || (st.st_size == 0)) { @@ -1461,7 +1458,10 @@ int git_open_noatime(const char *name) static int sha1_file_open_flag = O_NOATIME; for (;;) { - int fd = open(name, O_RDONLY | sha1_file_open_flag); + int fd; + + errno = 0; + fd = open(name, O_RDONLY | sha1_file_open_flag); if (fd >= 0) return fd; diff --git a/strbuf.c b/strbuf.c index bbaf32e..c606f33 100644 --- a/strbuf.c +++ b/strbuf.c @@ -364,19 +364,19 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) strbuf_grow(sb, hint ? hint : 8192); for (;;) { - ssize_t cnt; + ssize_t want = sb->alloc - sb->len - 1; + ssize_t got = read_in_full(fd, sb->buf + sb->len, want); - cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); - if (cnt < 0) { + if (got < 0) { if (oldalloc == 0) strbuf_release(sb); else strbuf_setlen(sb, oldlen); return -1; } - if (!cnt) + sb->len += got; + if (got < want) break; - sb->len += cnt; strbuf_grow(sb, 8192); } diff --git a/t/t0090-cache-tree.sh b/t/t0090-cache-tree.sh index 601d02d..f92dd1f 100755 --- a/t/t0090-cache-tree.sh +++ b/t/t0090-cache-tree.sh @@ -218,4 +218,14 @@ test_expect_success 'no phantom error when switching trees' ' ! test -s errors ' +test_expect_success 'switching trees does not invalidate shared index' ' + git update-index --split-index && + >split && + git add split && + test-dump-split-index .git/index | grep -v ^own >before && + git commit -m "as-is" && + test-dump-split-index .git/index | grep -v ^own >after && + test_cmp before after +' + test_done diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh index b6977d4..553a3f6 100755 --- a/t/t1509-root-worktree.sh +++ b/t/t1509-root-worktree.sh @@ -125,7 +125,7 @@ fi ONE_SHA1=d00491fd7e5bb6fa28c517a0bb32b8b506539d4d test_expect_success 'setup' ' - rm -rf /foo + rm -rf /foo && mkdir /foo && mkdir /foo/bar && echo 1 > /foo/foome && @@ -218,7 +218,7 @@ unset GIT_WORK_TREE test_expect_success 'go to /' 'cd /' test_expect_success 'setup' ' - rm -rf /.git + rm -rf /.git && echo "Initialized empty Git repository in /.git/" > expected && git init > result && test_cmp expected result @@ -241,8 +241,8 @@ say "auto bare gitdir" # DESTROYYYYY!!!!! test_expect_success 'setup' ' - rm -rf /refs /objects /info /hooks - rm /* + rm -rf /refs /objects /info /hooks && + rm -f /expected /ls.expected /me /result && cd / && echo "Initialized empty Git repository in /" > expected && git init --bare > result && diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh index 8396320..199b22d 100755 --- a/t/t2019-checkout-ambiguous-ref.sh +++ b/t/t2019-checkout-ambiguous-ref.sh @@ -69,7 +69,7 @@ test_expect_success 'wildcard ambiguation, paths win' ' ) ' -test_expect_success 'wildcard ambiguation, refs lose' ' +test_expect_success !MINGW 'wildcard ambiguation, refs lose' ' git init ambi2 && ( cd ambi2 && diff --git a/t/t3020-ls-files-error-unmatch.sh b/t/t3020-ls-files-error-unmatch.sh index ca01053..124e73b 100755 --- a/t/t3020-ls-files-error-unmatch.sh +++ b/t/t3020-ls-files-error-unmatch.sh @@ -22,7 +22,7 @@ test_expect_success \ 'test_must_fail git ls-files --error-unmatch foo bar-does-not-match' test_expect_success \ - 'git ls-files --error-unmatch should succeed eith matched paths.' \ + 'git ls-files --error-unmatch should succeed with matched paths.' \ 'git ls-files --error-unmatch foo bar' test_done diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 1b2e981..19277dd 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -871,4 +871,18 @@ test_expect_success 'log --graph --no-walk is forbidden' ' test_must_fail git log --graph --no-walk ' +test_expect_success 'log diagnoses bogus HEAD' ' + git init empty && + test_must_fail git -C empty log 2>stderr && + test_i18ngrep does.not.have.any.commits stderr && + echo 1234abcd >empty/.git/refs/heads/master && + test_must_fail git -C empty log 2>stderr && + test_i18ngrep broken stderr && + echo "ref: refs/heads/invalid.lock" >empty/.git/HEAD && + test_must_fail git -C empty log 2>stderr && + test_i18ngrep broken stderr && + test_must_fail git -C empty log --default totally-bogus 2>stderr && + test_i18ngrep broken stderr +' + test_done diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh index 654adda..cca2338 100755 --- a/t/t5004-archive-corner-cases.sh +++ b/t/t5004-archive-corner-cases.sh @@ -115,4 +115,44 @@ test_expect_success 'archive empty subtree by direct pathspec' ' check_dir extract sub ' +ZIPINFO=zipinfo + +test_lazy_prereq ZIPINFO ' + n=$("$ZIPINFO" "$TEST_DIRECTORY"/t5004/empty.zip | sed -n "2s/.* //p") + test "x$n" = "x0" +' + +test_expect_success ZIPINFO 'zip archive with many entries' ' + # add a directory with 256 files + mkdir 00 && + for a in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + for b in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + : >00/$a$b + done + done && + git add 00 && + git commit -m "256 files in 1 directory" && + + # duplicate it to get 65536 files in 256 directories + subtree=$(git write-tree --prefix=00/) && + for c in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f + do + echo "040000 tree $subtree $c$d" + done + done >tree && + tree=$(git mktree expect && + "$ZIPINFO" many.zip | head -2 | sed -n "2s/.* //p" >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh index 947b690..6ea7ac4 100755 --- a/t/t7006-pager.sh +++ b/t/t7006-pager.sh @@ -447,4 +447,13 @@ test_expect_success TTY 'external command pagers override sub-commands' ' test_cmp expect actual ' +test_expect_success 'command with underscores does not complain' ' + write_script git-under_score <<-\EOF && + echo ok + EOF + git --exec-path=. under_score >actual 2>&1 && + echo ok >expect && + test_cmp expect actual +' + test_done diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 99be5d9..634808a 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -432,9 +432,7 @@ test_expect_success 'nested git work tree' ' ( cd foo && git init && - >hello.world - git add . && - git commit -a -m nested + test_commit nested hello.world ) && ( cd bar && @@ -443,9 +441,7 @@ test_expect_success 'nested git work tree' ' ( cd baz/boo && git init && - >deeper.world - git add . && - git commit -a -m deeply.nested + test_commit deeply.nested deeper.world ) && git clean -f -d && test -f foo/.git/index && @@ -461,9 +457,7 @@ test_expect_success 'force removal of nested git work tree' ' ( cd foo && git init && - >hello.world - git add . && - git commit -a -m nested + test_commit nested hello.world ) && ( cd bar && @@ -472,9 +466,7 @@ test_expect_success 'force removal of nested git work tree' ' ( cd baz/boo && git init && - >deeper.world - git add . && - git commit -a -m deeply.nested + test_commit deeply.nested deeper.world ) && git clean -f -f -d && ! test -d foo && diff --git a/t/t7513-interpret-trailers.sh b/t/t7513-interpret-trailers.sh index bd0ab46..322c436 100755 --- a/t/t7513-interpret-trailers.sh +++ b/t/t7513-interpret-trailers.sh @@ -93,12 +93,39 @@ test_expect_success 'with config option on the command line' ' Acked-by: Johan Reviewed-by: Peff EOF - echo "Acked-by: Johan" | + { echo; echo "Acked-by: Johan"; } | git -c "trailer.Acked-by.ifexists=addifdifferent" interpret-trailers \ --trailer "Reviewed-by: Peff" --trailer "Acked-by: Johan" >actual && test_cmp expected actual ' +test_expect_success 'with only a title in the message' ' + cat >expected <<-\EOF && + area: change + + Reviewed-by: Peff + Acked-by: Johan + EOF + echo "area: change" | + git interpret-trailers --trailer "Reviewed-by: Peff" \ + --trailer "Acked-by: Johan" >actual && + test_cmp expected actual +' + +test_expect_success 'with multiline title in the message' ' + cat >expected <<-\EOF && + place of + code: change + + Reviewed-by: Peff + Acked-by: Johan + EOF + printf "%s\n" "place of" "code: change" | + git interpret-trailers --trailer "Reviewed-by: Peff" \ + --trailer "Acked-by: Johan" >actual && + test_cmp expected actual +' + test_expect_success 'with config setup' ' git config trailer.ack.key "Acked-by: " && cat >expected <<-\EOF && diff --git a/test-dump-split-index.c b/test-dump-split-index.c index 9cf3112..861d28c 100644 --- a/test-dump-split-index.c +++ b/test-dump-split-index.c @@ -26,9 +26,11 @@ int main(int ac, char **av) sha1_to_hex(ce->sha1), ce_stage(ce), ce->name); } printf("replacements:"); - ewah_each_bit(si->replace_bitmap, show_bit, NULL); + if (si->replace_bitmap) + ewah_each_bit(si->replace_bitmap, show_bit, NULL); printf("\ndeletions:"); - ewah_each_bit(si->delete_bitmap, show_bit, NULL); + if (si->delete_bitmap) + ewah_each_bit(si->delete_bitmap, show_bit, NULL); printf("\n"); return 0; } diff --git a/trailer.c b/trailer.c index 4b14a56..6f3416f 100644 --- a/trailer.c +++ b/trailer.c @@ -735,13 +735,22 @@ static int find_patch_start(struct strbuf **lines, int count) */ static int find_trailer_start(struct strbuf **lines, int count) { - int start, only_spaces = 1; + int start, end_of_title, only_spaces = 1; + + /* The first paragraph is the title and cannot be trailers */ + for (start = 0; start < count; start++) { + if (lines[start]->buf[0] == comment_line_char) + continue; + if (contains_only_spaces(lines[start]->buf)) + break; + } + end_of_title = start; /* * Get the start of the trailers by looking starting from the end * for a line with only spaces before lines with one separator. */ - for (start = count - 1; start >= 0; start--) { + for (start = count - 1; start >= end_of_title; start--) { if (lines[start]->buf[0] == comment_line_char) continue; if (contains_only_spaces(lines[start]->buf)) { diff --git a/unpack-trees.c b/unpack-trees.c index d6cf849..6e9f755 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -1441,15 +1441,18 @@ static int verify_absent_1(const struct cache_entry *ce, if (!len) return 0; else if (len > 0) { - char path[PATH_MAX + 1]; - memcpy(path, ce->name, len); - path[len] = 0; + char *path; + int ret; + + path = xmemdupz(ce->name, len); if (lstat(path, &st)) - return error("cannot stat '%s': %s", path, + ret = error("cannot stat '%s': %s", path, strerror(errno)); - - return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st, - error_type, o); + else + ret = check_ok_to_remove(path, len, DT_UNKNOWN, NULL, + &st, error_type, o); + free(path); + return ret; } else if (lstat(ce->name, &st)) { if (errno != ENOENT) return error("cannot stat '%s': %s", ce->name, diff --git a/usage.c b/usage.c index ed14645..82ff131 100644 --- a/usage.c +++ b/usage.c @@ -6,23 +6,22 @@ #include "git-compat-util.h" #include "cache.h" +static FILE *error_handle; +static int tweaked_error_buffering; + void vreportf(const char *prefix, const char *err, va_list params) { - char msg[4096]; - vsnprintf(msg, sizeof(msg), err, params); - fprintf(stderr, "%s%s\n", prefix, msg); -} + FILE *fh = error_handle ? error_handle : stderr; -void vwritef(int fd, const char *prefix, const char *err, va_list params) -{ - char msg[4096]; - int len = vsnprintf(msg, sizeof(msg), err, params); - if (len > sizeof(msg)) - len = sizeof(msg); + fflush(fh); + if (!tweaked_error_buffering) { + setvbuf(fh, NULL, _IOLBF, 0); + tweaked_error_buffering = 1; + } - write_in_full(fd, prefix, strlen(prefix)); - write_in_full(fd, msg, len); - write_in_full(fd, "\n", 1); + fputs(prefix, fh); + vfprintf(fh, err, params); + fputc('\n', fh); } static NORETURN void usage_builtin(const char *err, va_list params) @@ -76,6 +75,12 @@ void set_die_is_recursing_routine(int (*routine)(void)) die_is_recursing = routine; } +void set_error_handle(FILE *fh) +{ + error_handle = fh; + tweaked_error_buffering = 0; +} + void NORETURN usagef(const char *err, ...) { va_list params; diff --git a/wt-status.c b/wt-status.c index eaed4fe..e8c39ef 100644 --- a/wt-status.c +++ b/wt-status.c @@ -1,5 +1,4 @@ #include "cache.h" -#include "pathspec.h" #include "wt-status.h" #include "object.h" #include "dir.h" diff --git a/wt-status.h b/wt-status.h index e0a99f7..c9b3b74 100644 --- a/wt-status.h +++ b/wt-status.h @@ -4,6 +4,7 @@ #include #include "string-list.h" #include "color.h" +#include "pathspec.h" enum color_wt_status { WT_STATUS_HEADER = 0, -- 2.7.4