aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes/2.40.0.txt48
-rw-r--r--Documentation/config/format.txt3
-rw-r--r--Documentation/git-archive.txt5
-rw-r--r--Documentation/git-credential.txt6
-rw-r--r--Documentation/gitattributes.txt31
-rw-r--r--Documentation/gitcredentials.txt2
-rw-r--r--Documentation/rev-list-options.txt10
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--archive.c7
-rw-r--r--archive.h1
-rw-r--r--builtin/credential-cache--daemon.c3
-rw-r--r--builtin/fetch.c3
-rw-r--r--builtin/log.c2
-rw-r--r--credential.c20
-rw-r--r--credential.h2
-rw-r--r--delta-islands.c12
-rw-r--r--diff.c90
-rw-r--r--diff.h1
-rw-r--r--dir-iterator.c12
-rw-r--r--dir-iterator.h20
-rw-r--r--git.c2
-rw-r--r--gpg-interface.c8
-rw-r--r--range-diff.c11
-rw-r--r--refs.c93
-rw-r--r--sequencer.c57
-rw-r--r--t/helper/test-ctype.c30
-rw-r--r--t/helper/test-dir-iterator.c6
-rw-r--r--t/helper/test-genzeros.c11
-rw-r--r--t/lib-diff-alternative.sh38
-rw-r--r--t/lib-httpd.sh13
-rw-r--r--t/lib-httpd/apache.conf18
-rw-r--r--t/lib-httpd/proxy-passwd1
-rw-r--r--t/lib-rebase.sh10
-rwxr-xr-xt/t0066-dir-iterator.sh44
-rwxr-xr-xt/t0300-credentials.sh94
-rwxr-xr-xt/t1401-symbolic-ref.sh34
-rwxr-xr-xt/t2015-checkout-unborn.sh11
-rwxr-xr-xt/t3206-range-diff.sh32
-rwxr-xr-xt/t3404-rebase-interactive.sh35
-rwxr-xr-xt/t3437-rebase-fixup-options.sh26
-rwxr-xr-xt/t4014-format-patch.sh18
-rwxr-xr-xt/t5000-tar-tree.sh19
-rwxr-xr-xt/t5319-multi-pack-index.sh16
-rwxr-xr-xt/t5514-fetch-multiple.sh5
-rwxr-xr-xt/t5541-http-push-smart.sh57
-rwxr-xr-xt/t5551-http-fetch-smart.sh170
-rwxr-xr-xt/t5559-http-fetch-smart-http2.sh1
-rwxr-xr-xt/t5564-http-proxy.sh41
-rwxr-xr-xt/t7510-signed-commit.sh44
-rw-r--r--t/test-lib-functions.sh8
-rw-r--r--trace.c7
-rw-r--r--trace.h2
-rw-r--r--userdiff.c4
-rw-r--r--userdiff.h1
54 files changed, 932 insertions, 315 deletions
diff --git a/Documentation/RelNotes/2.40.0.txt b/Documentation/RelNotes/2.40.0.txt
index 4232ad8045..094a2937cc 100644
--- a/Documentation/RelNotes/2.40.0.txt
+++ b/Documentation/RelNotes/2.40.0.txt
@@ -54,6 +54,34 @@ UI, Workflows & Features
* Userdiff regexp update for Java language.
+ * "git fetch --jobs=0" used to hit a BUG(), which has been corrected
+ to use the available CPUs.
+
+ * An invalid label or ref in the "rebase -i" todo file used to
+ trigger an runtime error. SUch an error is now diagnosed while the
+ todo file is parsed.
+
+ * The "diff" drivers specified by the "diff" attribute attached to
+ paths can now specify which algorithm (e.g. histogram) to use.
+
+ * "git range-diff" learned --abbrev=<num> option.
+
+ * "git archive HEAD^{tree}" records the paths with the current
+ timestamp in the archive, making it harder to obtain a stable
+ output. The command learned the --mtime option to specify an
+ arbitrary timestamp (e.g. --mtime="@0 +0000" for the epoch).
+
+ * The credential subsystem learned that a password may have an
+ explicit expiration.
+
+ * The format.attach configuration variable lacked a way to override a
+ value defined in a lower-priority configuration file (e.g. the
+ system one) by redefining it in a higher-priority configuration
+ file. Now, setting format.attach to an empty string means show the
+ patch inline in the e-mail message, without using MIME attachment.
+
+ This is a backward incompatible change.
+
Performance, Internal Implementation, Development Support etc.
@@ -235,6 +263,24 @@ Fixes since v2.39
* Doc update.
(merge d9ec3b0dc0 jk/doc-ls-remote-matching later to maint).
+ * Error messages given upon a signature verification failure used to
+ discard the errors from underlying gpg program, which has been
+ corrected.
+ (merge ad6b320756 js/gpg-errors later to maint).
+
+ * Update --date=default documentation.
+ (merge 9deef088ae rd/doc-default-date-format later to maint).
+
+ * A test helper had a single write(2) of 256kB, which was too big for
+ some platforms (e.g. NonStop), which has been corrected by using
+ xwrite() wrapper appropriately.
+ (merge 58eab6ff13 jc/genzeros-avoid-raw-write later to maint).
+
+ * sscanf(3) used in "git symbolic-ref --short" implementation found
+ to be not working reliably on macOS in UTF-8 locales. Rewrite the
+ code to avoid sscanf() altogether to work it around.
+ (merge 613bef56b8 jk/shorten-unambiguous-ref-wo-sscanf later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge 4eb1ccecd4 dh/mingw-ownership-check-typofix later to maint).
(merge f95526419b ar/typofix-gitattributes-doc later to maint).
@@ -261,3 +307,5 @@ Fixes since v2.39
(merge e65b868d07 rs/size-t-fixes later to maint).
(merge 3eb1e1ca9a ab/config-h-remove-unused later to maint).
(merge d390e08076 cw/doc-pushurl-vs-url later to maint).
+ (merge 567342fc77 rs/ctype-test later to maint).
+ (merge d35d8f2e7a ap/t2015-style-update later to maint).
diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index 3bd78269e2..73678d88a1 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -3,7 +3,8 @@ format.attach::
'format-patch'. The value can also be a double quoted string
which will enable attachments as the default and set the
value as the boundary. See the --attach option in
- linkgit:git-format-patch[1].
+ linkgit:git-format-patch[1]. To countermand an earlier
+ value, set it to an empty string.
format.from::
Provides the default value for the `--from` option to format-patch.
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index 60c040988b..6bab201d37 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -86,6 +86,11 @@ cases, write an untracked file and use `--add-file` instead.
Look for attributes in .gitattributes files in the working tree
as well (see <<ATTRIBUTES>>).
+--mtime=<time>::
+ Set modification time of archive entries. Without this option
+ the committer time is used if `<tree-ish>` is a commit or tag,
+ and the current time if it is a tree.
+
<extra>::
This can be any options that the archiver backend understands.
See next section.
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index ac2818b9f6..29d184ab82 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -144,6 +144,12 @@ Git understands the following attributes:
The credential's password, if we are asking it to be stored.
+`password_expiry_utc`::
+
+ Generated passwords such as an OAuth access token may have an expiry date.
+ When reading credentials from helpers, `git credential fill` ignores expired
+ passwords. Represented as Unix time UTC, seconds since 1970.
+
`url`::
When this special attribute is read by `git credential`, the
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index c19e64ea0e..39bfbca1ff 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -758,6 +758,37 @@ with the above configuration, i.e. `j-c-diff`, with 7
parameters, just like `GIT_EXTERNAL_DIFF` program is called.
See linkgit:git[1] for details.
+Setting the internal diff algorithm
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The diff algorithm can be set through the `diff.algorithm` config key, but
+sometimes it may be helpful to set the diff algorithm per path. For example,
+one may want to use the `minimal` diff algorithm for .json files, and the
+`histogram` for .c files, and so on without having to pass in the algorithm
+through the command line each time.
+
+First, in `.gitattributes`, assign the `diff` attribute for paths.
+
+------------------------
+*.json diff=<name>
+------------------------
+
+Then, define a "diff.<name>.algorithm" configuration to specify the diff
+algorithm, choosing from `myers`, `patience`, `minimal`, or `histogram`.
+
+----------------------------------------------------------------
+[diff "<name>"]
+ algorithm = histogram
+----------------------------------------------------------------
+
+This diff algorithm applies to user facing diff output like git-diff(1),
+git-show(1) and is used for the `--stat` output as well. The merge machinery
+will not use the diff algorithm set through this method.
+
+NOTE: If `diff.<name>.command` is defined for path with the
+`diff=<name>` attribute, it is executed as an external diff driver
+(see above), and adding `diff.<name>.algorithm` has no effect, as the
+algorithm is not passed to the external diff driver.
Defining a custom hunk-header
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 4522471c33..100f045bb1 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -167,7 +167,7 @@ helper::
If there are multiple instances of the `credential.helper` configuration
variable, each helper will be tried in turn, and may provide a username,
password, or nothing. Once Git has acquired both a username and a
-password, no more helpers will be tried.
+non-expired password, no more helpers will be tried.
+
If `credential.helper` is configured to the empty string, this resets
the helper list to empty (so you may override a helper set by a
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index ff68e48406..0d90d5b154 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -1100,12 +1100,12 @@ preferred format. See the `strftime` manual for a complete list of
format placeholders. When using `-local`, the correct syntax is
`--date=format-local:...`.
-`--date=default` is the default format, and is similar to
-`--date=rfc2822`, with a few exceptions:
+`--date=default` is the default format, and is based on ctime(3)
+output. It shows a single line with three-letter day of the week,
+three-letter month, day-of-month, hour-minute-seconds in "HH:MM:SS"
+format, followed by 4-digit year, plus timezone information, unless
+the local time zone is used, e.g. `Thu Jan 1 00:00:00 1970 +0000`.
--
- - there is no comma after the day-of-week
-
- - the time zone is omitted when the local time zone is used
ifdef::git-rev-list[]
--header::
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index c4c2d3e022..dd62a3ea59 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.39.GIT
+DEF_VER=v2.40.0-rc0
LF='
'
diff --git a/archive.c b/archive.c
index f2a8756d84..9aeaf2bd87 100644
--- a/archive.c
+++ b/archive.c
@@ -472,6 +472,8 @@ static void parse_treeish_arg(const char **argv,
commit_oid = NULL;
archive_time = time(NULL);
}
+ if (ar_args->mtime_option)
+ archive_time = approxidate(ar_args->mtime_option);
tree = parse_tree_indirect(&oid);
if (!tree)
@@ -586,6 +588,7 @@ static int parse_archive_args(int argc, const char **argv,
const char *remote = NULL;
const char *exec = NULL;
const char *output = NULL;
+ const char *mtime_option = NULL;
int compression_level = -1;
int verbose = 0;
int i;
@@ -607,6 +610,9 @@ static int parse_archive_args(int argc, const char **argv,
OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
N_("read .gitattributes in working directory")),
OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
+ { OPTION_STRING, 0, "mtime", &mtime_option, N_("time"),
+ N_("set modification time of archive entries"),
+ PARSE_OPT_NONEG },
OPT_NUMBER_CALLBACK(&compression_level,
N_("set compression level"), number_callback),
OPT_GROUP(""),
@@ -668,6 +674,7 @@ static int parse_archive_args(int argc, const char **argv,
args->base = base;
args->baselen = strlen(base);
args->worktree_attributes = worktree_attributes;
+ args->mtime_option = mtime_option;
return argc;
}
diff --git a/archive.h b/archive.h
index 08bed3ed3a..7178e2a9a2 100644
--- a/archive.h
+++ b/archive.h
@@ -16,6 +16,7 @@ struct archiver_args {
struct tree *tree;
const struct object_id *commit_oid;
const struct commit *commit;
+ const char *mtime_option;
timestamp_t time;
struct pathspec pathspec;
unsigned int verbose : 1;
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index f3c89831d4..338058be7f 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -127,6 +127,9 @@ static void serve_one_client(FILE *in, FILE *out)
if (e) {
fprintf(out, "username=%s\n", e->item.username);
fprintf(out, "password=%s\n", e->item.password);
+ if (e->item.password_expiry_utc != TIME_MAX)
+ fprintf(out, "password_expiry_utc=%"PRItime"\n",
+ e->item.password_expiry_utc);
}
}
else if (!strcmp(action.buf, "exit")) {
diff --git a/builtin/fetch.c b/builtin/fetch.c
index a21ce89312..a09606b472 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -2196,6 +2196,9 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (dry_run)
write_fetch_head = 0;
+ if (!max_jobs)
+ max_jobs = online_cpus();
+
if (!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri) &&
fetch_bundle_uri(the_repository, bundle_uri, NULL))
warning(_("failed to fetch bundles from '%s'"), bundle_uri);
diff --git a/builtin/log.c b/builtin/log.c
index 04412dd9c9..a70fba198f 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1007,6 +1007,8 @@ static int git_format_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "format.attach")) {
if (value && *value)
default_attach = xstrdup(value);
+ else if (value && !*value)
+ FREE_AND_NULL(default_attach);
else
default_attach = xstrdup(git_version_string);
return 0;
diff --git a/credential.c b/credential.c
index f6389a5068..f32011343f 100644
--- a/credential.c
+++ b/credential.c
@@ -7,6 +7,7 @@
#include "prompt.h"
#include "sigchain.h"
#include "urlmatch.h"
+#include "git-compat-util.h"
void credential_init(struct credential *c)
{
@@ -234,6 +235,11 @@ int credential_read(struct credential *c, FILE *fp)
} else if (!strcmp(key, "path")) {
free(c->path);
c->path = xstrdup(value);
+ } else if (!strcmp(key, "password_expiry_utc")) {
+ errno = 0;
+ c->password_expiry_utc = parse_timestamp(value, NULL, 10);
+ if (c->password_expiry_utc == 0 || errno == ERANGE)
+ c->password_expiry_utc = TIME_MAX;
} else if (!strcmp(key, "url")) {
credential_from_url(c, value);
} else if (!strcmp(key, "quit")) {
@@ -269,6 +275,11 @@ void credential_write(const struct credential *c, FILE *fp)
credential_write_item(fp, "path", c->path, 0);
credential_write_item(fp, "username", c->username, 0);
credential_write_item(fp, "password", c->password, 0);
+ if (c->password_expiry_utc != TIME_MAX) {
+ char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
+ credential_write_item(fp, "password_expiry_utc", s, 0);
+ free(s);
+ }
}
static int run_credential_helper(struct credential *c,
@@ -342,6 +353,12 @@ void credential_fill(struct credential *c)
for (i = 0; i < c->helpers.nr; i++) {
credential_do(c, c->helpers.items[i].string, "get");
+ if (c->password_expiry_utc < time(NULL)) {
+ /* Discard expired password */
+ FREE_AND_NULL(c->password);
+ /* Reset expiry to maintain consistency */
+ c->password_expiry_utc = TIME_MAX;
+ }
if (c->username && c->password)
return;
if (c->quit)
@@ -360,7 +377,7 @@ void credential_approve(struct credential *c)
if (c->approved)
return;
- if (!c->username || !c->password)
+ if (!c->username || !c->password || c->password_expiry_utc < time(NULL))
return;
credential_apply_config(c);
@@ -381,6 +398,7 @@ void credential_reject(struct credential *c)
FREE_AND_NULL(c->username);
FREE_AND_NULL(c->password);
+ c->password_expiry_utc = TIME_MAX;
c->approved = 0;
}
diff --git a/credential.h b/credential.h
index f430e77fea..935b28a70f 100644
--- a/credential.h
+++ b/credential.h
@@ -126,10 +126,12 @@ struct credential {
char *protocol;
char *host;
char *path;
+ timestamp_t password_expiry_utc;
};
#define CREDENTIAL_INIT { \
.helpers = STRING_LIST_INIT_DUP, \
+ .password_expiry_utc = TIME_MAX, \
}
/* Initialize a credential structure, setting all fields to empty. */
diff --git a/delta-islands.c b/delta-islands.c
index 8b234cb85b..afdec0a878 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -517,11 +517,13 @@ void free_island_marks(void)
{
struct island_bitmap *bitmap;
- kh_foreach_value(island_marks, bitmap, {
- if (!--bitmap->refcount)
- free(bitmap);
- });
- kh_destroy_oid_map(island_marks);
+ if (island_marks) {
+ kh_foreach_value(island_marks, bitmap, {
+ if (!--bitmap->refcount)
+ free(bitmap);
+ });
+ kh_destroy_oid_map(island_marks);
+ }
/* detect use-after-free with a an address which is never valid: */
island_marks = (void *)-1;
diff --git a/diff.c b/diff.c
index 329eebf16a..469e18aed2 100644
--- a/diff.c
+++ b/diff.c
@@ -3437,6 +3437,22 @@ static int diff_filepair_is_phoney(struct diff_filespec *one,
return !DIFF_FILE_VALID(one) && !DIFF_FILE_VALID(two);
}
+static int set_diff_algorithm(struct diff_options *opts,
+ const char *alg)
+{
+ long value = parse_algorithm_value(alg);
+
+ if (value < 0)
+ return -1;
+
+ /* clear out previous settings */
+ DIFF_XDL_CLR(opts, NEED_MINIMAL);
+ opts->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
+ opts->xdl_opts |= value;
+
+ return 0;
+}
+
static void builtin_diff(const char *name_a,
const char *name_b,
struct diff_filespec *one,
@@ -4440,15 +4456,13 @@ static void run_diff_cmd(const char *pgm,
const char *xfrm_msg = NULL;
int complete_rewrite = (p->status == DIFF_STATUS_MODIFIED) && p->score;
int must_show_header = 0;
+ struct userdiff_driver *drv = NULL;
-
- if (o->flags.allow_external) {
- struct userdiff_driver *drv;
-
+ if (o->flags.allow_external || !o->ignore_driver_algorithm)
drv = userdiff_find_by_path(o->repo->index, attr_path);
- if (drv && drv->external)
- pgm = drv->external;
- }
+
+ if (o->flags.allow_external && drv && drv->external)
+ pgm = drv->external;
if (msg) {
/*
@@ -4465,12 +4479,16 @@ static void run_diff_cmd(const char *pgm,
run_external_diff(pgm, name, other, one, two, xfrm_msg, o);
return;
}
- if (one && two)
+ if (one && two) {
+ if (!o->ignore_driver_algorithm && drv && drv->algorithm)
+ set_diff_algorithm(o, drv->algorithm);
+
builtin_diff(name, other ? other : name,
one, two, xfrm_msg, must_show_header,
o, complete_rewrite);
- else
+ } else {
fprintf(o->file, "* Unmerged path %s\n", name);
+ }
}
static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *istate)
@@ -4567,6 +4585,14 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
const char *name;
const char *other;
+ if (!o->ignore_driver_algorithm) {
+ struct userdiff_driver *drv = userdiff_find_by_path(o->repo->index,
+ p->one->path);
+
+ if (drv && drv->algorithm)
+ set_diff_algorithm(o, drv->algorithm);
+ }
+
if (DIFF_PAIR_UNMERGED(p)) {
/* unmerged */
builtin_diffstat(p->one->path, NULL, NULL, NULL,
@@ -5107,17 +5133,32 @@ static int diff_opt_diff_algorithm(const struct option *opt,
const char *arg, int unset)
{
struct diff_options *options = opt->value;
- long value = parse_algorithm_value(arg);
BUG_ON_OPT_NEG(unset);
- if (value < 0)
+
+ if (set_diff_algorithm(options, arg))
return error(_("option diff-algorithm accepts \"myers\", "
"\"minimal\", \"patience\" and \"histogram\""));
- /* clear out previous settings */
- DIFF_XDL_CLR(options, NEED_MINIMAL);
- options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
- options->xdl_opts |= value;
+ options->ignore_driver_algorithm = 1;
+
+ return 0;
+}
+
+static int diff_opt_diff_algorithm_no_arg(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct diff_options *options = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
+
+ if (set_diff_algorithm(options, opt->long_name))
+ BUG("available diff algorithms include \"myers\", "
+ "\"minimal\", \"patience\" and \"histogram\"");
+
+ options->ignore_driver_algorithm = 1;
+
return 0;
}
@@ -5250,7 +5291,6 @@ static int diff_opt_patience(const struct option *opt,
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
- options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
/*
* Both --patience and --anchored use PATIENCE_DIFF
* internally, so remove any anchors previously
@@ -5259,7 +5299,9 @@ static int diff_opt_patience(const struct option *opt,
for (i = 0; i < options->anchors_nr; i++)
free(options->anchors[i]);
options->anchors_nr = 0;
- return 0;
+ options->ignore_driver_algorithm = 1;
+
+ return set_diff_algorithm(options, "patience");
}
static int diff_opt_ignore_regex(const struct option *opt,
@@ -5562,9 +5604,10 @@ struct option *add_diff_options(const struct option *opts,
N_("prevent rename/copy detection if the number of rename/copy targets exceeds given limit")),
OPT_GROUP(N_("Diff algorithm options")),
- OPT_BIT(0, "minimal", &options->xdl_opts,
- N_("produce the smallest possible diff"),
- XDF_NEED_MINIMAL),
+ OPT_CALLBACK_F(0, "minimal", options, NULL,
+ N_("produce the smallest possible diff"),
+ PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+ diff_opt_diff_algorithm_no_arg),
OPT_BIT_F('w', "ignore-all-space", &options->xdl_opts,
N_("ignore whitespace when comparing lines"),
XDF_IGNORE_WHITESPACE, PARSE_OPT_NONEG),
@@ -5590,9 +5633,10 @@ struct option *add_diff_options(const struct option *opts,
N_("generate diff using the \"patience diff\" algorithm"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
diff_opt_patience),
- OPT_BITOP(0, "histogram", &options->xdl_opts,
- N_("generate diff using the \"histogram diff\" algorithm"),
- XDF_HISTOGRAM_DIFF, XDF_DIFF_ALGORITHM_MASK),
+ OPT_CALLBACK_F(0, "histogram", options, NULL,
+ N_("generate diff using the \"histogram diff\" algorithm"),
+ PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+ diff_opt_diff_algorithm_no_arg),
OPT_CALLBACK_F(0, "diff-algorithm", options, N_("<algorithm>"),
N_("choose a diff algorithm"),
PARSE_OPT_NONEG, diff_opt_diff_algorithm),
diff --git a/diff.h b/diff.h
index 41eb2c3d42..8d770b1d57 100644
--- a/diff.h
+++ b/diff.h
@@ -333,6 +333,7 @@ struct diff_options {
int prefix_length;
const char *stat_sep;
int xdl_opts;
+ int ignore_driver_algorithm;
/* see Documentation/diff-options.txt */
char **anchors;
diff --git a/dir-iterator.c b/dir-iterator.c
index 3764dd81a1..cedd304759 100644
--- a/dir-iterator.c
+++ b/dir-iterator.c
@@ -112,10 +112,7 @@ static int prepare_next_entry_data(struct dir_iterator_int *iter,
iter->base.basename = iter->base.path.buf +
iter->levels[iter->levels_nr - 1].prefix_len;
- if (iter->flags & DIR_ITERATOR_FOLLOW_SYMLINKS)
- err = stat(iter->base.path.buf, &iter->base.st);
- else
- err = lstat(iter->base.path.buf, &iter->base.st);
+ err = lstat(iter->base.path.buf, &iter->base.st);
saved_errno = errno;
if (err && errno != ENOENT)
@@ -213,13 +210,10 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags)
iter->flags = flags;
/*
- * Note: stat/lstat already checks for NULL or empty strings and
+ * Note: lstat already checks for NULL or empty strings and
* nonexistent paths.
*/
- if (iter->flags & DIR_ITERATOR_FOLLOW_SYMLINKS)
- err = stat(iter->base.path.buf, &iter->base.st);
- else
- err = lstat(iter->base.path.buf, &iter->base.st);
+ err = lstat(iter->base.path.buf, &iter->base.st);
if (err < 0) {
saved_errno = errno;
diff --git a/dir-iterator.h b/dir-iterator.h
index e3b6ff2800..479e1ec784 100644
--- a/dir-iterator.h
+++ b/dir-iterator.h
@@ -54,24 +54,8 @@
* and ITER_ERROR is returned immediately. In both cases, a meaningful
* warning is emitted. Note: ENOENT errors are always ignored so that
* the API users may remove files during iteration.
- *
- * - DIR_ITERATOR_FOLLOW_SYMLINKS: make dir-iterator follow symlinks.
- * i.e., linked directories' contents will be iterated over and
- * iter->base.st will contain information on the referred files,
- * not the symlinks themselves, which is the default behavior. Broken
- * symlinks are ignored.
- *
- * Note: setting DIR_ITERATOR_FOLLOW_SYMLINKS affects resolving the
- * starting path as well (e.g., attempting to iterate starting at a
- * symbolic link pointing to a directory without FOLLOW_SYMLINKS will
- * result in an error).
- *
- * Warning: circular symlinks are also followed when
- * DIR_ITERATOR_FOLLOW_SYMLINKS is set. The iteration may end up with
- * an ELOOP if they happen and DIR_ITERATOR_PEDANTIC is set.
*/
#define DIR_ITERATOR_PEDANTIC (1 << 0)
-#define DIR_ITERATOR_FOLLOW_SYMLINKS (1 << 1)
struct dir_iterator {
/* The current path: */
@@ -88,9 +72,7 @@ struct dir_iterator {
const char *basename;
/*
- * The result of calling lstat() on path; or stat(), if the
- * DIR_ITERATOR_FOLLOW_SYMLINKS flag was set at
- * dir_iterator's initialization.
+ * The result of calling lstat() on path.
*/
struct stat st;
};
diff --git a/git.c b/git.c
index 96b0a2837d..6171fd6769 100644
--- a/git.c
+++ b/git.c
@@ -430,7 +430,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
use_pager = 1;
if (run_setup && startup_info->have_repository)
/* get_git_dir() may set up repo, avoid that */
- trace_repo_setup(prefix);
+ trace_repo_setup();
commit_pager_choice();
if (!help && p->option & NEED_WORK_TREE)
diff --git a/gpg-interface.c b/gpg-interface.c
index 687236430b..5cd66d3a78 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -977,9 +977,13 @@ static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
break; /* found */
}
ret |= !cp;
+ if (ret) {
+ error(_("gpg failed to sign the data:\n%s"),
+ gpg_status.len ? gpg_status.buf : "(no gpg output)");
+ strbuf_release(&gpg_status);
+ return -1;
+ }
strbuf_release(&gpg_status);
- if (ret)
- return error(_("gpg failed to sign the data"));
/* Strip CR from the line endings, in case we are on Windows. */
remove_cr_after(signature, bottom);
diff --git a/range-diff.c b/range-diff.c
index 8255ab4349..086365dffb 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -383,11 +383,14 @@ static void output_pair_header(struct diff_options *diffopt,
const char *color_new = diff_get_color_opt(diffopt, DIFF_FILE_NEW);
const char *color_commit = diff_get_color_opt(diffopt, DIFF_COMMIT);
const char *color;
+ char abbrev = diffopt->abbrev;
+
+ if (abbrev < 0)
+ abbrev = DEFAULT_ABBREV;
if (!dashes->len)
strbuf_addchars(dashes, '-',
- strlen(find_unique_abbrev(oid,
- DEFAULT_ABBREV)));
+ strlen(find_unique_abbrev(oid, abbrev)));
if (!b_util) {
color = color_old;
@@ -409,7 +412,7 @@ static void output_pair_header(struct diff_options *diffopt,
strbuf_addf(buf, "%*s: %s ", patch_no_width, "-", dashes->buf);
else
strbuf_addf(buf, "%*d: %s ", patch_no_width, a_util->i + 1,
- find_unique_abbrev(&a_util->oid, DEFAULT_ABBREV));
+ find_unique_abbrev(&a_util->oid, abbrev));
if (status == '!')
strbuf_addf(buf, "%s%s", color_reset, color);
@@ -421,7 +424,7 @@ static void output_pair_header(struct diff_options *diffopt,
strbuf_addf(buf, " %*s: %s", patch_no_width, "-", dashes->buf);
else
strbuf_addf(buf, " %*d: %s", patch_no_width, b_util->i + 1,
- find_unique_abbrev(&b_util->oid, DEFAULT_ABBREV));
+ find_unique_abbrev(&b_util->oid, abbrev));
commit = lookup_commit_reference(the_repository, oid);
if (commit) {
diff --git a/refs.c b/refs.c
index e31dbcda59..aeae31c972 100644
--- a/refs.c
+++ b/refs.c
@@ -1310,65 +1310,68 @@ int update_ref(const char *msg, const char *refname,
old_oid, flags, onerr);
}
+/*
+ * Check that the string refname matches a rule of the form
+ * "{prefix}%.*s{suffix}". So "foo/bar/baz" would match the rule
+ * "foo/%.*s/baz", and return the string "bar".
+ */
+static const char *match_parse_rule(const char *refname, const char *rule,
+ size_t *len)
+{
+ /*
+ * Check that rule matches refname up to the first percent in the rule.
+ * We can bail immediately if not, but otherwise we leave "rule" at the
+ * %-placeholder, and "refname" at the start of the potential matched
+ * name.
+ */
+ while (*rule != '%') {
+ if (!*rule)
+ BUG("rev-parse rule did not have percent");
+ if (*refname++ != *rule++)
+ return NULL;
+ }
+
+ /*
+ * Check that our "%" is the expected placeholder. This assumes there
+ * are no other percents (placeholder or quoted) in the string, but
+ * that is sufficient for our rev-parse rules.
+ */
+ if (!skip_prefix(rule, "%.*s", &rule))
+ return NULL;
+
+ /*
+ * And now check that our suffix (if any) matches.
+ */
+ if (!strip_suffix(refname, rule, len))
+ return NULL;
+
+ return refname; /* len set by strip_suffix() */
+}
+
char *refs_shorten_unambiguous_ref(struct ref_store *refs,
const char *refname, int strict)
{
int i;
- static char **scanf_fmts;
- static int nr_rules;
- char *short_name;
struct strbuf resolved_buf = STRBUF_INIT;
- if (!nr_rules) {
- /*
- * Pre-generate scanf formats from ref_rev_parse_rules[].
- * Generate a format suitable for scanf from a
- * ref_rev_parse_rules rule by interpolating "%s" at the
- * location of the "%.*s".
- */
- size_t total_len = 0;
- size_t offset = 0;
-
- /* the rule list is NULL terminated, count them first */
- for (nr_rules = 0; ref_rev_parse_rules[nr_rules]; nr_rules++)
- /* -2 for strlen("%.*s") - strlen("%s"); +1 for NUL */
- total_len += strlen(ref_rev_parse_rules[nr_rules]) - 2 + 1;
-
- scanf_fmts = xmalloc(st_add(st_mult(sizeof(char *), nr_rules), total_len));
-
- offset = 0;
- for (i = 0; i < nr_rules; i++) {
- assert(offset < total_len);
- scanf_fmts[i] = (char *)&scanf_fmts[nr_rules] + offset;
- offset += xsnprintf(scanf_fmts[i], total_len - offset,
- ref_rev_parse_rules[i], 2, "%s") + 1;
- }
- }
-
- /* bail out if there are no rules */
- if (!nr_rules)
- return xstrdup(refname);
-
- /* buffer for scanf result, at most refname must fit */
- short_name = xstrdup(refname);
-
/* skip first rule, it will always match */
- for (i = nr_rules - 1; i > 0 ; --i) {
+ for (i = NUM_REV_PARSE_RULES - 1; i > 0 ; --i) {
int j;
int rules_to_fail = i;
- int short_name_len;
+ const char *short_name;
+ size_t short_name_len;
- if (1 != sscanf(refname, scanf_fmts[i], short_name))
+ short_name = match_parse_rule(refname, ref_rev_parse_rules[i],
+ &short_name_len);
+ if (!short_name)
continue;
- short_name_len = strlen(short_name);
-
/*
* in strict mode, all (except the matched one) rules
* must fail to resolve to a valid non-ambiguous ref
*/
if (strict)
- rules_to_fail = nr_rules;
+ rules_to_fail = NUM_REV_PARSE_RULES;
/*
* check if the short name resolves to a valid ref,
@@ -1388,7 +1391,8 @@ char *refs_shorten_unambiguous_ref(struct ref_store *refs,
*/
strbuf_reset(&resolved_buf);
strbuf_addf(&resolved_buf, rule,
- short_name_len, short_name);
+ cast_size_t_to_int(short_name_len),
+ short_name);
if (refs_ref_exists(refs, resolved_buf.buf))
break;
}
@@ -1399,12 +1403,11 @@ char *refs_shorten_unambiguous_ref(struct ref_store *refs,
*/
if (j == rules_to_fail) {
strbuf_release(&resolved_buf);
- return short_name;
+ return xmemdupz(short_name, short_name_len);
}
}
strbuf_release(&resolved_buf);
- free(short_name);
return xstrdup(refname);
}
diff --git a/sequencer.c b/sequencer.c
index 65a34f9676..1c96a75b1e 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2479,12 +2479,39 @@ static int is_command(enum todo_command command, const char **bol)
{
const char *str = todo_command_info[command].str;
const char nick = todo_command_info[command].c;
- const char *p = *bol + 1;
+ const char *p = *bol;
- return skip_prefix(*bol, str, bol) ||
- ((nick && **bol == nick) &&
- (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || !*p) &&
- (*bol = p));
+ return (skip_prefix(p, str, &p) || (nick && *p++ == nick)) &&
+ (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || !*p) &&
+ (*bol = p);
+}
+
+static int check_label_or_ref_arg(enum todo_command command, const char *arg)
+{
+ switch (command) {
+ case TODO_LABEL:
+ /*
+ * '#' is not a valid label as the merge command uses it to
+ * separate merge parents from the commit subject.
+ */
+ if (!strcmp(arg, "#") ||
+ check_refname_format(arg, REFNAME_ALLOW_ONELEVEL))
+ return error(_("'%s' is not a valid label"), arg);
+ break;
+
+ case TODO_UPDATE_REF:
+ if (check_refname_format(arg, REFNAME_ALLOW_ONELEVEL))
+ return error(_("'%s' is not a valid refname"), arg);
+ if (check_refname_format(arg, 0))
+ return error(_("update-ref requires a fully qualified "
+ "refname e.g. refs/heads/%s"), arg);
+ break;
+
+ default:
+ BUG("unexpected todo_command");
+ }
+
+ return 0;
}
static int parse_insn_line(struct repository *r, struct todo_item *item,
@@ -2513,7 +2540,8 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
break;
}
if (i >= TODO_COMMENT)
- return -1;
+ return error(_("invalid command '%.*s'"),
+ (int)strcspn(bol, " \t\r\n"), bol);
/* Eat up extra spaces/ tabs before object name */
padding = strspn(bol, " \t");
@@ -2535,19 +2563,26 @@ static int parse_insn_line(struct repository *r, struct todo_item *item,
if (item->command == TODO_EXEC || item->command == TODO_LABEL ||
item->command == TODO_RESET || item->command == TODO_UPDATE_REF) {
+ int ret = 0;
+
item->commit = NULL;
item->arg_offset = bol - buf;
item->arg_len = (int)(eol - bol);
- return 0;
+ if (item->command == TODO_LABEL ||
+ item->command == TODO_UPDATE_REF) {
+ saved = *eol;
+ *eol = '\0';
+ ret = check_label_or_ref_arg(item->command, bol);
+ *eol = saved;
+ }
+ return ret;
}
if (item->command == TODO_FIXUP) {
- if (skip_prefix(bol, "-C", &bol) &&
- (*bol == ' ' || *bol == '\t')) {
+ if (skip_prefix(bol, "-C", &bol)) {
bol += strspn(bol, " \t");
item->flags |= TODO_REPLACE_FIXUP_MSG;
- } else if (skip_prefix(bol, "-c", &bol) &&
- (*bol == ' ' || *bol == '\t')) {
+ } else if (skip_prefix(bol, "-c", &bol)) {
bol += strspn(bol, " \t");
item->flags |= TODO_EDIT_FIXUP_MSG;
}
diff --git a/t/helper/test-ctype.c b/t/helper/test-ctype.c
index 92c4c2313e..b21bd672d9 100644
--- a/t/helper/test-ctype.c
+++ b/t/helper/test-ctype.c
@@ -11,9 +11,14 @@ static void report_error(const char *class, int ch)
static int is_in(const char *s, int ch)
{
- /* We can't find NUL using strchr. It's classless anyway. */
+ /*
+ * We can't find NUL using strchr. Accept it as the first
+ * character in the spec -- there are no empty classes.
+ */
if (ch == '\0')
- return 0;
+ return ch == *s;
+ if (*s == '\0')
+ s++;
return !!strchr(s, ch);
}
@@ -28,6 +33,20 @@ static int is_in(const char *s, int ch)
#define DIGIT "0123456789"
#define LOWER "abcdefghijklmnopqrstuvwxyz"
#define UPPER "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define PUNCT "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
+#define ASCII \
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
+ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" \
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" \
+ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" \
+ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" \
+ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" \
+ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+#define CNTRL \
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \
+ "\x7f"
int cmd__ctype(int argc, const char **argv)
{
@@ -38,6 +57,13 @@ int cmd__ctype(int argc, const char **argv)
TEST_CLASS(is_glob_special, "*?[\\");
TEST_CLASS(is_regex_special, "$()*+.?[\\^{|");
TEST_CLASS(is_pathspec_magic, "!\"#%&',-/:;<=>@_`~");
+ TEST_CLASS(isascii, ASCII);
+ TEST_CLASS(islower, LOWER);
+ TEST_CLASS(isupper, UPPER);
+ TEST_CLASS(iscntrl, CNTRL);
+ TEST_CLASS(ispunct, PUNCT);
+ TEST_CLASS(isxdigit, DIGIT "abcdefABCDEF");
+ TEST_CLASS(isprint, LOWER UPPER DIGIT PUNCT " ");
return rc;
}
diff --git a/t/helper/test-dir-iterator.c b/t/helper/test-dir-iterator.c
index 659b6bfa81..6b297bd753 100644
--- a/t/helper/test-dir-iterator.c
+++ b/t/helper/test-dir-iterator.c
@@ -15,7 +15,7 @@ static const char *error_name(int error_number)
/*
* usage:
- * tool-test dir-iterator [--follow-symlinks] [--pedantic] directory_path
+ * tool-test dir-iterator [--pedantic] directory_path
*/
int cmd__dir_iterator(int argc, const char **argv)
{
@@ -24,9 +24,7 @@ int cmd__dir_iterator(int argc, const char **argv)
int iter_status;
for (++argv, --argc; *argv && starts_with(*argv, "--"); ++argv, --argc) {
- if (strcmp(*argv, "--follow-symlinks") == 0)
- flags |= DIR_ITERATOR_FOLLOW_SYMLINKS;
- else if (strcmp(*argv, "--pedantic") == 0)
+ if (strcmp(*argv, "--pedantic") == 0)
flags |= DIR_ITERATOR_PEDANTIC;
else
die("invalid option '%s'", *argv);
diff --git a/t/helper/test-genzeros.c b/t/helper/test-genzeros.c
index 8ca988d621..47af843b68 100644
--- a/t/helper/test-genzeros.c
+++ b/t/helper/test-genzeros.c
@@ -17,15 +17,16 @@ int cmd__genzeros(int argc, const char **argv)
/* Writing out individual NUL bytes is slow... */
while (count < 0)
- if (write(1, zeros, ARRAY_SIZE(zeros)) < 0)
- return -1;
+ if (xwrite(1, zeros, ARRAY_SIZE(zeros)) < 0)
+ die_errno("write error");
while (count > 0) {
- n = write(1, zeros, count < ARRAY_SIZE(zeros) ?
- count : ARRAY_SIZE(zeros));
+ n = xwrite(1, zeros,
+ count < ARRAY_SIZE(zeros)
+ ? count : ARRAY_SIZE(zeros));
if (n < 0)
- return -1;
+ die_errno("write error");
count -= n;
}
diff --git a/t/lib-diff-alternative.sh b/t/lib-diff-alternative.sh
index 8d1e408bb5..a8f5d3274a 100644
--- a/t/lib-diff-alternative.sh
+++ b/t/lib-diff-alternative.sh
@@ -105,10 +105,46 @@ index $file1..$file2 100644
}
EOF
+ cat >expect_diffstat <<EOF
+ file1 => file2 | 21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+EOF
+
STRATEGY=$1
+ test_expect_success "$STRATEGY diff from attributes" '
+ echo "file* diff=driver" >.gitattributes &&
+ git config diff.driver.algorithm "$STRATEGY" &&
+ test_must_fail git diff --no-index file1 file2 > output &&
+ cat expect &&
+ cat output &&
+ test_cmp expect output
+ '
+
+ test_expect_success "$STRATEGY diff from attributes has valid diffstat" '
+ echo "file* diff=driver" >.gitattributes &&
+ git config diff.driver.algorithm "$STRATEGY" &&
+ test_must_fail git diff --stat --no-index file1 file2 > output &&
+ test_cmp expect_diffstat output
+ '
+
test_expect_success "$STRATEGY diff" '
- test_must_fail git diff --no-index "--$STRATEGY" file1 file2 > output &&
+ test_must_fail git diff --no-index "--diff-algorithm=$STRATEGY" file1 file2 > output &&
+ test_cmp expect output
+ '
+
+ test_expect_success "$STRATEGY diff command line precedence before attributes" '
+ echo "file* diff=driver" >.gitattributes &&
+ git config diff.driver.algorithm myers &&
+ test_must_fail git diff --no-index "--diff-algorithm=$STRATEGY" file1 file2 > output &&
+ test_cmp expect output
+ '
+
+ test_expect_success "$STRATEGY diff attributes precedence before config" '
+ git config diff.algorithm default &&
+ echo "file* diff=driver" >.gitattributes &&
+ git config diff.driver.algorithm "$STRATEGY" &&
+ test_must_fail git diff --no-index file1 file2 > output &&
test_cmp expect output
'
diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh
index 5d2d56c445..09cf5ed012 100644
--- a/t/lib-httpd.sh
+++ b/t/lib-httpd.sh
@@ -25,6 +25,7 @@
# LIB_HTTPD_DAV enable DAV
# LIB_HTTPD_SVN enable SVN at given location (e.g. "svn")
# LIB_HTTPD_SSL enable SSL
+# LIB_HTTPD_PROXY enable proxy
#
# Copyright (c) 2008 Clemens Buchacher <drizzd@aon.at>
#
@@ -133,6 +134,7 @@ install_script () {
prepare_httpd() {
mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH"
cp "$TEST_PATH"/passwd "$HTTPD_ROOT_PATH"
+ cp "$TEST_PATH"/proxy-passwd "$HTTPD_ROOT_PATH"
install_script incomplete-length-upload-pack-v2-http.sh
install_script incomplete-body-upload-pack-v2-http.sh
install_script error-no-report.sh
@@ -176,6 +178,11 @@ prepare_httpd() {
export LIB_HTTPD_SVN LIB_HTTPD_SVNPATH
fi
fi
+
+ if test -n "$LIB_HTTPD_PROXY"
+ then
+ HTTPD_PARA="$HTTPD_PARA -DPROXY"
+ fi
}
enable_http2 () {
@@ -283,11 +290,11 @@ expect_askpass() {
none)
;;
pass)
- echo "askpass: Password for 'http://$2@$dest': "
+ echo "askpass: Password for '$HTTPD_PROTO://$2@$dest': "
;;
both)
- echo "askpass: Username for 'http://$dest': "
- echo "askpass: Password for 'http://$2@$dest': "
+ echo "askpass: Username for '$HTTPD_PROTO://$dest': "
+ echo "askpass: Password for '$HTTPD_PROTO://$2@$dest': "
;;
*)
false
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 51a4fbcf62..31f82fa093 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -31,7 +31,7 @@ ErrorLog error.log
<IfDefine HTTP2>
LoadModule http2_module modules/mod_http2.so
-Protocols h2c
+Protocols h2 h2c
</IfDefine>
<IfModule !mod_auth_basic.c>
@@ -47,6 +47,22 @@ Protocols h2c
LoadModule authz_host_module modules/mod_authz_host.so
</IfModule>
+<IfDefine PROXY>
+<IfModule !mod_proxy.c>
+ LoadModule proxy_module modules/mod_proxy.so
+</IfModule>
+<IfModule !mod_proxy_http.c>
+ LoadModule proxy_http_module modules/mod_proxy_http.so
+</IfModule>
+ProxyRequests On
+<Proxy "*">
+ AuthType Basic
+ AuthName "proxy-auth"
+ AuthUserFile proxy-passwd
+ Require valid-user
+</Proxy>
+</IfDefine>
+
<IfModule !mod_authn_core.c>
LoadModule authn_core_module modules/mod_authn_core.so
</IfModule>
diff --git a/t/lib-httpd/proxy-passwd b/t/lib-httpd/proxy-passwd
new file mode 100644
index 0000000000..77c25138e0
--- /dev/null
+++ b/t/lib-httpd/proxy-passwd
@@ -0,0 +1 @@
+proxuser:2x7tAukjAED5M
diff --git a/t/lib-rebase.sh b/t/lib-rebase.sh
index b57541356b..7ca5b918f0 100644
--- a/t/lib-rebase.sh
+++ b/t/lib-rebase.sh
@@ -60,7 +60,7 @@ set_fake_editor () {
">")
echo >> "$1";;
bad)
- action="badcmd";;
+ action="pickled";;
fakesha)
test \& != "$action" || action=pick
echo "$action XXXXXXX False commit" >> "$1"
@@ -211,6 +211,9 @@ check_reworded_commits () {
# usage: set_replace_editor <file>
#
# Replace the todo file with the exact contents of the given file.
+# N.B. sets GIT_SEQUENCE_EDITOR rather than EDITOR so it can be
+# combined with set_fake_editor to reword commits and replace the
+# todo list
set_replace_editor () {
cat >script <<-\EOF &&
cat FILENAME >"$1"
@@ -219,6 +222,7 @@ set_replace_editor () {
cat "$1"
EOF
- sed -e "s/FILENAME/$1/g" <script | write_script fake-editor.sh &&
- test_set_editor "$(pwd)/fake-editor.sh"
+ sed -e "s/FILENAME/$1/g" script |
+ write_script fake-sequence-editor.sh &&
+ test_set_sequence_editor "$(pwd)/fake-sequence-editor.sh"
}
diff --git a/t/t0066-dir-iterator.sh b/t/t0066-dir-iterator.sh
index 04b811622b..7d0a0da8c0 100755
--- a/t/t0066-dir-iterator.sh
+++ b/t/t0066-dir-iterator.sh
@@ -106,13 +106,7 @@ test_expect_success SYMLINKS 'setup dirs with symlinks' '
ln -s d dir4/a/e &&
ln -s ../b dir4/a/f &&
- mkdir -p dir5/a/b &&
- mkdir -p dir5/a/c &&
- ln -s ../c dir5/a/b/d &&
- ln -s ../ dir5/a/b/e &&
- ln -s ../../ dir5/a/b/f &&
-
- ln -s dir4 dir6
+ ln -s dir4 dir5
'
test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default' '
@@ -131,44 +125,10 @@ test_expect_success SYMLINKS 'dir-iterator should not follow symlinks by default
test_cmp expected-no-follow-sorted-output actual-no-follow-sorted-output
'
-test_expect_success SYMLINKS 'dir-iterator should follow symlinks w/ follow flag' '
- cat >expected-follow-sorted-output <<-EOF &&
- [d] (a) [a] ./dir4/a
- [d] (a/f) [f] ./dir4/a/f
- [d] (a/f/c) [c] ./dir4/a/f/c
- [d] (b) [b] ./dir4/b
- [d] (b/c) [c] ./dir4/b/c
- [f] (a/d) [d] ./dir4/a/d
- [f] (a/e) [e] ./dir4/a/e
- EOF
-
- test-tool dir-iterator --follow-symlinks ./dir4 >out &&
- sort out >actual-follow-sorted-output &&
-
- test_cmp expected-follow-sorted-output actual-follow-sorted-output
-'
-
test_expect_success SYMLINKS 'dir-iterator does not resolve top-level symlinks' '
- test_must_fail test-tool dir-iterator ./dir6 >out &&
+ test_must_fail test-tool dir-iterator ./dir5 >out &&
grep "ENOTDIR" out
'
-test_expect_success SYMLINKS 'dir-iterator resolves top-level symlinks w/ follow flag' '
- cat >expected-follow-sorted-output <<-EOF &&
- [d] (a) [a] ./dir6/a
- [d] (a/f) [f] ./dir6/a/f
- [d] (a/f/c) [c] ./dir6/a/f/c
- [d] (b) [b] ./dir6/b
- [d] (b/c) [c] ./dir6/b/c
- [f] (a/d) [d] ./dir6/a/d
- [f] (a/e) [e] ./dir6/a/e
- EOF
-
- test-tool dir-iterator --follow-symlinks ./dir6 >out &&
- sort out >actual-follow-sorted-output &&
-
- test_cmp expected-follow-sorted-output actual-follow-sorted-output
-'
-
test_done
diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh
index 3485c0534e..c66d91e82d 100755
--- a/t/t0300-credentials.sh
+++ b/t/t0300-credentials.sh
@@ -35,6 +35,16 @@ test_expect_success 'setup helper scripts' '
test -z "$pass" || echo password=$pass
EOF
+ write_script git-credential-verbatim-with-expiry <<-\EOF &&
+ user=$1; shift
+ pass=$1; shift
+ pexpiry=$1; shift
+ . ./dump
+ test -z "$user" || echo username=$user
+ test -z "$pass" || echo password=$pass
+ test -z "$pexpiry" || echo password_expiry_utc=$pexpiry
+ EOF
+
PATH="$PWD:$PATH"
'
@@ -109,6 +119,43 @@ test_expect_success 'credential_fill continues through partial response' '
EOF
'
+test_expect_success 'credential_fill populates password_expiry_utc' '
+ check fill "verbatim-with-expiry one two 9999999999" <<-\EOF
+ protocol=http
+ host=example.com
+ --
+ protocol=http
+ host=example.com
+ username=one
+ password=two
+ password_expiry_utc=9999999999
+ --
+ verbatim-with-expiry: get
+ verbatim-with-expiry: protocol=http
+ verbatim-with-expiry: host=example.com
+ EOF
+'
+
+test_expect_success 'credential_fill ignores expired password' '
+ check fill "verbatim-with-expiry one two 5" "verbatim three four" <<-\EOF
+ protocol=http
+ host=example.com
+ --
+ protocol=http
+ host=example.com
+ username=three
+ password=four
+ --
+ verbatim-with-expiry: get
+ verbatim-with-expiry: protocol=http
+ verbatim-with-expiry: host=example.com
+ verbatim: get
+ verbatim: protocol=http
+ verbatim: host=example.com
+ verbatim: username=one
+ EOF
+'
+
test_expect_success 'credential_fill passes along metadata' '
check fill "verbatim one two" <<-\EOF
protocol=ftp
@@ -149,6 +196,24 @@ test_expect_success 'credential_approve calls all helpers' '
EOF
'
+test_expect_success 'credential_approve stores password expiry' '
+ check approve useless <<-\EOF
+ protocol=http
+ host=example.com
+ username=foo
+ password=bar
+ password_expiry_utc=9999999999
+ --
+ --
+ useless: store
+ useless: protocol=http
+ useless: host=example.com
+ useless: username=foo
+ useless: password=bar
+ useless: password_expiry_utc=9999999999
+ EOF
+'
+
test_expect_success 'do not bother storing password-less credential' '
check approve useless <<-\EOF
protocol=http
@@ -159,6 +224,17 @@ test_expect_success 'do not bother storing password-less credential' '
EOF
'
+test_expect_success 'credential_approve does not store expired password' '
+ check approve useless <<-\EOF
+ protocol=http
+ host=example.com
+ username=foo
+ password=bar
+ password_expiry_utc=5
+ --
+ --
+ EOF
+'
test_expect_success 'credential_reject calls all helpers' '
check reject useless "verbatim one two" <<-\EOF
@@ -181,6 +257,24 @@ test_expect_success 'credential_reject calls all helpers' '
EOF
'
+test_expect_success 'credential_reject erases credential regardless of expiry' '
+ check reject useless <<-\EOF
+ protocol=http
+ host=example.com
+ username=foo
+ password=bar
+ password_expiry_utc=5
+ --
+ --
+ useless: erase
+ useless: protocol=http
+ useless: host=example.com
+ useless: username=foo
+ useless: password=bar
+ useless: password_expiry_utc=5
+ EOF
+'
+
test_expect_success 'usernames can be preserved' '
check fill "verbatim \"\" three" <<-\EOF
protocol=http
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index d708acdb81..be23be30c7 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -189,4 +189,38 @@ test_expect_success 'symbolic-ref pointing at another' '
test_cmp expect actual
'
+test_expect_success 'symbolic-ref --short handles complex utf8 case' '
+ name="测试-加-增加-加-增加" &&
+ git symbolic-ref TEST_SYMREF "refs/heads/$name" &&
+ # In the real world, we saw problems with this case only
+ # when the locale includes UTF-8. Set it here to try to make things as
+ # hard as possible for us to pass, but in practice we should do the
+ # right thing regardless (and of course some platforms may not even
+ # have this locale).
+ LC_ALL=en_US.UTF-8 git symbolic-ref --short TEST_SYMREF >actual &&
+ echo "$name" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'symbolic-ref --short handles name with suffix' '
+ git symbolic-ref TEST_SYMREF "refs/remotes/origin/HEAD" &&
+ git symbolic-ref --short TEST_SYMREF >actual &&
+ echo "origin" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'symbolic-ref --short handles almost-matching name' '
+ git symbolic-ref TEST_SYMREF "refs/headsXfoo" &&
+ git symbolic-ref --short TEST_SYMREF >actual &&
+ echo "headsXfoo" >expect &&
+ test_cmp expect actual
+'
+
+test_expect_success 'symbolic-ref --short handles name with percent' '
+ git symbolic-ref TEST_SYMREF "refs/heads/%foo" &&
+ git symbolic-ref --short TEST_SYMREF >actual &&
+ echo "%foo" >expect &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh
index 9425aae639..fb0e13881c 100755
--- a/t/t2015-checkout-unborn.sh
+++ b/t/t2015-checkout-unborn.sh
@@ -9,11 +9,12 @@ TEST_PASSES_SANITIZE_LEAK=true
test_expect_success 'setup' '
mkdir parent &&
- (cd parent &&
- git init &&
- echo content >file &&
- git add file &&
- git commit -m base
+ (
+ cd parent &&
+ git init &&
+ echo content >file &&
+ git add file &&
+ git commit -m base
) &&
git fetch parent main:origin
'
diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh
index 84dd0cd26d..b5f4d6a653 100755
--- a/t/t3206-range-diff.sh
+++ b/t/t3206-range-diff.sh
@@ -33,6 +33,26 @@ test_expect_success 'setup' '
u3 sha256:736c4bc
u4 sha256:673e77d
+ # topic (abbrev=10)
+ t1_abbrev sha1:4de457d2c0
+ t2_abbrev sha1:fccce22f8c
+ t3_abbrev sha1:147e64ef53
+ t4_abbrev sha1:a63e992599
+ t1_abbrev sha256:b89f8b9092
+ t2_abbrev sha256:5f12aadf34
+ t3_abbrev sha256:ea8b273a6c
+ t4_abbrev sha256:14b73361fc
+
+ # unmodified (abbrev=10)
+ u1_abbrev sha1:35b9b25f76
+ u2_abbrev sha1:de345ab3de
+ u3_abbrev sha1:9af6654000
+ u4_abbrev sha1:2901f773f3
+ u1_abbrev sha256:e3731be242
+ u2_abbrev sha256:14fadf8cee
+ u3_abbrev sha256:736c4bcb44
+ u4_abbrev sha256:673e77d589
+
# reordered
r1 sha1:aca177a
r2 sha1:14ad629
@@ -153,6 +173,18 @@ test_expect_success 'simple A B C (unmodified)' '
test_cmp expect actual
'
+test_expect_success 'simple A..B A..C (unmodified) with --abbrev' '
+ git range-diff --no-color --abbrev=10 main..topic main..unmodified \
+ >actual &&
+ cat >expect <<-EOF &&
+ 1: $(test_oid t1_abbrev) = 1: $(test_oid u1_abbrev) s/5/A/
+ 2: $(test_oid t2_abbrev) = 2: $(test_oid u2_abbrev) s/4/A/
+ 3: $(test_oid t3_abbrev) = 3: $(test_oid u3_abbrev) s/11/B/
+ 4: $(test_oid t4_abbrev) = 4: $(test_oid u4_abbrev) s/12/B/
+ EOF
+ test_cmp expect actual
+'
+
test_expect_success 'A^! and A^-<n> (unmodified)' '
git range-diff --no-color topic^! unmodified^-1 >actual &&
cat >expect <<-EOF &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 462cefd25d..ff0afad63e 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1449,14 +1449,15 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = ig
test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = warn' '
cat >expect <<-EOF &&
- error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4)
+ error: invalid command '\''pickled'\''
+ error: invalid line 1: pickled $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4)
Warning: some commits may have been dropped accidentally.
Dropped commits (newer to older):
- $(git rev-list --pretty=oneline --abbrev-commit -1 primary)
- $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4)
To avoid this message, use "drop" to explicitly remove a commit.
EOF
- head -n4 expect >expect.2 &&
+ head -n5 expect >expect.2 &&
tail -n1 expect >>expect.2 &&
tail -n4 expect.2 >expect.3 &&
test_config rebase.missingCommitsCheck warn &&
@@ -1467,7 +1468,7 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = wa
git rebase -i --root &&
cp .git/rebase-merge/git-rebase-todo.backup orig &&
FAKE_LINES="2 3 4" git rebase --edit-todo 2>actual.2 &&
- head -n6 actual.2 >actual &&
+ head -n7 actual.2 >actual &&
test_cmp expect actual &&
cp orig .git/rebase-merge/git-rebase-todo &&
FAKE_LINES="1 2 3 4" git rebase --edit-todo 2>actual.2 &&
@@ -1483,7 +1484,8 @@ test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = wa
test_expect_success 'rebase --edit-todo respects rebase.missingCommitsCheck = error' '
cat >expect <<-EOF &&
- error: invalid line 1: badcmd $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4)
+ error: invalid command '\''pickled'\''
+ error: invalid line 1: pickled $(git rev-list --pretty=oneline --abbrev-commit -1 primary~4)
Warning: some commits may have been dropped accidentally.
Dropped commits (newer to older):
- $(git rev-list --pretty=oneline --abbrev-commit -1 primary)
@@ -1583,7 +1585,7 @@ test_expect_success 'static check of bad command' '
set_fake_editor &&
test_must_fail env FAKE_LINES="1 2 3 bad 4 5" \
git rebase -i --root 2>actual &&
- test_i18ngrep "badcmd $(git rev-list --oneline -1 primary~1)" \
+ test_i18ngrep "pickled $(git rev-list --oneline -1 primary~1)" \
actual &&
test_i18ngrep "You can fix this with .git rebase --edit-todo.." \
actual &&
@@ -2072,6 +2074,7 @@ test_expect_success '--update-refs: --edit-todo with no update-ref lines' '
'
test_expect_success '--update-refs: check failed ref update' '
+ test_when_finished "test_might_fail git rebase --abort" &&
git checkout -B update-refs-error no-conflict-branch &&
git branch -f base HEAD~4 &&
git branch -f first HEAD~3 &&
@@ -2123,6 +2126,28 @@ test_expect_success '--update-refs: check failed ref update' '
test_cmp expect err.trimmed
'
+test_expect_success 'bad labels and refs rejected when parsing todo list' '
+ test_when_finished "test_might_fail git rebase --abort" &&
+ cat >todo <<-\EOF &&
+ exec >execed
+ label #
+ label :invalid
+ update-ref :bad
+ update-ref topic
+ EOF
+ rm -f execed &&
+ (
+ set_replace_editor todo &&
+ test_must_fail git rebase -i HEAD 2>err
+ ) &&
+ grep "'\''#'\'' is not a valid label" err &&
+ grep "'\'':invalid'\'' is not a valid label" err &&
+ grep "'\'':bad'\'' is not a valid refname" err &&
+ grep "update-ref requires a fully qualified refname e.g. refs/heads/topic" \
+ err &&
+ test_path_is_missing execed
+'
+
# This must be the last test in this file
test_expect_success '$EDITOR and friends are unchanged' '
test_editor_unchanged
diff --git a/t/t3437-rebase-fixup-options.sh b/t/t3437-rebase-fixup-options.sh
index 274699dadb..dd3b301fa7 100755
--- a/t/t3437-rebase-fixup-options.sh
+++ b/t/t3437-rebase-fixup-options.sh
@@ -51,6 +51,7 @@ test_expect_success 'setup' '
body
EOF
+ test_commit initial &&
test_commit A A &&
test_commit B B &&
get_author HEAD >expected-author &&
@@ -209,4 +210,29 @@ test_expect_success 'fixup -C works upon --autosquash with amend!' '
actual-squash-message
'
+test_expect_success 'fixup -[Cc]<commit> works' '
+ test_when_finished "test_might_fail git rebase --abort" &&
+ cat >todo <<-\EOF &&
+ pick A
+ fixup -CA1
+ pick B
+ fixup -cA2
+ EOF
+ (
+ set_replace_editor todo &&
+ FAKE_COMMIT_MESSAGE="edited and fixed up" \
+ git rebase -i initial initial
+ ) &&
+ git log --pretty=format:%B initial.. >actual &&
+ cat >expect <<-EOF &&
+ edited and fixed up
+ $EMPTY
+ new subject
+ $EMPTY
+ new
+ body
+ EOF
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 012f155e10..f3313b8c58 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -2281,6 +2281,24 @@ test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
test_line_count = 1 output
'
+test_expect_success 'format-patch with format.attach' '
+ test_when_finished "rm -fr patches" &&
+ separator=attachment-separator &&
+ test_config format.attach "$separator" &&
+ filename=$(git format-patch -o patches -1) &&
+ grep "^Content-Type: multipart/.*$separator" "$filename"
+'
+
+test_expect_success 'format-patch with format.attach=disabled' '
+ test_when_finished "rm -fr patches" &&
+ separator=attachment-separator &&
+ test_config_global format.attach "$separator" &&
+ test_config format.attach "" &&
+ filename=$(git format-patch -o patches -1) &&
+ # The output should not even declare content type for text/plain.
+ ! grep "^Content-Type: multipart/" "$filename"
+'
+
test_expect_success '-c format.mboxrd format-patch' '
sp=" " &&
cat >msg <<-INPUT_END &&
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index eb3214bc17..918a2fc7c6 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -105,6 +105,18 @@ check_added() {
'
}
+check_mtime() {
+ dir=$1
+ path_in_archive=$2
+ mtime=$3
+
+ test_expect_success " validate mtime of $path_in_archive" '
+ test-tool chmtime --get $dir/$path_in_archive >actual.mtime &&
+ echo $mtime >expect.mtime &&
+ test_cmp expect.mtime actual.mtime
+ '
+}
+
test_expect_success 'setup' '
test_oid_cache <<-EOF
obj sha1:19f9c8273ec45a8938e6999cb59b3ff66739902a
@@ -174,6 +186,13 @@ test_expect_success 'git archive' '
check_tar b
+test_expect_success 'git archive --mtime' '
+ git archive --mtime=2002-02-02T02:02:02-0200 HEAD >with_mtime.tar
+'
+
+check_tar with_mtime
+check_mtime with_mtime a/a 1012622522
+
test_expect_success 'git archive --prefix=prefix/' '
git archive --prefix=prefix/ HEAD >with_prefix.tar
'
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index b5f9b10922..499d5d4c78 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -1015,4 +1015,20 @@ test_expect_success 'complains when run outside of a repository' '
grep "not a git repository" err
'
+test_expect_success 'repack with delta islands' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ test_commit first &&
+ git repack &&
+ test_commit second &&
+ git repack &&
+
+ git multi-pack-index write &&
+ git -c repack.useDeltaIslands=true multi-pack-index repack
+ )
+'
+
test_done
diff --git a/t/t5514-fetch-multiple.sh b/t/t5514-fetch-multiple.sh
index 511ba3bd45..54f422ced3 100755
--- a/t/t5514-fetch-multiple.sh
+++ b/t/t5514-fetch-multiple.sh
@@ -197,4 +197,9 @@ test_expect_success 'parallel' '
test_i18ngrep "could not fetch .two.*128" err
'
+test_expect_success 'git fetch --multiple --jobs=0 picks a default' '
+ (cd test &&
+ git fetch --multiple --jobs=0)
+'
+
test_done
diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
index fbad2d5ff5..d0211cd8be 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -36,28 +36,6 @@ test_expect_success 'setup remote repository' '
setup_askpass_helper
-cat >exp <<EOF
-GET /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
-POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200
-EOF
-test_expect_success 'no empty path components' '
- # Clear the log, so that it does not affect the "used receive-pack
- # service" test which reads the log too.
- test_when_finished ">\"\$HTTPD_ROOT_PATH\"/access.log" &&
-
- # In the URL, add a trailing slash, and see if git appends yet another
- # slash.
- cd "$ROOT_PATH" &&
- git clone $HTTPD_URL/smart/test_repo.git/ test_repo_clone &&
-
- # NEEDSWORK: If the overspecification of the expected result is reduced, we
- # might be able to run this test in all protocol versions.
- if test "$GIT_TEST_PROTOCOL_VERSION" = 0
- then
- check_access_log exp
- fi
-'
-
test_expect_success 'clone remote repository' '
rm -rf test_repo_clone &&
git clone $HTTPD_URL/smart/test_repo.git test_repo_clone &&
@@ -67,6 +45,10 @@ test_expect_success 'clone remote repository' '
'
test_expect_success 'push to remote repository (standard)' '
+ # Clear the log, so that the "used receive-pack service" test below
+ # sees just what we did here.
+ >"$HTTPD_ROOT_PATH"/access.log &&
+
cd "$ROOT_PATH"/test_repo_clone &&
: >path2 &&
git add path2 &&
@@ -80,6 +62,15 @@ test_expect_success 'push to remote repository (standard)' '
test $HEAD = $(git rev-parse --verify HEAD))
'
+test_expect_success 'used receive-pack service' '
+ cat >exp <<-\EOF &&
+ GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
+ POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200
+ EOF
+
+ check_access_log exp
+'
+
test_expect_success 'push to remote repository (standard) with sending Accept-Language' '
cat >exp <<-\EOF &&
=> Send header: Accept-Language: ko-KR, *;q=0.9
@@ -141,28 +132,6 @@ test_expect_success 'rejected update prints status' '
'
rm -f "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update"
-cat >exp <<EOF
-GET /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
-POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200
-GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
-POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200
-GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
-GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
-POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200
-GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
-POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200
-GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
-POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200
-EOF
-test_expect_success 'used receive-pack service' '
- # NEEDSWORK: If the overspecification of the expected result is reduced, we
- # might be able to run this test in all protocol versions.
- if test "$GIT_TEST_PROTOCOL_VERSION" = 0
- then
- check_access_log exp
- fi
-'
-
test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \
"$ROOT_PATH"/test_repo_clone main success
diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh
index bc0719a4fc..0908534f25 100755
--- a/t/t5551-http-fetch-smart.sh
+++ b/t/t5551-http-fetch-smart.sh
@@ -1,6 +1,6 @@
#!/bin/sh
-: ${HTTP_PROTO:=HTTP}
+: ${HTTP_PROTO:=HTTP/1.1}
test_description="test smart fetching over http via http-backend ($HTTP_PROTO)"
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
@@ -33,35 +33,71 @@ test_expect_success 'create http-accessible bare repository' '
setup_askpass_helper
test_expect_success 'clone http repository' '
- cat >exp <<-\EOF &&
- > GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1
- > Accept: */*
- > Accept-Encoding: ENCODINGS
- > Accept-Language: ko-KR, *;q=0.9
- > Pragma: no-cache
- < HTTP/1.1 200 OK
- < Pragma: no-cache
- < Cache-Control: no-cache, max-age=0, must-revalidate
- < Content-Type: application/x-git-upload-pack-advertisement
- > POST /smart/repo.git/git-upload-pack HTTP/1.1
- > Accept-Encoding: ENCODINGS
- > Content-Type: application/x-git-upload-pack-request
- > Accept: application/x-git-upload-pack-result
- > Accept-Language: ko-KR, *;q=0.9
- > Content-Length: xxx
- < HTTP/1.1 200 OK
- < Pragma: no-cache
- < Cache-Control: no-cache, max-age=0, must-revalidate
- < Content-Type: application/x-git-upload-pack-result
+ if test_have_prereq HTTP2 && test "$HTTPD_PROTO" = "https"
+ then
+ # ALPN lets us immediately use HTTP/2; likewise, POSTs with
+ # bodies can use it because they do not need to upgrade
+ INITIAL_PROTO=HTTP/2
+ else
+ # either we are not using HTTP/2, or the initial
+ # request is sent via HTTP/1.1 and asks for upgrade
+ INITIAL_PROTO=HTTP/1.1
+ fi &&
+
+ cat >exp.raw <<-EOF &&
+ > GET /smart/repo.git/info/refs?service=git-upload-pack $INITIAL_PROTO
+ > accept: */*
+ > accept-encoding: ENCODINGS
+ > accept-language: ko-KR, *;q=0.9
+ > pragma: no-cache
+ {V2} > git-protocol: version=2
+ < $HTTP_PROTO 200 OK
+ < pragma: no-cache
+ < cache-control: no-cache, max-age=0, must-revalidate
+ < content-type: application/x-git-upload-pack-advertisement
+ > POST /smart/repo.git/git-upload-pack $INITIAL_PROTO
+ > accept-encoding: ENCODINGS
+ > content-type: application/x-git-upload-pack-request
+ > accept: application/x-git-upload-pack-result
+ > accept-language: ko-KR, *;q=0.9
+ {V2} > git-protocol: version=2
+ > content-length: xxx
+ < $INITIAL_PROTO 200 OK
+ < pragma: no-cache
+ < cache-control: no-cache, max-age=0, must-revalidate
+ < content-type: application/x-git-upload-pack-result
+ {V2} > POST /smart/repo.git/git-upload-pack $INITIAL_PROTO
+ {V2} > accept-encoding: ENCODINGS
+ {V2} > content-type: application/x-git-upload-pack-request
+ {V2} > accept: application/x-git-upload-pack-result
+ {V2} > accept-language: ko-KR, *;q=0.9
+ {V2} > git-protocol: version=2
+ {V2} > content-length: xxx
+ {V2} < $INITIAL_PROTO 200 OK
+ {V2} < pragma: no-cache
+ {V2} < cache-control: no-cache, max-age=0, must-revalidate
+ {V2} < content-type: application/x-git-upload-pack-result
EOF
- GIT_TRACE_CURL=true GIT_TEST_PROTOCOL_VERSION=0 LANGUAGE="ko_KR.UTF-8" \
+ if test "$GIT_TEST_PROTOCOL_VERSION" = 0
+ then
+ sed "/^{V2}/d" <exp.raw >exp
+ else
+ sed "s/^{V2} //" <exp.raw >exp
+ fi &&
+
+ GIT_TRACE_CURL=true LANGUAGE="ko_KR.UTF-8" \
git clone --quiet $HTTPD_URL/smart/repo.git clone 2>err &&
test_cmp file clone/file &&
tr '\''\015'\'' Q <err |
+ perl -pe '\''
+ s/(Send|Recv) header: ([A-Za-z0-9-]+):/
+ "$1 header: " . lc($2) . ":"
+ /e;
+ '\'' |
sed -e "
s/Q\$//
- /^[*] /d
+ /^[^<=]/d
/^== Info:/d
/^=> Send header, /d
/^=> Send header:$/d
@@ -71,6 +107,8 @@ test_expect_success 'clone http repository' '
s/= Recv header://
/^<= Recv data/d
/^=> Send data/d
+ /^<= Recv SSL data/d
+ /^=> Send SSL data/d
/^$/d
/^< $/d
@@ -78,36 +116,35 @@ test_expect_success 'clone http repository' '
s/^/> /
}
- /^> User-Agent: /d
- /^> Host: /d
+ /^< HTTP/ {
+ s/200$/200 OK/
+ }
+ /^< HTTP\\/1.1 101/d
+ /^[><] connection: /d
+ /^[><] upgrade: /d
+ /^> http2-settings: /d
+
+ /^> user-agent: /d
+ /^> host: /d
/^> POST /,$ {
/^> Accept: [*]\\/[*]/d
}
- s/^> Content-Length: .*/> Content-Length: xxx/
+ s/^> content-length: .*/> content-length: xxx/
/^> 00..want /d
/^> 00.*done/d
- /^< Server: /d
- /^< Expires: /d
- /^< Date: /d
- /^< Content-Length: /d
- /^< Transfer-Encoding: /d
+ /^< server: /d
+ /^< expires: /d
+ /^< date: /d
+ /^< content-length: /d
+ /^< transfer-encoding: /d
" >actual &&
- # NEEDSWORK: If the overspecification of the expected result is reduced, we
- # might be able to run this test in all protocol versions.
- if test "$GIT_TEST_PROTOCOL_VERSION" = 0
- then
- sed -e "s/^> Accept-Encoding: .*/> Accept-Encoding: ENCODINGS/" \
- actual >actual.smudged &&
- test_cmp exp actual.smudged &&
-
- grep "Accept-Encoding:.*gzip" actual >actual.gzip &&
- test_line_count = 2 actual.gzip &&
+ sed -e "s/^> accept-encoding: .*/> accept-encoding: ENCODINGS/" \
+ actual >actual.smudged &&
+ test_cmp exp actual.smudged &&
- grep "Accept-Language: ko-KR, *" actual >actual.language &&
- test_line_count = 2 actual.language
- fi
+ grep "accept-encoding:.*gzip" actual >actual.gzip
'
test_expect_success 'fetch changes via http' '
@@ -119,19 +156,9 @@ test_expect_success 'fetch changes via http' '
'
test_expect_success 'used upload-pack service' '
- cat >exp <<-\EOF &&
- GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
- POST /smart/repo.git/git-upload-pack HTTP/1.1 200
- GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
- POST /smart/repo.git/git-upload-pack HTTP/1.1 200
- EOF
-
- # NEEDSWORK: If the overspecification of the expected result is reduced, we
- # might be able to run this test in all protocol versions.
- if test "$GIT_TEST_PROTOCOL_VERSION" = 0
- then
- check_access_log exp
- fi
+ strip_access_log >log &&
+ grep "GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/[0-9.]* 200" log &&
+ grep "POST /smart/repo.git/git-upload-pack HTTP/[0-9.]* 200" log
'
test_expect_success 'follow redirects (301)' '
@@ -280,21 +307,23 @@ test_expect_success 'cookies stored in http.cookiefile when http.savecookies set
127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue
EOF
sort >expect_cookies.txt <<-\EOF &&
-
127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue
+ 127.0.0.1 FALSE /smart_cookies/repo.git/ FALSE 0 name value
127.0.0.1 FALSE /smart_cookies/repo.git/info/ FALSE 0 name value
EOF
git config http.cookiefile cookies.txt &&
git config http.savecookies true &&
- git ls-remote $HTTPD_URL/smart_cookies/repo.git main &&
- # NEEDSWORK: If the overspecification of the expected result is reduced, we
- # might be able to run this test in all protocol versions.
- if test "$GIT_TEST_PROTOCOL_VERSION" = 0
- then
- tail -3 cookies.txt | sort >cookies_tail.txt &&
- test_cmp expect_cookies.txt cookies_tail.txt
- fi
+ test_when_finished "
+ git --git-dir=\"\$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" \
+ tag -d cookie-tag
+ " &&
+ git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+ tag -m "foo" cookie-tag &&
+ git fetch $HTTPD_URL/smart_cookies/repo.git cookie-tag &&
+
+ grep "^[^#]" cookies.txt | sort >cookies_stripped.txt &&
+ test_cmp expect_cookies.txt cookies_stripped.txt
'
test_expect_success 'transfer.hiderefs works over smart-http' '
@@ -666,4 +695,13 @@ test_expect_success 'push warns or fails when using username:password' '
test_line_count -ge 1 warnings
'
+test_expect_success 'no empty path components' '
+ # In the URL, add a trailing slash, and see if git appends yet another
+ # slash.
+ git clone $HTTPD_URL/smart/repo.git/ clone-with-slash &&
+
+ strip_access_log >log &&
+ ! grep "//" log
+'
+
test_done
diff --git a/t/t5559-http-fetch-smart-http2.sh b/t/t5559-http-fetch-smart-http2.sh
index 9eece71c2c..54aa9d3bff 100755
--- a/t/t5559-http-fetch-smart-http2.sh
+++ b/t/t5559-http-fetch-smart-http2.sh
@@ -1,4 +1,5 @@
#!/bin/sh
HTTP_PROTO=HTTP/2
+LIB_HTTPD_SSL=1
. ./t5551-http-fetch-smart.sh
diff --git a/t/t5564-http-proxy.sh b/t/t5564-http-proxy.sh
new file mode 100755
index 0000000000..9da5134614
--- /dev/null
+++ b/t/t5564-http-proxy.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+test_description="test fetching through http proxy"
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
+
+LIB_HTTPD_PROXY=1
+start_httpd
+
+test_expect_success 'setup repository' '
+ test_commit foo &&
+ git init --bare "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
+ git push --mirror "$HTTPD_DOCUMENT_ROOT_PATH/repo.git"
+'
+
+setup_askpass_helper
+
+# sanity check that our test setup is correctly using proxy
+test_expect_success 'proxy requires password' '
+ test_config_global http.proxy $HTTPD_DEST &&
+ test_must_fail git clone $HTTPD_URL/smart/repo.git 2>err &&
+ grep "error.*407" err
+'
+
+test_expect_success 'clone through proxy with auth' '
+ test_when_finished "rm -rf clone" &&
+ test_config_global http.proxy http://proxuser:proxpass@$HTTPD_DEST &&
+ GIT_TRACE_CURL=$PWD/trace git clone $HTTPD_URL/smart/repo.git clone &&
+ grep -i "Proxy-Authorization: Basic <redacted>" trace
+'
+
+test_expect_success 'clone can prompt for proxy password' '
+ test_when_finished "rm -rf clone" &&
+ test_config_global http.proxy http://proxuser@$HTTPD_DEST &&
+ set_askpass nobody proxpass &&
+ GIT_TRACE_CURL=$PWD/trace git clone $HTTPD_URL/smart/repo.git clone &&
+ expect_askpass pass proxuser
+'
+
+test_done
diff --git a/t/t7510-signed-commit.sh b/t/t7510-signed-commit.sh
index bc7a31ba3e..48f86cb367 100755
--- a/t/t7510-signed-commit.sh
+++ b/t/t7510-signed-commit.sh
@@ -387,4 +387,48 @@ test_expect_success GPG 'verify-commit verifies multiply signed commits' '
! grep "BAD signature from" actual
'
+test_expect_success 'custom `gpg.program`' '
+ write_script fake-gpg <<-\EOF &&
+ args="$*"
+
+ # skip uninteresting options
+ while case "$1" in
+ --status-fd=*|--keyid-format=*) ;; # skip
+ *) break;;
+ esac; do shift; done
+
+ case "$1" in
+ -bsau)
+ test -z "$LET_GPG_PROGRAM_FAIL" || {
+ echo "zOMG signing failed!" >&2
+ exit 1
+ }
+ cat >sign.file
+ echo "[GNUPG:] SIG_CREATED $args" >&2
+ echo "-----BEGIN PGP MESSAGE-----"
+ echo "$args"
+ echo "-----END PGP MESSAGE-----"
+ ;;
+ --verify)
+ cat "$2" >verify.file
+ exit 0
+ ;;
+ *)
+ echo "Unhandled args: $*" >&2
+ exit 1
+ ;;
+ esac
+ EOF
+
+ test_config gpg.program "$(pwd)/fake-gpg" &&
+ git commit -S --allow-empty -m signed-commit &&
+ test_path_exists sign.file &&
+ git show --show-signature &&
+ test_path_exists verify.file &&
+
+ test_must_fail env LET_GPG_PROGRAM_FAIL=1 \
+ git commit -S --allow-empty -m must-fail 2>err &&
+ grep zOMG err
+'
+
test_done
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 58cfd2f1fd..999d46fafe 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -32,6 +32,14 @@ test_set_editor () {
export EDITOR
}
+# Like test_set_editor but sets GIT_SEQUENCE_EDITOR instead of EDITOR
+test_set_sequence_editor () {
+ FAKE_SEQUENCE_EDITOR="$1"
+ export FAKE_SEQUENCE_EDITOR
+ GIT_SEQUENCE_EDITOR='"$FAKE_SEQUENCE_EDITOR"'
+ export GIT_SEQUENCE_EDITOR
+}
+
test_decode_color () {
awk '
function name(n) {
diff --git a/trace.c b/trace.c
index 794a087c21..efa4e2d8e0 100644
--- a/trace.c
+++ b/trace.c
@@ -291,10 +291,9 @@ static const char *quote_crnl(const char *path)
return new_path.buf;
}
-/* FIXME: move prefix to startup_info struct and get rid of this arg */
-void trace_repo_setup(const char *prefix)
+void trace_repo_setup(void)
{
- const char *git_work_tree;
+ const char *git_work_tree, *prefix = startup_info->prefix;
char *cwd;
if (!trace_want(&trace_setup_key))
@@ -305,7 +304,7 @@ void trace_repo_setup(const char *prefix)
if (!(git_work_tree = get_git_work_tree()))
git_work_tree = "(null)";
- if (!prefix)
+ if (!startup_info->prefix)
prefix = "(null)";
trace_printf_key(&trace_setup_key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
diff --git a/trace.h b/trace.h
index 4e771f86ac..b6e35b9470 100644
--- a/trace.h
+++ b/trace.h
@@ -93,7 +93,7 @@ extern struct trace_key trace_default_key;
extern struct trace_key trace_perf_key;
extern struct trace_key trace_setup_key;
-void trace_repo_setup(const char *prefix);
+void trace_repo_setup(void);
/**
* Checks whether the trace key is enabled. Used to prevent expensive
diff --git a/userdiff.c b/userdiff.c
index 94cca1a2a8..58a3d59ef8 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -293,7 +293,7 @@ PATTERNS("scheme",
"|([^][)(}{[ \t])+"),
PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
"\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"),
-{ "default", NULL, -1, { NULL, 0 } },
+{ "default", NULL, NULL, -1, { NULL, 0 } },
};
#undef PATTERNS
#undef IPATTERN
@@ -394,6 +394,8 @@ int userdiff_config(const char *k, const char *v)
return parse_bool(&drv->textconv_want_cache, k, v);
if (!strcmp(type, "wordregex"))
return git_config_string(&drv->word_regex, k, v);
+ if (!strcmp(type, "algorithm"))
+ return git_config_string(&drv->algorithm, k, v);
return 0;
}
diff --git a/userdiff.h b/userdiff.h
index aee91bc77e..24419db697 100644
--- a/userdiff.h
+++ b/userdiff.h
@@ -14,6 +14,7 @@ struct userdiff_funcname {
struct userdiff_driver {
const char *name;
const char *external;
+ const char *algorithm;
int binary;
struct userdiff_funcname funcname;
const char *word_regex;