@@ -165,6 +165,11 @@ ifndef::git-pull[]
Disable recursive fetching of submodules (this has the same effect as
using the `--recurse-submodules=no` option).
+--set-upstream::
+ If the new URL remote is correct, pull and add upstream (tracking)
+ reference, used by argument-less linkgit:git-push[1] and other commands.
+ For more information, see `branch.<name>.merge` in linkgit:git-config[1].
+
--submodule-prefix=<path>::
Prepend <path> to paths printed in informative messages
such as "Fetching submodule foo". This option is used
@@ -23,6 +23,7 @@
#include "packfile.h"
#include "list-objects-filter-options.h"
#include "commit-reach.h"
+#include "branch.h"
static const char * const builtin_fetch_usage[] = {
N_("git fetch [<options>] [<repository> [<refspec>...]]"),
@@ -46,7 +47,7 @@ static int fetch_prune_tags_config = -1; /* unspecified */
static int prune_tags = -1; /* unspecified */
#define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
-static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative;
+static int all, append, dry_run, force, keep, multiple, update_head_ok, verbosity, deepen_relative, set_upstream;
static int progress = -1;
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
static int max_children = 1;
@@ -113,6 +114,8 @@ static struct option builtin_fetch_options[] = {
OPT__VERBOSITY(&verbosity),
OPT_BOOL(0, "all", &all,
N_("fetch from all remotes")),
+ OPT_BOOL(0, "set-upstream", &set_upstream,
+ N_("set upstream for git pull/fetch")),
OPT_BOOL('a', "append", &append,
N_("append to .git/FETCH_HEAD instead of overwriting")),
OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
@@ -1317,6 +1320,61 @@ static int do_fetch(struct transport *transport,
retcode = 1;
goto cleanup;
}
+
+ /* TODO: remove debug trace */
+ if (set_upstream) {
+ struct branch *branch = branch_get("HEAD");
+ struct ref *rm;
+ struct ref *target = NULL;
+ /*
+ * We want to set the current branch config following the
+ * ref_map entry which fetches on FETCH_HEAD
+ * In case of "git pull <remote> --set-upstream" we
+ * don't want to set all branches' config.
+ * If there is no local ref which points on FETCH_HEAD
+ * we don't set the config for the current branch
+ * and warn the user.
+ * If there is a fetch of more than one branch for example:
+ * "git pull <remote> <branch> <branch> --set-upstream"
+ * setting the current branch's config makes no sense.
+ * Where we are in case of "git pull <remote> <branch>:<branch>" we
+ * don't want to set the config for the local branch
+ * can be improved in the future to set local branch's config.
+ */
+ for (rm = ref_map; rm; rm = rm->next) {
+ fprintf(stderr, "\n -%s", rm->name);
+ if (rm->peer_ref) {
+ fprintf(stderr, " -> %s", rm->peer_ref->name);
+ } else {
+ if (target) {
+ fprintf(stderr, " -> FETCH_HEAD\n");
+ warning(_("Multiple FETCH_HEAD"));
+ target = NULL;
+ break;
+ } else {
+ target = rm;
+ fprintf(stderr, " -> FETCH_HEAD");
+ }
+ }
+ }
+ fprintf(stderr, "\n\n");
+ if (target) {
+ if (!strcmp(ref_map->name, "HEAD") ||
+ starts_with(ref_map->name, "refs/heads/")) {
+ install_branch_config(0, branch->name,
+ transport->remote->name,
+ target->name);
+ } else if (starts_with(ref_map->name, "refs/remotes/")) {
+ warning(_("Not setting upstream for a remote remote-tracking branch"));
+ } else if (starts_with(ref_map->name, "refs/tags/")) {
+ warning(_("Tag upstream not set"));
+ } else {
+ warning(_("Unknown branch type"));
+ }
+ } else {
+ warning(_("Fetching more than one branch. Current branch's upstream not set"));
+ }
+ }
free_refs(ref_map);
/* if neither --no-tags nor --tags was specified, do automated tag
@@ -122,6 +122,7 @@ static char *opt_update_shallow;
static char *opt_refmap;
static char *opt_ipv4;
static char *opt_ipv6;
+static char *set_upstream;
static struct option pull_options[] = {
/* Shared options */
@@ -233,6 +234,9 @@ static struct option pull_options[] = {
OPT_PASSTHRU('6', "ipv6", &opt_ipv6, NULL,
N_("use IPv6 addresses only"),
PARSE_OPT_NOARG),
+ OPT_PASSTHRU(0, "set-upstream", &set_upstream, NULL,
+ N_("set upstream for git pull/fetch"),
+ PARSE_OPT_NOARG),
OPT_END()
};
@@ -541,6 +545,8 @@ static int run_fetch(const char *repo, const char **refspecs)
argv_array_push(&args, opt_ipv4);
if (opt_ipv6)
argv_array_push(&args, opt_ipv6);
+ if (set_upstream)
+ argv_array_push(&args, set_upstream);
if (repo) {
argv_array_push(&args, repo);
new file mode 100644
@@ -0,0 +1,141 @@
+#!/bin/sh
+
+test_description='"git fetch/pull --set-upstream" basic tests.
+
+'
+. ./test-lib.sh
+
+
+
+check_config() {
+ (echo $2; echo $3) >expect.$1
+ (git config branch.$1.remote
+ git config branch.$1.merge) >actual.$1
+ test_cmp expect.$1 actual.$1
+}
+
+check_config_empty() {
+ git config branch.$1.remote >remote.$1
+ test_must_be_empty remote.$1
+ git config branch.$1.merge >merge.$1
+ test_must_be_empty merge.$1
+}
+
+ensure_fresh_upstream() {
+ rm -rf parent && git init --bare parent
+}
+
+test_expect_success 'setup bare parent fetch' '
+ ensure_fresh_upstream &&
+ git remote add upstream parent &&
+ git remote add up parent
+'
+
+test_expect_success 'setup commit on master and other fetch' '
+ test_commit one &&
+ git push upstream master &&
+ git checkout -b other &&
+ test_commit two &&
+ git push upstream other
+'
+
+#tests for fetch --set-upstream
+
+test_expect_success 'fetch --set-upstream does not set branch other' '
+ git checkout master &&
+ git fetch --set-upstream upstream &&
+ check_config_empty master &&
+ check_config_empty other
+'
+
+#test_expect_success 'fetch --set-upstream does not set branch other' '
+# git checkout master &&
+# git fetch --set-upstream upstream &&
+# check_config master upstream refs/heads/master &&
+# check_config_empty other
+#'
+
+test_expect_success 'fetch --set-upstream upstream master sets branch master but not other' '
+ git fetch --set-upstream upstream master &&
+ check_config master upstream refs/heads/master &&
+ check_config_empty other
+'
+
+
+test_expect_success 'fetch --set-upstream upstream other sets branch other' '
+ git fetch --set-upstream upstream other &&
+ check_config master upstream refs/heads/other &&
+ check_config_empty other
+'
+
+
+test_expect_success 'fetch --set-upstream master:other does not set the branch other2' '
+ git fetch --set-upstream upstream master:other2 &&
+ check_config_empty other2
+'
+
+
+test_expect_success 'fetch --set-upstream http://nosuchdomain.example.com fails with the bad url' '
+ test_must_fail git fetch --set-upstream http://nosuchdomain.example.com
+'
+
+
+#tests for pull --set-upstream
+
+
+
+test_expect_success 'setup bare parent pull' '
+ git remote rm upstream &&
+ ensure_fresh_upstream &&
+ git remote add upstream parent
+'
+
+test_expect_success 'setup commit on master and other pull' '
+ test_commit three &&
+ git push --tags upstream master &&
+ test_commit four &&
+ git push upstream other
+'
+
+
+test_expect_success 'pull --set-upstream upstream master sets branch master but not other' '
+ git pull --set-upstream upstream master &&
+ check_config master upstream refs/heads/master &&
+ check_config_empty other
+'
+
+test_expect_success 'pull --set-upstream master:other2 does not set the branch other2' '
+ git pull --set-upstream upstream master:other2 &&
+ check_config_empty other2
+'
+
+test_expect_success 'pull --set-upstream upstream other sets branch other' '
+ git pull --set-upstream upstream other &&
+ check_config master upstream refs/heads/other &&
+ check_config_empty other
+'
+
+test_expect_success 'pull --set-upstream upstream tag does not set the tag' '
+ git pull --tags --set-upstream upstream three &&
+ check_config_empty three
+'
+
+test_expect_success 'pull --set-upstream http://nosuchdomain.example.com fails with the bad url' '
+ test_must_fail git pull --set-upstream http://nosuchdomain.example.com
+'
+
+test_expect_success 'pull --set-upstream upstream HEAD sets branch HEAD' '
+ git pull --set-upstream upstream HEAD &&
+ check_config master upstream HEAD &&
+ git checkout other &&
+ git pull --set-upstream upstream HEAD &&
+ check_config other upstream HEAD
+'
+
+test_expect_success 'pull --set-upstream upstream with more than one branch does nothing' '
+ git pull --set-upstream upstream master three &&
+ check_config master upstream HEAD &&
+ check_config_empty three
+'
+
+test_done