[RFC/PATCH] pull: set-upstream implementation

Subsystems: documentation, the rest

4 messages, 2 authors, 2016-06-16 · open the first message on its own page

[RFC/PATCH] pull: set-upstream implementation

From: Erwan Mathoniere <hidden>
Date: 2016-06-16 02:19:36

Implements pull [--set-upstream | -u] which sets the remote tracking
branch to the one the user just pulled from.

	git pull [--set-upstream | -u] <remote> <branch>

After successfully fetched from <remote>, sets branch.<name>.remote to
<remote> and branch.<name>.merge to follow <remote>/<branch>

Signed-off-by: Erwan Mathoniere <redacted>
Signed-off-by: Jordan De Gea <redacted>
Signed-off-by: Matthieu Moy <redacted>
---
Hello,

`git push --set-upstream <remote> <branch>` sets the remote and merge config
variables for <branch> after successfully pushed.

This patch implements an equivalent for `git pull` or
`git branch --set-upstream-to=<remote>/<branch>`.

Difficulties:
	- I can't figure out what remote branch sould be tracked
	in that case: `git pull -u origin :master`
	- Is the result of 'resolve_ref_unsafe' should be freed ?

What's your opinion ?


 Documentation/git-pull.txt |  7 +++++
 builtin/pull.c             | 61 +++++++++++++++++++++++++++++++++++++
 t/t5544-pull-upstream.sh   | 75 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+)
 create mode 100755 t/t5544-pull-upstream.sh
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index d033b25..3a2e0b7 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -93,6 +93,13 @@ OPTIONS
 	has to be called afterwards to bring the work tree up to date with the
 	merge result.
 
+-u::
+--set-upstream::
+	For each branch that is successfully pulled, 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].
+
 Options related to merging
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/builtin/pull.c b/builtin/pull.c
index 1d7333c..e096858 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -17,6 +17,7 @@
 #include "revision.h"
 #include "tempfile.h"
 #include "lockfile.h"
