diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index c1efaaa5c5..cc8f424bb7 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -11,7 +11,7 @@ SYNOPSIS [verse] 'git merge' [-n] [--stat] [--no-commit] [--squash] [-s ] [-X ] - [--[no-]rerere-autoupdate] [-m ] ... + [--[no-]rerere-autoupdate] [-m ] [...] 'git merge' HEAD ... 'git merge' --abort @@ -95,8 +95,13 @@ commit or stash your changes before running 'git merge'. ...:: Commits, usually other branch heads, to merge into our branch. - You need at least one . Specifying more than one - obviously means you are trying an Octopus. + Specifying more than one commit will create a merge with + more than two parents (affectionately called an Octopus merge). ++ +If no commit is given from the command line, and if `merge.defaultToUpstream` +configuration variable is set, merge the remote tracking branches +that the current branch is configured to use as its upstream. +See also the configuration section of this manual page. PRE-MERGE CHECKS diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 1e5c22c5e5..83dba63082 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -6,6 +6,16 @@ merge.conflictstyle:: a `>>>>>>>` marker. An alternate style, "diff3", adds a `|||||||` marker and the original text before the `=======` marker. +merge.defaultToUpstream:: + If merge is called without any commit argument, merge the upstream + branches configured for the current branch by using their last + observed values stored in their remote tracking branches. + The values of the `branch..merge` that name the + branches at the remote named by `branch..remote` + are consulted, and then they are mapped via `remote..fetch` + to their corresponding remote tracking branches, and the tips of + these tracking branches are merged. + merge.log:: In addition to branch names, populate the log message with at most the specified number of one-line descriptions from the diff --git a/builtin/merge.c b/builtin/merge.c index a2105ef90c..309bdd4dc7 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -25,6 +25,7 @@ #include "help.h" #include "merge-recursive.h" #include "resolve-undo.h" +#include "remote.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@ -37,7 +38,7 @@ struct strategy { }; static const char * const builtin_merge_usage[] = { - "git merge [options] ...", + "git merge [options] [...]", "git merge [options] HEAD ", "git merge --abort", NULL @@ -59,6 +60,7 @@ static int option_renormalize; static int verbosity; static int allow_rerere_auto; static int abort_current_merge; +static int default_to_upstream; static struct strategy all_strategy[] = { { "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL }, @@ -537,6 +539,9 @@ static int git_merge_config(const char *k, const char *v, void *cb) if (is_bool && shortlog_len) shortlog_len = DEFAULT_MERGE_LOG_LEN; return 0; + } else if (!strcmp(k, "merge.defaulttoupstream")) { + default_to_upstream = git_config_bool(k, v); + return 0; } return git_diff_ui_config(k, v, cb); } @@ -912,6 +917,35 @@ static int evaluate_result(void) return cnt; } +/* + * Pretend as if the user told us to merge with the tracking + * branch we have for the upstream of the current branch + */ +static int setup_with_upstream(const char ***argv) +{ + struct branch *branch = branch_get(NULL); + int i; + const char **args; + + if (!branch) + die("No current branch."); + if (!branch->remote) + die("No remote for the current branch."); + if (!branch->merge_nr) + die("No default upstream defined for the current branch."); + + 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", + branch->merge[i]->src, branch->remote_name); + args[i] = branch->merge[i]->dst; + } + args[i] = NULL; + *argv = args; + return i; +} + int cmd_merge(int argc, const char **argv, const char *prefix) { unsigned char result_tree[20]; @@ -984,6 +1018,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (!allow_fast_forward && fast_forward_only) die("You cannot combine --no-ff with --ff-only."); + if (!argc && !abort_current_merge && default_to_upstream) + argc = setup_with_upstream(&argv); + if (!argc) usage_with_options(builtin_merge_usage, builtin_merge_options);