diff options
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/add.c | 1 | ||||
-rw-r--r-- | builtin/apply.c | 4 | ||||
-rw-r--r-- | builtin/cat-file.c | 210 | ||||
-rw-r--r-- | builtin/checkout.c | 11 | ||||
-rw-r--r-- | builtin/clone.c | 23 | ||||
-rw-r--r-- | builtin/commit.c | 83 | ||||
-rw-r--r-- | builtin/log.c | 24 | ||||
-rw-r--r-- | builtin/merge.c | 59 | ||||
-rw-r--r-- | builtin/push.c | 55 | ||||
-rw-r--r-- | builtin/reset.c | 5 | ||||
-rw-r--r-- | builtin/rev-list.c | 1 | ||||
-rw-r--r-- | builtin/revert.c | 2 | ||||
-rw-r--r-- | builtin/shortlog.c | 1 | ||||
-rw-r--r-- | builtin/show-branch.c | 4 | ||||
-rw-r--r-- | builtin/show-ref.c | 8 |
15 files changed, 373 insertions, 118 deletions
diff --git a/builtin/add.c b/builtin/add.c index f45d9d4865..8266a9cb70 100644 --- a/builtin/add.c +++ b/builtin/add.c @@ -343,6 +343,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); rev.diffopt.output_format = DIFF_FORMAT_PATCH; + rev.diffopt.use_color = 0; DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES); out = open(file, O_CREAT | O_WRONLY, 0666); if (out < 0) diff --git a/builtin/apply.c b/builtin/apply.c index 023bb3aada..64310cd678 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -722,7 +722,7 @@ static char *find_name(const char *line, char *def, int p_value, int terminate) static char *find_name_traditional(const char *line, char *def, int p_value) { - size_t len = strlen(line); + size_t len; size_t date_len; if (*line == '"') { @@ -3848,7 +3848,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned const char *s = buf; if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1)) - die(_("corrupt patch for subproject %s"), path); + die(_("corrupt patch for submodule %s"), path); } else { if (!cached) { if (lstat(path, &st) < 0) diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 045cee7bce..0e64b4159c 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -13,9 +13,6 @@ #include "userdiff.h" #include "streaming.h" -#define BATCH 1 -#define BATCH_CHECK 2 - static int cat_one_file(int opt, const char *exp_type, const char *obj_name) { unsigned char sha1[20]; @@ -117,54 +114,174 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name) return 0; } -static int batch_one_object(const char *obj_name, int print_contents) -{ +struct expand_data { unsigned char sha1[20]; - enum object_type type = 0; + enum object_type type; unsigned long size; - void *contents = NULL; + unsigned long disk_size; + const char *rest; + + /* + * If mark_query is true, we do not expand anything, but rather + * just mark the object_info with items we wish to query. + */ + int mark_query; + + /* + * After a mark_query run, this object_info is set up to be + * passed to sha1_object_info_extended. It will point to the data + * elements above, so you can retrieve the response from there. + */ + struct object_info info; +}; + +static int is_atom(const char *atom, const char *s, int slen) +{ + int alen = strlen(atom); + return alen == slen && !memcmp(atom, s, alen); +} + +static void expand_atom(struct strbuf *sb, const char *atom, int len, + void *vdata) +{ + struct expand_data *data = vdata; + + if (is_atom("objectname", atom, len)) { + if (!data->mark_query) + strbuf_addstr(sb, sha1_to_hex(data->sha1)); + } else if (is_atom("objecttype", atom, len)) { + if (!data->mark_query) + strbuf_addstr(sb, typename(data->type)); + } else if (is_atom("objectsize", atom, len)) { + if (data->mark_query) + data->info.sizep = &data->size; + else + strbuf_addf(sb, "%lu", data->size); + } else if (is_atom("objectsize:disk", atom, len)) { + if (data->mark_query) + data->info.disk_sizep = &data->disk_size; + else + strbuf_addf(sb, "%lu", data->disk_size); + } else if (is_atom("rest", atom, len)) { + if (!data->mark_query && data->rest) + strbuf_addstr(sb, data->rest); + } else + die("unknown format element: %.*s", len, atom); +} + +static size_t expand_format(struct strbuf *sb, const char *start, void *data) +{ + const char *end; + + if (*start != '(') + return 0; + end = strchr(start + 1, ')'); + if (!end) + die("format element '%s' does not end in ')'", start); + + expand_atom(sb, start + 1, end - start - 1, data); + + return end - start + 1; +} + +static void print_object_or_die(int fd, const unsigned char *sha1, + enum object_type type, unsigned long size) +{ + if (type == OBJ_BLOB) { + if (stream_blob_to_fd(fd, sha1, NULL, 0) < 0) + die("unable to stream %s to stdout", sha1_to_hex(sha1)); + } + else { + enum object_type rtype; + unsigned long rsize; + void *contents; + + contents = read_sha1_file(sha1, &rtype, &rsize); + if (!contents) + die("object %s disappeared", sha1_to_hex(sha1)); + if (rtype != type) + die("object %s changed type!?", sha1_to_hex(sha1)); + if (rsize != size) + die("object %s change size!?", sha1_to_hex(sha1)); + + write_or_die(fd, contents, size); + free(contents); + } +} + +struct batch_options { + int enabled; + int print_contents; + const char *format; +}; + +static int batch_one_object(const char *obj_name, struct batch_options *opt, + struct expand_data *data) +{ + struct strbuf buf = STRBUF_INIT; if (!obj_name) return 1; - if (get_sha1(obj_name, sha1)) { + if (get_sha1(obj_name, data->sha1)) { printf("%s missing\n", obj_name); fflush(stdout); return 0; } - if (print_contents == BATCH) - contents = read_sha1_file(sha1, &type, &size); - else - type = sha1_object_info(sha1, &size); - - if (type <= 0) { + data->type = sha1_object_info_extended(data->sha1, &data->info); + if (data->type <= 0) { printf("%s missing\n", obj_name); fflush(stdout); - if (print_contents == BATCH) - free(contents); return 0; } - printf("%s %s %lu\n", sha1_to_hex(sha1), typename(type), size); - fflush(stdout); + strbuf_expand(&buf, opt->format, expand_format, data); + strbuf_addch(&buf, '\n'); + write_or_die(1, buf.buf, buf.len); + strbuf_release(&buf); - if (print_contents == BATCH) { - write_or_die(1, contents, size); - printf("\n"); - fflush(stdout); - free(contents); + if (opt->print_contents) { + print_object_or_die(1, data->sha1, data->type, data->size); + write_or_die(1, "\n", 1); } - return 0; } -static int batch_objects(int print_contents) +static int batch_objects(struct batch_options *opt) { struct strbuf buf = STRBUF_INIT; + struct expand_data data; + + if (!opt->format) + opt->format = "%(objectname) %(objecttype) %(objectsize)"; + + /* + * Expand once with our special mark_query flag, which will prime the + * object_info to be handed to sha1_object_info_extended for each + * object. + */ + memset(&data, 0, sizeof(data)); + data.mark_query = 1; + strbuf_expand(&buf, opt->format, expand_format, &data); + data.mark_query = 0; while (strbuf_getline(&buf, stdin, '\n') != EOF) { - int error = batch_one_object(buf.buf, print_contents); + char *p; + int error; + + /* + * Split at first whitespace, tying off the beginning of the + * string and saving the remainder (or NULL) in data.rest. + */ + p = strpbrk(buf.buf, " \t"); + if (p) { + while (*p && strchr(" \t", *p)) + *p++ = '\0'; + } + data.rest = p; + + error = batch_one_object(buf.buf, opt, &data); if (error) return error; } @@ -186,10 +303,29 @@ static int git_cat_file_config(const char *var, const char *value, void *cb) return git_default_config(var, value, cb); } +static int batch_option_callback(const struct option *opt, + const char *arg, + int unset) +{ + struct batch_options *bo = opt->value; + + if (unset) { + memset(bo, 0, sizeof(*bo)); + return 0; + } + + bo->enabled = 1; + bo->print_contents = !strcmp(opt->long_name, "batch"); + bo->format = arg; + + return 0; +} + int cmd_cat_file(int argc, const char **argv, const char *prefix) { - int opt = 0, batch = 0; + int opt = 0; const char *exp_type = NULL, *obj_name = NULL; + struct batch_options batch = {0}; const struct option options[] = { OPT_GROUP(N_("<type> can be one of: blob, tree, commit, tag")), @@ -200,12 +336,12 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix) OPT_SET_INT('p', NULL, &opt, N_("pretty-print object's content"), 'p'), OPT_SET_INT(0, "textconv", &opt, N_("for blob objects, run textconv on object's content"), 'c'), - OPT_SET_INT(0, "batch", &batch, - N_("show info and content of objects fed from the standard input"), - BATCH), - OPT_SET_INT(0, "batch-check", &batch, - N_("show info about objects fed from the standard input"), - BATCH_CHECK), + { OPTION_CALLBACK, 0, "batch", &batch, "format", + N_("show info and content of objects fed from the standard input"), + PARSE_OPT_OPTARG, batch_option_callback }, + { OPTION_CALLBACK, 0, "batch-check", &batch, "format", + N_("show info about objects fed from the standard input"), + PARSE_OPT_OPTARG, batch_option_callback }, OPT_END() }; @@ -222,19 +358,19 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix) else usage_with_options(cat_file_usage, options); } - if (!opt && !batch) { + if (!opt && !batch.enabled) { if (argc == 2) { exp_type = argv[0]; obj_name = argv[1]; } else usage_with_options(cat_file_usage, options); } - if (batch && (opt || argc)) { + if (batch.enabled && (opt || argc)) { usage_with_options(cat_file_usage, options); } - if (batch) - return batch_objects(batch); + if (batch.enabled) + return batch_objects(&batch); return cat_one_file(opt, exp_type, obj_name); } diff --git a/builtin/checkout.c b/builtin/checkout.c index 69f9efa757..7025938ae3 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -587,7 +587,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts, struct branch_info *new) { struct strbuf msg = STRBUF_INIT; - const char *old_desc; + const char *old_desc, *reflog_msg; if (opts->new_branch) { if (opts->new_orphan_branch) { if (opts->new_branch_log && !log_all_ref_updates) { @@ -620,8 +620,13 @@ static void update_refs_for_switch(const struct checkout_opts *opts, old_desc = old->name; if (!old_desc && old->commit) old_desc = sha1_to_hex(old->commit->object.sha1); - strbuf_addf(&msg, "checkout: moving from %s to %s", - old_desc ? old_desc : "(invalid)", new->name); + + reflog_msg = getenv("GIT_REFLOG_ACTION"); + if (!reflog_msg) + strbuf_addf(&msg, "checkout: moving from %s to %s", + old_desc ? old_desc : "(invalid)", new->name); + else + strbuf_insert(&msg, 0, reflog_msg, strlen(reflog_msg)); if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) { /* Nothing to do. */ diff --git a/builtin/clone.c b/builtin/clone.c index 14b1323568..430307b298 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -545,17 +545,20 @@ static void update_remote_refs(const struct ref *refs, const struct ref *remote_head_points_at, const char *branch_top, const char *msg, - struct transport *transport) + struct transport *transport, + int check_connectivity) { const struct ref *rm = mapped_refs; - if (0 <= option_verbosity) - printf(_("Checking connectivity... ")); - if (check_everything_connected_with_transport(iterate_ref_map, - 0, &rm, transport)) - die(_("remote did not send all necessary objects")); - if (0 <= option_verbosity) - printf(_("done\n")); + if (check_connectivity) { + if (0 <= option_verbosity) + printf(_("Checking connectivity... ")); + if (check_everything_connected_with_transport(iterate_ref_map, + 0, &rm, transport)) + die(_("remote did not send all necessary objects")); + if (0 <= option_verbosity) + printf(_("done\n")); + } if (refs) { write_remote_refs(mapped_refs); @@ -701,7 +704,7 @@ static void write_refspec_config(const char* src_ref_prefix, /* * otherwise, the next "git fetch" will * simply fetch from HEAD without updating - * any remote tracking branch, which is what + * any remote-tracking branch, which is what * we want. */ } else { @@ -963,7 +966,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) transport_fetch_refs(transport, mapped_refs); update_remote_refs(refs, mapped_refs, remote_head_points_at, - branch_top.buf, reflog_msg.buf, transport); + branch_top.buf, reflog_msg.buf, transport, !is_local); update_head(our_head_points_at, remote_head, reflog_msg.buf); diff --git a/builtin/commit.c b/builtin/commit.c index c9cbb811b0..65cf2a79b7 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -112,12 +112,14 @@ static int show_ignored_in_status, have_option_m; static const char *only_include_assumed; static struct strbuf message = STRBUF_INIT; -static enum { +static enum status_format { STATUS_FORMAT_NONE = 0, STATUS_FORMAT_LONG, STATUS_FORMAT_SHORT, - STATUS_FORMAT_PORCELAIN -} status_format; + STATUS_FORMAT_PORCELAIN, + + STATUS_FORMAT_UNSPECIFIED +} status_format = STATUS_FORMAT_UNSPECIFIED; static int opt_parse_m(const struct option *opt, const char *arg, int unset) { @@ -460,6 +462,9 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int case STATUS_FORMAT_PORCELAIN: wt_porcelain_print(s); break; + case STATUS_FORMAT_UNSPECIFIED: + die("BUG: finalize_deferred_config() should have been called"); + break; case STATUS_FORMAT_NONE: case STATUS_FORMAT_LONG: wt_status_print(s); @@ -961,6 +966,42 @@ static const char *read_commit_message(const char *name) return logmsg_reencode(commit, NULL, out_enc); } +/* + * Enumerate what needs to be propagated when --porcelain + * is not in effect here. + */ +static struct status_deferred_config { + enum status_format status_format; + int show_branch; +} status_deferred_config = { + STATUS_FORMAT_UNSPECIFIED, + -1 /* unspecified */ +}; + +static void finalize_deferred_config(struct wt_status *s) +{ + int use_deferred_config = (status_format != STATUS_FORMAT_PORCELAIN && + !s->null_termination); + + if (s->null_termination) { + if (status_format == STATUS_FORMAT_NONE || + status_format == STATUS_FORMAT_UNSPECIFIED) + status_format = STATUS_FORMAT_PORCELAIN; + else if (status_format == STATUS_FORMAT_LONG) + die(_("--long and -z are incompatible")); + } + + if (use_deferred_config && status_format == STATUS_FORMAT_UNSPECIFIED) + status_format = status_deferred_config.status_format; + if (status_format == STATUS_FORMAT_UNSPECIFIED) + status_format = STATUS_FORMAT_NONE; + + if (use_deferred_config && s->show_branch < 0) + s->show_branch = status_deferred_config.show_branch; + if (s->show_branch < 0) + s->show_branch = 0; +} + static int parse_and_validate_options(int argc, const char *argv[], const struct option *options, const char * const usage[], @@ -971,6 +1012,7 @@ static int parse_and_validate_options(int argc, const char *argv[], int f = 0; argc = parse_options(argc, argv, prefix, options, usage, 0); + finalize_deferred_config(s); if (force_author && !strchr(force_author, '>')) force_author = find_author_by_nickname(force_author); @@ -1055,12 +1097,6 @@ static int parse_and_validate_options(int argc, const char *argv[], if (all && argc > 0) die(_("Paths with -a does not make sense.")); - if (s->null_termination) { - if (status_format == STATUS_FORMAT_NONE) - status_format = STATUS_FORMAT_PORCELAIN; - else if (status_format == STATUS_FORMAT_LONG) - die(_("--long and -z are incompatible")); - } if (status_format != STATUS_FORMAT_NONE) dry_run = 1; @@ -1113,6 +1149,17 @@ static int git_status_config(const char *k, const char *v, void *cb) s->submodule_summary = -1; return 0; } + if (!strcmp(k, "status.short")) { + if (git_config_bool(k, v)) + status_deferred_config.status_format = STATUS_FORMAT_SHORT; + else + status_deferred_config.status_format = STATUS_FORMAT_NONE; + return 0; + } + if (!strcmp(k, "status.branch")) { + status_deferred_config.show_branch = git_config_bool(k, v); + return 0; + } if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) { s->use_color = git_config_colorbool(k, v); return 0; @@ -1155,8 +1202,8 @@ int cmd_status(int argc, const char **argv, const char *prefix) OPT__VERBOSE(&verbose, N_("be verbose")), OPT_SET_INT('s', "short", &status_format, N_("show status concisely"), STATUS_FORMAT_SHORT), - OPT_BOOLEAN('b', "branch", &s.show_branch, - N_("show branch information")), + OPT_BOOL('b', "branch", &s.show_branch, + N_("show branch information")), OPT_SET_INT(0, "porcelain", &status_format, N_("machine-readable output"), STATUS_FORMAT_PORCELAIN), @@ -1189,13 +1236,7 @@ int cmd_status(int argc, const char **argv, const char *prefix) builtin_status_options, builtin_status_usage, 0); finalize_colopts(&s.colopts, -1); - - if (s.null_termination) { - if (status_format == STATUS_FORMAT_NONE) - status_format = STATUS_FORMAT_PORCELAIN; - else if (status_format == STATUS_FORMAT_LONG) - die(_("--long and -z are incompatible")); - } + finalize_deferred_config(&s); handle_untracked_files_arg(&s); if (show_ignored_in_status) @@ -1224,6 +1265,9 @@ int cmd_status(int argc, const char **argv, const char *prefix) case STATUS_FORMAT_PORCELAIN: wt_porcelain_print(&s); break; + case STATUS_FORMAT_UNSPECIFIED: + die("BUG: finalize_deferred_config() should have been called"); + break; case STATUS_FORMAT_NONE: case STATUS_FORMAT_LONG: s.verbose = verbose; @@ -1392,7 +1436,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) OPT_BOOLEAN(0, "dry-run", &dry_run, N_("show what would be committed")), OPT_SET_INT(0, "short", &status_format, N_("show status concisely"), STATUS_FORMAT_SHORT), - OPT_BOOLEAN(0, "branch", &s.show_branch, N_("show branch information")), + OPT_BOOL(0, "branch", &s.show_branch, N_("show branch information")), OPT_SET_INT(0, "porcelain", &status_format, N_("machine-readable output"), STATUS_FORMAT_PORCELAIN), OPT_SET_INT(0, "long", &status_format, @@ -1433,6 +1477,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix) wt_status_prepare(&s); gitmodules_config(); git_config(git_commit_config, &s); + status_format = STATUS_FORMAT_NONE; /* Ignore status.short */ determine_whence(&s); s.colopts = 0; diff --git a/builtin/log.c b/builtin/log.c index e3222ed9f9..2625f9881a 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1112,6 +1112,21 @@ static int cc_callback(const struct option *opt, const char *arg, int unset) return 0; } +static int from_callback(const struct option *opt, const char *arg, int unset) +{ + char **from = opt->value; + + free(*from); + + if (unset) + *from = NULL; + else if (arg) + *from = xstrdup(arg); + else + *from = xstrdup(git_committer_info(IDENT_NO_DATE)); + return 0; +} + int cmd_format_patch(int argc, const char **argv, const char *prefix) { struct commit *commit; @@ -1134,6 +1149,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) int quiet = 0; int reroll_count = -1; char *branch_name = NULL; + char *from = NULL; const struct option builtin_format_patch_options[] = { { OPTION_CALLBACK, 'n', "numbered", &numbered, NULL, N_("use [PATCH n/m] even with a single patch"), @@ -1177,6 +1193,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) 0, to_callback }, { OPTION_CALLBACK, 0, "cc", NULL, N_("email"), N_("add Cc: header"), 0, cc_callback }, + { OPTION_CALLBACK, 0, "from", &from, N_("ident"), + N_("set From address to <ident> (or committer ident if absent)"), + PARSE_OPT_OPTARG, from_callback }, OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"), N_("make first mail a reply to <message-id>")), { OPTION_CALLBACK, 0, "attach", &rev, N_("boundary"), @@ -1264,6 +1283,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) rev.extra_headers = strbuf_detach(&buf, NULL); + if (from) { + if (split_ident_line(&rev.from_ident, from, strlen(from))) + die(_("invalid ident line: %s"), from); + } + if (start_number < 0) start_number = 1; diff --git a/builtin/merge.c b/builtin/merge.c index 74c0746a93..34a6166b52 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -47,8 +47,8 @@ static const char * const builtin_merge_usage[] = { }; static int show_diffstat = 1, shortlog_len = -1, squash; -static int option_commit = 1, allow_fast_forward = 1; -static int fast_forward_only, option_edit = -1; +static int option_commit = 1; +static int option_edit = -1; static int allow_trivial = 1, have_message, verify_signatures; static int overwrite_ignore = 1; static struct strbuf merge_msg = STRBUF_INIT; @@ -76,6 +76,14 @@ static struct strategy all_strategy[] = { static const char *pull_twohead, *pull_octopus; +enum ff_type { + FF_NO, + FF_ALLOW, + FF_ONLY +}; + +static enum ff_type fast_forward = FF_ALLOW; + static int option_parse_message(const struct option *opt, const char *arg, int unset) { @@ -178,6 +186,13 @@ static int option_parse_n(const struct option *opt, return 0; } +static int option_parse_ff_only(const struct option *opt, + const char *arg, int unset) +{ + fast_forward = FF_ONLY; + return 0; +} + static struct option builtin_merge_options[] = { { OPTION_CALLBACK, 'n', NULL, NULL, NULL, N_("do not show a diffstat at the end of the merge"), @@ -194,10 +209,10 @@ static struct option builtin_merge_options[] = { N_("perform a commit if the merge succeeds (default)")), OPT_BOOL('e', "edit", &option_edit, N_("edit message before committing")), - OPT_BOOLEAN(0, "ff", &allow_fast_forward, - N_("allow fast-forward (default)")), - OPT_BOOLEAN(0, "ff-only", &fast_forward_only, - N_("abort if fast-forward is not possible")), + OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW), + { OPTION_CALLBACK, 0, "ff-only", NULL, NULL, + N_("abort if fast-forward is not possible"), + PARSE_OPT_NOARG | PARSE_OPT_NONEG, option_parse_ff_only }, OPT_RERERE_AUTOUPDATE(&allow_rerere_auto), OPT_BOOL(0, "verify-signatures", &verify_signatures, N_("Verify that the named commit has a valid GPG signature")), @@ -581,10 +596,9 @@ static int git_merge_config(const char *k, const char *v, void *cb) else if (!strcmp(k, "merge.ff")) { int boolval = git_config_maybe_bool(k, v); if (0 <= boolval) { - allow_fast_forward = boolval; + fast_forward = boolval ? FF_ALLOW : FF_NO; } else if (v && !strcmp(v, "only")) { - allow_fast_forward = 1; - fast_forward_only = 1; + fast_forward = FF_ONLY; } /* do not barf on values from future versions of git */ return 0; } else if (!strcmp(k, "merge.defaulttoupstream")) { @@ -863,7 +877,7 @@ static int finish_automerge(struct commit *head, free_commit_list(common); parents = remoteheads; - if (!head_subsumed || !allow_fast_forward) + if (!head_subsumed || fast_forward == FF_NO) commit_list_insert(head, &parents); strbuf_addch(&merge_msg, '\n'); prepare_to_commit(remoteheads); @@ -948,7 +962,7 @@ static int evaluate_result(void) } /* - * Pretend as if the user told us to merge with the tracking + * Pretend as if the user told us to merge with the remote-tracking * branch we have for the upstream of the current branch */ static int setup_with_upstream(const char ***argv) @@ -967,7 +981,7 @@ static int setup_with_upstream(const char ***argv) args = xcalloc(branch->merge_nr + 1, sizeof(char *)); for (i = 0; i < branch->merge_nr; i++) { if (!branch->merge[i]->dst) - die(_("No remote tracking branch for %s from %s"), + die(_("No remote-tracking branch for %s from %s"), branch->merge[i]->src, branch->remote_name); args[i] = branch->merge[i]->dst; } @@ -1008,7 +1022,7 @@ static void write_merge_state(struct commit_list *remoteheads) if (fd < 0) die_errno(_("Could not open '%s' for writing"), filename); strbuf_reset(&buf); - if (!allow_fast_forward) + if (fast_forward == FF_NO) strbuf_addf(&buf, "no-ff"); if (write_in_full(fd, buf.buf, buf.len) != buf.len) die_errno(_("Could not write to '%s'"), filename); @@ -1157,14 +1171,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix) show_diffstat = 0; if (squash) { - if (!allow_fast_forward) + if (fast_forward == FF_NO) die(_("You cannot combine --squash with --no-ff.")); option_commit = 0; } - if (!allow_fast_forward && fast_forward_only) - die(_("You cannot combine --no-ff with --ff-only.")); - if (!abort_current_merge) { if (!argc) { if (default_to_upstream) @@ -1206,7 +1217,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) "empty head")); if (squash) die(_("Squash commit into empty head not supported yet")); - if (!allow_fast_forward) + if (fast_forward == FF_NO) die(_("Non-fast-forward commit does not make sense into " "an empty head")); remoteheads = collect_parents(head_commit, &head_subsumed, argc, argv); @@ -1294,11 +1305,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix) sha1_to_hex(commit->object.sha1)); setenv(buf.buf, merge_remote_util(commit)->name, 1); strbuf_reset(&buf); - if (!fast_forward_only && + if (fast_forward != FF_ONLY && merge_remote_util(commit) && merge_remote_util(commit)->obj && merge_remote_util(commit)->obj->type == OBJ_TAG) - allow_fast_forward = 0; + fast_forward = FF_NO; } if (option_edit < 0) @@ -1315,7 +1326,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) for (i = 0; i < use_strategies_nr; i++) { if (use_strategies[i]->attr & NO_FAST_FORWARD) - allow_fast_forward = 0; + fast_forward = FF_NO; if (use_strategies[i]->attr & NO_TRIVIAL) allow_trivial = 0; } @@ -1345,7 +1356,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) */ finish_up_to_date("Already up-to-date."); goto done; - } else if (allow_fast_forward && !remoteheads->next && + } else if (fast_forward != FF_NO && !remoteheads->next && !common->next && !hashcmp(common->item->object.sha1, head_commit->object.sha1)) { /* Again the most common case of merging one remote. */ @@ -1392,7 +1403,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * only one common. */ refresh_cache(REFRESH_QUIET); - if (allow_trivial && !fast_forward_only) { + if (allow_trivial && fast_forward != FF_ONLY) { /* See if it is really trivial. */ git_committer_info(IDENT_STRICT); printf(_("Trying really trivial in-index merge...\n")); @@ -1433,7 +1444,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) } } - if (fast_forward_only) + if (fast_forward == FF_ONLY) die(_("Not possible to fast-forward, aborting.")); /* We are going to make a new commit. */ diff --git a/builtin/push.c b/builtin/push.c index 2d84d10720..6d36c24268 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -120,10 +120,11 @@ static const char message_detached_head_die[] = "\n" " git push %s HEAD:<name-of-remote-branch>\n"); -static void setup_push_upstream(struct remote *remote, int simple) +static void setup_push_upstream(struct remote *remote, struct branch *branch, + int triangular) { struct strbuf refspec = STRBUF_INIT; - struct branch *branch = branch_get(NULL); + if (!branch) die(_(message_detached_head_die), remote->name); if (!branch->merge_nr || !branch->merge || !branch->remote_name) @@ -137,18 +138,29 @@ static void setup_push_upstream(struct remote *remote, int simple) if (branch->merge_nr != 1) die(_("The current branch %s has multiple upstream branches, " "refusing to push."), branch->name); - if (strcmp(branch->remote_name, remote->name)) + if (triangular) die(_("You are pushing to remote '%s', which is not the upstream of\n" "your current branch '%s', without telling me what to push\n" "to update which remote branch."), remote->name, branch->name); - if (simple && strcmp(branch->refname, branch->merge[0]->src)) - die_push_simple(branch, remote); + + if (push_default == PUSH_DEFAULT_SIMPLE) { + /* Additional safety */ + if (strcmp(branch->refname, branch->merge[0]->src)) + die_push_simple(branch, remote); + } strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src); add_refspec(refspec.buf); } +static void setup_push_current(struct remote *remote, struct branch *branch) +{ + if (!branch) + die(_(message_detached_head_die), remote->name); + add_refspec(branch->name); +} + static char warn_unspecified_push_default_msg[] = N_("push.default is unset; its implicit value is changing in\n" "Git 2.0 from 'matching' to 'simple'. To squelch this message\n" @@ -173,9 +185,16 @@ static void warn_unspecified_push_default_configuration(void) warning("%s\n", _(warn_unspecified_push_default_msg)); } +static int is_workflow_triangular(struct remote *remote) +{ + struct remote *fetch_remote = remote_get(NULL); + return (fetch_remote && fetch_remote != remote); +} + static void setup_default_push_refspecs(struct remote *remote) { - struct branch *branch; + struct branch *branch = branch_get(NULL); + int triangular = is_workflow_triangular(remote); switch (push_default) { default: @@ -188,18 +207,18 @@ static void setup_default_push_refspecs(struct remote *remote) break; case PUSH_DEFAULT_SIMPLE: - setup_push_upstream(remote, 1); + if (triangular) + setup_push_current(remote, branch); + else + setup_push_upstream(remote, branch, triangular); break; case PUSH_DEFAULT_UPSTREAM: - setup_push_upstream(remote, 0); + setup_push_upstream(remote, branch, triangular); break; case PUSH_DEFAULT_CURRENT: - branch = branch_get(NULL); - if (!branch) - die(_(message_detached_head_die), remote->name); - add_refspec(branch->name); + setup_push_current(remote, branch); break; case PUSH_DEFAULT_NOTHING: @@ -211,8 +230,8 @@ static void setup_default_push_refspecs(struct remote *remote) static const char message_advice_pull_before_push[] = N_("Updates were rejected because the tip of your current branch is behind\n" - "its remote counterpart. Merge the remote changes (e.g. 'git pull')\n" - "before pushing again.\n" + "its remote counterpart. Integrate the remote changes (e.g.\n" + "'git pull ...') before pushing again.\n" "See the 'Note about fast-forwards' in 'git push --help' for details."); static const char message_advice_use_upstream[] = @@ -223,15 +242,15 @@ static const char message_advice_use_upstream[] = static const char message_advice_checkout_pull_push[] = N_("Updates were rejected because a pushed branch tip is behind its remote\n" - "counterpart. Check out this branch and merge the remote changes\n" - "(e.g. 'git pull') before pushing again.\n" + "counterpart. Check out this branch and integrate the remote changes\n" + "(e.g. 'git pull ...') before pushing again.\n" "See the 'Note about fast-forwards' in 'git push --help' for details."); static const char message_advice_ref_fetch_first[] = N_("Updates were rejected because the remote contains work that you do\n" "not have locally. This is usually caused by another repository pushing\n" - "to the same ref. You may want to first merge the remote changes (e.g.,\n" - "'git pull') before pushing again.\n" + "to the same ref. You may want to first integrate the remote changes\n" + "(e.g., 'git pull ...') before pushing again.\n" "See the 'Note about fast-forwards' in 'git push --help' for details."); static const char message_advice_ref_already_exists[] = diff --git a/builtin/reset.c b/builtin/reset.c index 6032131a90..afa6e020e8 100644 --- a/builtin/reset.c +++ b/builtin/reset.c @@ -93,10 +93,12 @@ static int reset_index(const unsigned char *sha1, int reset_type, int quiet) static void print_new_head_line(struct commit *commit) { const char *hex, *body; + char *msg; hex = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV); printf(_("HEAD is now at %s"), hex); - body = strstr(commit->buffer, "\n\n"); + msg = logmsg_reencode(commit, NULL, get_log_output_encoding()); + body = strstr(msg, "\n\n"); if (body) { const char *eol; size_t len; @@ -107,6 +109,7 @@ static void print_new_head_line(struct commit *commit) } else printf("\n"); + logmsg_free(msg, commit); } static void update_index_from_diff(struct diff_queue_struct *q, diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 67701be551..a5ec30d74e 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -111,6 +111,7 @@ static void show_commit(struct commit *commit, void *data) ctx.date_mode = revs->date_mode; ctx.date_mode_explicit = revs->date_mode_explicit; ctx.fmt = revs->commit_format; + ctx.output_encoding = get_log_output_encoding(); pretty_print_commit(&ctx, commit, &buf); if (revs->graph) { if (buf.len) { diff --git a/builtin/revert.c b/builtin/revert.c index 0401fdb02c..1d2648b756 100644 --- a/builtin/revert.c +++ b/builtin/revert.c @@ -54,6 +54,7 @@ static int option_parse_x(const struct option *opt, return 0; } +LAST_ARG_MUST_BE_NULL static void verify_opt_compatible(const char *me, const char *base_opt, ...) { const char *this_opt; @@ -70,6 +71,7 @@ static void verify_opt_compatible(const char *me, const char *base_opt, ...) die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt); } +LAST_ARG_MUST_BE_NULL static void verify_opt_mutually_compatible(const char *me, ...) { const char *opt1, *opt2 = NULL; diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 1fd6f8ac59..1434f8fee4 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -137,6 +137,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit) ctx.subject = ""; ctx.after_subject = ""; ctx.date_mode = DATE_NORMAL; + ctx.output_encoding = get_log_output_encoding(); pretty_print_commit(&ctx, commit, &ufbuf); buffer = ufbuf.buf; } else if (*buffer) { diff --git a/builtin/show-branch.c b/builtin/show-branch.c index 99ec4af224..9788eb115b 100644 --- a/builtin/show-branch.c +++ b/builtin/show-branch.c @@ -673,8 +673,8 @@ int cmd_show_branch(int ac, const char **av, const char *prefix) OPT_SET_INT(0, "sparse", &dense, N_("show merges reachable from only one tip"), 0), OPT_SET_INT(0, "date-order", &sort_order, - N_("show commits where no parent comes before its " - "children"), + N_("topologically sort, maintaining date order " + "where possible"), REV_SORT_BY_COMMIT_DATE), { OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"), N_("show <n> most recent ref-log entries starting at " diff --git a/builtin/show-ref.c b/builtin/show-ref.c index 4a0310da37..87806ad5b0 100644 --- a/builtin/show-ref.c +++ b/builtin/show-ref.c @@ -31,6 +31,9 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo const char *hex; unsigned char peeled[20]; + if (show_head && !strcmp(refname, "HEAD")) + goto match; + if (tags_only || heads_only) { int match; @@ -167,9 +170,10 @@ static const struct option show_ref_options[] = { OPT_BOOLEAN(0, "verify", &verify, N_("stricter reference checking, " "requires exact ref path")), { OPTION_BOOLEAN, 'h', NULL, &show_head, NULL, - N_("show the HEAD reference"), + N_("show the HEAD reference, even if it would be filtered out"), PARSE_OPT_NOARG | PARSE_OPT_HIDDEN }, - OPT_BOOLEAN(0, "head", &show_head, N_("show the HEAD reference")), + OPT_BOOLEAN(0, "head", &show_head, + N_("show the HEAD reference, even if it would be filtered out")), OPT_BOOLEAN('d', "dereference", &deref_tags, N_("dereference tags into object IDs")), { OPTION_CALLBACK, 's', "hash", &abbrev, N_("n"), |