mirror of
https://github.com/git/git
synced 2024-10-05 16:19:28 +00:00
Merge branch 'maint-1.7.11' into maint
This commit is contained in:
commit
3503e9ab32
|
@ -84,11 +84,11 @@ entries; instead, unmerged entries are ignored.
|
||||||
When checking out paths from the index, check out stage #2
|
When checking out paths from the index, check out stage #2
|
||||||
('ours') or #3 ('theirs') for unmerged paths.
|
('ours') or #3 ('theirs') for unmerged paths.
|
||||||
|
|
||||||
-b::
|
-b <new_branch>::
|
||||||
Create a new branch named <new_branch> and start it at
|
Create a new branch named <new_branch> and start it at
|
||||||
<start_point>; see linkgit:git-branch[1] for details.
|
<start_point>; see linkgit:git-branch[1] for details.
|
||||||
|
|
||||||
-B::
|
-B <new_branch>::
|
||||||
Creates the branch <new_branch> and start it at <start_point>;
|
Creates the branch <new_branch> and start it at <start_point>;
|
||||||
if it already exists, then reset it to <start_point>. This is
|
if it already exists, then reset it to <start_point>. This is
|
||||||
equivalent to running "git branch" with "-f"; see
|
equivalent to running "git branch" with "-f"; see
|
||||||
|
@ -124,7 +124,7 @@ explicitly give a name with '-b' in such a case.
|
||||||
<commit> is not a branch name. See the "DETACHED HEAD" section
|
<commit> is not a branch name. See the "DETACHED HEAD" section
|
||||||
below for details.
|
below for details.
|
||||||
|
|
||||||
--orphan::
|
--orphan <new_branch>::
|
||||||
Create a new 'orphan' branch, named <new_branch>, started from
|
Create a new 'orphan' branch, named <new_branch>, started from
|
||||||
<start_point> and switch to it. The first commit made on this
|
<start_point> and switch to it. The first commit made on this
|
||||||
new branch will have no parents and it will be the root of a new
|
new branch will have no parents and it will be the root of a new
|
||||||
|
|
|
@ -213,6 +213,13 @@ of 'r1' and 'r2' and is defined as
|
||||||
It is the set of commits that are reachable from either one of
|
It is the set of commits that are reachable from either one of
|
||||||
'r1' or 'r2' but not from both.
|
'r1' or 'r2' but not from both.
|
||||||
|
|
||||||
|
In these two shorthands, you can omit one end and let it default to HEAD.
|
||||||
|
For example, 'origin..' is a shorthand for 'origin..HEAD' and asks "What
|
||||||
|
did I do since I forked from the origin branch?" Similarly, '..origin'
|
||||||
|
is a shorthand for 'HEAD..origin' and asks "What did the origin do since
|
||||||
|
I forked from them?" Note that '..' would mean 'HEAD..HEAD' which is an
|
||||||
|
empty range that is both reachable and unreachable from HEAD.
|
||||||
|
|
||||||
Two other shorthands for naming a set that is formed by a commit
|
Two other shorthands for naming a set that is formed by a commit
|
||||||
and its parent commits exist. The 'r1{caret}@' notation means all
|
and its parent commits exist. The 'r1{caret}@' notation means all
|
||||||
parents of 'r1'. 'r1{caret}!' includes commit 'r1' but excludes
|
parents of 'r1'. 'r1{caret}!' includes commit 'r1' but excludes
|
||||||
|
|
|
@ -1095,15 +1095,23 @@ static int gitdiff_unrecognized(const char *line, struct patch *patch)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *stop_at_slash(const char *line, int llen)
|
/*
|
||||||
|
* Skip p_value leading components from "line"; as we do not accept
|
||||||
|
* absolute paths, return NULL in that case.
|
||||||
|
*/
|
||||||
|
static const char *skip_tree_prefix(const char *line, int llen)
|
||||||
{
|
{
|
||||||
int nslash = p_value;
|
int nslash;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!p_value)
|
||||||
|
return (llen && line[0] == '/') ? NULL : line;
|
||||||
|
|
||||||
|
nslash = p_value;
|
||||||
for (i = 0; i < llen; i++) {
|
for (i = 0; i < llen; i++) {
|
||||||
int ch = line[i];
|
int ch = line[i];
|
||||||
if (ch == '/' && --nslash <= 0)
|
if (ch == '/' && --nslash <= 0)
|
||||||
return &line[i];
|
return (i == 0) ? NULL : &line[i + 1];
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1133,12 +1141,11 @@ static char *git_header_name(const char *line, int llen)
|
||||||
if (unquote_c_style(&first, line, &second))
|
if (unquote_c_style(&first, line, &second))
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
|
|
||||||
/* advance to the first slash */
|
/* strip the a/b prefix including trailing slash */
|
||||||
cp = stop_at_slash(first.buf, first.len);
|
cp = skip_tree_prefix(first.buf, first.len);
|
||||||
/* we do not accept absolute paths */
|
if (!cp)
|
||||||
if (!cp || cp == first.buf)
|
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
strbuf_remove(&first, 0, cp + 1 - first.buf);
|
strbuf_remove(&first, 0, cp - first.buf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* second points at one past closing dq of name.
|
* second points at one past closing dq of name.
|
||||||
|
@ -1152,22 +1159,21 @@ static char *git_header_name(const char *line, int llen)
|
||||||
if (*second == '"') {
|
if (*second == '"') {
|
||||||
if (unquote_c_style(&sp, second, NULL))
|
if (unquote_c_style(&sp, second, NULL))
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
cp = stop_at_slash(sp.buf, sp.len);
|
cp = skip_tree_prefix(sp.buf, sp.len);
|
||||||
if (!cp || cp == sp.buf)
|
if (!cp)
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
/* They must match, otherwise ignore */
|
/* They must match, otherwise ignore */
|
||||||
if (strcmp(cp + 1, first.buf))
|
if (strcmp(cp, first.buf))
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
strbuf_release(&sp);
|
strbuf_release(&sp);
|
||||||
return strbuf_detach(&first, NULL);
|
return strbuf_detach(&first, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unquoted second */
|
/* unquoted second */
|
||||||
cp = stop_at_slash(second, line + llen - second);
|
cp = skip_tree_prefix(second, line + llen - second);
|
||||||
if (!cp || cp == second)
|
if (!cp)
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
cp++;
|
if (line + llen - cp != first.len ||
|
||||||
if (line + llen - cp != first.len + 1 ||
|
|
||||||
memcmp(first.buf, cp, first.len))
|
memcmp(first.buf, cp, first.len))
|
||||||
goto free_and_fail1;
|
goto free_and_fail1;
|
||||||
return strbuf_detach(&first, NULL);
|
return strbuf_detach(&first, NULL);
|
||||||
|
@ -1179,10 +1185,9 @@ static char *git_header_name(const char *line, int llen)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unquoted first name */
|
/* unquoted first name */
|
||||||
name = stop_at_slash(line, llen);
|
name = skip_tree_prefix(line, llen);
|
||||||
if (!name || name == line)
|
if (!name)
|
||||||
return NULL;
|
return NULL;
|
||||||
name++;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* since the first name is unquoted, a dq if exists must be
|
* since the first name is unquoted, a dq if exists must be
|
||||||
|
@ -1196,10 +1201,9 @@ static char *git_header_name(const char *line, int llen)
|
||||||
if (unquote_c_style(&sp, second, NULL))
|
if (unquote_c_style(&sp, second, NULL))
|
||||||
goto free_and_fail2;
|
goto free_and_fail2;
|
||||||
|
|
||||||
np = stop_at_slash(sp.buf, sp.len);
|
np = skip_tree_prefix(sp.buf, sp.len);
|
||||||
if (!np || np == sp.buf)
|
if (!np)
|
||||||
goto free_and_fail2;
|
goto free_and_fail2;
|
||||||
np++;
|
|
||||||
|
|
||||||
len = sp.buf + sp.len - np;
|
len = sp.buf + sp.len - np;
|
||||||
if (len < second - name &&
|
if (len < second - name &&
|
||||||
|
@ -1231,16 +1235,30 @@ static char *git_header_name(const char *line, int llen)
|
||||||
case '\n':
|
case '\n':
|
||||||
return NULL;
|
return NULL;
|
||||||
case '\t': case ' ':
|
case '\t': case ' ':
|
||||||
second = stop_at_slash(name + len, line_len - len);
|
/*
|
||||||
|
* Is this the separator between the preimage
|
||||||
|
* and the postimage pathname? Again, we are
|
||||||
|
* only interested in the case where there is
|
||||||
|
* no rename, as this is only to set def_name
|
||||||
|
* and a rename patch has the names elsewhere
|
||||||
|
* in an unambiguous form.
|
||||||
|
*/
|
||||||
|
if (!name[len + 1])
|
||||||
|
return NULL; /* no postimage name */
|
||||||
|
second = skip_tree_prefix(name + len + 1,
|
||||||
|
line_len - (len + 1));
|
||||||
if (!second)
|
if (!second)
|
||||||
return NULL;
|
return NULL;
|
||||||
second++;
|
/*
|
||||||
if (second[len] == '\n' && !strncmp(name, second, len)) {
|
* Does len bytes starting at "name" and "second"
|
||||||
|
* (that are separated by one HT or SP we just
|
||||||
|
* found) exactly match?
|
||||||
|
*/
|
||||||
|
if (second[len] == '\n' && !strncmp(name, second, len))
|
||||||
return xmemdupz(name, len);
|
return xmemdupz(name, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify that we recognize the lines following a git header */
|
/* Verify that we recognize the lines following a git header */
|
||||||
static int parse_git_header(const char *line, int len, unsigned int size, struct patch *patch)
|
static int parse_git_header(const char *line, int len, unsigned int size, struct patch *patch)
|
||||||
|
|
|
@ -962,7 +962,9 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
|
||||||
if (!arg) /* should --no-sort void the list ? */
|
if (!arg) /* should --no-sort void the list ? */
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
*sort_tail = s = xcalloc(1, sizeof(*s));
|
s = xcalloc(1, sizeof(*s));
|
||||||
|
s->next = *sort_tail;
|
||||||
|
*sort_tail = s;
|
||||||
|
|
||||||
if (*arg == '-') {
|
if (*arg == '-') {
|
||||||
s->reverse = 1;
|
s->reverse = 1;
|
||||||
|
|
|
@ -230,6 +230,7 @@ static int try_difference(const char *arg)
|
||||||
const char *next;
|
const char *next;
|
||||||
const char *this;
|
const char *this;
|
||||||
int symmetric;
|
int symmetric;
|
||||||
|
static const char head_by_default[] = "HEAD";
|
||||||
|
|
||||||
if (!(dotdot = strstr(arg, "..")))
|
if (!(dotdot = strstr(arg, "..")))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -241,9 +242,20 @@ static int try_difference(const char *arg)
|
||||||
next += symmetric;
|
next += symmetric;
|
||||||
|
|
||||||
if (!*next)
|
if (!*next)
|
||||||
next = "HEAD";
|
next = head_by_default;
|
||||||
if (dotdot == arg)
|
if (dotdot == arg)
|
||||||
this = "HEAD";
|
this = head_by_default;
|
||||||
|
|
||||||
|
if (this == head_by_default && next == head_by_default &&
|
||||||
|
!symmetric) {
|
||||||
|
/*
|
||||||
|
* Just ".."? That is not a range but the
|
||||||
|
* pathspec for the parent directory.
|
||||||
|
*/
|
||||||
|
*dotdot = '.';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) {
|
if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) {
|
||||||
show_rev(NORMAL, end, next);
|
show_rev(NORMAL, end, next);
|
||||||
show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
|
show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
|
||||||
|
|
55
http.c
55
http.c
|
@ -745,6 +745,35 @@ char *get_remote_object_url(const char *url, const char *hex,
|
||||||
return strbuf_detach(&buf, NULL);
|
return strbuf_detach(&buf, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int handle_curl_result(struct active_request_slot *slot)
|
||||||
|
{
|
||||||
|
struct slot_results *results = slot->results;
|
||||||
|
|
||||||
|
if (results->curl_result == CURLE_OK) {
|
||||||
|
credential_approve(&http_auth);
|
||||||
|
return HTTP_OK;
|
||||||
|
} else if (missing_target(results))
|
||||||
|
return HTTP_MISSING_TARGET;
|
||||||
|
else if (results->http_code == 401) {
|
||||||
|
if (http_auth.username && http_auth.password) {
|
||||||
|
credential_reject(&http_auth);
|
||||||
|
return HTTP_NOAUTH;
|
||||||
|
} else {
|
||||||
|
credential_fill(&http_auth);
|
||||||
|
init_curl_http_auth(slot->curl);
|
||||||
|
return HTTP_REAUTH;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#if LIBCURL_VERSION_NUM >= 0x070c00
|
||||||
|
if (!curl_errorstr[0])
|
||||||
|
strlcpy(curl_errorstr,
|
||||||
|
curl_easy_strerror(results->curl_result),
|
||||||
|
sizeof(curl_errorstr));
|
||||||
|
#endif
|
||||||
|
return HTTP_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* http_request() targets */
|
/* http_request() targets */
|
||||||
#define HTTP_REQUEST_STRBUF 0
|
#define HTTP_REQUEST_STRBUF 0
|
||||||
#define HTTP_REQUEST_FILE 1
|
#define HTTP_REQUEST_FILE 1
|
||||||
|
@ -792,28 +821,7 @@ static int http_request(const char *url, void *result, int target, int options)
|
||||||
|
|
||||||
if (start_active_slot(slot)) {
|
if (start_active_slot(slot)) {
|
||||||
run_active_slot(slot);
|
run_active_slot(slot);
|
||||||
if (results.curl_result == CURLE_OK)
|
ret = handle_curl_result(slot);
|
||||||
ret = HTTP_OK;
|
|
||||||
else if (missing_target(&results))
|
|
||||||
ret = HTTP_MISSING_TARGET;
|
|
||||||
else if (results.http_code == 401) {
|
|
||||||
if (http_auth.username && http_auth.password) {
|
|
||||||
credential_reject(&http_auth);
|
|
||||||
ret = HTTP_NOAUTH;
|
|
||||||
} else {
|
|
||||||
credential_fill(&http_auth);
|
|
||||||
init_curl_http_auth(slot->curl);
|
|
||||||
ret = HTTP_REAUTH;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#if LIBCURL_VERSION_NUM >= 0x070c00
|
|
||||||
if (!curl_errorstr[0])
|
|
||||||
strlcpy(curl_errorstr,
|
|
||||||
curl_easy_strerror(results.curl_result),
|
|
||||||
sizeof(curl_errorstr));
|
|
||||||
#endif
|
|
||||||
ret = HTTP_ERROR;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
error("Unable to start HTTP request for %s", url);
|
error("Unable to start HTTP request for %s", url);
|
||||||
ret = HTTP_START_FAILED;
|
ret = HTTP_START_FAILED;
|
||||||
|
@ -822,9 +830,6 @@ static int http_request(const char *url, void *result, int target, int options)
|
||||||
curl_slist_free_all(headers);
|
curl_slist_free_all(headers);
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
|
|
||||||
if (ret == HTTP_OK)
|
|
||||||
credential_approve(&http_auth);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
http.h
1
http.h
|
@ -78,6 +78,7 @@ extern int start_active_slot(struct active_request_slot *slot);
|
||||||
extern void run_active_slot(struct active_request_slot *slot);
|
extern void run_active_slot(struct active_request_slot *slot);
|
||||||
extern void finish_active_slot(struct active_request_slot *slot);
|
extern void finish_active_slot(struct active_request_slot *slot);
|
||||||
extern void finish_all_active_slots(void);
|
extern void finish_all_active_slots(void);
|
||||||
|
extern int handle_curl_result(struct active_request_slot *slot);
|
||||||
|
|
||||||
#ifdef USE_CURL_MULTI
|
#ifdef USE_CURL_MULTI
|
||||||
extern void fill_active_slots(void);
|
extern void fill_active_slots(void);
|
||||||
|
|
|
@ -362,15 +362,16 @@ static size_t rpc_in(char *ptr, size_t eltsize,
|
||||||
|
|
||||||
static int run_slot(struct active_request_slot *slot)
|
static int run_slot(struct active_request_slot *slot)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err;
|
||||||
struct slot_results results;
|
struct slot_results results;
|
||||||
|
|
||||||
slot->results = &results;
|
slot->results = &results;
|
||||||
slot->curl_result = curl_easy_perform(slot->curl);
|
slot->curl_result = curl_easy_perform(slot->curl);
|
||||||
finish_active_slot(slot);
|
finish_active_slot(slot);
|
||||||
|
|
||||||
if (results.curl_result != CURLE_OK) {
|
err = handle_curl_result(slot);
|
||||||
err |= error("RPC failed; result=%d, HTTP code = %ld",
|
if (err != HTTP_OK && err != HTTP_REAUTH) {
|
||||||
|
error("RPC failed; result=%d, HTTP code = %ld",
|
||||||
results.curl_result, results.http_code);
|
results.curl_result, results.http_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -436,9 +437,11 @@ static int post_rpc(struct rpc_state *rpc)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (large_request) {
|
if (large_request) {
|
||||||
|
do {
|
||||||
err = probe_rpc(rpc);
|
err = probe_rpc(rpc);
|
||||||
if (err)
|
} while (err == HTTP_REAUTH);
|
||||||
return err;
|
if (err != HTTP_OK)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
slot = get_active_slot();
|
slot = get_active_slot();
|
||||||
|
@ -525,7 +528,11 @@ static int post_rpc(struct rpc_state *rpc)
|
||||||
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
|
curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
|
||||||
curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
|
curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
|
||||||
|
|
||||||
|
do {
|
||||||
err = run_slot(slot);
|
err = run_slot(slot);
|
||||||
|
} while (err == HTTP_REAUTH && !large_request && !use_gzip);
|
||||||
|
if (err != HTTP_OK)
|
||||||
|
err = -1;
|
||||||
|
|
||||||
curl_slist_free_all(headers);
|
curl_slist_free_all(headers);
|
||||||
free(gzip_body);
|
free(gzip_body);
|
||||||
|
|
16
revision.c
16
revision.c
|
@ -1134,15 +1134,27 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
|
||||||
const char *this = arg;
|
const char *this = arg;
|
||||||
int symmetric = *next == '.';
|
int symmetric = *next == '.';
|
||||||
unsigned int flags_exclude = flags ^ UNINTERESTING;
|
unsigned int flags_exclude = flags ^ UNINTERESTING;
|
||||||
|
static const char head_by_default[] = "HEAD";
|
||||||
unsigned int a_flags;
|
unsigned int a_flags;
|
||||||
|
|
||||||
*dotdot = 0;
|
*dotdot = 0;
|
||||||
next += symmetric;
|
next += symmetric;
|
||||||
|
|
||||||
if (!*next)
|
if (!*next)
|
||||||
next = "HEAD";
|
next = head_by_default;
|
||||||
if (dotdot == arg)
|
if (dotdot == arg)
|
||||||
this = "HEAD";
|
this = head_by_default;
|
||||||
|
if (this == head_by_default && next == head_by_default &&
|
||||||
|
!symmetric) {
|
||||||
|
/*
|
||||||
|
* Just ".."? That is not a range but the
|
||||||
|
* pathspec for the parent directory.
|
||||||
|
*/
|
||||||
|
if (!cant_be_filename) {
|
||||||
|
*dotdot = '.';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!get_sha1_committish(this, from_sha1) &&
|
if (!get_sha1_committish(this, from_sha1) &&
|
||||||
!get_sha1_committish(next, sha1)) {
|
!get_sha1_committish(next, sha1)) {
|
||||||
struct commit *a, *b;
|
struct commit *a, *b;
|
||||||
|
|
|
@ -167,3 +167,42 @@ test_http_push_nonff() {
|
||||||
test_i18ngrep "Updates were rejected because" output
|
test_i18ngrep "Updates were rejected because" output
|
||||||
'
|
'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setup_askpass_helper() {
|
||||||
|
test_expect_success 'setup askpass helper' '
|
||||||
|
write_script "$TRASH_DIRECTORY/askpass" <<-\EOF &&
|
||||||
|
echo >>"$TRASH_DIRECTORY/askpass-query" "askpass: $*" &&
|
||||||
|
cat "$TRASH_DIRECTORY/askpass-response"
|
||||||
|
EOF
|
||||||
|
GIT_ASKPASS="$TRASH_DIRECTORY/askpass" &&
|
||||||
|
export GIT_ASKPASS &&
|
||||||
|
export TRASH_DIRECTORY
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
set_askpass() {
|
||||||
|
>"$TRASH_DIRECTORY/askpass-query" &&
|
||||||
|
echo "$*" >"$TRASH_DIRECTORY/askpass-response"
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_askpass() {
|
||||||
|
dest=$HTTPD_DEST
|
||||||
|
{
|
||||||
|
case "$1" in
|
||||||
|
none)
|
||||||
|
;;
|
||||||
|
pass)
|
||||||
|
echo "askpass: Password for 'http://$2@$dest': "
|
||||||
|
;;
|
||||||
|
both)
|
||||||
|
echo "askpass: Username for 'http://$dest': "
|
||||||
|
echo "askpass: Password for 'http://$2@$dest': "
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
false
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
} >"$TRASH_DIRECTORY/askpass-expect" &&
|
||||||
|
test_cmp "$TRASH_DIRECTORY/askpass-expect" \
|
||||||
|
"$TRASH_DIRECTORY/askpass-query"
|
||||||
|
}
|
||||||
|
|
|
@ -46,24 +46,22 @@ PassEnv GIT_VALGRIND
|
||||||
PassEnv GIT_VALGRIND_OPTIONS
|
PassEnv GIT_VALGRIND_OPTIONS
|
||||||
|
|
||||||
Alias /dumb/ www/
|
Alias /dumb/ www/
|
||||||
Alias /auth/ www/auth/
|
Alias /auth/dumb/ www/auth/dumb/
|
||||||
|
|
||||||
<Location /smart/>
|
<LocationMatch /smart/>
|
||||||
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
|
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
|
||||||
SetEnv GIT_HTTP_EXPORT_ALL
|
SetEnv GIT_HTTP_EXPORT_ALL
|
||||||
</Location>
|
</LocationMatch>
|
||||||
<Location /smart_noexport/>
|
<LocationMatch /smart_noexport/>
|
||||||
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
|
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
|
||||||
</Location>
|
</LocationMatch>
|
||||||
<Location /smart_custom_env/>
|
<LocationMatch /smart_custom_env/>
|
||||||
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
|
SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
|
||||||
SetEnv GIT_HTTP_EXPORT_ALL
|
SetEnv GIT_HTTP_EXPORT_ALL
|
||||||
SetEnv GIT_COMMITTER_NAME "Custom User"
|
SetEnv GIT_COMMITTER_NAME "Custom User"
|
||||||
SetEnv GIT_COMMITTER_EMAIL custom@example.com
|
SetEnv GIT_COMMITTER_EMAIL custom@example.com
|
||||||
</Location>
|
</LocationMatch>
|
||||||
ScriptAlias /smart/ ${GIT_EXEC_PATH}/git-http-backend/
|
ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
|
||||||
ScriptAlias /smart_noexport/ ${GIT_EXEC_PATH}/git-http-backend/
|
|
||||||
ScriptAlias /smart_custom_env/ ${GIT_EXEC_PATH}/git-http-backend/
|
|
||||||
<Directory ${GIT_EXEC_PATH}>
|
<Directory ${GIT_EXEC_PATH}>
|
||||||
Options FollowSymlinks
|
Options FollowSymlinks
|
||||||
</Directory>
|
</Directory>
|
||||||
|
@ -94,6 +92,13 @@ SSLEngine On
|
||||||
Require valid-user
|
Require valid-user
|
||||||
</Location>
|
</Location>
|
||||||
|
|
||||||
|
<LocationMatch "^/auth-push/.*/git-receive-pack$">
|
||||||
|
AuthType Basic
|
||||||
|
AuthName "git-auth"
|
||||||
|
AuthUserFile passwd
|
||||||
|
Require valid-user
|
||||||
|
</LocationMatch>
|
||||||
|
|
||||||
<IfDefine DAV>
|
<IfDefine DAV>
|
||||||
LoadModule dav_module modules/mod_dav.so
|
LoadModule dav_module modules/mod_dav.so
|
||||||
LoadModule dav_fs_module modules/mod_dav_fs.so
|
LoadModule dav_fs_module modules/mod_dav_fs.so
|
||||||
|
|
|
@ -182,4 +182,18 @@ test_expect_success '<commit>:file correctly diagnosed after a pathname' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'dotdot is not an empty set' '
|
||||||
|
( H=$(git rev-parse HEAD) && echo $H && echo ^$H ) >expect &&
|
||||||
|
|
||||||
|
git rev-parse HEAD.. >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
git rev-parse ..HEAD >actual &&
|
||||||
|
test_cmp expect actual &&
|
||||||
|
|
||||||
|
echo .. >expect &&
|
||||||
|
git rev-parse .. >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
|
@ -8,30 +8,28 @@ test_description='git apply handling binary patches
|
||||||
'
|
'
|
||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
# setup
|
test_expect_success 'setup' '
|
||||||
|
cat >file1 <<-\EOF &&
|
||||||
cat >file1 <<EOF
|
|
||||||
A quick brown fox jumps over the lazy dog.
|
A quick brown fox jumps over the lazy dog.
|
||||||
A tiny little penguin runs around in circles.
|
A tiny little penguin runs around in circles.
|
||||||
There is a flag with Linux written on it.
|
There is a flag with Linux written on it.
|
||||||
A slow black-and-white panda just sits there,
|
A slow black-and-white panda just sits there,
|
||||||
munching on his bamboo.
|
munching on his bamboo.
|
||||||
EOF
|
EOF
|
||||||
cat file1 >file2
|
cat file1 >file2 &&
|
||||||
cat file1 >file4
|
cat file1 >file4 &&
|
||||||
|
|
||||||
test_expect_success 'setup' "
|
|
||||||
git update-index --add --remove file1 file2 file4 &&
|
git update-index --add --remove file1 file2 file4 &&
|
||||||
git commit -m 'Initial Version' 2>/dev/null &&
|
git commit -m "Initial Version" 2>/dev/null &&
|
||||||
|
|
||||||
git checkout -b binary &&
|
git checkout -b binary &&
|
||||||
"$PERL_PATH" -pe 'y/x/\000/' <file1 >file3 &&
|
"$PERL_PATH" -pe "y/x/\000/" <file1 >file3 &&
|
||||||
cat file3 >file4 &&
|
cat file3 >file4 &&
|
||||||
git add file2 &&
|
git add file2 &&
|
||||||
"$PERL_PATH" -pe 'y/\000/v/' <file3 >file1 &&
|
"$PERL_PATH" -pe "y/\000/v/" <file3 >file1 &&
|
||||||
rm -f file2 &&
|
rm -f file2 &&
|
||||||
git update-index --add --remove file1 file2 file3 file4 &&
|
git update-index --add --remove file1 file2 file3 file4 &&
|
||||||
git commit -m 'Second Version' &&
|
git commit -m "Second Version" &&
|
||||||
|
|
||||||
git diff-tree -p master binary >B.diff &&
|
git diff-tree -p master binary >B.diff &&
|
||||||
git diff-tree -p -C master binary >C.diff &&
|
git diff-tree -p -C master binary >C.diff &&
|
||||||
|
@ -42,17 +40,25 @@ test_expect_success 'setup' "
|
||||||
git diff-tree -p --full-index master binary >B-index.diff &&
|
git diff-tree -p --full-index master binary >B-index.diff &&
|
||||||
git diff-tree -p -C --full-index master binary >C-index.diff &&
|
git diff-tree -p -C --full-index master binary >C-index.diff &&
|
||||||
|
|
||||||
|
git diff-tree -p --binary --no-prefix master binary -- file3 >B0.diff &&
|
||||||
|
|
||||||
git init other-repo &&
|
git init other-repo &&
|
||||||
(cd other-repo &&
|
(
|
||||||
|
cd other-repo &&
|
||||||
git fetch .. master &&
|
git fetch .. master &&
|
||||||
git reset --hard FETCH_HEAD
|
git reset --hard FETCH_HEAD
|
||||||
)
|
)
|
||||||
"
|
'
|
||||||
|
|
||||||
test_expect_success 'stat binary diff -- should not fail.' \
|
test_expect_success 'stat binary diff -- should not fail.' \
|
||||||
'git checkout master &&
|
'git checkout master &&
|
||||||
git apply --stat --summary B.diff'
|
git apply --stat --summary B.diff'
|
||||||
|
|
||||||
|
test_expect_success 'stat binary -p0 diff -- should not fail.' '
|
||||||
|
git checkout master &&
|
||||||
|
git apply --stat -p0 B0.diff
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'stat binary diff (copy) -- should not fail.' \
|
test_expect_success 'stat binary diff (copy) -- should not fail.' \
|
||||||
'git checkout master &&
|
'git checkout master &&
|
||||||
git apply --stat --summary C.diff'
|
git apply --stat --summary C.diff'
|
||||||
|
@ -143,4 +149,10 @@ test_expect_success 'apply binary diff (copy).' \
|
||||||
git apply --allow-binary-replacement --index CF.diff &&
|
git apply --allow-binary-replacement --index CF.diff &&
|
||||||
test -z "$(git diff --name-status binary)"'
|
test -z "$(git diff --name-status binary)"'
|
||||||
|
|
||||||
|
test_expect_success 'apply binary -p0 diff' '
|
||||||
|
do_reset &&
|
||||||
|
git apply -p0 --index B0.diff &&
|
||||||
|
test -z "$(git diff --name-status binary -- file3)"
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
|
@ -806,4 +806,11 @@ test_expect_success 'log --graph with diff and stats' '
|
||||||
test_cmp expect actual.sanitized
|
test_cmp expect actual.sanitized
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'dotdot is a parent directory' '
|
||||||
|
mkdir -p a/b &&
|
||||||
|
( echo sixth && echo fifth ) >expect &&
|
||||||
|
( cd a/b && git log --format=%s .. ) >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
|
|
@ -46,15 +46,7 @@ test_expect_success 'create password-protected repository' '
|
||||||
"$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git"
|
"$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git"
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'setup askpass helper' '
|
setup_askpass_helper
|
||||||
cat >askpass <<-\EOF &&
|
|
||||||
#!/bin/sh
|
|
||||||
echo user@host
|
|
||||||
EOF
|
|
||||||
chmod +x askpass &&
|
|
||||||
GIT_ASKPASS="$PWD/askpass" &&
|
|
||||||
export GIT_ASKPASS
|
|
||||||
'
|
|
||||||
|
|
||||||
test_expect_success 'clone remote repository' '
|
test_expect_success 'clone remote repository' '
|
||||||
cd "$ROOT_PATH" &&
|
cd "$ROOT_PATH" &&
|
||||||
|
@ -162,6 +154,7 @@ test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \
|
||||||
|
|
||||||
test_expect_success 'push to password-protected repository (user in URL)' '
|
test_expect_success 'push to password-protected repository (user in URL)' '
|
||||||
test_commit pw-user &&
|
test_commit pw-user &&
|
||||||
|
set_askpass user@host &&
|
||||||
git push "$HTTPD_URL_USER/auth/dumb/test_repo.git" HEAD &&
|
git push "$HTTPD_URL_USER/auth/dumb/test_repo.git" HEAD &&
|
||||||
git rev-parse --verify HEAD >expect &&
|
git rev-parse --verify HEAD >expect &&
|
||||||
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
|
||||||
|
@ -169,9 +162,15 @@ test_expect_success 'push to password-protected repository (user in URL)' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_failure 'user was prompted only once for password' '
|
||||||
|
expect_askpass pass user@host
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_failure 'push to password-protected repository (no user in URL)' '
|
test_expect_failure 'push to password-protected repository (no user in URL)' '
|
||||||
test_commit pw-nouser &&
|
test_commit pw-nouser &&
|
||||||
|
set_askpass user@host &&
|
||||||
git push "$HTTPD_URL/auth/dumb/test_repo.git" HEAD &&
|
git push "$HTTPD_URL/auth/dumb/test_repo.git" HEAD &&
|
||||||
|
expect_askpass both user@host
|
||||||
git rev-parse --verify HEAD >expect &&
|
git rev-parse --verify HEAD >expect &&
|
||||||
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
|
||||||
rev-parse --verify HEAD >actual &&
|
rev-parse --verify HEAD >actual &&
|
||||||
|
|
|
@ -36,6 +36,8 @@ test_expect_success 'setup remote repository' '
|
||||||
mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
|
mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
|
||||||
'
|
'
|
||||||
|
|
||||||
|
setup_askpass_helper
|
||||||
|
|
||||||
cat >exp <<EOF
|
cat >exp <<EOF
|
||||||
GET /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
|
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
|
POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200
|
||||||
|
@ -266,5 +268,29 @@ test_expect_success 'http push respects GIT_COMMITTER_* in reflog' '
|
||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'push over smart http with auth' '
|
||||||
|
cd "$ROOT_PATH/test_repo_clone" &&
|
||||||
|
echo push-auth-test >expect &&
|
||||||
|
test_commit push-auth-test &&
|
||||||
|
set_askpass user@host &&
|
||||||
|
git push "$HTTPD_URL"/auth/smart/test_repo.git &&
|
||||||
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
|
||||||
|
log -1 --format=%s >actual &&
|
||||||
|
expect_askpass both user@host &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'push to auth-only-for-push repo' '
|
||||||
|
cd "$ROOT_PATH/test_repo_clone" &&
|
||||||
|
echo push-half-auth >expect &&
|
||||||
|
test_commit push-half-auth &&
|
||||||
|
set_askpass user@host &&
|
||||||
|
git push "$HTTPD_URL"/auth-push/smart/test_repo.git &&
|
||||||
|
git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
|
||||||
|
log -1 --format=%s >actual &&
|
||||||
|
expect_askpass both user@host &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
stop_httpd
|
stop_httpd
|
||||||
test_done
|
test_done
|
||||||
|
|
|
@ -41,68 +41,34 @@ test_expect_success 'clone http repository' '
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'create password-protected repository' '
|
test_expect_success 'create password-protected repository' '
|
||||||
mkdir "$HTTPD_DOCUMENT_ROOT_PATH/auth/" &&
|
mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/" &&
|
||||||
cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
|
cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
|
||||||
"$HTTPD_DOCUMENT_ROOT_PATH/auth/repo.git"
|
"$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/repo.git"
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'setup askpass helpers' '
|
setup_askpass_helper
|
||||||
cat >askpass <<-EOF &&
|
|
||||||
#!/bin/sh
|
|
||||||
echo >>"$PWD/askpass-query" "askpass: \$*" &&
|
|
||||||
cat "$PWD/askpass-response"
|
|
||||||
EOF
|
|
||||||
chmod +x askpass &&
|
|
||||||
GIT_ASKPASS="$PWD/askpass" &&
|
|
||||||
export GIT_ASKPASS
|
|
||||||
'
|
|
||||||
|
|
||||||
expect_askpass() {
|
|
||||||
dest=$HTTPD_DEST
|
|
||||||
{
|
|
||||||
case "$1" in
|
|
||||||
none)
|
|
||||||
;;
|
|
||||||
pass)
|
|
||||||
echo "askpass: Password for 'http://$2@$dest': "
|
|
||||||
;;
|
|
||||||
both)
|
|
||||||
echo "askpass: Username for 'http://$dest': "
|
|
||||||
echo "askpass: Password for 'http://$2@$dest': "
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
false
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
} >askpass-expect &&
|
|
||||||
test_cmp askpass-expect askpass-query
|
|
||||||
}
|
|
||||||
|
|
||||||
test_expect_success 'cloning password-protected repository can fail' '
|
test_expect_success 'cloning password-protected repository can fail' '
|
||||||
>askpass-query &&
|
set_askpass wrong &&
|
||||||
echo wrong >askpass-response &&
|
test_must_fail git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-fail &&
|
||||||
test_must_fail git clone "$HTTPD_URL/auth/repo.git" clone-auth-fail &&
|
|
||||||
expect_askpass both wrong
|
expect_askpass both wrong
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'http auth can use user/pass in URL' '
|
test_expect_success 'http auth can use user/pass in URL' '
|
||||||
>askpass-query &&
|
set_askpass wrong &&
|
||||||
echo wrong >askpass-response &&
|
git clone "$HTTPD_URL_USER_PASS/auth/dumb/repo.git" clone-auth-none &&
|
||||||
git clone "$HTTPD_URL_USER_PASS/auth/repo.git" clone-auth-none &&
|
|
||||||
expect_askpass none
|
expect_askpass none
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'http auth can use just user in URL' '
|
test_expect_success 'http auth can use just user in URL' '
|
||||||
>askpass-query &&
|
set_askpass user@host &&
|
||||||
echo user@host >askpass-response &&
|
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-pass &&
|
||||||
git clone "$HTTPD_URL_USER/auth/repo.git" clone-auth-pass &&
|
|
||||||
expect_askpass pass user@host
|
expect_askpass pass user@host
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'http auth can request both user and pass' '
|
test_expect_success 'http auth can request both user and pass' '
|
||||||
>askpass-query &&
|
set_askpass user@host &&
|
||||||
echo user@host >askpass-response &&
|
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-both &&
|
||||||
git clone "$HTTPD_URL/auth/repo.git" clone-auth-both &&
|
|
||||||
expect_askpass both user@host
|
expect_askpass both user@host
|
||||||
'
|
'
|
||||||
|
|
||||||
|
@ -112,25 +78,22 @@ test_expect_success 'http auth respects credential helper config' '
|
||||||
echo username=user@host
|
echo username=user@host
|
||||||
echo password=user@host
|
echo password=user@host
|
||||||
}; f" &&
|
}; f" &&
|
||||||
>askpass-query &&
|
set_askpass wrong &&
|
||||||
echo wrong >askpass-response &&
|
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-helper &&
|
||||||
git clone "$HTTPD_URL/auth/repo.git" clone-auth-helper &&
|
|
||||||
expect_askpass none
|
expect_askpass none
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'http auth can get username from config' '
|
test_expect_success 'http auth can get username from config' '
|
||||||
test_config_global "credential.$HTTPD_URL.username" user@host &&
|
test_config_global "credential.$HTTPD_URL.username" user@host &&
|
||||||
>askpass-query &&
|
set_askpass user@host &&
|
||||||
echo user@host >askpass-response &&
|
git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-user &&
|
||||||
git clone "$HTTPD_URL/auth/repo.git" clone-auth-user &&
|
|
||||||
expect_askpass pass user@host
|
expect_askpass pass user@host
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'configured username does not override URL' '
|
test_expect_success 'configured username does not override URL' '
|
||||||
test_config_global "credential.$HTTPD_URL.username" wrong &&
|
test_config_global "credential.$HTTPD_URL.username" wrong &&
|
||||||
>askpass-query &&
|
set_askpass user@host &&
|
||||||
echo user@host >askpass-response &&
|
git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-user2 &&
|
||||||
git clone "$HTTPD_URL_USER/auth/repo.git" clone-auth-user2 &&
|
|
||||||
expect_askpass pass user@host
|
expect_askpass pass user@host
|
||||||
'
|
'
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ test_expect_success 'create http-accessible bare repository' '
|
||||||
git push public master:master
|
git push public master:master
|
||||||
'
|
'
|
||||||
|
|
||||||
|
setup_askpass_helper
|
||||||
|
|
||||||
cat >exp <<EOF
|
cat >exp <<EOF
|
||||||
> GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1
|
> GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1
|
||||||
> Accept: */*
|
> Accept: */*
|
||||||
|
@ -109,6 +111,24 @@ test_expect_success 'follow redirects (302)' '
|
||||||
git clone $HTTPD_URL/smart-redir-temp/repo.git --quiet repo-t
|
git clone $HTTPD_URL/smart-redir-temp/repo.git --quiet repo-t
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'clone from password-protected repository' '
|
||||||
|
echo two >expect &&
|
||||||
|
set_askpass user@host &&
|
||||||
|
git clone --bare "$HTTPD_URL/auth/smart/repo.git" smart-auth &&
|
||||||
|
expect_askpass both user@host &&
|
||||||
|
git --git-dir=smart-auth log -1 --format=%s >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'clone from auth-only-for-push repository' '
|
||||||
|
echo two >expect &&
|
||||||
|
set_askpass wrong &&
|
||||||
|
git clone --bare "$HTTPD_URL/auth-push/smart/repo.git" smart-noauth &&
|
||||||
|
expect_askpass none &&
|
||||||
|
git --git-dir=smart-noauth log -1 --format=%s >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
|
test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
|
||||||
|
|
||||||
test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
|
test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
|
||||||
|
|
|
@ -456,4 +456,14 @@ test_atom refs/tags/signed-long contents "subject line
|
||||||
body contents
|
body contents
|
||||||
$sig"
|
$sig"
|
||||||
|
|
||||||
|
cat >expected <<\EOF
|
||||||
|
408fe76d02a785a006c2e9c669b7be5589ede96d <committer@example.com> refs/tags/master
|
||||||
|
90b5ebede4899eda64893bc2a4c8f1d6fb6dfc40 <committer@example.com> refs/tags/bogo
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'Verify sort with multiple keys' '
|
||||||
|
git for-each-ref --format="%(objectname) %(taggeremail) %(refname)" --sort=objectname --sort=taggeremail \
|
||||||
|
refs/tags/bogo refs/tags/master > actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
test_done
|
test_done
|
||||||
|
|
Loading…
Reference in a new issue