aboutsummaryrefslogtreecommitdiffstats
path: root/builtin/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin/log.c')
-rw-r--r--builtin/log.c174
1 files changed, 129 insertions, 45 deletions
diff --git a/builtin/log.c b/builtin/log.c
index d104d5c688..0a7ed4bef9 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -33,7 +33,6 @@
#include "commit-slab.h"
#include "repository.h"
#include "commit-reach.h"
-#include "interdiff.h"
#include "range-diff.h"
#define MAIL_DEFAULT_WRAP 72
@@ -599,8 +598,8 @@ static int show_tree_object(const struct object_id *oid,
static void show_setup_revisions_tweak(struct rev_info *rev,
struct setup_revision_opt *opt)
{
- if (rev->ignore_merges) {
- /* There was no "-m" on the command line */
+ if (rev->ignore_merges < 0) {
+ /* There was no "-m" variant on the command line */
rev->ignore_merges = 0;
if (!rev->first_parent_only && !rev->combine_merges) {
/* No "--first-parent", "-c", or "--cc" */
@@ -732,8 +731,7 @@ static void log_setup_revisions_tweak(struct rev_info *rev,
if (!rev->diffopt.output_format && rev->combine_merges)
rev->diffopt.output_format = DIFF_FORMAT_PATCH;
- /* Turn -m on when --cc/-c was given */
- if (rev->combine_merges)
+ if (rev->first_parent_only && rev->ignore_merges < 0)
rev->ignore_merges = 0;
}
@@ -807,9 +805,15 @@ enum cover_from_description {
COVER_FROM_AUTO
};
+enum auto_base_setting {
+ AUTO_BASE_NEVER,
+ AUTO_BASE_ALWAYS,
+ AUTO_BASE_WHEN_ABLE
+};
+
static enum thread_level thread;
static int do_signoff;
-static int base_auto;
+static enum auto_base_setting auto_base;
static char *from;
static const char *signature = git_version_string;
static const char *signature_file;
@@ -908,7 +912,11 @@ static int git_format_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "format.outputdirectory"))
return git_config_string(&config_output_directory, var, value);
if (!strcmp(var, "format.useautobase")) {
- base_auto = git_config_bool(var, value);
+ if (value && !strcasecmp(value, "whenAble")) {
+ auto_base = AUTO_BASE_WHEN_ABLE;
+ return 0;
+ }
+ auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
return 0;
}
if (!strcmp(var, "format.from")) {
@@ -1062,7 +1070,7 @@ static char *find_branch_name(struct rev_info *rev)
return NULL;
ref = rev->cmdline.rev[positive].name;
tip_oid = &rev->cmdline.rev[positive].item->oid;
- if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref) &&
+ if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref, 0) &&
skip_prefix(full_ref, "refs/heads/", &v) &&
oideq(tip_oid, &branch_oid))
branch = xstrdup(v);
@@ -1128,18 +1136,18 @@ do_pp:
static int get_notes_refs(struct string_list_item *item, void *arg)
{
- argv_array_pushf(arg, "--notes=%s", item->string);
+ strvec_pushf(arg, "--notes=%s", item->string);
return 0;
}
-static void get_notes_args(struct argv_array *arg, struct rev_info *rev)
+static void get_notes_args(struct strvec *arg, struct rev_info *rev)
{
if (!rev->show_notes) {
- argv_array_push(arg, "--no-notes");
+ strvec_push(arg, "--no-notes");
} else if (rev->notes_opt.use_default_notes > 0 ||
(rev->notes_opt.use_default_notes == -1 &&
!rev->notes_opt.extra_notes_refs.nr)) {
- argv_array_push(arg, "--notes");
+ strvec_push(arg, "--notes");
} else {
for_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);
}
@@ -1197,6 +1205,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
log.in1 = 2;
log.in2 = 4;
log.file = rev->diffopt.file;
+ log.groups = SHORTLOG_GROUP_AUTHOR;
for (i = 0; i < nr; i++)
shortlog_add_commit(&log, list[i]);
@@ -1208,7 +1217,8 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
if (rev->idiff_oid1) {
fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title);
- show_interdiff(rev, 0);
+ show_interdiff(rev->idiff_oid1, rev->idiff_oid2, 0,
+ &rev->diffopt);
}
if (rev->rdiff1) {
@@ -1217,7 +1227,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
* can be added later if deemed desirable.
*/
struct diff_options opts;
- struct argv_array other_arg = ARGV_ARRAY_INIT;
+ struct strvec other_arg = STRVEC_INIT;
diff_setup(&opts);
opts.file = rev->diffopt.file;
opts.use_color = rev->diffopt.use_color;
@@ -1226,7 +1236,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
get_notes_args(&other_arg, rev);
show_range_diff(rev->rdiff1, rev->rdiff2,
rev->creation_factor, 1, &opts, &other_arg);
- argv_array_clear(&other_arg);
+ strvec_clear(&other_arg);
}
}
@@ -1425,6 +1435,23 @@ static int from_callback(const struct option *opt, const char *arg, int unset)
return 0;
}
+static int base_callback(const struct option *opt, const char *arg, int unset)
+{
+ const char **base_commit = opt->value;
+
+ if (unset) {
+ auto_base = AUTO_BASE_NEVER;
+ *base_commit = NULL;
+ } else if (!strcmp(arg, "auto")) {
+ auto_base = AUTO_BASE_ALWAYS;
+ *base_commit = NULL;
+ } else {
+ auto_base = AUTO_BASE_NEVER;
+ *base_commit = arg;
+ }
+ return 0;
+}
+
struct base_tree_info {
struct object_id base_commit;
int nr_patch_id, alloc_patch_id;
@@ -1437,13 +1464,36 @@ static struct commit *get_base_commit(const char *base_commit,
{
struct commit *base = NULL;
struct commit **rev;
- int i = 0, rev_nr = 0;
+ int i = 0, rev_nr = 0, auto_select, die_on_failure;
- if (base_commit && strcmp(base_commit, "auto")) {
+ switch (auto_base) {
+ case AUTO_BASE_NEVER:
+ if (base_commit) {
+ auto_select = 0;
+ die_on_failure = 1;
+ } else {
+ /* no base information is requested */
+ return NULL;
+ }
+ break;
+ case AUTO_BASE_ALWAYS:
+ case AUTO_BASE_WHEN_ABLE:
+ if (base_commit) {
+ BUG("requested automatic base selection but a commit was provided");
+ } else {
+ auto_select = 1;
+ die_on_failure = auto_base == AUTO_BASE_ALWAYS;
+ }
+ break;
+ default:
+ BUG("unexpected automatic base selection method");
+ }
+
+ if (!auto_select) {
base = lookup_commit_reference_by_name(base_commit);
if (!base)
die(_("unknown commit %s"), base_commit);
- } else if ((base_commit && !strcmp(base_commit, "auto"))) {
+ } else {
struct branch *curr_branch = branch_get(NULL);
const char *upstream = branch_get_upstream(curr_branch, NULL);
if (upstream) {
@@ -1451,19 +1501,32 @@ static struct commit *get_base_commit(const char *base_commit,
struct commit *commit;
struct object_id oid;
- if (get_oid(upstream, &oid))
- die(_("failed to resolve '%s' as a valid ref"), upstream);
+ if (get_oid(upstream, &oid)) {
+ if (die_on_failure)
+ die(_("failed to resolve '%s' as a valid ref"), upstream);
+ else
+ return NULL;
+ }
commit = lookup_commit_or_die(&oid, "upstream base");
base_list = get_merge_bases_many(commit, total, list);
/* There should be one and only one merge base. */
- if (!base_list || base_list->next)
- die(_("could not find exact merge base"));
+ if (!base_list || base_list->next) {
+ if (die_on_failure) {
+ die(_("could not find exact merge base"));
+ } else {
+ free_commit_list(base_list);
+ return NULL;
+ }
+ }
base = base_list->item;
free_commit_list(base_list);
} else {
- die(_("failed to get upstream, if you want to record base commit automatically,\n"
- "please use git branch --set-upstream-to to track a remote branch.\n"
- "Or you could specify base commit by --base=<base-commit-id> manually"));
+ if (die_on_failure)
+ die(_("failed to get upstream, if you want to record base commit automatically,\n"
+ "please use git branch --set-upstream-to to track a remote branch.\n"
+ "Or you could specify base commit by --base=<base-commit-id> manually"));
+ else
+ return NULL;
}
}
@@ -1480,8 +1543,14 @@ static struct commit *get_base_commit(const char *base_commit,
for (i = 0; i < rev_nr / 2; i++) {
struct commit_list *merge_base;
merge_base = get_merge_bases(rev[2 * i], rev[2 * i + 1]);
- if (!merge_base || merge_base->next)
- die(_("failed to find exact merge base"));
+ if (!merge_base || merge_base->next) {
+ if (die_on_failure) {
+ die(_("failed to find exact merge base"));
+ } else {
+ free(rev);
+ return NULL;
+ }
+ }
rev[i] = merge_base->item;
}
@@ -1491,12 +1560,24 @@ static struct commit *get_base_commit(const char *base_commit,
rev_nr = DIV_ROUND_UP(rev_nr, 2);
}
- if (!in_merge_bases(base, rev[0]))
- die(_("base commit should be the ancestor of revision list"));
+ if (!in_merge_bases(base, rev[0])) {
+ if (die_on_failure) {
+ die(_("base commit should be the ancestor of revision list"));
+ } else {
+ free(rev);
+ return NULL;
+ }
+ }
for (i = 0; i < total; i++) {
- if (base == list[i])
- die(_("base commit shouldn't be in revision list"));
+ if (base == list[i]) {
+ if (die_on_failure) {
+ die(_("base commit shouldn't be in revision list"));
+ } else {
+ free(rev);
+ return NULL;
+ }
+ }
}
free(rev);
@@ -1596,16 +1677,20 @@ static void infer_range_diff_ranges(struct strbuf *r1,
struct commit *head)
{
const char *head_oid = oid_to_hex(&head->object.oid);
+ int prev_is_range = !!strstr(prev, "..");
- if (!strstr(prev, "..")) {
+ if (prev_is_range)
+ strbuf_addstr(r1, prev);
+ else
strbuf_addf(r1, "%s..%s", head_oid, prev);
+
+ if (origin)
+ strbuf_addf(r2, "%s..%s", oid_to_hex(&origin->object.oid), head_oid);
+ else if (prev_is_range)
+ die(_("failed to infer range-diff origin of current series"));
+ else {
+ warning(_("using '%s' as range-diff origin of current series"), prev);
strbuf_addf(r2, "%s..%s", prev, head_oid);
- } else if (!origin) {
- die(_("failed to infer range-diff ranges"));
- } else {
- strbuf_addstr(r1, prev);
- strbuf_addf(r2, "%s..%s",
- oid_to_hex(&origin->object.oid), head_oid);
}
}
@@ -1635,6 +1720,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
char *branch_name = NULL;
char *base_commit = NULL;
struct base_tree_info bases;
+ struct commit *base;
int show_progress = 0;
struct progress *progress = NULL;
struct oid_array idiff_prev = OID_ARRAY_INIT;
@@ -1711,8 +1797,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
PARSE_OPT_OPTARG, thread_callback),
OPT_STRING(0, "signature", &signature, N_("signature"),
N_("add a signature")),
- OPT_STRING(0, "base", &base_commit, N_("base-commit"),
- N_("add prerequisite tree info to the patch series")),
+ OPT_CALLBACK_F(0, "base", &base_commit, N_("base-commit"),
+ N_("add prerequisite tree info to the patch series"),
+ 0, base_callback),
OPT_FILENAME(0, "signature-file", &signature_file,
N_("add a signature from a file")),
OPT__QUIET(&quiet, N_("don't print the patch filenames")),
@@ -1749,9 +1836,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
s_r_opt.def = "HEAD";
s_r_opt.revarg_opt = REVARG_COMMITTISH;
- if (base_auto)
- base_commit = "auto";
-
if (default_attach) {
rev.mime_boundary = default_attach;
rev.no_inline = 1;
@@ -2015,8 +2099,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
}
memset(&bases, 0, sizeof(bases));
- if (base_commit) {
- struct commit *base = get_base_commit(base_commit, list, nr);
+ base = get_base_commit(base_commit, list, nr);
+ if (base) {
reset_revision_walk();
clear_object_flags(UNINTERESTING);
prepare_bases(&bases, base, list, nr);