summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2021-03-03 15:16:04 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2021-03-03 15:16:04 +0900
commitde6d895af03d07b5ec73d7d4c56f79ec555c7325 (patch)
treeaedca6f5040624a3a745347590eba827d33e00f6
parente0c2b742e0fece8aeee415331f0b988dd7765abd (diff)
downloadgit-de6d895af03d07b5ec73d7d4c56f79ec555c7325.tar.gz
git-de6d895af03d07b5ec73d7d4c56f79ec555c7325.tar.bz2
git-de6d895af03d07b5ec73d7d4c56f79ec555c7325.zip
Imported Upstream version 2.12.1upstream/2.12.1
-rw-r--r--.travis.yml21
-rw-r--r--Documentation/RelNotes/2.12.1.txt41
-rw-r--r--Documentation/git.txt3
-rwxr-xr-xGIT-VERSION-GEN2
l---------RelNotes2
-rw-r--r--abspath.c4
-rw-r--r--bisect.c9
-rw-r--r--builtin/init-db.c6
-rw-r--r--cache.h2
-rwxr-xr-xci/run-linux32-build.sh30
-rw-r--r--config.mak.uname1
-rw-r--r--dir.c4
-rw-r--r--environment.c2
-rwxr-xr-xgit-add--interactive.perl8
-rw-r--r--http.c53
-rw-r--r--line-log.c18
-rw-r--r--progress.c11
-rw-r--r--setup.c4
-rw-r--r--submodule.c10
-rw-r--r--t/lib-httpd/apache.conf9
-rwxr-xr-xt/t1501-work-tree.sh8
-rwxr-xr-xt/t3701-add-interactive.sh18
-rwxr-xr-xt/t4211-line-log.sh10
-rwxr-xr-xt/t5550-http-fetch-dumb.sh9
-rw-r--r--transport.c2
-rw-r--r--worktree.c2
26 files changed, 239 insertions, 50 deletions
diff --git a/.travis.yml b/.travis.yml
index 9c63c8c3..591cc57b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -39,6 +39,27 @@ env:
matrix:
include:
+ - env: Linux32
+ os: linux
+ services:
+ - docker
+ before_install:
+ - docker pull daald/ubuntu32:xenial
+ before_script:
+ script:
+ - >
+ docker run
+ --interactive
+ --env DEFAULT_TEST_TARGET
+ --env GIT_PROVE_OPTS
+ --env GIT_TEST_OPTS
+ --env GIT_TEST_CLONE_2GB
+ --volume "${PWD}:/usr/src/git"
+ daald/ubuntu32:xenial
+ /usr/src/git/ci/run-linux32-build.sh $(id -u $USER)
+ # Use the following command to debug the docker build locally:
+ # $ docker run -itv "${PWD}:/usr/src/git" --entrypoint /bin/bash daald/ubuntu32:xenial
+ # root@container:/# /usr/src/git/ci/run-linux32-build.sh
- env: Documentation
os: linux
compiler: clang
diff --git a/Documentation/RelNotes/2.12.1.txt b/Documentation/RelNotes/2.12.1.txt
new file mode 100644
index 00000000..a74f7db7
--- /dev/null
+++ b/Documentation/RelNotes/2.12.1.txt
@@ -0,0 +1,41 @@
+Git v2.12.1 Release Notes
+=========================
+
+Fixes since v2.12
+-----------------
+
+ * Reduce authentication round-trip over HTTP when the server supports
+ just a single authentication method. This also improves the
+ behaviour when Git is misconfigured to enable http.emptyAuth
+ against a server that does not authenticate without a username
+ (i.e. not using Kerberos etc., which makes http.emptyAuth
+ pointless).
+
+ * Windows port wants to use OpenSSL's implementation of SHA-1
+ routines, so let them.
+
+ * Add 32-bit Linux variant to the set of platforms to be tested with
+ Travis CI.
+
+ * When a redirected http transport gets an error during the
+ redirected request, we ignored the error we got from the server,
+ and ended up giving a not-so-useful error message.
+
+ * The patch subcommand of "git add -i" was meant to have paths
+ selection prompt just like other subcommand, unlike "git add -p"
+ directly jumps to hunk selection. Recently, this was broken and
+ "add -i" lost the paths selection dialog, but it now has been
+ fixed.
+
+ * Git v2.12 was shipped with an embarrassing breakage where various
+ operations that verify paths given from the user stopped dying when
+ seeing an issue, and instead later triggering segfault.
+
+ * The code to parse "git log -L..." command line was buggy when there
+ are many ranges specified with -L; overrun of the allocated buffer
+ has been fixed.
+
+ * The command-line parsing of "git log -L" copied internal data
+ structures using incorrect size on ILP32 systems.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/git.txt b/Documentation/git.txt
index aa895da4..25560f69 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -44,9 +44,10 @@ unreleased) version of Git, that is available from the 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v2.12.0/git.html[documentation for release 2.12.0]
+* link:v2.12.1/git.html[documentation for release 2.12.1]
* release notes for
+ link:RelNotes/2.12.1.txt[2.12.1].
link:RelNotes/2.12.0.txt[2.12].
* link:v2.11.1/git.html[documentation for release 2.11.1]
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 6a208e92..d18eb6d9 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.12.0
+DEF_VER=v2.12.1
LF='
'
diff --git a/RelNotes b/RelNotes
index d09c3d51..95f2e5e6 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.12.0.txt \ No newline at end of file
+Documentation/RelNotes/2.12.1.txt \ No newline at end of file
diff --git a/abspath.c b/abspath.c
index 2f0c26e0..b02e068a 100644
--- a/abspath.c
+++ b/abspath.c
@@ -214,12 +214,12 @@ const char *real_path_if_valid(const char *path)
return strbuf_realpath(&realpath, path, 0);
}
-char *real_pathdup(const char *path)
+char *real_pathdup(const char *path, int die_on_error)
{
struct strbuf realpath = STRBUF_INIT;
char *retval = NULL;
- if (strbuf_realpath(&realpath, path, 0))
+ if (strbuf_realpath(&realpath, path, die_on_error))
retval = strbuf_detach(&realpath, NULL);
strbuf_release(&realpath);
diff --git a/bisect.c b/bisect.c
index 8e63c40d..30808cad 100644
--- a/bisect.c
+++ b/bisect.c
@@ -940,7 +940,7 @@ int bisect_next_all(const char *prefix, int no_checkout)
struct commit_list *tried;
int reaches = 0, all = 0, nr, steps;
const unsigned char *bisect_rev;
- char steps_msg[32];
+ char *steps_msg;
read_bisect_terms(&term_bad, &term_good);
if (read_bisect_refs())
@@ -990,14 +990,15 @@ int bisect_next_all(const char *prefix, int no_checkout)
nr = all - reaches - 1;
steps = estimate_bisect_steps(all);
- xsnprintf(steps_msg, sizeof(steps_msg),
- Q_("(roughly %d step)", "(roughly %d steps)", steps),
- steps);
+
+ steps_msg = xstrfmt(Q_("(roughly %d step)", "(roughly %d steps)",
+ steps), steps);
/* TRANSLATORS: the last %s will be replaced with
"(roughly %d steps)" translation */
printf(Q_("Bisecting: %d revision left to test after this %s\n",
"Bisecting: %d revisions left to test after this %s\n",
nr), nr, steps_msg);
+ free(steps_msg);
return bisect_checkout(bisect_rev, no_checkout);
}
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 1d4d6a00..8a6acb0e 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -338,7 +338,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
{
int reinit;
int exist_ok = flags & INIT_DB_EXIST_OK;
- char *original_git_dir = real_pathdup(git_dir);
+ char *original_git_dir = real_pathdup(git_dir, 1);
if (real_git_dir) {
struct stat st;
@@ -489,7 +489,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
if (real_git_dir && !is_absolute_path(real_git_dir))
- real_git_dir = real_pathdup(real_git_dir);
+ real_git_dir = real_pathdup(real_git_dir, 1);
if (argc == 1) {
int mkdir_tried = 0;
@@ -560,7 +560,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
const char *git_dir_parent = strrchr(git_dir, '/');
if (git_dir_parent) {
char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
- git_work_tree_cfg = real_pathdup(rel);
+ git_work_tree_cfg = real_pathdup(rel, 1);
free(rel);
}
if (!git_work_tree_cfg)
diff --git a/cache.h b/cache.h
index 61fc86e6..c26c45f8 100644
--- a/cache.h
+++ b/cache.h
@@ -1109,7 +1109,7 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
int die_on_error);
const char *real_path(const char *path);
const char *real_path_if_valid(const char *path);
-char *real_pathdup(const char *path);
+char *real_pathdup(const char *path, int die_on_error);
const char *absolute_path(const char *path);
char *absolute_pathdup(const char *path);
const char *remove_leading_path(const char *in, const char *prefix);
diff --git a/ci/run-linux32-build.sh b/ci/run-linux32-build.sh
new file mode 100755
index 00000000..e30fb2cd
--- /dev/null
+++ b/ci/run-linux32-build.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# Build and test Git in a 32-bit environment
+#
+# Usage:
+# run-linux32-build.sh [host-user-id]
+#
+
+# Update packages to the latest available versions
+linux32 --32bit i386 sh -c '
+ apt update >/dev/null &&
+ apt install -y build-essential libcurl4-openssl-dev libssl-dev \
+ libexpat-dev gettext python >/dev/null
+' &&
+
+# If this script runs inside a docker container, then all commands are
+# usually executed as root. Consequently, the host user might not be
+# able to access the test output files.
+# If a host user id is given, then create a user "ci" with the host user
+# id to make everything accessible to the host user.
+HOST_UID=$1 &&
+CI_USER=$USER &&
+test -z $HOST_UID || (CI_USER="ci" && useradd -u $HOST_UID $CI_USER) &&
+
+# Build and test
+linux32 --32bit i386 su -m -l $CI_USER -c '
+ cd /usr/src/git &&
+ make --jobs=2 &&
+ make --quiet test
+'
diff --git a/config.mak.uname b/config.mak.uname
index 447f36ac..a07936da 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -515,7 +515,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
NO_REGEX = YesPlease
NO_PYTHON = YesPlease
- BLK_SHA1 = YesPlease
ETAGS_TARGET = ETAGS
NO_INET_PTON = YesPlease
NO_INET_NTOP = YesPlease
diff --git a/dir.c b/dir.c
index 4541f9e1..aeeb5ce1 100644
--- a/dir.c
+++ b/dir.c
@@ -2730,8 +2730,8 @@ void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_)
{
struct strbuf file_name = STRBUF_INIT;
struct strbuf rel_path = STRBUF_INIT;
- char *git_dir = real_pathdup(git_dir_);
- char *work_tree = real_pathdup(work_tree_);
+ char *git_dir = real_pathdup(git_dir_, 1);
+ char *work_tree = real_pathdup(work_tree_, 1);
/* Update gitfile */
strbuf_addf(&file_name, "%s/.git", work_tree);
diff --git a/environment.c b/environment.c
index c07fb17f..42dc3106 100644
--- a/environment.c
+++ b/environment.c
@@ -259,7 +259,7 @@ void set_git_work_tree(const char *new_work_tree)
return;
}
git_work_tree_initialized = 1;
- work_tree = real_pathdup(new_work_tree);
+ work_tree = real_pathdup(new_work_tree, 1);
}
const char *get_git_work_tree(void)
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 982593c8..f5c816e2 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -92,7 +92,7 @@ sub colored {
}
# command line options
-my $cmd;
+my $patch_mode_only;
my $patch_mode;
my $patch_mode_revision;
@@ -1299,7 +1299,7 @@ sub patch_update_cmd {
}
return 0;
}
- if ($patch_mode) {
+ if ($patch_mode_only) {
@them = @mods;
}
else {
@@ -1721,7 +1721,7 @@ sub process_args {
die sprintf(__("invalid argument %s, expecting --"),
$arg) unless $arg eq "--";
%patch_mode_flavour = %{$patch_modes{$patch_mode}};
- $cmd = 1;
+ $patch_mode_only = 1;
}
elsif ($arg ne "--") {
die sprintf(__("invalid argument %s, expecting --"), $arg);
@@ -1758,7 +1758,7 @@ sub main_loop {
process_args();
refresh();
-if ($cmd) {
+if ($patch_mode_only) {
patch_update_cmd();
}
else {
diff --git a/http.c b/http.c
index 90a1c0f1..96d84bbe 100644
--- a/http.c
+++ b/http.c
@@ -109,7 +109,7 @@ static int curl_save_cookies;
struct credential http_auth = CREDENTIAL_INIT;
static int http_proactive_auth;
static const char *user_agent;
-static int curl_empty_auth;
+static int curl_empty_auth = -1;
enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
@@ -125,6 +125,14 @@ static struct credential cert_auth = CREDENTIAL_INIT;
static int ssl_cert_password_required;
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
static unsigned long http_auth_methods = CURLAUTH_ANY;
+static int http_auth_methods_restricted;
+/* Modes for which empty_auth cannot actually help us. */
+static unsigned long empty_auth_useless =
+ CURLAUTH_BASIC
+#ifdef CURLAUTH_DIGEST_IE
+ | CURLAUTH_DIGEST_IE
+#endif
+ | CURLAUTH_DIGEST;
#endif
static struct curl_slist *pragma_header;
@@ -333,7 +341,10 @@ static int http_options(const char *var, const char *value, void *cb)
return git_config_string(&user_agent, var, value);
if (!strcmp("http.emptyauth", var)) {
- curl_empty_auth = git_config_bool(var, value);
+ if (value && !strcmp("auto", value))
+ curl_empty_auth = -1;
+ else
+ curl_empty_auth = git_config_bool(var, value);
return 0;
}
@@ -382,10 +393,37 @@ static int http_options(const char *var, const char *value, void *cb)
return git_default_config(var, value, cb);
}
+static int curl_empty_auth_enabled(void)
+{
+ if (curl_empty_auth >= 0)
+ return curl_empty_auth;
+
+#ifndef LIBCURL_CAN_HANDLE_AUTH_ANY
+ /*
+ * Our libcurl is too old to do AUTH_ANY in the first place;
+ * just default to turning the feature off.
+ */
+#else
+ /*
+ * In the automatic case, kick in the empty-auth
+ * hack as long as we would potentially try some
+ * method more exotic than "Basic" or "Digest".
+ *
+ * But only do this when this is our second or
+ * subsequent request, as by then we know what
+ * methods are available.
+ */
+ if (http_auth_methods_restricted &&
+ (http_auth_methods & ~empty_auth_useless))
+ return 1;
+#endif
+ return 0;
+}
+
static void init_curl_http_auth(CURL *result)
{
if (!http_auth.username || !*http_auth.username) {
- if (curl_empty_auth)
+ if (curl_empty_auth_enabled())
curl_easy_setopt(result, CURLOPT_USERPWD, ":");
return;
}
@@ -1079,7 +1117,7 @@ struct active_request_slot *get_active_slot(void)
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
#endif
- if (http_auth.password || curl_empty_auth)
+ if (http_auth.password || curl_empty_auth_enabled())
init_curl_http_auth(slot->curl);
return slot;
@@ -1347,6 +1385,10 @@ static int handle_curl_result(struct slot_results *results)
} else {
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE;
+ if (results->auth_avail) {
+ http_auth_methods &= results->auth_avail;
+ http_auth_methods_restricted = 1;
+ }
#endif
return HTTP_REAUTH;
}
@@ -1727,6 +1769,9 @@ static int http_request_reauth(const char *url,
{
int ret = http_request(url, result, target, options);
+ if (ret != HTTP_OK && ret != HTTP_REAUTH)
+ return ret;
+
if (options && options->effective_url && options->base_url) {
if (update_url_from_redirect(options->base_url,
url, options->effective_url)) {
diff --git a/line-log.c b/line-log.c
index 65f3558b..a23b9104 100644
--- a/line-log.c
+++ b/line-log.c
@@ -43,9 +43,10 @@ void range_set_release(struct range_set *rs)
static void range_set_copy(struct range_set *dst, struct range_set *src)
{
range_set_init(dst, src->nr);
- memcpy(dst->ranges, src->ranges, src->nr*sizeof(struct range_set));
+ COPY_ARRAY(dst->ranges, src->ranges, src->nr);
dst->nr = src->nr;
}
+
static void range_set_move(struct range_set *dst, struct range_set *src)
{
range_set_release(dst);
@@ -144,7 +145,7 @@ void sort_and_merge_range_set(struct range_set *rs)
static void range_set_union(struct range_set *out,
struct range_set *a, struct range_set *b)
{
- int i = 0, j = 0, o = 0;
+ int i = 0, j = 0;
struct range *ra = a->ranges;
struct range *rb = b->ranges;
/* cannot make an alias of out->ranges: it may change during grow */
@@ -167,16 +168,15 @@ static void range_set_union(struct range_set *out,
new = &rb[j++];
if (new->start == new->end)
; /* empty range */
- else if (!o || out->ranges[o-1].end < new->start) {
+ else if (!out->nr || out->ranges[out->nr-1].end < new->start) {
range_set_grow(out, 1);
- out->ranges[o].start = new->start;
- out->ranges[o].end = new->end;
- o++;
- } else if (out->ranges[o-1].end < new->end) {
- out->ranges[o-1].end = new->end;
+ out->ranges[out->nr].start = new->start;
+ out->ranges[out->nr].end = new->end;
+ out->nr++;
+ } else if (out->ranges[out->nr-1].end < new->end) {
+ out->ranges[out->nr-1].end = new->end;
}
}
- out->nr = o;
}
/*
diff --git a/progress.c b/progress.c
index 76a88c57..29378caa 100644
--- a/progress.c
+++ b/progress.c
@@ -243,21 +243,18 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)
*p_progress = NULL;
if (progress->last_value != -1) {
/* Force the last update */
- char buf[128], *bufp;
- size_t len = strlen(msg) + 5;
+ char *buf;
struct throughput *tp = progress->throughput;
- bufp = (len < sizeof(buf)) ? buf : xmallocz(len);
if (tp) {
unsigned int rate = !tp->avg_misecs ? 0 :
tp->avg_bytes / tp->avg_misecs;
throughput_string(&tp->display, tp->curr_total, rate);
}
progress_update = 1;
- xsnprintf(bufp, len + 1, ", %s.\n", msg);
- display(progress, progress->last_value, bufp);
- if (buf != bufp)
- free(bufp);
+ buf = xstrfmt(", %s.\n", msg);
+ display(progress, progress->last_value, buf);
+ free(buf);
}
clear_progress_signal();
if (progress->throughput)
diff --git a/setup.c b/setup.c
index 967f289f..6b48cb91 100644
--- a/setup.c
+++ b/setup.c
@@ -698,7 +698,7 @@ static const char *setup_discovered_git_dir(const char *gitdir,
/* --work-tree is set without --git-dir; use discovered one */
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
if (offset != cwd->len && !is_absolute_path(gitdir))
- gitdir = real_pathdup(gitdir);
+ gitdir = real_pathdup(gitdir, 1);
if (chdir(cwd->buf))
die_errno("Could not come back to cwd");
return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
@@ -806,7 +806,7 @@ static int canonicalize_ceiling_entry(struct string_list_item *item,
/* Keep entry but do not canonicalize it */
return 1;
} else {
- char *real_path = real_pathdup(ceil);
+ char *real_path = real_pathdup(ceil, 0);
if (!real_path) {
return 0;
}
diff --git a/submodule.c b/submodule.c
index 3b98766a..0a2831d8 100644
--- a/submodule.c
+++ b/submodule.c
@@ -1403,7 +1403,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
/* If it is an actual gitfile, it doesn't need migration. */
return;
- real_old_git_dir = real_pathdup(old_git_dir);
+ real_old_git_dir = real_pathdup(old_git_dir, 1);
sub = submodule_from_path(null_sha1, path);
if (!sub)
@@ -1412,7 +1412,7 @@ static void relocate_single_git_dir_into_superproject(const char *prefix,
new_git_dir = git_path("modules/%s", sub->name);
if (safe_create_leading_directories_const(new_git_dir) < 0)
die(_("could not create directory '%s'"), new_git_dir);
- real_new_git_dir = real_pathdup(new_git_dir);
+ real_new_git_dir = real_pathdup(new_git_dir, 1);
if (!prefix)
prefix = get_super_prefix();
@@ -1472,14 +1472,14 @@ void absorb_git_dir_into_superproject(const char *prefix,
new_git_dir = git_path("modules/%s", sub->name);
if (safe_create_leading_directories_const(new_git_dir) < 0)
die(_("could not create directory '%s'"), new_git_dir);
- real_new_git_dir = real_pathdup(new_git_dir);
+ real_new_git_dir = real_pathdup(new_git_dir, 1);
connect_work_tree_and_git_dir(path, real_new_git_dir);
free(real_new_git_dir);
} else {
/* Is it already absorbed into the superprojects git dir? */
- char *real_sub_git_dir = real_pathdup(sub_git_dir);
- char *real_common_git_dir = real_pathdup(get_git_common_dir());
+ char *real_sub_git_dir = real_pathdup(sub_git_dir, 1);
+ char *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);
if (!starts_with(real_sub_git_dir, real_common_git_dir))
relocate_single_git_dir_into_superproject(prefix, path);
diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf
index 69174c6e..0642ae7e 100644
--- a/t/lib-httpd/apache.conf
+++ b/t/lib-httpd/apache.conf
@@ -133,6 +133,15 @@ RewriteRule ^/ftp-redir/(.*)$ ftp://localhost:1000/$1 [R=302]
RewriteRule ^/loop-redir/x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-(.*) /$1 [R=302]
RewriteRule ^/loop-redir/(.*)$ /loop-redir/x-$1 [R=302]
+# redir-to/502/x?y -> really-redir-to?path=502/x&qs=y which returns 502
+# redir-to/x?y -> really-redir-to?path=x&qs=y -> x?y
+RewriteCond %{QUERY_STRING} ^(.*)$
+RewriteRule ^/redir-to/(.*)$ /really-redir-to?path=$1&qs=%1 [R=302]
+RewriteCond %{QUERY_STRING} ^path=502/(.*)&qs=(.*)$
+RewriteRule ^/really-redir-to$ - [R=502,L]
+RewriteCond %{QUERY_STRING} ^path=(.*)&qs=(.*)$
+RewriteRule ^/really-redir-to$ /%1?%2 [R=302]
+
# The first rule issues a client-side redirect to something
# that _doesn't_ look like a git repo. The second rule is a
# server-side rewrite, so that it turns out the odd-looking
diff --git a/t/t1501-work-tree.sh b/t/t1501-work-tree.sh
index cc5b870e..b06210ec 100755
--- a/t/t1501-work-tree.sh
+++ b/t/t1501-work-tree.sh
@@ -423,4 +423,12 @@ test_expect_success '$GIT_WORK_TREE overrides $GIT_DIR/common' '
)
'
+test_expect_success 'error out gracefully on invalid $GIT_WORK_TREE' '
+ (
+ GIT_WORK_TREE=/.invalid/work/tree &&
+ export GIT_WORK_TREE &&
+ test_expect_code 128 git rev-parse
+ )
+'
+
test_done
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index 5ffe78e9..aaa258da 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -394,4 +394,22 @@ test_expect_success 'diffs can be colorized' '
grep "$(printf "\\033")" output
'
+test_expect_success 'patch-mode via -i prompts for files' '
+ git reset --hard &&
+
+ echo one >file &&
+ echo two >test &&
+ git add -i <<-\EOF &&
+ patch
+ test
+
+ y
+ quit
+ EOF
+
+ echo test >expect &&
+ git diff --cached --name-only >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index 9d87777b..d0377fae 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -106,4 +106,14 @@ test_expect_success '-L with --output' '
test_line_count = 70 log
'
+test_expect_success 'range_set_union' '
+ test_seq 500 > c.c &&
+ git add c.c &&
+ git commit -m "many lines" &&
+ test_seq 1000 > c.c &&
+ git add c.c &&
+ git commit -m "modify many lines" &&
+ git log $(for x in $(test_seq 200); do echo -L $((2*x)),+1:c.c; done)
+'
+
test_done
diff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh
index aeb3a63f..2d3b1e9f 100755
--- a/t/t5550-http-fetch-dumb.sh
+++ b/t/t5550-http-fetch-dumb.sh
@@ -378,5 +378,14 @@ test_expect_success 'http-alternates triggers not-from-user protocol check' '
clone $HTTPD_URL/dumb/evil.git evil-user
'
+test_expect_success 'can redirect through non-"info/refs?service=git-upload-pack" URL' '
+ git clone "$HTTPD_URL/redir-to/dumb/repo.git"
+'
+
+test_expect_success 'print HTTP error when any intermediate redirect throws error' '
+ test_must_fail git clone "$HTTPD_URL/redir-to/502" 2> stderr &&
+ test_i18ngrep "unable to access.*/redir-to/502" stderr
+'
+
stop_httpd
test_done
diff --git a/transport.c b/transport.c
index d72e0894..b6c5652d 100644
--- a/transport.c
+++ b/transport.c
@@ -1221,7 +1221,7 @@ static int refs_from_alternate_cb(struct alternate_object_database *e,
const struct ref *extra;
struct alternate_refs_data *cb = data;
- other = real_pathdup(e->path);
+ other = real_pathdup(e->path, 1);
len = strlen(other);
while (other[len-1] == '/')
diff --git a/worktree.c b/worktree.c
index d6337615..0486e31a 100644
--- a/worktree.c
+++ b/worktree.c
@@ -255,7 +255,7 @@ struct worktree *find_worktree(struct worktree **list,
return wt;
arg = prefix_filename(prefix, strlen(prefix), arg);
- path = real_pathdup(arg);
+ path = real_pathdup(arg, 1);
for (; *list; list++)
if (!fspathcmp(path, real_path((*list)->path)))
break;