From: Junio C Hamano Date: Mon, 28 Sep 2015 22:33:56 +0000 (-0700) Subject: Sync with 2.4.10 X-Git-Tag: v2.5.4~1 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/11a458befcd7662fbe6d2d53c76d49ae2b0fe219?ds=inline;hp=-c Sync with 2.4.10 --- 11a458befcd7662fbe6d2d53c76d49ae2b0fe219 diff --combined Documentation/git.txt index 2b39aa9f51,a405e4f2e7..b2d88688aa --- a/Documentation/git.txt +++ b/Documentation/git.txt @@@ -43,17 -43,10 +43,18 @@@ unreleased) version of Git, that is ava branch of the `git.git` repository. Documentation for older releases are available here: +* link:v2.5.3/git.html[documentation for release 2.5.3] + +* release notes for + link:RelNotes/2.5.3.txt[2.5.3], + link:RelNotes/2.5.2.txt[2.5.2], + link:RelNotes/2.5.1.txt[2.5.1], + link:RelNotes/2.5.0.txt[2.5]. + - * link:v2.4.9/git.html[documentation for release 2.4.9] + * link:v2.4.10/git.html[documentation for release 2.4.10] * release notes for + link:RelNotes/2.4.10.txt[2.4.10], link:RelNotes/2.4.9.txt[2.4.9], link:RelNotes/2.4.8.txt[2.4.8], link:RelNotes/2.4.7.txt[2.4.7], @@@ -65,9 -58,10 +66,10 @@@ link:RelNotes/2.4.1.txt[2.4.1], link:RelNotes/2.4.0.txt[2.4]. - * link:v2.3.9/git.html[documentation for release 2.3.9] + * link:v2.3.10/git.html[documentation for release 2.3.10] * release notes for + link:RelNotes/2.3.10.txt[2.3.10], link:RelNotes/2.3.9.txt[2.3.9], link:RelNotes/2.3.8.txt[2.3.8], link:RelNotes/2.3.7.txt[2.3.7], @@@ -787,7 -781,7 +789,7 @@@ The Git Repositor ~~~~~~~~~~~~~~~~~~ These environment variables apply to 'all' core Git commands. Nb: it is worth noting that they may be used/overridden by SCMS sitting above -Git so take care if using Cogito etc. +Git so take care if using a foreign front-end. 'GIT_INDEX_FILE':: This environment allows the specification of an alternate @@@ -853,15 -847,6 +855,15 @@@ an explicit repository directory set via 'GIT_DIR' or on the command line. +'GIT_COMMON_DIR':: + If this variable is set to a path, non-worktree files that are + normally in $GIT_DIR will be taken from this path + instead. Worktree-specific files such as HEAD or index are + taken from $GIT_DIR. See linkgit:gitrepository-layout[5] and + linkgit:git-worktree[1] for + details. This variable has lower precedence than other path + variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY... + Git Commits ~~~~~~~~~~~ 'GIT_AUTHOR_NAME':: @@@ -1076,6 -1061,33 +1078,33 @@@ GIT_ICASE_PATHSPECS: an operation has touched every ref (e.g., because you are cloning a repository to make a backup). + `GIT_ALLOW_PROTOCOL`:: + If set, provide a colon-separated list of protocols which are + allowed to be used with fetch/push/clone. This is useful to + restrict recursive submodule initialization from an untrusted + repository. Any protocol not mentioned will be disallowed (i.e., + this is a whitelist, not a blacklist). If the variable is not + set at all, all protocols are enabled. The protocol names + currently used by git are: + + - `file`: any local file-based path (including `file://` URLs, + or local paths) + + - `git`: the anonymous git protocol over a direct TCP + connection (or proxy, if configured) + + - `ssh`: git over ssh (including `host:path` syntax, + `git+ssh://`, etc). + + - `rsync`: git over rsync + + - `http`: git over http, both "smart http" and "dumb http". + Note that this does _not_ include `https`; if you want both, + you should specify both as `http:https`. + + - any external helpers are named by their protocol (e.g., use + `hg` to allow the `git-remote-hg` helper) + Discussion[[Discussion]] ------------------------ diff --combined builtin/blame.c index a22ac17407,048ed53c2f..191368bfab --- a/builtin/blame.c +++ b/builtin/blame.c @@@ -973,7 -973,10 +973,10 @@@ static void pass_blame_to_parent(struc fill_origin_blob(&sb->revs->diffopt, target, &file_o); num_get_patch++; - diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d); + if (diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d)) + die("unable to generate diff (%s -> %s)", + sha1_to_hex(parent->commit->object.sha1), + sha1_to_hex(target->commit->object.sha1)); /* The rest are the same as the parent */ blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent); *d.dstq = NULL; @@@ -1119,7 -1122,9 +1122,9 @@@ static void find_copy_in_blob(struct sc * file_p partially may match that image. */ memset(split, 0, sizeof(struct blame_entry [3])); - diff_hunks(file_p, &file_o, 1, handle_split_cb, &d); + if (diff_hunks(file_p, &file_o, 1, handle_split_cb, &d)) + die("unable to generate diff (%s)", + sha1_to_hex(parent->commit->object.sha1)); /* remainder, if any, all match the preimage */ handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split); } @@@ -2176,14 -2181,6 +2181,14 @@@ static int git_blame_config(const char blank_boundary = git_config_bool(var, value); return 0; } + if (!strcmp(var, "blame.showemail")) { + int *output_option = cb; + if (git_config_bool(var, value)) + *output_option |= OUTPUT_SHOW_EMAIL; + else + *output_option &= ~OUTPUT_SHOW_EMAIL; + return 0; + } if (!strcmp(var, "blame.date")) { if (!value) return config_error_nonbool(var); @@@ -2528,7 -2525,7 +2533,7 @@@ int cmd_blame(int argc, const char **ar unsigned int range_i; long anchor; - git_config(git_blame_config, NULL); + git_config(git_blame_config, &output_option); init_revisions(&revs, NULL); revs.date_mode = blame_date_mode; DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV); diff --combined combine-diff.c index 30c7eb6d3c,5cae5fbd62..0f62f54b5e --- a/combine-diff.c +++ b/combine-diff.c @@@ -44,9 -44,9 +44,9 @@@ static struct combine_diff_path *inters memset(p->parent, 0, sizeof(p->parent[0]) * num_parent); - hashcpy(p->sha1, q->queue[i]->two->sha1); + hashcpy(p->oid.hash, q->queue[i]->two->sha1); p->mode = q->queue[i]->two->mode; - hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1); + hashcpy(p->parent[n].oid.hash, q->queue[i]->one->sha1); p->parent[n].mode = q->queue[i]->one->mode; p->parent[n].status = q->queue[i]->status; *tail = p; @@@ -77,7 -77,7 +77,7 @@@ continue; } - hashcpy(p->parent[n].sha1, q->queue[i]->one->sha1); + hashcpy(p->parent[n].oid.hash, q->queue[i]->one->sha1); p->parent[n].mode = q->queue[i]->one->mode; p->parent[n].status = q->queue[i]->status; @@@ -284,7 -284,7 +284,7 @@@ static struct lline *coalesce_lines(str return base; } -static char *grab_blob(const unsigned char *sha1, unsigned int mode, +static char *grab_blob(const struct object_id *oid, unsigned int mode, unsigned long *size, struct userdiff_driver *textconv, const char *path) { @@@ -294,20 -294,20 +294,20 @@@ if (S_ISGITLINK(mode)) { blob = xmalloc(100); *size = snprintf(blob, 100, - "Subproject commit %s\n", sha1_to_hex(sha1)); - } else if (is_null_sha1(sha1)) { + "Subproject commit %s\n", oid_to_hex(oid)); + } else if (is_null_oid(oid)) { /* deleted blob */ *size = 0; return xcalloc(1, 1); } else if (textconv) { struct diff_filespec *df = alloc_filespec(path); - fill_filespec(df, sha1, 1, mode); + fill_filespec(df, oid->hash, 1, mode); *size = fill_textconv(textconv, df, &blob); free_filespec(df); } else { - blob = read_sha1_file(sha1, &type, size); + blob = read_sha1_file(oid->hash, &type, size); if (type != OBJ_BLOB) - die("object '%s' is not a blob!", sha1_to_hex(sha1)); + die("object '%s' is not a blob!", oid_to_hex(oid)); } return blob; } @@@ -389,7 -389,7 +389,7 @@@ static void consume_line(void *state_, } } -static void combine_diff(const unsigned char *parent, unsigned int mode, +static void combine_diff(const struct object_id *parent, unsigned int mode, mmfile_t *result_file, struct sline *sline, unsigned int cnt, int n, int num_parent, int result_deleted, @@@ -419,8 -419,10 +419,10 @@@ state.num_parent = num_parent; state.n = n; - xdi_diff_outf(&parent_file, result_file, consume_line, &state, - &xpp, &xecfg); + if (xdi_diff_outf(&parent_file, result_file, consume_line, &state, + &xpp, &xecfg)) + die("unable to generate combined diff for %s", - sha1_to_hex(parent)); ++ oid_to_hex(parent)); free(parent_file.ptr); /* Assign line numbers for this parent. @@@ -897,7 -899,7 +899,7 @@@ static void show_combined_header(struc int show_file_header) { struct diff_options *opt = &rev->diffopt; - int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? 40 : DEFAULT_ABBREV; + int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? GIT_SHA1_HEXSZ : DEFAULT_ABBREV; const char *a_prefix = opt->a_prefix ? opt->a_prefix : "a/"; const char *b_prefix = opt->b_prefix ? opt->b_prefix : "b/"; const char *c_meta = diff_get_color_opt(opt, DIFF_METAINFO); @@@ -914,11 -916,11 +916,11 @@@ "", elem->path, line_prefix, c_meta, c_reset); printf("%s%sindex ", line_prefix, c_meta); for (i = 0; i < num_parent; i++) { - abb = find_unique_abbrev(elem->parent[i].sha1, + abb = find_unique_abbrev(elem->parent[i].oid.hash, abbrev); printf("%s%s", i ? "," : "", abb); } - abb = find_unique_abbrev(elem->sha1, abbrev); + abb = find_unique_abbrev(elem->oid.hash, abbrev); printf("..%s%s\n", abb, c_reset); if (mode_differs) { @@@ -991,7 -993,7 +993,7 @@@ static void show_patch_diff(struct comb /* Read the result of merge first */ if (!working_tree_file) - result = grab_blob(elem->sha1, elem->mode, &result_size, + result = grab_blob(&elem->oid, elem->mode, &result_size, textconv, elem->path); else { /* Used by diff-tree to read from the working tree */ @@@ -1013,12 -1015,12 +1015,12 @@@ result = strbuf_detach(&buf, NULL); elem->mode = canon_mode(st.st_mode); } else if (S_ISDIR(st.st_mode)) { - unsigned char sha1[20]; - if (resolve_gitlink_ref(elem->path, "HEAD", sha1) < 0) - result = grab_blob(elem->sha1, elem->mode, + struct object_id oid; + if (resolve_gitlink_ref(elem->path, "HEAD", oid.hash) < 0) + result = grab_blob(&elem->oid, elem->mode, &result_size, NULL, NULL); else - result = grab_blob(sha1, elem->mode, + result = grab_blob(&oid, elem->mode, &result_size, NULL, NULL); } else if (textconv) { struct diff_filespec *df = alloc_filespec(elem->path); @@@ -1090,7 -1092,7 +1092,7 @@@ for (i = 0; !is_binary && i < num_parent; i++) { char *buf; unsigned long size; - buf = grab_blob(elem->parent[i].sha1, + buf = grab_blob(&elem->parent[i].oid, elem->parent[i].mode, &size, NULL, NULL); if (buffer_is_binary(buf, size)) @@@ -1139,14 -1141,14 +1141,14 @@@ for (i = 0; i < num_parent; i++) { int j; for (j = 0; j < i; j++) { - if (!hashcmp(elem->parent[i].sha1, - elem->parent[j].sha1)) { + if (!oidcmp(&elem->parent[i].oid, + &elem->parent[j].oid)) { reuse_combine_diff(sline, cnt, i, j); break; } } if (i <= j) - combine_diff(elem->parent[i].sha1, + combine_diff(&elem->parent[i].oid, elem->parent[i].mode, &result_file, sline, cnt, i, num_parent, result_deleted, @@@ -1206,9 -1208,9 +1208,9 @@@ static void show_raw_diff(struct combin /* Show sha1's */ for (i = 0; i < num_parent; i++) - printf(" %s", diff_unique_abbrev(p->parent[i].sha1, + printf(" %s", diff_unique_abbrev(p->parent[i].oid.hash, opt->abbrev)); - printf(" %s ", diff_unique_abbrev(p->sha1, opt->abbrev)); + printf(" %s ", diff_unique_abbrev(p->oid.hash, opt->abbrev)); } if (opt->output_format & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) { @@@ -1271,16 -1273,16 +1273,16 @@@ static struct diff_filepair *combined_p for (i = 0; i < num_parent; i++) { pair->one[i].path = p->path; pair->one[i].mode = p->parent[i].mode; - hashcpy(pair->one[i].sha1, p->parent[i].sha1); - pair->one[i].sha1_valid = !is_null_sha1(p->parent[i].sha1); + hashcpy(pair->one[i].sha1, p->parent[i].oid.hash); + pair->one[i].sha1_valid = !is_null_oid(&p->parent[i].oid); pair->one[i].has_more_entries = 1; } pair->one[num_parent - 1].has_more_entries = 0; pair->two->path = p->path; pair->two->mode = p->mode; - hashcpy(pair->two->sha1, p->sha1); - pair->two->sha1_valid = !is_null_sha1(p->sha1); + hashcpy(pair->two->sha1, p->oid.hash); + pair->two->sha1_valid = !is_null_oid(&p->oid); return pair; } diff --combined diff.c index 0f17ec5506,f62b7f73d8..71f0274ce0 --- a/diff.c +++ b/diff.c @@@ -478,59 -478,26 +478,59 @@@ static int new_blank_line_at_eof(struc return ws_blank_line(line, len, ecbdata->ws_rule); } -static void emit_add_line(const char *reset, - struct emit_callback *ecbdata, - const char *line, int len) +static void emit_line_checked(const char *reset, + struct emit_callback *ecbdata, + const char *line, int len, + enum color_diff color, + unsigned ws_error_highlight, + char sign) { - const char *ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); - const char *set = diff_get_color(ecbdata->color_diff, DIFF_FILE_NEW); + const char *set = diff_get_color(ecbdata->color_diff, color); + const char *ws = NULL; - if (!*ws) - emit_line_0(ecbdata->opt, set, reset, '+', line, len); - else if (new_blank_line_at_eof(ecbdata, line, len)) + if (ecbdata->opt->ws_error_highlight & ws_error_highlight) { + ws = diff_get_color(ecbdata->color_diff, DIFF_WHITESPACE); + if (!*ws) + ws = NULL; + } + + if (!ws) + emit_line_0(ecbdata->opt, set, reset, sign, line, len); + else if (sign == '+' && new_blank_line_at_eof(ecbdata, line, len)) /* Blank line at EOF - paint '+' as well */ - emit_line_0(ecbdata->opt, ws, reset, '+', line, len); + emit_line_0(ecbdata->opt, ws, reset, sign, line, len); else { /* Emit just the prefix, then the rest. */ - emit_line_0(ecbdata->opt, set, reset, '+', "", 0); + emit_line_0(ecbdata->opt, set, reset, sign, "", 0); ws_check_emit(line, len, ecbdata->ws_rule, ecbdata->opt->file, set, reset, ws); } } +static void emit_add_line(const char *reset, + struct emit_callback *ecbdata, + const char *line, int len) +{ + emit_line_checked(reset, ecbdata, line, len, + DIFF_FILE_NEW, WSEH_NEW, '+'); +} + +static void emit_del_line(const char *reset, + struct emit_callback *ecbdata, + const char *line, int len) +{ + emit_line_checked(reset, ecbdata, line, len, + DIFF_FILE_OLD, WSEH_OLD, '-'); +} + +static void emit_context_line(const char *reset, + struct emit_callback *ecbdata, + const char *line, int len) +{ + emit_line_checked(reset, ecbdata, line, len, + DIFF_CONTEXT, WSEH_CONTEXT, ' '); +} + static void emit_hunk_header(struct emit_callback *ecbdata, const char *line, int len) { @@@ -636,6 -603,7 +636,6 @@@ static void emit_rewrite_lines(struct e { const char *endp = NULL; static const char *nneof = " No newline at end of file\n"; - const char *old = diff_get_color(ecb->color_diff, DIFF_FILE_OLD); const char *reset = diff_get_color(ecb->color_diff, DIFF_RESET); while (0 < size) { @@@ -645,7 -613,8 +645,7 @@@ len = endp ? (endp - data + 1) : size; if (prefix != '+') { ecb->lno_in_preimage++; - emit_line_0(ecb->opt, old, reset, '-', - data, len); + emit_del_line(reset, ecb, data, len); } else { ecb->lno_in_postimage++; emit_add_line(reset, ecb, data, len); @@@ -1033,8 -1002,9 +1033,9 @@@ static void diff_words_show(struct diff xpp.flags = 0; /* as only the hunk header will be parsed, we need a 0-context */ xecfg.ctxlen = 0; - xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, - &xpp, &xecfg); + if (xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, + &xpp, &xecfg)) + die("unable to generate word diff"); free(minus.ptr); free(plus.ptr); if (diff_words->current_plus != diff_words->plus.text.ptr + @@@ -1281,27 -1251,17 +1282,27 @@@ static void fn_out_consume(void *priv, return; } - if (line[0] != '+') { - const char *color = - diff_get_color(ecbdata->color_diff, - line[0] == '-' ? DIFF_FILE_OLD : DIFF_CONTEXT); - ecbdata->lno_in_preimage++; - if (line[0] == ' ') - ecbdata->lno_in_postimage++; - emit_line(ecbdata->opt, color, reset, line, len); - } else { + switch (line[0]) { + case '+': ecbdata->lno_in_postimage++; emit_add_line(reset, ecbdata, line + 1, len - 1); + break; + case '-': + ecbdata->lno_in_preimage++; + emit_del_line(reset, ecbdata, line + 1, len - 1); + break; + case ' ': + ecbdata->lno_in_postimage++; + ecbdata->lno_in_preimage++; + emit_context_line(reset, ecbdata, line + 1, len - 1); + break; + default: + /* incomplete line at the end */ + ecbdata->lno_in_preimage++; + emit_line(ecbdata->opt, + diff_get_color(ecbdata->color_diff, DIFF_CONTEXT), + reset, line, len); + break; } } @@@ -2441,8 -2401,9 +2442,9 @@@ static void builtin_diff(const char *na xecfg.ctxlen = strtoul(v, NULL, 10); if (o->word_diff) init_diff_words_data(&ecbdata, o, one, two); - xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, - &xpp, &xecfg); + if (xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, + &xpp, &xecfg)) + die("unable to generate diff for %s", one->path); if (o->word_diff) free_diff_words_data(&ecbdata); if (textconv_one) @@@ -2519,8 -2480,9 +2521,9 @@@ static void builtin_diffstat(const cha xpp.flags = o->xdl_opts; xecfg.ctxlen = o->context; xecfg.interhunkctxlen = o->interhunkcontext; - xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, - &xpp, &xecfg); + if (xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, + &xpp, &xecfg)) + die("unable to generate diffstat for %s", one->path); } diff_free_filespec_data(one); @@@ -2566,8 -2528,9 +2569,9 @@@ static void builtin_checkdiff(const cha memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 1; /* at least one context line */ xpp.flags = 0; - xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data, - &xpp, &xecfg); + if (xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data, + &xpp, &xecfg)) + die("unable to generate checkdiff for %s", one->path); if (data.ws_rule & WS_BLANK_AT_EOF) { struct emit_callback ecbdata; @@@ -3264,7 -3227,6 +3268,7 @@@ void diff_setup(struct diff_options *op options->rename_limit = -1; options->dirstat_permille = diff_dirstat_permille_default; options->context = diff_context_default; + options->ws_error_highlight = WSEH_NEW; DIFF_OPT_SET(options, RENAME_EMPTY); /* pathchange left =NULL by default */ @@@ -3651,45 -3613,6 +3655,45 @@@ static void enable_patch_output(int *fm *fmt |= DIFF_FORMAT_PATCH; } +static int parse_one_token(const char **arg, const char *token) +{ + const char *rest; + if (skip_prefix(*arg, token, &rest) && (!*rest || *rest == ',')) { + *arg = rest; + return 1; + } + return 0; +} + +static int parse_ws_error_highlight(struct diff_options *opt, const char *arg) +{ + const char *orig_arg = arg; + unsigned val = 0; + while (*arg) { + if (parse_one_token(&arg, "none")) + val = 0; + else if (parse_one_token(&arg, "default")) + val = WSEH_NEW; + else if (parse_one_token(&arg, "all")) + val = WSEH_NEW | WSEH_OLD | WSEH_CONTEXT; + else if (parse_one_token(&arg, "new")) + val |= WSEH_NEW; + else if (parse_one_token(&arg, "old")) + val |= WSEH_OLD; + else if (parse_one_token(&arg, "context")) + val |= WSEH_CONTEXT; + else { + error("unknown value after ws-error-highlight=%.*s", + (int)(arg - orig_arg), orig_arg); + return 0; + } + if (*arg) + arg++; + } + opt->ws_error_highlight = val; + return 1; +} + int diff_opt_parse(struct diff_options *options, const char **av, int ac) { const char *arg = av[0]; @@@ -3887,8 -3810,6 +3891,8 @@@ DIFF_OPT_SET(options, SUBMODULE_LOG); else if (skip_prefix(arg, "--submodule=", &arg)) return parse_submodule_opt(options, arg); + else if (skip_prefix(arg, "--ws-error-highlight=", &arg)) + return parse_ws_error_highlight(options, arg); /* misc options */ else if (!strcmp(arg, "-z")) @@@ -4508,8 -4429,10 +4512,10 @@@ static int diff_get_patch_id(struct dif xpp.flags = 0; xecfg.ctxlen = 3; xecfg.flags = 0; - xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data, - &xpp, &xecfg); + if (xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data, + &xpp, &xecfg)) + return error("unable to generate patch-id diff for %s", + p->one->path); } git_SHA1_Final(sha1, &ctx); diff --combined git-submodule.sh index 25b1ddf252,78c2740fdb..82e35582cd --- a/git-submodule.sh +++ b/git-submodule.sh @@@ -22,6 -22,15 +22,15 @@@ require_work_tre wt_prefix=$(git rev-parse --show-prefix) cd_to_toplevel + # Restrict ourselves to a vanilla subset of protocols; the URLs + # we get are under control of a remote repository, and we do not + # want them kicking off arbitrary git-remote-* programs. + # + # If the user has already specified a set of allowed protocols, + # we assume they know what they're doing and use that instead. + : ${GIT_ALLOW_PROTOCOL=file:git:http:https:ssh} + export GIT_ALLOW_PROTOCOL + command= branch= force= @@@ -904,7 -913,7 +913,7 @@@ Maybe you want to use 'update --init'?" ;; !*) command="${update_module#!}" - die_msg="$(eval_gettext "Execution of '\$command \$sha1' failed in submodule path '\$prefix\$sm_path'")" + die_msg="$(eval_gettext "Execution of '\$command \$sha1' failed in submodule path '\$prefix\$sm_path'")" say_msg="$(eval_gettext "Submodule path '\$prefix\$sm_path': '\$command \$sha1'")" must_die_on_failure=yes ;; diff --combined http.c index e9c6fdd835,9448c50f0f..45348fb9bd --- a/http.c +++ b/http.c @@@ -9,6 -9,7 +9,7 @@@ #include "version.h" #include "pkt-line.h" #include "gettext.h" + #include "transport.h" int active_requests; int http_is_verbose; @@@ -36,7 -37,6 +37,7 @@@ char curl_errorstr[CURL_ERROR_SIZE] static int curl_ssl_verify = -1; static int curl_ssl_try; static const char *ssl_cert; +static const char *ssl_cipherlist; #if LIBCURL_VERSION_NUM >= 0x070903 static const char *ssl_key; #endif @@@ -188,8 -188,6 +189,8 @@@ static int http_options(const char *var curl_ssl_verify = git_config_bool(var, value); return 0; } + if (!strcmp("http.sslcipherlist", var)) + return git_config_string(&ssl_cipherlist, var, value); if (!strcmp("http.sslcert", var)) return git_config_string(&ssl_cert, var, value); #if LIBCURL_VERSION_NUM >= 0x070903 @@@ -340,6 -338,7 +341,7 @@@ static void set_curl_keepalive(CURL *c static CURL *get_curl_handle(void) { CURL *result = curl_easy_init(); + long allowed_protocols = 0; if (!result) die("curl_easy_init failed"); @@@ -364,13 -363,6 +366,13 @@@ if (http_proactive_auth) init_curl_http_auth(result); + if (getenv("GIT_SSL_CIPHER_LIST")) + ssl_cipherlist = getenv("GIT_SSL_CIPHER_LIST"); + + if (ssl_cipherlist != NULL && *ssl_cipherlist) + curl_easy_setopt(result, CURLOPT_SSL_CIPHER_LIST, + ssl_cipherlist); + if (ssl_cert != NULL) curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert); if (has_cert_password()) @@@ -394,11 -386,27 +396,27 @@@ } curl_easy_setopt(result, CURLOPT_FOLLOWLOCATION, 1); + curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20); #if LIBCURL_VERSION_NUM >= 0x071301 curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL); #elif LIBCURL_VERSION_NUM >= 0x071101 curl_easy_setopt(result, CURLOPT_POST301, 1); #endif + #if LIBCURL_VERSION_NUM >= 0x071304 + if (is_transport_allowed("http")) + allowed_protocols |= CURLPROTO_HTTP; + if (is_transport_allowed("https")) + allowed_protocols |= CURLPROTO_HTTPS; + if (is_transport_allowed("ftp")) + allowed_protocols |= CURLPROTO_FTP; + if (is_transport_allowed("ftps")) + allowed_protocols |= CURLPROTO_FTPS; + curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols); + #else + if (transport_restrict_protocols()) + warning("protocol restrictions not applied to curl redirects because\n" + "your curl version is too old (>= 7.19.4)"); + #endif if (getenv("GIT_CURL_VERBOSE")) curl_easy_setopt(result, CURLOPT_VERBOSE, 1); diff --combined ll-merge.c index fc3c049594,4e789f5330..bf83290793 --- a/ll-merge.c +++ b/ll-merge.c @@@ -9,7 -9,6 +9,7 @@@ #include "xdiff-interface.h" #include "run-command.h" #include "ll-merge.h" +#include "quote.h" struct ll_merge_driver; @@@ -89,7 -88,10 +89,10 @@@ static int ll_xdl_merge(const struct ll xmparam_t xmp; assert(opts); - if (buffer_is_binary(orig->ptr, orig->size) || + if (orig->size > MAX_XDIFF_SIZE || + src1->size > MAX_XDIFF_SIZE || + src2->size > MAX_XDIFF_SIZE || + buffer_is_binary(orig->ptr, orig->size) || buffer_is_binary(src1->ptr, src1->size) || buffer_is_binary(src2->ptr, src2->size)) { return ll_binary_merge(drv_unused, result, @@@ -167,20 -169,17 +170,20 @@@ static int ll_ext_merge(const struct ll { char temp[4][50]; struct strbuf cmd = STRBUF_INIT; - struct strbuf_expand_dict_entry dict[5]; + struct strbuf_expand_dict_entry dict[6]; + struct strbuf path_sq = STRBUF_INIT; const char *args[] = { NULL, NULL }; int status, fd, i; struct stat st; assert(opts); + sq_quote_buf(&path_sq, path); dict[0].placeholder = "O"; dict[0].value = temp[0]; dict[1].placeholder = "A"; dict[1].value = temp[1]; dict[2].placeholder = "B"; dict[2].value = temp[2]; dict[3].placeholder = "L"; dict[3].value = temp[3]; - dict[4].placeholder = NULL; dict[4].value = NULL; + dict[4].placeholder = "P"; dict[4].value = path_sq.buf; + dict[5].placeholder = NULL; dict[5].value = NULL; if (fn->cmdline == NULL) die("custom merge driver %s lacks command line.", fn->name); @@@ -214,7 -213,6 +217,7 @@@ for (i = 0; i < 3; i++) unlink_or_warn(temp[i]); strbuf_release(&cmd); + strbuf_release(&path_sq); return status; } @@@ -274,7 -272,6 +277,7 @@@ static int read_merge_config(const cha * %A - temporary file name for our version. * %B - temporary file name for the other branches' version. * %L - conflict marker length + * %P - the original path (safely quoted for the shell) * * The external merge driver should write the results in the * file named by %A, and signal that it has done with zero exit diff --combined transport-helper.c index 68e498eebd,b486441c48..12f50d5b94 --- a/transport-helper.c +++ b/transport-helper.c @@@ -490,8 -490,7 +490,8 @@@ static int fetch_with_import(struct tra else private = xstrdup(name); if (private) { - read_ref(private, posn->old_sha1); + if (read_ref(private, posn->old_sha1) < 0) + die("Could not read ref %s", private); free(private); } } @@@ -1020,10 -1019,7 +1020,10 @@@ static struct ref *get_refs_list(struc if (eon) { if (has_attribute(eon + 1, "unchanged")) { (*tail)->status |= REF_STATUS_UPTODATE; - read_ref((*tail)->name, (*tail)->old_sha1); + if (read_ref((*tail)->name, + (*tail)->old_sha1) < 0) + die(N_("Could not read ref %s"), + (*tail)->name); } } tail = &((*tail)->next); @@@ -1043,6 -1039,8 +1043,8 @@@ int transport_helper_init(struct transp struct helper_data *data = xcalloc(1, sizeof(*data)); data->name = name; + transport_check_allowed(name); + if (getenv("GIT_TRANSPORT_HELPER_DEBUG")) debug = 1; diff --combined transport.c index 40692f8ae8,198502d0ba..164a716053 --- a/transport.c +++ b/transport.c @@@ -278,11 -278,12 +278,11 @@@ static int fetch_objs_via_rsync(struct return run_command(&rsync); } -static int write_one_ref(const char *name, const unsigned char *sha1, - int flags, void *data) +static int write_one_ref(const char *name, const struct object_id *oid, + int flags, void *data) { struct strbuf *buf = data; int len = buf->len; - FILE *f; /* when called via for_each_ref(), flags is non-zero */ if (flags && !starts_with(name, "refs/heads/") && @@@ -291,26 -292,27 +291,26 @@@ strbuf_addstr(buf, name); if (safe_create_leading_directories(buf->buf) || - !(f = fopen(buf->buf, "w")) || - fprintf(f, "%s\n", sha1_to_hex(sha1)) < 0 || - fclose(f)) - return error("problems writing temporary file %s", buf->buf); + write_file(buf->buf, 0, "%s\n", oid_to_hex(oid))) + return error("problems writing temporary file %s: %s", + buf->buf, strerror(errno)); strbuf_setlen(buf, len); return 0; } static int write_refs_to_temp_dir(struct strbuf *temp_dir, - int refspec_nr, const char **refspec) + int refspec_nr, const char **refspec) { int i; for (i = 0; i < refspec_nr; i++) { - unsigned char sha1[20]; + struct object_id oid; char *ref; - if (dwim_ref(refspec[i], strlen(refspec[i]), sha1, &ref) != 1) + if (dwim_ref(refspec[i], strlen(refspec[i]), oid.hash, &ref) != 1) return error("Could not get ref %s", refspec[i]); - if (write_one_ref(ref, sha1, 0, temp_dir)) { + if (write_one_ref(ref, &oid, 0, temp_dir)) { free(ref); return -1; } @@@ -912,6 -914,42 +912,42 @@@ static int external_specification_len(c return strchr(url, ':') - url; } + static const struct string_list *protocol_whitelist(void) + { + static int enabled = -1; + static struct string_list allowed = STRING_LIST_INIT_DUP; + + if (enabled < 0) { + const char *v = getenv("GIT_ALLOW_PROTOCOL"); + if (v) { + string_list_split(&allowed, v, ':', -1); + string_list_sort(&allowed); + enabled = 1; + } else { + enabled = 0; + } + } + + return enabled ? &allowed : NULL; + } + + int is_transport_allowed(const char *type) + { + const struct string_list *allowed = protocol_whitelist(); + return !allowed || string_list_has_string(allowed, type); + } + + void transport_check_allowed(const char *type) + { + if (!is_transport_allowed(type)) + die("transport '%s' not allowed", type); + } + + int transport_restrict_protocols(void) + { + return !!protocol_whitelist(); + } + struct transport *transport_get(struct remote *remote, const char *url) { const char *helper; @@@ -943,12 -981,14 +979,14 @@@ if (helper) { transport_helper_init(ret, helper); } else if (starts_with(url, "rsync:")) { + transport_check_allowed("rsync"); ret->get_refs_list = get_refs_via_rsync; ret->fetch = fetch_objs_via_rsync; ret->push = rsync_transport_push; ret->smart_options = NULL; } else if (url_is_local_not_ssh(url) && is_file(url) && is_bundle(url, 1)) { struct bundle_transport_data *data = xcalloc(1, sizeof(*data)); + transport_check_allowed("file"); ret->data = data; ret->get_refs_list = get_refs_from_bundle; ret->fetch = fetch_refs_from_bundle; @@@ -960,7 -1000,10 +998,10 @@@ || starts_with(url, "ssh://") || starts_with(url, "git+ssh://") || starts_with(url, "ssh+git://")) { - /* These are builtin smart transports. */ + /* + * These are builtin smart transports; "allowed" transports + * will be checked individually in git_connect. + */ struct git_transport_data *data = xcalloc(1, sizeof(*data)); ret->data = data; ret->set_option = NULL;