diff options
37 files changed, 573 insertions, 319 deletions
diff --git a/Documentation/RelNotes/1.8.2.2.txt b/Documentation/RelNotes/1.8.2.2.txt index 3b919e89ef..dab4831ca0 100644 --- a/Documentation/RelNotes/1.8.2.2.txt +++ b/Documentation/RelNotes/1.8.2.2.txt @@ -4,6 +4,42 @@ Git v1.8.2.2 Release Notes Fixes since v1.8.2.1 -------------------- + * Zsh completion forgot that '%' character used to signal untracked + files needs to be escaped with another '%'. + + * A commit object whose author or committer ident are malformed + crashed some code that trusted that a name, an email and an + timestamp can always be found in it. + + * The new core.commentchar configuration was not applied to a few + places. + + * "git pull --rebase" did not pass "-v/-q" options to underlying + "git rebase". + + * When receive-pack detects error in the pack header it received in + order to decide which of unpack-objects or index-pack to run, it + returned without closing the error stream, which led to a hang + sideband thread. + + * "git diff --diff-algorithm=algo" was understood by the command line + parser, but "git diff --diff-algorithm algo" was not. + + * "git log -S/-G" started paying attention to textconv filter, but + there was no way to disable this. Make it honor --no-textconv + option. + + * "git merge $(git rev-parse v1.8.2)" behaved quite differently from + "git merge v1.8.2", as if v1.8.2 were written as v1.8.2^0 and did + not pay much attention to the annotated tag payload. Make the code + notice the type of the tag object, in addition to the dwim_ref() + based classification the current code uses (i.e. the name appears + in refs/tags/) to decide when to special case merging of tags. + + * "git cherry-pick" and "git revert" can take more than one commit + on the command line these days, but it was not mentioned on the usage + text. + * Perl scripts like "git-svn" closed (not redirecting to /dev/null) the standard error stream, which is not a very smart thing to do. Later open may return file descriptor #2 for unrelated purpose, and diff --git a/Documentation/config.txt b/Documentation/config.txt index 323827962c..e97faccb7d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1090,11 +1090,11 @@ format.thread:: value disables threading. format.signoff:: - A boolean value which lets you enable the `-s/--signoff` option of - format-patch by default. *Note:* Adding the Signed-off-by: line to a - patch should be a conscious act and means that you certify you have - the rights to submit this work under the same open source license. - Please see the 'SubmittingPatches' document for further discussion. + A boolean value which lets you enable the `-s/--signoff` option of + format-patch by default. *Note:* Adding the Signed-off-by: line to a + patch should be a conscious act and means that you certify you have + the rights to submit this work under the same open source license. + Please see the 'SubmittingPatches' document for further discussion. filter.<driver>.clean:: The command which is used to convert the content of a worktree @@ -1206,7 +1206,7 @@ gitcvs.dbname:: gitcvs.dbdriver:: Used Perl DBI driver. You can specify any available driver - for this here, but it might not work. git-cvsserver is tested + for this here, but it might not work. git-cvsserver is tested with 'DBD::SQLite', reported to work with 'DBD::Pg', and reported *not* to work with 'DBD::mysql'. Experimental feature. May not contain double colons (`:`). Default: 'SQLite'. diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 9b1be5581d..8172938653 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -197,8 +197,8 @@ variable (see linkgit:git-config[1]). -e:: --edit:: The message taken from file with `-F`, command line with - `-m`, and from file with `-C` are usually used as the - commit log message unmodified. This option lets you + `-m`, and from commit object with `-C` are usually used as + the commit log message unmodified. This option lets you further edit the message taken from these sources. --no-edit:: diff --git a/Documentation/git.txt b/Documentation/git.txt index 807a13c806..8438c076c3 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,10 @@ unreleased) version of Git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.8.2.1/git.html[documentation for release 1.8.2.1] +* link:v1.8.2.2/git.html[documentation for release 1.8.2.2] * release notes for + link:RelNotes/1.8.2.2.txt[1.8.2.2]. link:RelNotes/1.8.2.1.txt[1.8.2.1]. link:RelNotes/1.8.2.txt[1.8.2]. diff --git a/Documentation/gitweb.conf.txt b/Documentation/gitweb.conf.txt index eb636317be..ea0526ecc4 100644 --- a/Documentation/gitweb.conf.txt +++ b/Documentation/gitweb.conf.txt @@ -857,6 +857,13 @@ adding the following lines to your gitweb configuration file: $known_snapshot_formats{'zip'}{'disabled'} = 1; $known_snapshot_formats{'tgz'}{'compressor'} = ['gzip','-6']; +BUGS +---- +Debugging would be easier if the fallback configuration file +(`/etc/gitweb.conf`) and environment variable to override its location +('GITWEB_CONFIG_SYSTEM') had names reflecting their "fallback" role. +The current names are kept to avoid breaking working setups. + ENVIRONMENT ----------- The location of per-instance and system-wide configuration files can be diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index ce3e4fae73..68a18e1497 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -420,9 +420,7 @@ should not be combined with other pathspec. <<def_merge,merge>> left behind. [[def_revision]]revision:: - A particular state of files and directories which was stored in the - <<def_object_database,object database>>. It is referenced by a - <<def_commit_object,commit object>>. + Synonym for <<def_commit,commit>> (the noun). [[def_rewind]]rewind:: To throw away part of the development, i.e. to assign the diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt index 66db80296f..49a9a7d53f 100644 --- a/Documentation/merge-strategies.txt +++ b/Documentation/merge-strategies.txt @@ -48,6 +48,12 @@ patience;; this when the branches to be merged have diverged wildly. See also linkgit:git-diff[1] `--patience`. +diff-algorithm=[patience|minimal|histogram|myers];; + Tells 'merge-recursive' to use a different diff algorithm, which + can help avoid mismerges that occur due to unimportant matching + lines (such as braces from distinct functions). See also + linkgit:git-diff[1] `--diff-algorithm`. + ignore-space-change;; ignore-all-space;; ignore-space-at-eol;; diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 26422bfc22..7186e774a8 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.8.2.1 +DEF_VER=v1.8.2.2 LF=' ' diff --git a/builtin/blame.c b/builtin/blame.c index 86100e9662..77707819af 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1375,10 +1375,15 @@ static void get_ac_line(const char *inbuf, const char *what, maillen = ident.mail_end - ident.mail_begin; mailbuf = ident.mail_begin; - *time = strtoul(ident.date_begin, NULL, 10); + if (ident.date_begin && ident.date_end) + *time = strtoul(ident.date_begin, NULL, 10); + else + *time = 0; - len = ident.tz_end - ident.tz_begin; - strbuf_add(tz, ident.tz_begin, len); + if (ident.tz_begin && ident.tz_end) + strbuf_add(tz, ident.tz_begin, ident.tz_end - ident.tz_begin); + else + strbuf_addstr(tz, "(unknown)"); /* * Now, convert both name and e-mail using mailmap diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 40f87b4649..045cee7bce 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -16,73 +16,6 @@ #define BATCH 1 #define BATCH_CHECK 2 -static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size) -{ - /* the parser in tag.c is useless here. */ - const char *endp = buf + size; - const char *cp = buf; - - while (cp < endp) { - char c = *cp++; - if (c != '\n') - continue; - if (7 <= endp - cp && !memcmp("tagger ", cp, 7)) { - const char *tagger = cp; - - /* Found the tagger line. Copy out the contents - * of the buffer so far. - */ - write_or_die(1, buf, cp - buf); - - /* - * Do something intelligent, like pretty-printing - * the date. - */ - while (cp < endp) { - if (*cp++ == '\n') { - /* tagger to cp is a line - * that has ident and time. - */ - const char *sp = tagger; - char *ep; - unsigned long date; - long tz; - while (sp < cp && *sp != '>') - sp++; - if (sp == cp) { - /* give up */ - write_or_die(1, tagger, - cp - tagger); - break; - } - while (sp < cp && - !('0' <= *sp && *sp <= '9')) - sp++; - write_or_die(1, tagger, sp - tagger); - date = strtoul(sp, &ep, 10); - tz = strtol(ep, NULL, 10); - sp = show_date(date, tz, 0); - write_or_die(1, sp, strlen(sp)); - xwrite(1, "\n", 1); - break; - } - } - break; - } - if (cp < endp && *cp == '\n') - /* end of header */ - break; - } - /* At this point, we have copied out the header up to the end of - * the tagger line and cp points at one past \n. It could be the - * next header line after the tagger line, or it could be another - * \n that marks the end of the headers. We need to copy out the - * remainder as is. - */ - if (cp < endp) - write_or_die(1, cp, endp - cp); -} - static int cat_one_file(int opt, const char *exp_type, const char *obj_name) { unsigned char sha1[20]; @@ -133,10 +66,6 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name) buf = read_sha1_file(sha1, &type, &size); if (!buf) die("Cannot read object %s", obj_name); - if (type == OBJ_TAG) { - pprint_tag(sha1, buf, size); - return 0; - } /* otherwise just spit out the data */ break; diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c index 265a9253bf..1c04070869 100644 --- a/builtin/fmt-merge-msg.c +++ b/builtin/fmt-merge-msg.c @@ -287,10 +287,10 @@ static void credit_people(struct strbuf *out, const char *me; if (kind == 'a') { - label = "\n# By "; + label = "By"; me = git_author_info(IDENT_NO_DATE); } else { - label = "\n# Via "; + label = "Via"; me = git_committer_info(IDENT_NO_DATE); } @@ -300,7 +300,7 @@ static void credit_people(struct strbuf *out, (me = skip_prefix(me, them->items->string)) != NULL && skip_prefix(me, " <"))) return; - strbuf_addstr(out, label); + strbuf_addf(out, "\n%c %s ", comment_line_char, label); add_people_count(out, them); } @@ -503,14 +503,18 @@ static void fmt_merge_msg_sigs(struct strbuf *out) } else { if (tag_number == 2) { struct strbuf tagline = STRBUF_INIT; - strbuf_addf(&tagline, "\n# %s\n", - origins.items[first_tag].string); + strbuf_addch(&tagline, '\n'); + strbuf_add_commented_lines(&tagline, + origins.items[first_tag].string, + strlen(origins.items[first_tag].string)); strbuf_insert(&tagbuf, 0, tagline.buf, tagline.len); strbuf_release(&tagline); } - strbuf_addf(&tagbuf, "\n# %s\n", - origins.items[i].string); + strbuf_addch(&tagbuf, '\n'); + strbuf_add_commented_lines(&tagbuf, + origins.items[i].string, + strlen(origins.items[i].string)); fmt_tag_signature(&tagbuf, &sig, buf, len); } strbuf_release(&sig); diff --git a/builtin/merge.c b/builtin/merge.c index 7c8922c8b0..0d94d89e74 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -516,6 +516,19 @@ static void merge_name(const char *remote, struct strbuf *msg) strbuf_release(&line); goto cleanup; } + + if (remote_head->util) { + struct merge_remote_desc *desc; + desc = merge_remote_util(remote_head); + if (desc && desc->obj && desc->obj->type == OBJ_TAG) { + strbuf_addf(msg, "%s\t\t%s '%s'\n", + sha1_to_hex(desc->obj->sha1), + typename(desc->obj->type), + remote); + goto cleanup; + } + } + strbuf_addf(msg, "%s\t\tcommit '%s'\n", sha1_to_hex(remote_head->object.sha1), remote); cleanup: diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 62ba6e7a3d..89792b0a33 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -828,8 +828,11 @@ static const char *unpack(int err_fd) : 0); hdr_err = parse_pack_header(&hdr); - if (hdr_err) + if (hdr_err) { + if (err_fd > 0) + close(err_fd); return hdr_err; + } snprintf(hdr_arg, sizeof(hdr_arg), "--pack_header=%"PRIu32",%"PRIu32, ntohl(hdr.hdr_version), ntohl(hdr.hdr_entries)); diff --git a/builtin/revert.c b/builtin/revert.c index c5e36b94c0..0401fdb02c 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -19,13 +19,13 @@ */ static const char * const revert_usage[] = { - N_("git revert [options] <commit-ish>"), + N_("git revert [options] <commit-ish>..."), N_("git revert <subcommand>"), NULL }; static const char * const cherry_pick_usage[] = { - N_("git cherry-pick [options] <commit-ish>"), + N_("git cherry-pick [options] <commit-ish>..."), N_("git cherry-pick <subcommand>"), NULL }; diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 93eba46750..e769800393 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1182,13 +1182,6 @@ _git_commit () ;; esac - case "$prev" in - -c|-C) - __gitcomp_nl "$(__git_refs)" "" "${cur}" - return - ;; - esac - case "$cur" in --cleanup=*) __gitcomp "default strip verbatim whitespace @@ -1827,6 +1820,10 @@ _git_config () __gitcomp_nl "$(__git_refs)" return ;; + branch.*.rebase) + __gitcomp "false true" + return + ;; remote.*.fetch) local remote="${prev#remote.}" remote="${remote%.fetch}" @@ -1866,6 +1863,10 @@ _git_config () " return ;; + diff.submodule) + __gitcomp "log short" + return + ;; help.format) __gitcomp "man info web html" return @@ -2061,13 +2062,14 @@ _git_config () core.whitespace core.worktree diff.autorefreshindex - diff.statGraphWidth diff.external diff.ignoreSubmodules diff.mnemonicprefix diff.noprefix diff.renameLimit diff.renames + diff.statGraphWidth + diff.submodule diff.suppressBlankEmpty diff.tool diff.wordRegex diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh index cf8116d477..2565d2eef4 100644 --- a/contrib/completion/git-completion.zsh +++ b/contrib/completion/git-completion.zsh @@ -2,6 +2,8 @@ # zsh completion wrapper for git # +# Copyright (c) 2012-2013 Felipe Contreras <felipe.contreras@gmail.com> +# # You need git's bash completion script installed somewhere, by default on the # same directory as this script. # @@ -21,6 +23,9 @@ complete () return 0 } +zstyle -T ':completion:*:*:git:*' tag-order && \ + zstyle ':completion:*:*:git:*' tag-order 'common-commands' + zstyle -s ":completion:*:*:git:*" script script test -z "$script" && script="$(dirname ${funcsourcetrace[1]%:*})"/git-completion.bash ZSH_VERSION='' . "$script" @@ -69,18 +74,131 @@ __gitcomp_file () compadd -Q -p "${2-}" -f -- ${=1} && _ret=0 } +__git_zsh_bash_func () +{ + emulate -L ksh + + local command=$1 + + local completion_func="_git_${command//-/_}" + declare -f $completion_func >/dev/null && $completion_func && return + + local expansion=$(__git_aliased_command "$command") + if [ -n "$expansion" ]; then + completion_func="_git_${expansion//-/_}" + declare -f $completion_func >/dev/null && $completion_func + fi +} + +__git_zsh_cmd_common () +{ + local -a list + list=( + add:'add file contents to the index' + bisect:'find by binary search the change that introduced a bug' + branch:'list, create, or delete branches' + checkout:'checkout a branch or paths to the working tree' + clone:'clone a repository into a new directory' + commit:'record changes to the repository' + diff:'show changes between commits, commit and working tree, etc' + fetch:'download objects and refs from another repository' + grep:'print lines matching a pattern' + init:'create an empty Git repository or reinitialize an existing one' + log:'show commit logs' + merge:'join two or more development histories together' + mv:'move or rename a file, a directory, or a symlink' + pull:'fetch from and merge with another repository or a local branch' + push:'update remote refs along with associated objects' + rebase:'forward-port local commits to the updated upstream head' + reset:'reset current HEAD to the specified state' + rm:'remove files from the working tree and from the index' + show:'show various types of objects' + status:'show the working tree status' + tag:'create, list, delete or verify a tag object signed with GPG') + _describe -t common-commands 'common commands' list && _ret=0 +} + +__git_zsh_cmd_alias () +{ + local -a list + list=(${${${(0)"$(git config -z --get-regexp '^alias\.')"}#alias.}%$'\n'*}) + _describe -t alias-commands 'aliases' list $* && _ret=0 +} + +__git_zsh_cmd_all () +{ + local -a list + emulate ksh -c __git_compute_all_commands + list=( ${=__git_all_commands} ) + _describe -t all-commands 'all commands' list && _ret=0 +} + +__git_zsh_main () +{ + local curcontext="$curcontext" state state_descr line + typeset -A opt_args + local -a orig_words + + orig_words=( ${words[@]} ) + + _arguments -C \ + '(-p --paginate --no-pager)'{-p,--paginate}'[pipe all output into ''less'']' \ + '(-p --paginate)--no-pager[do not pipe git output into a pager]' \ + '--git-dir=-[set the path to the repository]: :_directories' \ + '--bare[treat the repository as a bare repository]' \ + '(- :)--version[prints the git suite version]' \ + '--exec-path=-[path to where your core git programs are installed]:: :_directories' \ + '--html-path[print the path where git''s HTML documentation is installed]' \ + '--info-path[print the path where the Info files are installed]' \ + '--man-path[print the manpath (see `man(1)`) for the man pages]' \ + '--work-tree=-[set the path to the working tree]: :_directories' \ + '--namespace=-[set the git namespace]' \ + '--no-replace-objects[do not use replacement refs to replace git objects]' \ + '(- :)--help[prints the synopsis and a list of the most commonly used commands]: :->arg' \ + '(-): :->command' \ + '(-)*:: :->arg' && return + + case $state in + (command) + _alternative \ + 'alias-commands:alias:__git_zsh_cmd_alias' \ + 'common-commands:common:__git_zsh_cmd_common' \ + 'all-commands:all:__git_zsh_cmd_all' && _ret=0 + ;; + (arg) + local command="${words[1]}" __git_dir + + if (( $+opt_args[--bare] )); then + __git_dir='.' + else + __git_dir=${opt_args[--git-dir]} + fi + + (( $+opt_args[--help] )) && command='help' + + words=( ${orig_words[@]} ) + + __git_zsh_bash_func $command + ;; + esac +} + _git () { local _ret=1 - () { - emulate -L ksh - local cur cword prev - cur=${words[CURRENT-1]} - prev=${words[CURRENT-2]} - let cword=CURRENT-1 - __${service}_main - } - let _ret && _default -S '' && _ret=0 + local cur cword prev + + cur=${words[CURRENT]} + prev=${words[CURRENT-1]} + let cword=CURRENT-1 + + if (( $+functions[__${service}_zsh_main] )); then + __${service}_zsh_main + else + emulate ksh -c __${service}_main + fi + + let _ret && _default && _ret=0 return _ret } diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh index 756a951459..054c52e90a 100644 --- a/contrib/completion/git-prompt.sh +++ b/contrib/completion/git-prompt.sh @@ -340,7 +340,7 @@ __git_ps1 () [ "$(git config --bool bash.showUntrackedFiles)" != "false" ] && [ -n "$(git ls-files --others --exclude-standard)" ] then - u="%" + u="%${ZSH_VERSION+%}" fi if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then diff --git a/contrib/remote-helpers/test-hg-bidi.sh b/contrib/remote-helpers/test-hg-bidi.sh index 1d61982436..2a5d85dd72 100755 --- a/contrib/remote-helpers/test-hg-bidi.sh +++ b/contrib/remote-helpers/test-hg-bidi.sh @@ -65,10 +65,10 @@ setup () { ) >> "$HOME"/.hgrc && git config --global remote-hg.hg-git-compat true - export HGEDITOR=/usr/bin/true - - export GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" - export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" + HGEDITOR=/usr/bin/true + GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" + GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" + export HGEDITOR GIT_AUTHOR_DATE GIT_COMMITTER_DATE } setup @@ -85,7 +85,8 @@ test_expect_success 'encoding' ' git add alpha && git commit -m "add älphà" && - export GIT_AUTHOR_NAME="tést èncödîng" && + GIT_AUTHOR_NAME="tést èncödîng" && + export GIT_AUTHOR_NAME && echo beta > beta && git add beta && git commit -m "add beta" && diff --git a/contrib/remote-helpers/test-hg-hg-git.sh b/contrib/remote-helpers/test-hg-hg-git.sh index 7e3967f5b6..9aaf043669 100755 --- a/contrib/remote-helpers/test-hg-hg-git.sh +++ b/contrib/remote-helpers/test-hg-hg-git.sh @@ -101,10 +101,11 @@ setup () { git config --global receive.denycurrentbranch warn git config --global remote-hg.hg-git-compat true - export HGEDITOR=/usr/bin/true + HGEDITOR=/usr/bin/true - export GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" - export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" + GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" + GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" + export HGEDITOR GIT_AUTHOR_DATE GIT_COMMITTER_DATE } setup @@ -295,7 +296,8 @@ test_expect_success 'encoding' ' git add alpha && git commit -m "add älphà" && - export GIT_AUTHOR_NAME="tést èncödîng" && + GIT_AUTHOR_NAME="tést èncödîng" && + export GIT_AUTHOR_NAME && echo beta > beta && git add beta && git commit -m "add beta" && @@ -3596,8 +3596,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); else if (!strcmp(arg, "--histogram")) options->xdl_opts = DIFF_WITH_ALG(options, HISTOGRAM_DIFF); - else if (!prefixcmp(arg, "--diff-algorithm=")) { - long value = parse_algorithm_value(arg+17); + else if ((argcount = parse_long_opt("diff-algorithm", av, &optarg))) { + long value = parse_algorithm_value(optarg); if (value < 0) return error("option diff-algorithm accepts \"myers\", " "\"minimal\", \"patience\" and \"histogram\""); @@ -3605,6 +3605,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_XDL_CLR(options, NEED_MINIMAL); options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK; options->xdl_opts |= value; + return argcount; } /* flags options */ diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c index b097fa7661..63722f86dc 100644 --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -8,7 +8,12 @@ #include "xdiff-interface.h" #include "kwset.h" -typedef int (*pickaxe_fn)(struct diff_filepair *p, struct diff_options *o, regex_t *regexp, kwset_t kws); +typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two, + struct diff_options *o, + regex_t *regexp, kwset_t kws); + +static int pickaxe_match(struct diff_filepair *p, struct diff_options *o, + regex_t *regexp, kwset_t kws, pickaxe_fn fn); static void pickaxe(struct diff_queue_struct *q, struct diff_options *o, regex_t *regexp, kwset_t kws, pickaxe_fn fn) @@ -22,7 +27,7 @@ static void pickaxe(struct diff_queue_struct *q, struct diff_options *o, /* Showing the whole changeset if needle exists */ for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - if (fn(p, o, regexp, kws)) + if (pickaxe_match(p, o, regexp, kws, fn)) return; /* do not munge the queue */ } @@ -37,7 +42,7 @@ static void pickaxe(struct diff_queue_struct *q, struct diff_options *o, /* Showing only the filepairs that has the needle */ for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; - if (fn(p, o, regexp, kws)) + if (pickaxe_match(p, o, regexp, kws, fn)) diff_q(&outq, p); else diff_free_filepair(p); @@ -74,64 +79,33 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len) line[len] = hold; } -static void fill_one(struct diff_filespec *one, - mmfile_t *mf, struct userdiff_driver **textconv) -{ - if (DIFF_FILE_VALID(one)) { - *textconv = get_textconv(one); - mf->size = fill_textconv(*textconv, one, &mf->ptr); - } else { - memset(mf, 0, sizeof(*mf)); - } -} - -static int diff_grep(struct diff_filepair *p, struct diff_options *o, +static int diff_grep(mmfile_t *one, mmfile_t *two, + struct diff_options *o, regex_t *regexp, kwset_t kws) { regmatch_t regmatch; - struct userdiff_driver *textconv_one = NULL; - struct userdiff_driver *textconv_two = NULL; - mmfile_t mf1, mf2; - int hit; + struct diffgrep_cb ecbdata; + xpparam_t xpp; + xdemitconf_t xecfg; - if (diff_unmodified_pair(p)) - return 0; + if (!one) + return !regexec(regexp, two->ptr, 1, ®match, 0); + if (!two) + return !regexec(regexp, one->ptr, 1, ®match, 0); - fill_one(p->one, &mf1, &textconv_one); - fill_one(p->two, &mf2, &textconv_two); - - if (!mf1.ptr) { - if (!mf2.ptr) - return 0; /* ignore unmerged */ - /* created "two" -- does it have what we are looking for? */ - hit = !regexec(regexp, mf2.ptr, 1, ®match, 0); - } else if (!mf2.ptr) { - /* removed "one" -- did it have what we are looking for? */ - hit = !regexec(regexp, mf1.ptr, 1, ®match, 0); - } else { - /* - * We have both sides; need to run textual diff and see if - * the pattern appears on added/deleted lines. - */ - struct diffgrep_cb ecbdata; - xpparam_t xpp; - xdemitconf_t xecfg; - - memset(&xpp, 0, sizeof(xpp)); - memset(&xecfg, 0, sizeof(xecfg)); - ecbdata.regexp = regexp; - ecbdata.hit = 0; - xecfg.ctxlen = o->context; - xecfg.interhunkctxlen = o->interhunkcontext; - xdi_diff_outf(&mf1, &mf2, diffgrep_consume, &ecbdata, - &xpp, &xecfg); - hit = ecbdata.hit; - } - if (textconv_one) - free(mf1.ptr); - if (textconv_two) - free(mf2.ptr); - return hit; + /* + * We have both sides; need to run textual diff and see if + * the pattern appears on added/deleted lines. + */ + memset(&xpp, 0, sizeof(xpp)); + memset(&xecfg, 0, sizeof(xecfg)); + ecbdata.regexp = regexp; + ecbdata.hit = 0; + xecfg.ctxlen = o->context; + xecfg.interhunkctxlen = o->interhunkcontext; + xdi_diff_outf(one, two, diffgrep_consume, &ecbdata, + &xpp, &xecfg); + return ecbdata.hit; } static void diffcore_pickaxe_grep(struct diff_options *o) @@ -198,17 +172,37 @@ static unsigned int contains(mmfile_t *mf, struct diff_options *o, return cnt; } -static int has_changes(struct diff_filepair *p, struct diff_options *o, +static int has_changes(mmfile_t *one, mmfile_t *two, + struct diff_options *o, regex_t *regexp, kwset_t kws) { - struct userdiff_driver *textconv_one = get_textconv(p->one); - struct userdiff_driver *textconv_two = get_textconv(p->two); + if (!one) + return contains(two, o, regexp, kws) != 0; + if (!two) + return contains(one, o, regexp, kws) != 0; + return contains(one, o, regexp, kws) != contains(two, o, regexp, kws); +} + +static int pickaxe_match(struct diff_filepair *p, struct diff_options *o, + regex_t *regexp, kwset_t kws, pickaxe_fn fn) +{ + struct userdiff_driver *textconv_one = NULL; + struct userdiff_driver *textconv_two = NULL; mmfile_t mf1, mf2; int ret; if (!o->pickaxe[0]) return 0; + /* ignore unmerged */ + if (!DIFF_FILE_VALID(p->one) && !DIFF_FILE_VALID(p->two)) + return 0; + + if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) { + textconv_one = get_textconv(p->one); + textconv_two = get_textconv(p->two); + } + /* * If we have an unmodified pair, we know that the count will be the * same and don't even have to load the blobs. Unless textconv is in @@ -219,20 +213,12 @@ static int has_changes(struct diff_filepair *p, struct diff_options *o, if (textconv_one == textconv_two && diff_unmodified_pair(p)) return 0; - fill_one(p->one, &mf1, &textconv_one); - fill_one(p->two, &mf2, &textconv_two); + mf1.size = fill_textconv(textconv_one, p->one, &mf1.ptr); + mf2.size = fill_textconv(textconv_two, p->two, &mf2.ptr); - if (!mf1.ptr) { - if (!mf2.ptr) - ret = 0; /* ignore unmerged */ - /* created */ - ret = contains(&mf2, o, regexp, kws) != 0; - } - else if (!mf2.ptr) /* removed */ - ret = contains(&mf1, o, regexp, kws) != 0; - else - ret = contains(&mf1, o, regexp, kws) != - contains(&mf2, o, regexp, kws); + ret = fn(DIFF_FILE_VALID(p->one) ? &mf1 : NULL, + DIFF_FILE_VALID(p->two) ? &mf2 : NULL, + o, regexp, kws); if (textconv_one) free(mf1.ptr); diff --git a/git-compat-util.h b/git-compat-util.h index e715285e7c..ad4762499e 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -327,6 +327,7 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))) 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 int prefixcmp(const char *str, const char *prefix); extern int suffixcmp(const char *str, const char *suffix); diff --git a/git-pull.sh b/git-pull.sh index 266e682f6c..5d97e97bd9 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -279,7 +279,7 @@ fi merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit case "$rebase" in true) - eval="git-rebase $diffstat $strategy_args $merge_args" + eval="git-rebase $diffstat $strategy_args $merge_args $verbosity" eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}" ;; *) diff --git a/gitweb/INSTALL b/gitweb/INSTALL index 08f3dda02d..408f2859d3 100644 --- a/gitweb/INSTALL +++ b/gitweb/INSTALL @@ -243,14 +243,11 @@ for gitweb (in gitweb/README), and gitweb.conf(5) manpage. GITWEB_CONFIG_SYSTEM build configuration variable, and override it through the GITWEB_CONFIG_SYSTEM environment variable. - Note that if per-instance configuration file exists, then system-wide - configuration is _not used at all_. This is quite untypical and surprising - behavior. On the other hand changing current behavior would break backwards - compatibility and can lead to unexpected changes in gitweb behavior. - Therefore gitweb also looks for common system-wide configuration file, - normally /etc/gitweb-common.conf (set during build time using build time - configuration variable GITWEB_CONFIG_COMMON, set it at runtime using - environment variable with the same name). Settings from per-instance or + Note that the GITWEB_CONFIG_SYSTEM system-wide configuration file is + only used for instances that lack per-instance configuration file. + You can use GITWEB_CONFIG_COMMON common system-wide configuration + file (normally /etc/gitweb-common.conf) to keep common default + settings that apply to all instances. Settings from per-instance or system-wide configuration file override those from common system-wide configuration file. @@ -393,6 +393,19 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len, strbuf_addstr(sb, "?="); } +static const char *show_ident_date(const struct ident_split *ident, + enum date_mode mode) +{ + unsigned long date = 0; + int tz = 0; + + if (ident->date_begin && ident->date_end) + date = strtoul(ident->date_begin, NULL, 10); + if (ident->tz_begin && ident->tz_end) + tz = strtol(ident->tz_begin, NULL, 10); + return show_date(date, tz, mode); +} + void pp_user_info(const struct pretty_print_context *pp, const char *what, struct strbuf *sb, const char *line, const char *encoding) @@ -401,12 +414,10 @@ void pp_user_info(const struct pretty_print_context *pp, struct strbuf mail; struct ident_split ident; int linelen; - char *line_end, *date; + char *line_end; const char *mailbuf, *namebuf; size_t namelen, maillen; int max_length = 78; /* per rfc2822 */ - unsigned long time; - int tz; if (pp->fmt == CMIT_FMT_ONELINE) return; @@ -438,8 +449,6 @@ void pp_user_info(const struct pretty_print_context *pp, strbuf_add(&name, namebuf, namelen); namelen = name.len + mail.len + 3; /* ' ' + '<' + '>' */ - time = strtoul(ident.date_begin, &date, 10); - tz = strtol(date, NULL, 10); if (pp->fmt == CMIT_FMT_EMAIL) { strbuf_addstr(sb, "From: "); @@ -472,13 +481,16 @@ void pp_user_info(const struct pretty_print_context *pp, switch (pp->fmt) { case CMIT_FMT_MEDIUM: - strbuf_addf(sb, "Date: %s\n", show_date(time, tz, pp->date_mode)); + strbuf_addf(sb, "Date: %s\n", + show_ident_date(&ident, pp->date_mode)); break; case CMIT_FMT_EMAIL: - strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822)); + strbuf_addf(sb, "Date: %s\n", + show_ident_date(&ident, DATE_RFC2822)); break; case CMIT_FMT_FULLER: - strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, pp->date_mode)); + strbuf_addf(sb, "%sDate: %s\n", what, + show_ident_date(&ident, pp->date_mode)); break; default: /* notin' */ @@ -688,8 +700,6 @@ static size_t format_person_part(struct strbuf *sb, char part, { /* currently all placeholders have same length */ const int placeholder_len = 2; - int tz; - unsigned long date = 0; struct ident_split s; const char *name, *mail; size_t maillen, namelen; @@ -716,30 +726,23 @@ static size_t format_person_part(struct strbuf *sb, char part, if (!s.date_begin) goto skip; - date = strtoul(s.date_begin, NULL, 10); - if (part == 't') { /* date, UNIX timestamp */ strbuf_add(sb, s.date_begin, s.date_end - s.date_begin); return placeholder_len; } - /* parse tz */ - tz = strtoul(s.tz_begin + 1, NULL, 10); - if (*s.tz_begin == '-') - tz = -tz; - switch (part) { case 'd': /* date */ - strbuf_addstr(sb, show_date(date, tz, dmode)); + strbuf_addstr(sb, show_ident_date(&s, dmode)); return placeholder_len; case 'D': /* date, RFC2822 style */ - strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822)); + strbuf_addstr(sb, show_ident_date(&s, DATE_RFC2822)); return placeholder_len; case 'r': /* date, relative */ - strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE)); + strbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE)); return placeholder_len; case 'i': /* date, ISO 8601 */ - strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601)); + strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601)); return placeholder_len; } diff --git a/run-command.c b/run-command.c index 765c2ce056..1b32a12a29 100644 --- a/run-command.c +++ b/run-command.c @@ -588,6 +588,7 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const static pthread_t main_thread; static int main_thread_set; static pthread_key_t async_key; +static pthread_key_t async_die_counter; static void *run_thread(void *data) { @@ -614,6 +615,14 @@ static NORETURN void die_async(const char *err, va_list params) exit(128); } + +static int async_die_is_recursing(void) +{ + void *ret = pthread_getspecific(async_die_counter); + pthread_setspecific(async_die_counter, (void *)1); + return ret != NULL; +} + #endif int start_async(struct async *async) @@ -695,7 +704,9 @@ int start_async(struct async *async) main_thread_set = 1; main_thread = pthread_self(); pthread_key_create(&async_key, NULL); + pthread_key_create(&async_die_counter, NULL); set_die_routine(die_async); + set_die_is_recursing_routine(async_die_is_recursing); } if (proc_in >= 0) diff --git a/t/Makefile b/t/Makefile index 1923cc104b..44ca7d32dc 100644 --- a/t/Makefile +++ b/t/Makefile @@ -83,42 +83,4 @@ valgrind: perf: $(MAKE) -C perf/ all -# Smoke testing targets --include ../GIT-VERSION-FILE -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo unknown') -uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo unknown') - -test-results: - mkdir -p test-results - -test-results/git-smoke.tar.gz: test-results - '$(PERL_PATH_SQ)' ./harness \ - --archive="test-results/git-smoke.tar.gz" \ - $(T) - -smoke: test-results/git-smoke.tar.gz - -SMOKE_UPLOAD_FLAGS = -ifdef SMOKE_USERNAME - SMOKE_UPLOAD_FLAGS += -F username="$(SMOKE_USERNAME)" -F password="$(SMOKE_PASSWORD)" -endif -ifdef SMOKE_COMMENT - SMOKE_UPLOAD_FLAGS += -F comments="$(SMOKE_COMMENT)" -endif -ifdef SMOKE_TAGS - SMOKE_UPLOAD_FLAGS += -F tags="$(SMOKE_TAGS)" -endif - -smoke_report: smoke - curl \ - -H "Expect: " \ - -F project=Git \ - -F architecture="$(uname_M)" \ - -F platform="$(uname_S)" \ - -F revision="$(GIT_VERSION)" \ - -F report_file=@test-results/git-smoke.tar.gz \ - $(SMOKE_UPLOAD_FLAGS) \ - http://smoke.git.nix.is/app/projects/process_add_report/1 \ - | grep -v ^Redirecting - .PHONY: pre-clean $(T) aggregate-results clean valgrind perf diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh index 9820f70c84..9cc5c6bf4d 100755 --- a/t/t1006-cat-file.sh +++ b/t/t1006-cat-file.sh @@ -135,14 +135,11 @@ tag_description="This is a tag" tag_content="$tag_header_without_timestamp 0000000000 +0000 $tag_description" -tag_pretty_content="$tag_header_without_timestamp Thu Jan 1 00:00:00 1970 +0000 - -$tag_description" tag_sha1=$(echo_without_newline "$tag_content" | git mktag) tag_size=$(strlen "$tag_content") -run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_pretty_content" 1 +run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" 1 test_expect_success \ "Reach a blob from a tag pointing to it" \ diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh index eed727341d..38fb80f643 100755 --- a/t/t4209-log-pickaxe.sh +++ b/t/t4209-log-pickaxe.sh @@ -80,6 +80,20 @@ test_expect_success 'log -G -i (match)' ' test_cmp expect actual ' +test_expect_success 'log -G --textconv (missing textconv tool)' ' + echo "* diff=test" >.gitattributes && + test_must_fail git -c diff.test.textconv=missing log -Gfoo && + rm .gitattributes +' + +test_expect_success 'log -G --no-textconv (missing textconv tool)' ' + echo "* diff=test" >.gitattributes && + git -c diff.test.textconv=missing log -Gfoo --no-textconv >actual && + >expect && + test_cmp expect actual && + rm .gitattributes +' + test_expect_success 'log -S (nomatch)' ' git log -Spicked --format=%H >actual && >expect && @@ -116,4 +130,18 @@ test_expect_success 'log -S -i (nomatch)' ' test_cmp expect actual ' +test_expect_success 'log -S --textconv (missing textconv tool)' ' + echo "* diff=test" >.gitattributes && + test_must_fail git -c diff.test.textconv=missing log -Sfoo && + rm .gitattributes +' + +test_expect_success 'log -S --no-textconv (missing textconv tool)' ' + echo "* diff=test" >.gitattributes && + git -c diff.test.textconv=missing log -Sfoo --no-textconv >actual && + >expect && + test_cmp expect actual && + rm .gitattributes +' + test_done diff --git a/t/t4212-log-corrupt.sh b/t/t4212-log-corrupt.sh new file mode 100755 index 0000000000..ec5099b83d --- /dev/null +++ b/t/t4212-log-corrupt.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +test_description='git log with invalid commit headers' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit foo && + + git cat-file commit HEAD | + sed "/^author /s/>/>-<>/" >broken_email.commit && + git hash-object -w -t commit broken_email.commit >broken_email.hash && + git update-ref refs/heads/broken_email $(cat broken_email.hash) +' + +test_expect_success 'git log with broken author email' ' + { + echo commit $(cat broken_email.hash) + echo "Author: A U Thor <author@example.com>" + echo "Date: Thu Jan 1 00:00:00 1970 +0000" + echo + echo " foo" + } >expect.out && + : >expect.err && + + git log broken_email >actual.out 2>actual.err && + + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success 'git log --format with broken author email' ' + echo "A U Thor+author@example.com+" >expect.out && + : >expect.err && + + git log --format="%an+%ae+%ad" broken_email >actual.out 2>actual.err && + + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_done diff --git a/t/t5004-archive-corner-cases.sh b/t/t5004-archive-corner-cases.sh index cdb7d7a7f9..bfdb56a069 100755 --- a/t/t5004-archive-corner-cases.sh +++ b/t/t5004-archive-corner-cases.sh @@ -28,7 +28,7 @@ check_dir() { } test_expect_success 'tar archive of empty tree is empty' ' - git archive --format=tar HEAD >empty.tar && + git archive --format=tar HEAD: >empty.tar && make_dir extract && "$TAR" xf empty.tar -C extract && check_dir extract diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh index 1b06691bb4..aa31abe32b 100755 --- a/t/t5521-pull-options.sh +++ b/t/t5521-pull-options.sh @@ -19,6 +19,17 @@ test_expect_success 'git pull -q' ' test ! -s out) ' +test_expect_success 'git pull -q --rebase' ' + mkdir clonedqrb && + (cd clonedqrb && git init && + git pull -q --rebase "../parent" >out 2>err && + test ! -s err && + test ! -s out && + git pull -q --rebase "../parent" >out 2>err && + test ! -s err && + test ! -s out) +' + test_expect_success 'git pull' ' mkdir cloned && (cd cloned && git init && @@ -27,6 +38,14 @@ test_expect_success 'git pull' ' test ! -s out) ' +test_expect_success 'git pull --rebase' ' + mkdir clonedrb && + (cd clonedrb && git init && + git pull --rebase "../parent" >out 2>err && + test -s err && + test ! -s out) +' + test_expect_success 'git pull -v' ' mkdir clonedv && (cd clonedv && git init && @@ -35,6 +54,14 @@ test_expect_success 'git pull -v' ' test ! -s out) ' +test_expect_success 'git pull -v --rebase' ' + mkdir clonedvrb && + (cd clonedvrb && git init && + git pull -v --rebase "../parent" >out 2>err && + test -s err && + test ! -s out) +' + test_expect_success 'git pull -v -q' ' mkdir clonedvq && (cd clonedvq && git init && diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index 992c2a0467..54b5744cc5 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -112,8 +112,8 @@ test_expect_success '[merge] summary/log configuration' ' Common #1 EOF - git config merge.log true && - test_might_fail git config --unset-all merge.summary && + test_config merge.log true && + test_unconfig merge.summary && git checkout master && test_tick && @@ -121,8 +121,8 @@ test_expect_success '[merge] summary/log configuration' ' git fmt-merge-msg <.git/FETCH_HEAD >actual1 && - test_might_fail git config --unset-all merge.log && - git config merge.summary true && + test_unconfig merge.log && + test_config merge.summary true && git checkout master && test_tick && @@ -134,11 +134,6 @@ test_expect_success '[merge] summary/log configuration' ' test_cmp expected actual2 ' -test_expect_success 'setup: clear [merge] configuration' ' - test_might_fail git config --unset-all merge.log && - test_might_fail git config --unset-all merge.summary -' - test_expect_success 'setup FETCH_HEAD' ' git checkout master && test_tick && @@ -180,6 +175,24 @@ test_expect_success 'merge.log=5 shows all 5 commits' ' test_cmp expected actual ' +test_expect_success '--log=5 with custom comment character' ' + cat >expected <<-EOF && + Merge branch ${apos}left${apos} + + x By Another Author (3) and A U Thor (2) + x Via Another Committer + * left: + Left #5 + Left #4 + Left #3 + Common #2 + Common #1 + EOF + + git -c core.commentchar="x" fmt-merge-msg --log=5 <.git/FETCH_HEAD >actual && + test_cmp expected actual +' + test_expect_success 'merge.log=0 disables shortlog' ' echo "Merge branch ${apos}left${apos}" >expected git -c merge.log=0 fmt-merge-msg <.git/FETCH_HEAD >actual && @@ -248,14 +261,14 @@ test_expect_success 'fmt-merge-msg -m' ' Common #1 EOF - test_might_fail git config --unset merge.log && - test_might_fail git config --unset merge.summary && + test_unconfig merge.log && + test_unconfig merge.summary && git checkout master && git fetch "$(pwd)" left && git fmt-merge-msg -m "Sync with left" <.git/FETCH_HEAD >actual && git fmt-merge-msg --log -m "Sync with left" \ <.git/FETCH_HEAD >actual.log && - git config merge.log true && + test_config merge.log true && git fmt-merge-msg -m "Sync with left" \ <.git/FETCH_HEAD >actual.log-config && git fmt-merge-msg --no-log -m "Sync with left" \ @@ -290,29 +303,29 @@ test_expect_success 'setup: expected shortlog for two branches' ' ' test_expect_success 'shortlog for two branches' ' - git config merge.log true && - test_might_fail git config --unset-all merge.summary && + test_config merge.log true && + test_unconfig merge.summary && git checkout master && test_tick && git fetch . left right && git fmt-merge-msg <.git/FETCH_HEAD >actual1 && - test_might_fail git config --unset-all merge.log && - git config merge.summary true && + test_unconfig merge.log && + test_config merge.summary true && git checkout master && test_tick && git fetch . left right && git fmt-merge-msg <.git/FETCH_HEAD >actual2 && - git config merge.log yes && - test_might_fail git config --unset-all merge.summary && + test_config merge.log yes && + test_unconfig merge.summary && git checkout master && test_tick && git fetch . left right && git fmt-merge-msg <.git/FETCH_HEAD >actual3 && - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && git fetch . left right && @@ -325,8 +338,8 @@ test_expect_success 'shortlog for two branches' ' ' test_expect_success 'merge-msg -F' ' - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && git fetch . left right && @@ -335,8 +348,8 @@ test_expect_success 'merge-msg -F' ' ' test_expect_success 'merge-msg -F in subdirectory' ' - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && git fetch . left right && @@ -350,8 +363,8 @@ test_expect_success 'merge-msg -F in subdirectory' ' ' test_expect_success 'merge-msg with nothing to merge' ' - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && >empty && @@ -376,8 +389,8 @@ test_expect_success 'merge-msg tag' ' Common #1 EOF - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && @@ -406,8 +419,8 @@ test_expect_success 'merge-msg two tags' ' Common #1 EOF - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && @@ -436,8 +449,8 @@ test_expect_success 'merge-msg tag and branch' ' Common #1 EOF - test_might_fail git config --unset-all merge.log && - git config merge.summary yes && + test_unconfig merge.log && + test_config merge.summary yes && git checkout master && test_tick && @@ -464,6 +477,8 @@ test_expect_success 'merge-msg lots of commits' ' echo " ..." } >expected && + test_config merge.summary yes && + git checkout master && test_tick && git fetch . long && @@ -472,4 +487,43 @@ test_expect_success 'merge-msg lots of commits' ' test_cmp expected actual ' +test_expect_success 'merge-msg with "merging" an annotated tag' ' + test_config merge.log true && + + git checkout master^0 && + git commit --allow-empty -m "One step ahead" && + git tag -a -m "An annotated one" annote HEAD && + + git checkout master && + git fetch . annote && + + git fmt-merge-msg <.git/FETCH_HEAD >actual && + { + cat <<-\EOF + Merge tag '\''annote'\'' + + An annotated one + + * tag '\''annote'\'': + One step ahead + EOF + } >expected && + test_cmp expected actual && + + test_when_finished "git reset --hard" && + annote=$(git rev-parse annote) && + git merge --no-commit $annote && + { + cat <<-EOF + Merge tag '\''$annote'\'' + + An annotated one + + * tag '\''$annote'\'': + One step ahead + EOF + } >expected && + test_cmp expected .git/MERGE_MSG +' + test_done diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh index 2fec13dcd3..c20717181e 100755 --- a/t/t7409-submodule-detached-worktree.sh +++ b/t/t7409-submodule-detached-worktree.sh @@ -23,7 +23,9 @@ test_expect_success 'submodule on detached working tree' ' mkdir home && ( cd home && - export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + GIT_WORK_TREE="$(pwd)" && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_WORK_TREE GIT_DIR && git clone --bare ../remote .dotfiles && git submodule add ../bundle1 .vim/bundle/sogood && test_commit "sogood" && @@ -39,7 +41,9 @@ test_expect_success 'submodule on detached working tree' ' ( cd home2 && git clone --bare ../remote .dotfiles && - export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + GIT_WORK_TREE="$(pwd)" && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_WORK_TREE GIT_DIR && git checkout master && git submodule update --init && ( @@ -55,7 +59,8 @@ test_expect_success 'submodule on detached working pointed by core.worktree' ' mkdir home3 && ( cd home3 && - export GIT_DIR="$(pwd)/.dotfiles" && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_DIR && git clone --bare ../remote "$GIT_DIR" && git config core.bare false && git config core.worktree .. && @@ -66,7 +71,8 @@ test_expect_success 'submodule on detached working pointed by core.worktree' ' ) && ( cd home && - export GIT_DIR="$(pwd)/.dotfiles" && + GIT_DIR="$(pwd)/.dotfiles" && + export GIT_DIR && git config core.bare false && git config core.worktree .. && git pull && diff --git a/t/t9020-remote-svn.sh b/t/t9020-remote-svn.sh index 2d2f016f6f..d9f6b73ab0 100755 --- a/t/t9020-remote-svn.sh +++ b/t/t9020-remote-svn.sh @@ -74,7 +74,8 @@ test_expect_success REMOTE_SVN 'mark-file regeneration' ' ' test_expect_success REMOTE_SVN 'incremental imports must lead to the same head' ' - export SVNRMAX=3 && + SVNRMAX=3 && + export SVNRMAX && init_git && git fetch svnsim && test_cmp .git/refs/svn/svnsim/master .git/refs/remotes/svnsim/master && diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh index ef86948d21..d3a5bac754 100755 --- a/t/t9501-gitweb-standalone-http-status.sh +++ b/t/t9501-gitweb-standalone-http-status.sh @@ -130,7 +130,8 @@ test_expect_success DATE_PARSER 'modification: feed last-modified' ' test_debug 'cat gitweb.headers' test_expect_success DATE_PARSER 'modification: feed if-modified-since (modified)' ' - export HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + export HTTP_IF_MODIFIED_SINCE && test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && gitweb_run "p=.git;a=atom;h=master" && grep "Status: 200 OK" gitweb.headers @@ -138,7 +139,8 @@ test_expect_success DATE_PARSER 'modification: feed if-modified-since (modified) test_debug 'cat gitweb.headers' test_expect_success DATE_PARSER 'modification: feed if-modified-since (unmodified)' ' - export HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" && + HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" && + export HTTP_IF_MODIFIED_SINCE && test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && gitweb_run "p=.git;a=atom;h=master" && grep "Status: 304 Not Modified" gitweb.headers @@ -153,7 +155,8 @@ test_expect_success DATE_PARSER 'modification: snapshot last-modified' ' test_debug 'cat gitweb.headers' test_expect_success DATE_PARSER 'modification: snapshot if-modified-since (modified)' ' - export HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + export HTTP_IF_MODIFIED_SINCE && test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && gitweb_run "p=.git;a=snapshot;h=master;sf=tgz" && grep "Status: 200 OK" gitweb.headers @@ -161,7 +164,8 @@ test_expect_success DATE_PARSER 'modification: snapshot if-modified-since (modif test_debug 'cat gitweb.headers' test_expect_success DATE_PARSER 'modification: snapshot if-modified-since (unmodified)' ' - export HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" && + HTTP_IF_MODIFIED_SINCE="Thu, 7 Apr 2005 22:14:13 +0000" && + export HTTP_IF_MODIFIED_SINCE && test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && gitweb_run "p=.git;a=snapshot;h=master;sf=tgz" && grep "Status: 304 Not Modified" gitweb.headers @@ -170,7 +174,8 @@ test_debug 'cat gitweb.headers' test_expect_success DATE_PARSER 'modification: tree snapshot' ' ID=`git rev-parse --verify HEAD^{tree}` && - export HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + HTTP_IF_MODIFIED_SINCE="Wed, 6 Apr 2005 22:14:13 +0000" && + export HTTP_IF_MODIFIED_SINCE && test_when_finished "unset HTTP_IF_MODIFIED_SINCE" && gitweb_run "p=.git;a=snapshot;h=$ID;sf=tgz" && grep "Status: 200 OK" gitweb.headers && @@ -6,8 +6,6 @@ #include "git-compat-util.h" #include "cache.h" -static int dying; - void vreportf(const char *prefix, const char *err, va_list params) { char msg[4096]; @@ -49,12 +47,19 @@ static void warn_builtin(const char *warn, va_list params) vreportf("warning: ", warn, params); } +static int die_is_recursing_builtin(void) +{ + static int dying; + return dying++; +} + /* If we are in a dlopen()ed .so write to a global variable would segfault * (ugh), so keep things static. */ static NORETURN_PTR void (*usage_routine)(const char *err, va_list params) = usage_builtin; static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin; static void (*error_routine)(const char *err, va_list params) = error_builtin; static void (*warn_routine)(const char *err, va_list params) = warn_builtin; +static int (*die_is_recursing)(void) = die_is_recursing_builtin; void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params)) { @@ -66,6 +71,11 @@ void set_error_routine(void (*routine)(const char *err, va_list params)) error_routine = routine; } +void set_die_is_recursing_routine(int (*routine)(void)) +{ + die_is_recursing = routine; +} + void NORETURN usagef(const char *err, ...) { va_list params; @@ -84,11 +94,10 @@ void NORETURN die(const char *err, ...) { va_list params; - if (dying) { + if (die_is_recursing()) { fputs("fatal: recursion detected in die handler\n", stderr); exit(128); } - dying = 1; va_start(params, err); die_routine(err, params); @@ -102,12 +111,11 @@ void NORETURN die_errno(const char *fmt, ...) char str_error[256], *err; int i, j; - if (dying) { + if (die_is_recursing()) { fputs("fatal: recursion detected in die_errno handler\n", stderr); exit(128); } - dying = 1; err = strerror(errno); for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) { |