diff options
-rw-r--r-- | Documentation/RelNotes/1.7.10.txt | 45 | ||||
-rw-r--r-- | Documentation/RelNotes/1.7.9.3.txt | 27 | ||||
-rw-r--r-- | Documentation/config.txt | 7 | ||||
-rw-r--r-- | Documentation/diff-config.txt | 4 | ||||
-rw-r--r-- | Documentation/diff-options.txt | 21 | ||||
-rw-r--r-- | Documentation/git-fsck.txt | 2 | ||||
-rw-r--r-- | Documentation/git-symbolic-ref.txt | 7 | ||||
-rw-r--r-- | Documentation/git.txt | 3 | ||||
-rw-r--r-- | builtin/diff.c | 4 | ||||
-rw-r--r-- | builtin/log.c | 4 | ||||
-rw-r--r-- | builtin/merge.c | 2 | ||||
-rw-r--r-- | builtin/symbolic-ref.c | 11 | ||||
-rw-r--r-- | bundle.c | 2 | ||||
-rwxr-xr-x | contrib/completion/git-completion.bash | 1 | ||||
-rw-r--r-- | diff.c | 114 | ||||
-rw-r--r-- | diff.h | 1 | ||||
-rw-r--r-- | fast-import.c | 2 | ||||
-rwxr-xr-x | git-am.sh | 11 | ||||
-rwxr-xr-x | gitweb/gitweb.perl | 97 | ||||
-rw-r--r-- | parse-options.c | 2 | ||||
-rwxr-xr-x | t/perf/p4000-diff-algorithms.sh | 29 | ||||
-rwxr-xr-x | t/t0040-parse-options.sh | 10 | ||||
-rwxr-xr-x | t/t0300-credentials.sh | 5 | ||||
-rwxr-xr-x | t/t4052-stat-output.sh | 220 | ||||
-rwxr-xr-x | t/t4150-am.sh | 15 | ||||
-rwxr-xr-x | t/t5510-fetch.sh | 57 | ||||
-rwxr-xr-x | t/t5512-ls-remote.sh | 27 | ||||
-rwxr-xr-x | t/t5704-bundle.sh | 4 | ||||
-rw-r--r-- | t/test-lib.sh | 9 |
29 files changed, 605 insertions, 138 deletions
diff --git a/Documentation/RelNotes/1.7.10.txt b/Documentation/RelNotes/1.7.10.txt index 7813ea12cc..b966a8e853 100644 --- a/Documentation/RelNotes/1.7.10.txt +++ b/Documentation/RelNotes/1.7.10.txt @@ -52,6 +52,9 @@ UI, Workflows & Features * "git push" learned the "--prune" option, similar to "git fetch". + * "git symbolic-ref" learned the "--short" option to abbreviate the + refname it shows unambiguously. + * "git tag --list" can be given "--points-at <object>" to limit its output to those that point at the given object. @@ -64,6 +67,9 @@ UI, Workflows & Features needed (including the ones that are not necessary for a specific task). + * Project search in "gitweb" shows the substring that matched in the + project name and description highlighted. + Foreign Interface * Improved handling of views, labels and branches in git-p4 (in contrib). @@ -112,39 +118,10 @@ Unless otherwise noted, all the fixes since v1.7.9 in the maintenance releases are contained in this release (see release notes to them for details). - * "git branch --with $that" assumed incorrectly that the user will never - ask the question with nonsense value in $that. - (merge 6c41e97 cn/maint-branch-with-bad later to maint). - - * An invalid regular expression pattern given by an end user made - "gitweb" to return garbled response. - (merge 36612e4 jn/maint-gitweb-invalid-regexp later to maint). - - * "git rev-list --verify-objects -q" omitted the extra verification - it needs to do over "git rev-list --objects -q" by mistake. - (merge 9899372 nd/maint-verify-objects later to maint). - - * The bulk check-in codepath streamed contents that needs - smudge/clean filters without running them, instead of punting and - delegating to the codepath to run filters after slurping everything - to core. - (merge 4f22b10 jk/maint-avoid-streaming-filtered-contents later to maint). - - * When the filter driver exits before reading the content before the - main git process writes the contents to be filtered to the pipe to - it, the latter could be killed with SIGPIPE instead of ignoring - such an event as an error. - (merge 6424c2a jb/filter-ignore-sigpipe later to maint). - - * When a remote helper exits before reading the blank line from the - main git process to signal the end of commands, the latter could be - killed with SIGPIPE. Instead we should ignore such event as a - non-error. - (merge c34fe63 sp/smart-http-failure-to-push later to maint). - - * "git bundle create" produced a corrupt bundle file upon seeing - commits with excessively long subject line. - (merge 8a557bb tr/maint-bundle-long-subject later to maint). + * The code to synthesize the fake ancestor tree used by 3-way merge + fallback in "git am" was not prepared to read a patch created with + a non-standard -p<num> value. + (merge a61ba26 jc/am-3-nonstandard-popt later to maint). * "gitweb" used to drop warnings in the log file when "heads" view is accessed in a repository whose HEAD does not point at a valid @@ -152,7 +129,7 @@ details). --- exec >/var/tmp/1 -O=v1.7.9.2-358-g64d1544 +O=v1.7.9.2-383-gb8b5290 echo O=$(git describe) git log --first-parent --oneline ^maint $O.. echo diff --git a/Documentation/RelNotes/1.7.9.3.txt b/Documentation/RelNotes/1.7.9.3.txt index d7be177681..91c65012f9 100644 --- a/Documentation/RelNotes/1.7.9.3.txt +++ b/Documentation/RelNotes/1.7.9.3.txt @@ -11,14 +11,41 @@ Fixes since v1.7.9.2 to link the binary with -lintl even when libintl.h is missing from the system. + * When the filter driver exits before reading the content before the + main git process writes the contents to be filtered to the pipe to + it, the latter could be killed with SIGPIPE instead of ignoring + such an event as an error. + * "git add --refresh <pathspec>" used to warn about unmerged paths outside the given pathspec. + * The bulk check-in codepath in "git add" streamed contents that + needs smudge/clean filters without running them, instead of punting + and delegating to the codepath to run filters after slurping + everything to core. + + * "git branch --with $that" assumed incorrectly that the user will never + ask the question with nonsense value in $that. + + * "git bundle create" produced a corrupt bundle file upon seeing + commits with excessively long subject line. + + * When a remote helper exits before reading the blank line from the + main git process to signal the end of commands, the latter could be + killed with SIGPIPE. Instead we should ignore such event as a + non-error. + * The commit log template given with "git merge --edit" did not have a short instructive text like what "git commit" gives. + * "git rev-list --verify-objects -q" omitted the extra verification + it needs to do over "git rev-list --objects -q" by mistake. + * "gitweb" used to drop warnings in the log file when "heads" view is accessed in a repository whose HEAD does not point at a valid branch. + * An invalid regular expression pattern given by an end user made + "gitweb" to return garbled response. + Also contains minor fixes and documentation updates. diff --git a/Documentation/config.txt b/Documentation/config.txt index 5367ba9cae..c081657be7 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1275,9 +1275,10 @@ help.autocorrect:: This is the default. http.proxy:: - Override the HTTP proxy, normally configured using the 'http_proxy' - environment variable (see linkgit:curl[1]). This can be overridden - on a per-remote basis; see remote.<name>.proxy + Override the HTTP proxy, normally configured using the 'http_proxy', + 'https_proxy', and 'all_proxy' environment variables (see + `curl(1)`). This can be overridden on a per-remote basis; see + remote.<name>.proxy http.cookiefile:: File containing previously stored cookie lines which should be used diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt index 1aed79e7dc..6aa1be0478 100644 --- a/Documentation/diff-config.txt +++ b/Documentation/diff-config.txt @@ -52,6 +52,10 @@ directories with less than 10% of the total amount of changed files, and accumulating child directory counts in the parent directories: `files,10,cumulative`. +diff.statGraphWidth:: + Limit the width of the graph part in --stat output. If set, applies + to all commands generating --stat outuput except format-patch. + diff.external:: If this config variable is set, diff generation is not performed using the internal diff machinery, but using the diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 9f7cba2be6..7d4566f829 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -52,14 +52,23 @@ endif::git-format-patch[] --patience:: Generate a diff using the "patience diff" algorithm. +--histogram:: + Generate a diff using the "histogram diff" algorithm. + --stat[=<width>[,<name-width>[,<count>]]]:: - Generate a diffstat. You can override the default - output width for 80-column terminal by `--stat=<width>`. - The width of the filename part can be controlled by - giving another width to it separated by a comma. + Generate a diffstat. By default, as much space as necessary + will be used for the filename part, and the rest for the graph + part. Maximum width defaults to terminal width, or 80 columns + if not connected to a terminal, and can be overriden by + `<width>`. The width of the filename part can be limited by + giving another width `<name-width>` after a comma. The width + of the graph part can be limited by using + `--stat-graph-width=<width>` (affects all commands generating + a stat graph) or by setting `diff.statGraphWidth=<width>` + (does not affect `git format-patch`). By giving a third parameter `<count>`, you can limit the - output to the first `<count>` lines, followed by - `...` if there are more. + output to the first `<count>` lines, followed by `...` if + there are more. + These parameters can also be set individually with `--stat-width=<width>`, `--stat-name-width=<name-width>` and `--stat-count=<count>`. diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt index 47e2f19218..bbb25da2dd 100644 --- a/Documentation/git-fsck.txt +++ b/Documentation/git-fsck.txt @@ -33,7 +33,7 @@ index file, all SHA1 references in .git/refs/*, and all reflogs (unless --dangling:: --no-dangling:: Print objects that exist but that are never 'directly' used (default). - `--no-dangling` can be used to squech this information from the output. + `--no-dangling` can be used to omit this information from the output. --root:: Report root nodes. diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt index a45d4c4f29..981d3a8fc1 100644 --- a/Documentation/git-symbolic-ref.txt +++ b/Documentation/git-symbolic-ref.txt @@ -8,7 +8,8 @@ git-symbolic-ref - Read and modify symbolic refs SYNOPSIS -------- [verse] -'git symbolic-ref' [-q] [-m <reason>] <name> [<ref>] +'git symbolic-ref' [-m <reason>] <name> <ref> +'git symbolic-ref' [-q] [--short] <name> DESCRIPTION ----------- @@ -33,6 +34,10 @@ OPTIONS symbolic ref but a detached HEAD; instead exit with non-zero status silently. +--short:: + When showing the value of <name> as a symbolic ref, try to shorten the + value, e.g. from `refs/heads/master` to `master`. + -m:: Update the reflog for <name> with <reason>. This is valid only when creating or updating a symbolic ref. diff --git a/Documentation/git.txt b/Documentation/git.txt index 22fadeb114..b257d80c75 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -44,9 +44,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.7.9.2/git.html[documentation for release 1.7.9.2] +* link:v1.7.9.3/git.html[documentation for release 1.7.9.3] * release notes for + link:RelNotes/1.7.9.3.txt[1.7.9.3], link:RelNotes/1.7.9.2.txt[1.7.9.2], link:RelNotes/1.7.9.1.txt[1.7.9.1], link:RelNotes/1.7.9.txt[1.7.9]. diff --git a/builtin/diff.c b/builtin/diff.c index 387afa7568..424c815f9b 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -285,6 +285,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix) /* Otherwise, we are doing the usual "git" diff */ rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index; + /* Scale to real terminal size and respect statGraphWidth config */ + rev.diffopt.stat_width = -1; + rev.diffopt.stat_graph_width = -1; + /* Default to let external and textconv be used */ DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV); diff --git a/builtin/log.c b/builtin/log.c index 7d1f6f88a0..8a47012b0b 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -77,6 +77,8 @@ static void cmd_log_init_defaults(struct rev_info *rev) get_commit_format(fmt_pretty, rev); rev->verbose_header = 1; DIFF_OPT_SET(&rev->diffopt, RECURSIVE); + rev->diffopt.stat_width = -1; /* use full terminal width */ + rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */ rev->abbrev_commit = default_abbrev_commit; rev->show_root_diff = default_show_root; rev->subject_prefix = fmt_patch_subject_prefix; @@ -447,6 +449,8 @@ int cmd_show(int argc, const char **argv, const char *prefix) rev.diff = 1; rev.always_show_header = 1; rev.no_walk = 1; + rev.diffopt.stat_width = -1; /* Scale to real terminal size */ + memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; opt.tweak = show_rev_tweak_rev; diff --git a/builtin/merge.c b/builtin/merge.c index d3e1e8dc9e..cb8f14910b 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -399,6 +399,8 @@ static void finish(struct commit *head_commit, if (new_head && show_diffstat) { struct diff_options opts; diff_setup(&opts); + opts.stat_width = -1; /* use full terminal width */ + opts.stat_graph_width = -1; /* respect statGraphWidth config */ opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c index 2ef5962386..801d62ece5 100644 --- a/builtin/symbolic-ref.c +++ b/builtin/symbolic-ref.c @@ -8,13 +8,15 @@ static const char * const git_symbolic_ref_usage[] = { NULL }; +static int shorten; + static void check_symref(const char *HEAD, int quiet) { unsigned char sha1[20]; int flag; - const char *refs_heads_master = resolve_ref_unsafe(HEAD, sha1, 0, &flag); + const char *refname = resolve_ref_unsafe(HEAD, sha1, 0, &flag); - if (!refs_heads_master) + if (!refname) die("No such ref: %s", HEAD); else if (!(flag & REF_ISSYMREF)) { if (!quiet) @@ -22,7 +24,9 @@ static void check_symref(const char *HEAD, int quiet) else exit(1); } - puts(refs_heads_master); + if (shorten) + refname = shorten_unambiguous_ref(refname, 0); + puts(refname); } int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) @@ -32,6 +36,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) struct option options[] = { OPT__QUIET(&quiet, "suppress error message for non-symbolic (detached) refs"), + OPT_BOOL(0, "short", &shorten, "shorten ref output"), OPT_STRING('m', NULL, &msg, "reason", "reason of the update"), OPT_END(), }; @@ -273,7 +273,7 @@ int create_bundle(struct bundle_header *header, const char *path, if (!get_sha1_hex(buf.buf + 1, sha1)) { struct object *object = parse_object(sha1); object->flags |= UNINTERESTING; - add_pending_object(&revs, object, buf.buf); + add_pending_object(&revs, object, xstrdup(buf.buf)); } } else if (!get_sha1_hex(buf.buf, sha1)) { struct object *object = parse_object(sha1); diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 33f0e4dd69..fba076dde2 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2092,6 +2092,7 @@ _git_config () core.whitespace core.worktree diff.autorefreshindex + diff.statGraphWidth diff.external diff.ignoreSubmodules diff.mnemonicprefix @@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; static int diff_no_prefix; +static int diff_stat_graph_width; static int diff_dirstat_permille_default = 30; static struct diff_options default_diff_options; @@ -156,6 +157,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) diff_no_prefix = git_config_bool(var, value); return 0; } + if (!strcmp(var, "diff.statgraphwidth")) { + diff_stat_graph_width = git_config_int(var, value); + return 0; + } if (!strcmp(var, "diff.external")) return git_config_string(&external_diff_cmd_cfg, var, value); if (!strcmp(var, "diff.wordregex")) @@ -1375,7 +1380,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) int i, len, add, del, adds = 0, dels = 0; uintmax_t max_change = 0, max_len = 0; int total_files = data->nr; - int width, name_width, count; + int width, name_width, graph_width, number_width = 4, count; const char *reset, *add_c, *del_c; const char *line_prefix = ""; int extra_shown = 0; @@ -1389,25 +1394,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) line_prefix = msg->buf; } - width = options->stat_width ? options->stat_width : 80; - name_width = options->stat_name_width ? options->stat_name_width : 50; count = options->stat_count ? options->stat_count : data->nr; - /* Sanity: give at least 5 columns to the graph, - * but leave at least 10 columns for the name. - */ - if (width < 25) - width = 25; - if (name_width < 10) - name_width = 10; - else if (width < name_width + 15) - name_width = width - 15; - - /* Find the longest filename and max number of changes */ reset = diff_get_color_opt(options, DIFF_RESET); add_c = diff_get_color_opt(options, DIFF_FILE_NEW); del_c = diff_get_color_opt(options, DIFF_FILE_OLD); + /* + * Find the longest filename and max number of changes + */ for (i = 0; (i < count) && (i < data->nr); i++) { struct diffstat_file *file = data->files[i]; uintmax_t change = file->added + file->deleted; @@ -1428,19 +1423,72 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) } count = i; /* min(count, data->nr) */ - /* Compute the width of the graph part; - * 10 is for one blank at the beginning of the line plus - * " | count " between the name and the graph. + /* + * We have width = stat_width or term_columns() columns total. + * We want a maximum of min(max_len, stat_name_width) for the name part. + * We want a maximum of min(max_change, stat_graph_width) for the +- part. + * We also need 1 for " " and 4 + decimal_width(max_change) + * for " | NNNN " and one the empty column at the end, altogether + * 6 + decimal_width(max_change). + * + * If there's not enough space, we will use the smaller of + * stat_name_width (if set) and 5/8*width for the filename, + * and the rest for constant elements + graph part, but no more + * than stat_graph_width for the graph part. + * (5/8 gives 50 for filename and 30 for the constant parts + graph + * for the standard terminal size). * - * From here on, name_width is the width of the name area, - * and width is the width of the graph area. + * In other words: stat_width limits the maximum width, and + * stat_name_width fixes the maximum width of the filename, + * and is also used to divide available columns if there + * aren't enough. */ - name_width = (name_width < max_len) ? name_width : max_len; - if (width < (name_width + 10) + max_change) - width = width - (name_width + 10); + + if (options->stat_width == -1) + width = term_columns(); else - width = max_change; + width = options->stat_width ? options->stat_width : 80; + + if (options->stat_graph_width == -1) + options->stat_graph_width = diff_stat_graph_width; + /* + * Guarantee 3/8*16==6 for the graph part + * and 5/8*16==10 for the filename part + */ + if (width < 16 + 6 + number_width) + width = 16 + 6 + number_width; + + /* + * First assign sizes that are wanted, ignoring available width. + */ + graph_width = (options->stat_graph_width && + options->stat_graph_width < max_change) ? + options->stat_graph_width : max_change; + name_width = (options->stat_name_width > 0 && + options->stat_name_width < max_len) ? + options->stat_name_width : max_len; + + /* + * Adjust adjustable widths not to exceed maximum width + */ + if (name_width + number_width + 6 + graph_width > width) { + if (graph_width > width * 3/8 - number_width - 6) + graph_width = width * 3/8 - number_width - 6; + if (options->stat_graph_width && + graph_width > options->stat_graph_width) + graph_width = options->stat_graph_width; + if (name_width > width - number_width - 6 - graph_width) + name_width = width - number_width - 6 - graph_width; + else + graph_width = width - number_width - 6 - name_width; + } + + /* + * From here name_width is the width of the name area, + * and graph_width is the width of the graph area. + * max_change is used to scale graph properly. + */ for (i = 0; i < count; i++) { const char *prefix = ""; char *name = data->files[i]->print_name; @@ -1496,18 +1544,18 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) adds += add; dels += del; - if (width <= max_change) { + if (graph_width <= max_change) { int total = add + del; - total = scale_linear(add + del, width, max_change); + total = scale_linear(add + del, graph_width, max_change); if (total < 2 && add && del) /* width >= 2 due to the sanity check */ total = 2; if (add < del) { - add = scale_linear(add, width, max_change); + add = scale_linear(add, graph_width, max_change); del = total - add; } else { - del = scale_linear(del, width, max_change); + del = scale_linear(del, graph_width, max_change); add = total - del; } } @@ -3299,6 +3347,7 @@ static int stat_opt(struct diff_options *options, const char **av) char *end; int width = options->stat_width; int name_width = options->stat_name_width; + int graph_width = options->stat_graph_width; int count = options->stat_count; int argcount = 1; @@ -3327,6 +3376,16 @@ static int stat_opt(struct diff_options *options, const char **av) name_width = strtoul(av[1], &end, 10); argcount = 2; } + } else if (!prefixcmp(arg, "-graph-width")) { + arg += strlen("-graph-width"); + if (*arg == '=') + graph_width = strtoul(arg + 1, &end, 10); + else if (!*arg && !av[1]) + die("Option '--stat-graph-width' requires a value"); + else if (!*arg) { + graph_width = strtoul(av[1], &end, 10); + argcount = 2; + } } else if (!prefixcmp(arg, "-count")) { arg += strlen("-count"); if (*arg == '=') @@ -3352,6 +3411,7 @@ static int stat_opt(struct diff_options *options, const char **av) return 0; options->output_format |= DIFF_FORMAT_DIFFSTAT; options->stat_name_width = name_width; + options->stat_graph_width = graph_width; options->stat_width = width; options->stat_count = count; return argcount; @@ -129,6 +129,7 @@ struct diff_options { int stat_width; int stat_name_width; + int stat_graph_width; int stat_count; const char *word_regex; enum diff_words_type word_diff; diff --git a/fast-import.c b/fast-import.c index 6cd19e580b..c1486cabba 100644 --- a/fast-import.c +++ b/fast-import.c @@ -2712,7 +2712,7 @@ static void parse_new_tag(void) /* Obtain the new tag name from the rest of our command */ sp = strchr(command_buf.buf, ' ') + 1; t = pool_alloc(sizeof(struct tag)); - t->next_tag = NULL; + memset(t, 0, sizeof(struct tag)); t->name = pool_strdup(sp); if (last_tag) last_tag->next_tag = t; @@ -128,15 +128,18 @@ fall_back_3way () { mkdir "$dotest/patch-merge-tmp-dir" # First see if the patch records the index info that we can use. - git apply --build-fake-ancestor "$dotest/patch-merge-tmp-index" \ - "$dotest/patch" && + cmd="git apply $git_apply_opt --build-fake-ancestor" && + cmd="$cmd "'"$dotest/patch-merge-tmp-index" "$dotest/patch"' && + eval "$cmd" && GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ git write-tree >"$dotest/patch-merge-base+" || cannot_fallback "$(gettext "Repository lacks necessary blobs to fall back on 3-way merge.")" say Using index info to reconstruct a base tree... - if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ - git apply --cached <"$dotest/patch" + + cmd='GIT_INDEX_FILE="$dotest/patch-merge-tmp-index"' + cmd="$cmd git apply --cached $git_apply_opt"' <"$dotest/patch"' + if eval "$cmd" then mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base" mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index" diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 7729ed26b5..cd98888a93 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1724,6 +1724,88 @@ sub chop_and_escape_str { } } +# Highlight selected fragments of string, using given CSS class, +# and escape HTML. It is assumed that fragments do not overlap. +# Regions are passed as list of pairs (array references). +# +# Example: esc_html_hl_regions("foobar", "mark", [ 0, 3 ]) returns +# '<span class="mark">foo</span>bar' +sub esc_html_hl_regions { + my ($str, $css_class, @sel) = @_; + return esc_html($str) unless @sel; + + my $out = ''; + my $pos = 0; + + for my $s (@sel) { + $out .= esc_html(substr($str, $pos, $s->[0] - $pos)) + if ($s->[0] - $pos > 0); + $out .= $cgi->span({-class => $css_class}, + esc_html(substr($str, $s->[0], $s->[1] - $s->[0]))); + + $pos = $s->[1]; + } + $out .= esc_html(substr($str, $pos)) + if ($pos < length($str)); + + return $out; +} + +# return positions of beginning and end of each match +sub matchpos_list { + my ($str, $regexp) = @_; + return unless (defined $str && defined $regexp); + + my @matches; + while ($str =~ /$regexp/g) { + push @matches, [$-[0], $+[0]]; + } + return @matches; +} + +# highlight match (if any), and escape HTML +sub esc_html_match_hl { + my ($str, $regexp) = @_; + return esc_html($str) unless defined $regexp; + + my @matches = matchpos_list($str, $regexp); + return esc_html($str) unless @matches; + + return esc_html_hl_regions($str, 'match', @matches); +} + + +# highlight match (if any) of shortened string, and escape HTML +sub esc_html_match_hl_chopped { + my ($str, $chopped, $regexp) = @_; + return esc_html_match_hl($str, $regexp) unless defined $chopped; + + my @matches = matchpos_list($str, $regexp); + return esc_html($chopped) unless @matches; + + # filter matches so that we mark chopped string + my $tail = "... "; # see chop_str + unless ($chopped =~ s/\Q$tail\E$//) { + $tail = ''; + } + my $chop_len = length($chopped); + my $tail_len = length($tail); + my @filtered; + + for my $m (@matches) { + if ($m->[0] > $chop_len) { + push @filtered, [ $chop_len, $chop_len + $tail_len ] if ($tail_len > 0); + last; + } elsif ($m->[1] > $chop_len) { + push @filtered, [ $m->[0], $chop_len + $tail_len ]; + last; + } + push @filtered, $m; + } + + return esc_html_hl_regions($chopped . $tail, 'match', @filtered); +} + ## ---------------------------------------------------------------------- ## functions returning short strings @@ -5174,7 +5256,7 @@ sub git_patchset_body { # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . sub git_project_search_form { - my ($searchtext, $search_use_regexp); + my ($searchtext, $search_use_regexp) = @_; my $limit = ''; if ($project_filter) { @@ -5368,10 +5450,17 @@ sub git_project_list_rows { print "</td>\n"; } print "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"), - -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" . + -class => "list"}, + esc_html_match_hl($pr->{'path'}, $search_regexp)) . + "</td>\n" . "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"), - -class => "list", -title => $pr->{'descr_long'}}, - esc_html($pr->{'descr'})) . "</td>\n" . + -class => "list", + -title => $pr->{'descr_long'}}, + $search_regexp + ? esc_html_match_hl_chopped($pr->{'descr_long'}, + $pr->{'descr'}, $search_regexp) + : esc_html($pr->{'descr'})) . + "</td>\n" . "<td><i>" . chop_and_escape_str($pr->{'owner'}, 15) . "</i></td>\n"; print "<td class=\"". age_class($pr->{'age'}) . "\">" . (defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</td>\n" . diff --git a/parse-options.c b/parse-options.c index 190899611e..850cfa78c9 100644 --- a/parse-options.c +++ b/parse-options.c @@ -393,6 +393,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, case -1: return parse_options_usage(ctx, usagestr, options, 1); case -2: + if (ctx->opt) + check_typos(arg + 1, options); goto unknown; } if (ctx->opt) diff --git a/t/perf/p4000-diff-algorithms.sh b/t/perf/p4000-diff-algorithms.sh new file mode 100755 index 0000000000..d6e505c78c --- /dev/null +++ b/t/perf/p4000-diff-algorithms.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +test_description="Tests diff generation performance" + +. ./perf-lib.sh + +test_perf_default_repo + +test_perf 'log -3000 (baseline)' ' + git log -1000 >/dev/null +' + +test_perf 'log --raw -3000 (tree-only)' ' + git log --raw -3000 >/dev/null +' + +test_perf 'log -p -3000 (Myers)' ' + git log -p -3000 >/dev/null +' + +test_perf 'log -p -3000 --histogram' ' + git log -p -3000 --histogram >/dev/null +' + +test_perf 'log -p -3000 --patience' ' + git log -p -3000 --patience >/dev/null +' + +test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index a44bcb9b39..e3f354a45e 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -236,6 +236,16 @@ test_expect_success 'detect possible typos' ' test_cmp typo.err output.err ' +cat > typo.err << EOF +error: did you mean \`--ambiguous\` (with two dashes ?) +EOF + +test_expect_success 'detect possible typos' ' + test_must_fail test-parse-options -ambiguous > output 2> output.err && + test ! -s output && + test_cmp typo.err output.err +' + cat > expect <<EOF boolean: 0 integer: 0 diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 8621ab036f..20e28e34e7 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -8,10 +8,13 @@ test_expect_success 'setup helper scripts' ' cat >dump <<-\EOF && whoami=`echo $0 | sed s/.*git-credential-//` echo >&2 "$whoami: $*" - while IFS== read key value; do + OIFS=$IFS + IFS== + while read key value; do echo >&2 "$whoami: $key=$value" eval "$key=$value" done + IFS=$OIFS EOF write_script git-credential-useless <<-\EOF && diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh new file mode 100755 index 0000000000..328aa8f398 --- /dev/null +++ b/t/t4052-stat-output.sh @@ -0,0 +1,220 @@ +#!/bin/sh +# +# Copyright (c) 2012 Zbigniew Jędrzejewski-Szmek +# + +test_description='test --stat output of various commands' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh + +# 120 character name +name=aaaaaaaaaa +name=$name$name$name$name$name$name$name$name$name$name$name$name +test_expect_success 'preparation' ' + >"$name" && + git add "$name" && + git commit -m message && + echo a >"$name" && + git commit -m message "$name" +' + +while read cmd args +do + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd: small change with long name gives more space to the name" ' + git $cmd $args >output && + grep " | " output >actual && + test_cmp expect actual + ' + + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd --stat=width: a long name is given more room when the bar is short" ' + git $cmd $args --stat=40 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-width=width with long name" ' + git $cmd $args --stat-width=40 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd --stat=...,name-width with long name" ' + git $cmd $args --stat=60,30 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-name-width with long name" ' + git $cmd $args --stat-name-width=30 >output && + grep " | " output >actual && + test_cmp expect actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + + +test_expect_success 'preparation for big change tests' ' + >abcd && + git add abcd && + git commit -m message && + i=0 && + while test $i -lt 1000 + do + echo $i && i=$(($i + 1)) + done >abcd && + git commit -m message abcd +' + +cat >expect80 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF + +cat >expect200 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF + +while read verb expect cmd args +do + test_expect_success "$cmd $verb COLUMNS (big change)" ' + COLUMNS=200 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect200 diff HEAD^ HEAD --stat +respects expect200 show --stat +respects expect200 log -1 --stat +EOF + +cat >expect40 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++ +EOF + +while read verb expect cmd args +do + test_expect_success "$cmd $verb not enough COLUMNS (big change)" ' + COLUMNS=40 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' + + test_expect_success "$cmd $verb statGraphWidth config" ' + git -c diff.statGraphWidth=26 $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect40 diff HEAD^ HEAD --stat +respects expect40 show --stat +respects expect40 log -1 --stat +EOF + + +cat >expect <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++ +EOF +while read cmd args +do + test_expect_success "$cmd --stat=width with big change" ' + git $cmd $args --stat=40 >output + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-width=width with big change" ' + git $cmd $args --stat-width=40 >output + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-graph--width with big change" ' + git $cmd $args --stat-graph-width=26 >output + grep " | " output >actual && + test_cmp expect actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + +test_expect_success 'preparation for long filename tests' ' + cp abcd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + git add aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + git commit -m message +' + +cat >expect <<'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++ +EOF +while read cmd args +do + test_expect_success "$cmd --stat=width with big change is more balanced" ' + git $cmd $args --stat-width=60 >output && + grep " | " output >actual && + test_cmp expect actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + +cat >expect80 <<'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++ +EOF +cat >expect200 <<'EOF' + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +while read verb expect cmd args +do + test_expect_success "$cmd $verb COLUMNS (long filename)" ' + COLUMNS=200 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect200 diff HEAD^ HEAD --stat +respects expect200 show --stat +respects expect200 log -1 --stat +EOF + +cat >expect <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +test_expect_success 'merge --stat respects COLUMNS (big change)' ' + git checkout -b branch HEAD^^ && + COLUMNS=100 git merge --stat --no-ff master^ >output && + grep " | " output >actual + test_cmp expect actual +' + +cat >expect <<'EOF' + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++ +EOF +test_expect_success 'merge --stat respects COLUMNS (long filename)' ' + COLUMNS=100 git merge --stat --no-ff master >output && + grep " | " output >actual + test_cmp expect actual +' + +test_done diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 6f77fffee6..ccc0280f52 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -123,6 +123,7 @@ test_expect_success setup ' git commit -m "added another file" && git format-patch --stdout master >lorem-move.patch && + git format-patch --no-prefix --stdout master >lorem-zero.patch && git checkout -b rename && git mv file renamed && @@ -286,6 +287,20 @@ test_expect_success 'am -3 falls back to 3-way merge' ' git diff --exit-code lorem ' +test_expect_success 'am -3 -p0 can read --no-prefix patch' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout -b lorem3 master2 && + sed -n -e "3,\$p" msg >file && + head -n 9 msg >>file && + git add file && + test_tick && + git commit -m "copied stuff" && + git am -3 -p0 lorem-zero.patch && + ! test -d .git/rebase-apply && + git diff --exit-code lorem +' + test_expect_success 'am can rename a file' ' grep "^rename from" rename.patch && rm -fr .git/rebase-apply && diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 79ee913130..308c02ea75 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -14,6 +14,14 @@ test_bundle_object_count () { test "$2" = $(grep '^[0-9a-f]\{40\} ' verify.out | wc -l) } +convert_bundle_to_pack () { + while read x && test -n "$x" + do + :; + done + cat +} + test_expect_success setup ' echo >file original && git add file && @@ -206,13 +214,7 @@ test_expect_success 'unbundle 1' ' test_expect_success 'bundle 1 has only 3 files ' ' cd "$D" && - ( - while read x && test -n "$x" - do - :; - done - cat - ) <bundle1 >bundle.pack && + convert_bundle_to_pack <bundle1 >bundle.pack && git index-pack bundle.pack && test_bundle_object_count bundle.pack 3 ' @@ -229,13 +231,7 @@ test_expect_success 'bundle does not prerequisite objects' ' git add file2 && git commit -m add.file2 file2 && git bundle create bundle3 -1 HEAD && - ( - while read x && test -n "$x" - do - :; - done - cat - ) <bundle3 >bundle.pack && + convert_bundle_to_pack <bundle3 >bundle.pack && git index-pack bundle.pack && test_bundle_object_count bundle.pack 3 ' @@ -433,14 +429,31 @@ test_expect_success 'fetch --dry-run' ' ' test_expect_success "should be able to fetch with duplicate refspecs" ' - mkdir dups && - cd dups && - git init && - git config branch.master.remote three && - git config remote.three.url ../three/.git && - git config remote.three.fetch +refs/heads/*:refs/remotes/origin/* && - git config --add remote.three.fetch +refs/heads/*:refs/remotes/origin/* && - git fetch three + mkdir dups && + ( + cd dups && + git init && + git config branch.master.remote three && + git config remote.three.url ../three/.git && + git config remote.three.fetch +refs/heads/*:refs/remotes/origin/* && + git config --add remote.three.fetch +refs/heads/*:refs/remotes/origin/* && + git fetch three + ) +' + +test_expect_success 'all boundary commits are excluded' ' + test_commit base && + test_commit oneside && + git checkout HEAD^ && + test_commit otherside && + git checkout master && + test_tick && + git merge otherside && + ad=$(git log --no-walk --format=%ad HEAD) && + git bundle create twoside-boundary.bdl master --since="$ad" && + convert_bundle_to_pack <twoside-boundary.bdl >twoside-boundary.pack && + pack=$(git index-pack --fix-thin --stdin <twoside-boundary.pack) && + test_bundle_object_count .git/objects/pack/pack-${pack##pack }.pack 3 ' test_done diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 5c546c99a5..6764d511ce 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -5,7 +5,6 @@ test_description='git ls-remote' . ./test-lib.sh test_expect_success setup ' - >file && git add file && test_tick && @@ -18,45 +17,33 @@ test_expect_success setup ' ) >expected.all && git remote add self "$(pwd)/.git" - ' test_expect_success 'ls-remote --tags .git' ' - git ls-remote --tags .git >actual && test_cmp expected.tag actual - ' test_expect_success 'ls-remote .git' ' - git ls-remote .git >actual && test_cmp expected.all actual - ' test_expect_success 'ls-remote --tags self' ' - git ls-remote --tags self >actual && test_cmp expected.tag actual - ' test_expect_success 'ls-remote self' ' - git ls-remote self >actual && test_cmp expected.all actual - ' test_expect_success 'dies when no remote specified and no default remotes found' ' - test_must_fail git ls-remote - ' test_expect_success 'use "origin" when no remote specified' ' - URL="$(pwd)/.git" && echo "From $URL" >exp_err && @@ -65,18 +52,14 @@ test_expect_success 'use "origin" when no remote specified' ' test_cmp exp_err actual_err && test_cmp expected.all actual - ' test_expect_success 'suppress "From <url>" with -q' ' - git ls-remote -q 2>actual_err && test_must_fail test_cmp exp_err actual_err - ' test_expect_success 'use branch.<name>.remote if possible' ' - # # Test that we are indeed using branch.<name>.remote, not "origin", even # though the "origin" remote has been set. @@ -99,14 +82,13 @@ test_expect_success 'use branch.<name>.remote if possible' ' git ls-remote 2>actual_err >actual && test_cmp exp_err actual_err && test_cmp exp actual - ' -cat >exp <<EOF -fatal: 'refs*master' does not appear to be a git repository -fatal: The remote end hung up unexpectedly -EOF test_expect_success 'confuses pattern as remote when no remote specified' ' + cat >exp <<-\EOF && + fatal: '\''refs*master'\'' does not appear to be a git repository + fatal: The remote end hung up unexpectedly + EOF # # Do not expect "git ls-remote <pattern>" to work; ls-remote, correctly, # confuses <pattern> for <remote>. Although ugly, this behaviour is akin @@ -120,7 +102,6 @@ test_expect_success 'confuses pattern as remote when no remote specified' ' # role as a pattern. test_must_fail git ls-remote refs*master >actual 2>&1 && test_cmp exp actual - ' test_expect_success 'die with non-2 for wrong repository even with --exit-code' ' diff --git a/t/t5704-bundle.sh b/t/t5704-bundle.sh index a51c8b0560..9e43731fe5 100755 --- a/t/t5704-bundle.sh +++ b/t/t5704-bundle.sh @@ -54,8 +54,8 @@ test_expect_success 'ridiculously long subject in boundary' ' git bundle list-heads long-subject-bundle.bdl >heads && test -s heads && git fetch long-subject-bundle.bdl && - sed -n "/^-/{p;q}" long-subject-bundle.bdl >boundary && - grep "^-$_x40 " boundary + sed -n "/^-/{p;q;}" long-subject-bundle.bdl >boundary && + grep "^-[0-9a-f]\\{40\\} " boundary ' test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index d75766adaf..30ed4d74bb 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -42,10 +42,11 @@ TZ=UTC TERM=dumb export LANG LC_ALL PAGER TERM TZ EDITOR=: -unset VISUAL -unset EMAIL -unset LANGUAGE -unset $(perl -e ' +# A call to "unset" with no arguments causes at least Solaris 10 +# /usr/xpg4/bin/sh and /bin/ksh to bail out. So keep the unsets +# deriving from the command substitution clustered with the other +# ones. +unset VISUAL EMAIL LANGUAGE $(perl -e ' my @env = keys %ENV; my $ok = join("|", qw( TRACE |