+#include "branch.h"
 
 enum rebase_type {
 	REBASE_INVALID = -1,
@@ -109,6 +110,9 @@ static char *opt_unshallow;
 static char *opt_update_shallow;
 static char *opt_refmap;
 
+/* Options about upstream */
+static int opt_set_upstream;
+
 static struct option pull_options[] = {
 	/* Shared options */
 	OPT__VERBOSITY(&opt_verbosity),
@@ -116,6 +120,9 @@ static struct option pull_options[] = {
 		N_("force progress reporting"),
 		PARSE_OPT_NOARG),
 
+	/* Options about upstream */
+	OPT_BOOL('u', "set-upstream", &opt_set_upstream, N_("set upstream for git pull/status")),
+
 	/* Options passed to git-merge or git-rebase */
 	OPT_GROUP(N_("Options related to merging")),
 	{ OPTION_CALLBACK, 'r', "rebase", &opt_rebase,
@@ -829,6 +836,57 @@ static int run_rebase(const unsigned char *curr_head,
 	return ret;
 }
 
+static int set_pull_upstream(const char *repo, const char **refspecs_name)
+{
+	unsigned char sha1[GIT_SHA1_RAWSZ];
+	const char *local_branch, *remote_branch;
+	struct strbuf remote_name;
+	struct refspec *refspecs;
+	int nr_refspec, i;
+
+	if (repo == NULL) {
+		warning(N_("no remote was specified"));
+		return 1;
+	}
+
+	for (nr_refspec = 0; refspecs_name[nr_refspec] != NULL; nr_refspec++);
+
+	if (nr_refspec == 0) {
+		warning(N_("no refspec was specified"));
+		return 1;
+	}
+
+	refspecs = parse_fetch_refspec(nr_refspec, refspecs_name);
+
+	for (i = 0; i < nr_refspec; i++) {
+		if (refspecs[i].src != NULL && strlen(refspecs[i].src) > 0) {
+			remote_branch = refspecs[i].src;
+		} else {
+			warning(N_("not yet implemented"));
+			continue;
+		}
+
+		if (refspecs[i].dst != NULL && strlen(refspecs[i].dst) > 0) {
+			local_branch = refspecs[i].dst;
+		} else {
+			// TODO : Should it be freed ?
+			local_branch = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
+			skip_prefix(local_branch, "refs/heads/", &local_branch);
+		}
+
+		strbuf_init(&remote_name, strlen(repo) + strlen(remote_branch) + 1);
+		strbuf_addf(&remote_name, "%s/%s", repo, remote_branch);
+
+		create_branch(local_branch, local_branch, remote_name.buf, 0, 0, 0, opt_verbosity < 0, BRANCH_TRACK_OVERRIDE);
+
+		strbuf_release(&remote_name);
+	}
+
+	free_refspec(nr_refspec, refspecs);
+
+	return 0;
+}
+
 int cmd_pull(int argc, const char **argv, const char *prefix)
 {
 	const char *repo, **refspecs;
@@ -884,6 +942,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (opt_dry_run)
 		return 0;
 
+	if (opt_set_upstream)
+		set_pull_upstream(repo, refspecs);
+
 	if (get_sha1("HEAD", curr_head))
 		hashclr(curr_head);
 
diff --git a/t/t5544-pull-upstream.sh b/t/t5544-pull-upstream.sh
new file mode 100755
index 0000000..38eb51d
--- /dev/null
+++ b/t/t5544-pull-upstream.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+test_description='pull with --set-upstream'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
+
+ensure_fresh_upstream() {
+	rm -rf parent &&
+	git init parent &&
+	cd parent &&
+	(
+		echo content >file &&
+		git add file &&
+		git commit -m one &&
+		git checkout -b other &&
+		echo content >file2 &&
+		git add file2 &&
+		git commit -m two &&
+		git checkout -b master2 &&
+		git checkout master
+	) &&
+	cd ..
+}
+
+test_expect_success 'setup bare parent' '
+	ensure_fresh_upstream &&
+	git remote add upstream parent &&
+	git pull upstream master
+'
+
+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
+}
+
+test_expect_success 'pull -u master' '
+	git pull -u upstream master &&
+	check_config master upstream refs/heads/master
+'
+
+test_expect_success 'pull -u master:other' '
+	git pull -u upstream master:other &&
+	check_config other upstream refs/heads/master
+'
+
+test_expect_success 'pull -u --dry-run other:other' '
+	git pull -u --dry-run upstream other:other &&
+	check_config other upstream refs/heads/master
+'
+
+test_expect_success 'pull -u master2:master2 master:other' '
+	git branch master2 &&
+	git pull -u upstream master2:master2 master:other &&
+	check_config master2 upstream refs/heads/master2 &&
+	check_config other upstream refs/heads/master
+'
+
+test_expect_success 'pull -u HEAD' '
+	git clone parent son &&
+	cd son &&
+	git checkout -b headbranch &&
+	git pull -u origin HEAD &&
+	check_config headbranch origin refs/heads/master
+'
+
+test_expect_success TTY 'quiet pull' '
+	ensure_fresh_upstream &&
+
+	test_terminal git pull -u --quiet upstream master 2>&1 | tee output &&
+	test_cmp /dev/null output
+'
+
+test_done
-- 
2.8.2.562.gdbf6e3e

[RFC/PATCH v2] pull: add --set-upstream

From: Erwan Mathoniere <hidden>
Date: 2016-06-16 02:19:45

Implement `git pull [--set-upstream | -u] <remote> <refspecs>` that set
tracking to the remote branch the user just pulled from.

After successfully pulling from `<remote>`, for each `<refspec>`
described in format `<remote_branch>:<local_branch>`, set
`branch.<local_branch>.remote` to `<remote>` and
`branch.<local_branch>.merge` to `refs/heads/<remote_branch>`. If
`<refspec>` lacks `<local_branch>` in the previous format or directly
refers to a branch, use the current branch as `<local_branch>` in the
above configuration setting.

`git push` has already its `--set-upstream`, it makes sense to have its
symmetrical for `git pull`.

For a beginner, when trying to use argumentless `git pull` without
tracking information set, advising to use 
`git branch --set-upstream-to` to set upstream can be quite confusing.
Using this `git pull --set-upstream` is easier and more natural.

Signed-off-by: Erwan Mathoniere <redacted>
Signed-off-by: Jordan De Gea <redacted>
Signed-off-by: Matthieu Moy <redacted>
---

Changes from v1:
- Code reshaped to :
  * warn + no-op when pulling from or to something that isn't a branch
or a configured remote
  * set upstream only after successfully merging/rebasing
- More relevant documentation
- Tests reshaped to be more independent from each others
- More tests (tags, detached heads, non-configured remote...)


For now, the documentation is quite hard to understand, but I didn't
figure how to explain without using too technical words. Should it stay
as it is or should I write something similar the above commit message?

Allowing to set non-configured repository as upstream isn't easy to
handle since the type of refspec must be checked and this is done by
verifying the existence of the remote-tracking branch at
`refs/remotes/<remote>/<branch>`.


 Documentation/git-pull.txt |  18 +++++
 builtin/pull.c             | 106 ++++++++++++++++++++++++++++-
 t/t5544-pull-upstream.sh   | 164 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 285 insertions(+), 3 deletions(-)
 create mode 100755 t/t5544-pull-upstream.sh
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index d033b25..6ae5e58 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -93,6 +93,24 @@ OPTIONS
 	has to be called afterwards to bring the work tree up to date with the
 	merge result.
 
+-u::
+--set-upstream::
+	After successfully pulling from explicitly given <repository> and
+	<refspecs>, set the configuration of the local branches pulled on, so
+	that each one tracks the remote branch pulled from. If a configuration
+	already exists, it is overwriten. For example, with `git pull -u origin
+	branch` the current branch will track `branch` from `origin`.
++
+If two or more branches are pulled on the same local branch, only the last one
+in arguments will be tracked.
++
+The given <repository> must be a configured remote. Can only set tracking to
+remote branches (e.g. can't set upstream to remote HEAD).
++
+Works symmetrically as `--set-upstream` for linkgit:git-push[1]. Allow using
+argumentless linkgit:git-pull[1] and other commands.  For more information, see
+`branch.<name>.merge` in linkgit:git-config[1].
+
 Options related to merging
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/builtin/pull.c b/builtin/pull.c
index 1d7333c..d9823d5 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -17,6 +17,7 @@
 #include "revision.h"
 #include "tempfile.h"
 #include "lockfile.h"
+#include "branch.h"
 
 enum rebase_type {
 	REBASE_INVALID = -1,
@@ -109,6 +110,9 @@ static char *opt_unshallow;
 static char *opt_update_shallow;
 static char *opt_refmap;
 
+/* Options about upstream */
+static int opt_set_upstream;
+
 static struct option pull_options[] = {
 	/* Shared options */
 	OPT__VERBOSITY(&opt_verbosity),
@@ -116,6 +120,9 @@ static struct option pull_options[] = {
 		N_("force progress reporting"),
 		PARSE_OPT_NOARG),
 
+	/* Options about upstream */
+	OPT_BOOL('u', "set-upstream", &opt_set_upstream, N_("set upstream for git pull/status")),
+
 	/* Options passed to git-merge or git-rebase */
 	OPT_GROUP(N_("Options related to merging")),
 	{ OPTION_CALLBACK, 'r', "rebase", &opt_rebase,
@@ -497,6 +504,10 @@ static void NORETURN die_no_merge_candidates(const char *repo, const char **refs
 		fprintf(stderr, "\n");
 		fprintf_ln(stderr, _("If you wish to set tracking information for this branch you can do so with:"));
 		fprintf(stderr, "\n");
+		fprintf_ln(stderr, "    git pull -u %s %s", _("<remote>"), _("<branch>"));
+		fprintf(stderr, "\n");
+		fprintf_ln(stderr, _("or"));
+		fprintf(stderr, "\n");
 		fprintf_ln(stderr, "    git branch --set-upstream-to=%s/%s %s\n",
 				remote_name, _("<branch>"), curr_branch->name);
 	} else
@@ -829,8 +840,92 @@ static int run_rebase(const unsigned char *curr_head,
 	return ret;
 }
 
+static void set_pull_upstream(const char *repo, const char **refspecs_name)
+{
+	unsigned char sha1[GIT_SHA1_RAWSZ];
+	struct refspec *refspec;
+	struct branch *branch;
+	struct remote *remote;
+	struct strbuf buf;
+	struct refspec tracking_refspec;
+	int nr_refspec, i, flags;
+
+	if (!repo) {
+		warning(_("a remote must be specified to set the upstream"));
+		return;
+	}
+
+	remote = remote_get(repo);
+	if (!remote) {
+		warning(_("cannot set upstream: "
+			"'%s' is not a configured remote"), repo);
+	}
+
+	for (nr_refspec = 0; refspecs_name[nr_refspec] != NULL; nr_refspec++)
+		; /* just counting */
+
+	if (nr_refspec == 0) {
+		warning(_("a remote branch must be specified to set the upstream"));
+		return;
+	}
+
+	strbuf_init(&buf, 0);
+	refspec = parse_fetch_refspec(nr_refspec, refspecs_name);
+
+	for (i = 0; i < nr_refspec; i++) {
+		if (refspec[i].pattern) {
+			warning(_("upstream cannot be set for patterns"));
+			continue;
+		}
+
+		branch = branch_get(refspec[i].dst);
+		if (!branch || !ref_exists(branch->refname)) {
+			if (!refspec[i].dst || !*refspec[i].dst)
+				warning(_("could not set upstream of HEAD when "
+					"it does not point to any branch."));
+			else
+				warning(_("cannot set upstream: "
+					"'%s' is not a branch"), refspec[i].dst);
+
+			continue;
+		}
+
+		if (!refspec[i].src || !*refspec[i].src) {
+			warning(_("remote branch must be specified "
+				"to set upstream"));
+			continue;
+		}
+		
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "refs/heads/%s", refspec[i].src);
+		memset(&tracking_refspec, 0, sizeof(struct refspec));
+		tracking_refspec.src = buf.buf;
+
+		if (remote_find_tracking(remote, &tracking_refspec)) {
+			warning(_("cannot set upstream: "
+				"no such remote branch '%s'"), refspec[i].src);
+			continue;
+		}
+
+		if (!resolve_ref_unsafe(tracking_refspec.dst, RESOLVE_REF_READING,
+					sha1, &flags)
+				|| (flags & REF_ISSYMREF)) {
+			warning(_("cannot set upstream: "
+				"no such remote branch '%s'"), refspec[i].src);
+			continue;
+		}
+
+		install_branch_config((opt_verbosity >= 0 ? BRANCH_CONFIG_VERBOSE : 0),
+		      branch->name, repo, buf.buf);
+	}
+
+	free_refspec(nr_refspec, refspec);
+	strbuf_release(&buf);
+}
+
 int cmd_pull(int argc, const char **argv, const char *prefix)
 {
+	int ret;
 	const char *repo, **refspecs;
 	struct sha1_array merge_heads = SHA1_ARRAY_INIT;
 	unsigned char orig_head[GIT_SHA1_RAWSZ], curr_head[GIT_SHA1_RAWSZ];
@@ -918,11 +1013,16 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (is_null_sha1(orig_head)) {
 		if (merge_heads.nr > 1)
 			die(_("Cannot merge multiple branches into empty head."));
-		return pull_into_void(*merge_heads.sha1, curr_head);
+		ret = pull_into_void(*merge_heads.sha1, curr_head);
 	} else if (opt_rebase) {
 		if (merge_heads.nr > 1)
 			die(_("Cannot rebase onto multiple branches."));
-		return run_rebase(curr_head, *merge_heads.sha1, rebase_fork_point);
+		ret = run_rebase(curr_head, *merge_heads.sha1, rebase_fork_point);
 	} else
-		return run_merge();
+		ret = run_merge();
+
+	if (opt_set_upstream && ret < 128)
+		set_pull_upstream(repo, refspecs);
+
+	return ret;
 }
diff --git a/t/t5544-pull-upstream.sh b/t/t5544-pull-upstream.sh
new file mode 100755
index 0000000..59f009d
--- /dev/null
+++ b/t/t5544-pull-upstream.sh
@@ -0,0 +1,164 @@
+#!/bin/sh
+
+test_description='pull with --set-upstream'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
+
+test_config_unchanged () {
+	git config --list --local >original
+	"$@"
+	git config --list --local >modified
+	test_cmp original modified
+}
+
+check_config () {
+	(echo "$2"; echo "$3") >expect
+	(git config branch.$1.remote
+	 git config branch.$1.merge) >actual
+	test_cmp expect actual
+}
+
+test_expect_success 'setup repos' '
+	git init parent &&
+	(
+		cd parent &&
+		echo content >file &&
+		git add file &&
+		git commit -am one &&
+		git tag initial_tag &&
+		git checkout -b master2 &&
+		echo content_modified >file &&
+		git commit -am "file modification"
+		git checkout -b other master &&
+		echo content >file2 &&
+		git add file2 &&
+		git commit -am two &&
+		git checkout -b other2
+	) &&
+	git init step_parent &&
+	(
+		cd step_parent &&
+		echo step_content >step_file &&
+		git add step_file &&
+		git commit -m step_one
+	) &&
+	git remote add upstream parent &&
+	git remote add step_upstream step_parent &&
+	git pull upstream master &&
+	git branch other
+'
+
+test_expect_success 'pull -u master' '
+	git pull -u upstream master &&
+	check_config master upstream refs/heads/master
+'
+
+test_expect_success 'pull -u takes the last branch as upstream' '
+	test_might_fail git config --unset branch.master.merge &&
+	test_might_fail git config --unset branch.master.remote &&
+	git pull -u upstream master master2 &&
+	check_config master upstream refs/heads/master2
+'
+
+test_expect_success 'pull -u master:other' '
+	git pull -u upstream master:other &&
+	check_config other upstream refs/heads/master
+'
+
+
+test_expect_success 'pull -u tracking non-local branch' '
+	git checkout -b master2_local &&
+	git pull -u upstream master2 &&
+	check_config master2_local upstream refs/heads/master2
+'
+
+
+test_expect_success 'pull -u --dry-run other:other' '
+	git config branch.other.merge refs/heads/master &&
+	git config branch.other.remote upstream &&
+	git pull -u --dry-run upstream other:other &&
+	check_config other upstream refs/heads/master
+'
+
+test_expect_success 'pull -u master2:master2 master:other' '
+	git branch master2 &&
+	git pull -u upstream master2:master2 master:other &&
+	check_config master2 upstream refs/heads/master2 &&
+	check_config other upstream refs/heads/master
+'
+
+test_expect_success 'pull -u HEAD does not track origin/HEAD nor remote HEAD on origin' '
+	git checkout -b other_head master &&
+	git fetch upstream other &&
+	git remote set-head upstream other &&
+	test_config_unchanged git pull -u upstream HEAD
+'
+
+test_expect_success 'pull -u sets upstream when merge conflicts occur' '
+	git checkout -b master_edited master &&
+	echo conflict >file2 &&
+	git add file2 &&
+	git commit -am conflict &&
+	test_must_fail git pull -u upstream other &&
+	git rm file2 &&
+	git commit &&
+	check_config master_edited upstream refs/heads/other
+'
+
+test_expect_success 'pull -u should not work when merging unrelated histories' '
+	git checkout master &&
+	test_config_unchanged test_must_fail git pull -u step_parent master
+'
+
+test_expect_success 'pull -u sets upstream after rebasing' '
+	git checkout -b other_rebased other &&
+	git config branch.other_rebased.merge master &&
+	ls .git/refs/remotes/upstream &&
+	git pull -r -u upstream master2 &&
+	git branch --set-upstream-to=upstream/master2 &&
+	ls .git/refs/remotes/upstream &&
+	check_config other_rebased upstream refs/heads/master2
+'
+
+test_expect_success 'pull -u refs/heads/*:refs/remotes/origin/* should not work' '
+	git checkout master &&
+	test_config_unchanged git pull -u upstream "refs/heads/*:refs/remotes/upstream/*"
+'
+
+test_expect_success 'pull -u master:refs/remotes/origin/master should not work' '
+	test_config_unchanged git pull -u upstream master:refs/remotes/upstream/master
+'
+
+test_expect_success 'pull -u with a tag should not work' '
+	git checkout master &&
+	test_config_unchanged git pull -u upstream initial_tag
+'
+
+test_expect_success 'pull -u on detached head should not work' '
+	git checkout HEAD^0 &&
+	test_config_unchanged git pull -u upstream master2 &&
+	git checkout -
+'
+
+test_expect_success 'pull -u with an unconfigured remote should not work' '
+	git checkout master &&
+	git clone parent unconfigured_parent &&
+	test_config_unchanged git pull -u "$(pwd)/unconfigured_parent" other2
+'
+
+test_expect_success 'pull -u with a modified remote.fetch' '
+	git remote add origin_modified parent &&
+	git push upstream master:custom_branch &&
+	git config remote.origin_modified.fetch "+refs/heads/*:refs/remotes/custom/*" &&
+	git checkout -b lonely_branch master &&
+	git pull -u origin_modified custom_branch &&
+	check_config lonely_branch origin_modified refs/heads/custom_branch
+'
+
+test_expect_success TTY 'quiet pull' '
+	git checkout master &&
+	test_terminal git pull -u --quiet upstream master 2>&1 | tee output &&
+	test_cmp /dev/null output
+'
+
+test_done
-- 
2.8.2.662.g22d3535.dirty

Re: [RFC/PATCH v2] pull: add --set-upstream

From: Philip Oakley <hidden>
Date: 2016-06-16 02:19:45

From: "Erwan Mathoniere" <redacted>
quoted hunk
Implement `git pull [--set-upstream | -u] <remote> <refspecs>` that set
tracking to the remote branch the user just pulled from.

After successfully pulling from `<remote>`, for each `<refspec>`
described in format `<remote_branch>:<local_branch>`, set
`branch.<local_branch>.remote` to `<remote>` and
`branch.<local_branch>.merge` to `refs/heads/<remote_branch>`. If
`<refspec>` lacks `<local_branch>` in the previous format or directly
refers to a branch, use the current branch as `<local_branch>` in the
above configuration setting.

`git push` has already its `--set-upstream`, it makes sense to have its
symmetrical for `git pull`.

For a beginner, when trying to use argumentless `git pull` without
tracking information set, advising to use
`git branch --set-upstream-to` to set upstream can be quite confusing.
Using this `git pull --set-upstream` is easier and more natural.

Signed-off-by: Erwan Mathoniere <redacted>
Signed-off-by: Jordan De Gea <redacted>
Signed-off-by: Matthieu Moy <redacted>
---

Changes from v1:
- Code reshaped to :
 * warn + no-op when pulling from or to something that isn't a branch
or a configured remote
 * set upstream only after successfully merging/rebasing
- More relevant documentation
- Tests reshaped to be more independent from each others
- More tests (tags, detached heads, non-configured remote...)


For now, the documentation is quite hard to understand, but I didn't
figure how to explain without using too technical words. Should it stay
as it is or should I write something similar the above commit message?

Allowing to set non-configured repository as upstream isn't easy to
handle since the type of refspec must be checked and this is done by
verifying the existence of the remote-tracking branch at
`refs/remotes/<remote>/<branch>`.


Documentation/git-pull.txt |  18 +++++
builtin/pull.c             | 106 ++++++++++++++++++++++++++++-
t/t5544-pull-upstream.sh   | 164 
+++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 285 insertions(+), 3 deletions(-)
create mode 100755 t/t5544-pull-upstream.sh
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index d033b25..6ae5e58 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -93,6 +93,24 @@ OPTIONS
 has to be called afterwards to bring the work tree up to date with the
 merge result.

+-u::
+--set-upstream::
+ After successfully pulling from explicitly given <repository> and
s/from explicitly/from an explicitly/
+ <refspecs>, set the configuration of the local branches pulled on, so
s/branches pulled on/branches that were pulled/
+ that each one tracks the remote branch pulled from. If a configuration
+ already exists, it is overwriten. For example, with `git pull -u origin
+ branch` the current branch will track `branch` from `origin`.
++
+If two or more branches are pulled on the same local branch, only the 
last one
+in arguments will be tracked.
Is this specific to this pull --setupstream or a general worning ? i.e. that 
a second entry is created in the config file, or that only the last branch 
refspec will be added?
quoted hunk
++
+The given <repository> must be a configured remote. Can only set tracking 
to
+remote branches (e.g. can't set upstream to remote HEAD).
++
+Works symmetrically as `--set-upstream` for linkgit:git-push[1]. Allow 
using
+argumentless linkgit:git-pull[1] and other commands.  For more 
information, see
+`branch.<name>.merge` in linkgit:git-config[1].
+
Options related to merging
~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/builtin/pull.c b/builtin/pull.c
[snip] 

Re: [RFC/PATCH v2] pull: add --set-upstream

From: Erwan Mathoniere <hidden>
Date: 2016-06-16 02:19:47


On 06/06/2016 18:29, Philip Oakley wrote:
quoted
+ that each one tracks the remote branch pulled from. If a configuration
+ already exists, it is overwriten. For example, with `git pull -u origin
+ branch` the current branch will track `branch` from `origin`.
++
+If two or more branches are pulled on the same local branch, only the
last one
+in arguments will be tracked.
Is this specific to this pull --setupstream or a general worning ? i.e.
that a second entry is created in the config file, or that only the last
branch refspec will be added?
Only the last branch will be added. More precisely, its behavior is just 
like `git push --set-upstream`. If you do `git push --set-upstream 
master:master master:other`, git will change its configuration twice and 
will print out:

$ git push --set-upstream origin master:master master:other
[...]
Branch master set up to track remote branch master from origin.
Branch master set up to track remote branch other from origin.

And at the end, "master" will only track "other" from origin and both 
"branch.master.{merge, remote}" will be set once.
So for now, `git pull --set-upstream` does the same and for example, on 
master:

$ git pull --set-upstream origin master other
[...]
Branch master set up to track remote branch master from origin.
Branch master set up to track remote branch other from origin.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help