git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Corentin BOMPARD <corentin.bompard@etu.univ-lyon1.fr>
To: <corentin.bompard@etu.univ-lyon1.fr>
Cc: <git@vger.kernel.org>, <matthieu.moy@univ-lyon1.fr>,
	<nathan.berbezier@etu.univ-lyon1.fr>,
	<pablo.chabanne@etu.univ-lyon1.fr>
Subject: [PATCH] [WIP/RFC] add git pull and git fetch --set-upstream
Date: Wed, 17 Apr 2019 18:01:38 +0200	[thread overview]
Message-ID: <20190417160138.6114-1-corentin.bompard@etu.univ-lyon1.fr> (raw)
In-Reply-To: <20190409125205.13754-1-corentin.bompard@etu.univ-lyon1.fr>

Add the --set-upstream option to git pull/fetch
which lets the user set the upstream configuration
for the current branch.

For example a typical use-case like
    git clone http://example.com/my-public-fork
    git remote add main http://example.com/project-main-repo
    git pull main master --set-upstream
or, instead of the last line
    git fetch main master --set-upstream
    git merge # or git rebase

This foncionality works like git push --set-upstream.

Signed-off-by: Corentin BOMPARD <corentin.bompard@etu.univ-lyon1.fr>
Signed-off-by: Nathan BERBEZIER <nathan.berbezier@etu.univ-lyon1.fr>
Signed-off-by: Pablo CHABANNE <pablo.chabanne@etu.univ-lyon1.fr>
Signed-off-by: Matthieu MOY <matthieu.moy@univ-lyon1.fr>
---
 Sorry for being so long.

 Documentation/fetch-options.txt |   5 ++
 builtin/fetch.c                 |  55 ++++++++++++-
 builtin/pull.c                  |   6 ++
 t/t5553-set-upstream.sh         | 142 ++++++++++++++++++++++++++++++++
 4 files changed, 207 insertions(+), 1 deletion(-)
 create mode 100644 t/t5553-set-upstream.sh

diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index fa0a3151b..4d2d55643 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -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
diff --git a/builtin/fetch.c b/builtin/fetch.c
index b620fd54b..b43a4e0a2 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -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,56 @@ 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 *source_ref = NULL;
+		/*
+		 * We're setting the upstream configuration for the current branch. The
+		 * relevent upstream is the fetched branch that is meant to be merged with
+		 * the current one, i.e. the one fetched to FETCH_HEAD.
+		 *
+		 * When there are several such branches, consider the request ambiguous and
+		 * err on the safe side by doing nothing and just emit a waring.
+		 */
+		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 (source_ref) {
+					fprintf(stderr, " -> FETCH_HEAD\n");
+					warning(_("Multiple branch detected, incompatible with set-upstream"));
+					source_ref = NULL;
+					goto skip;
+				} else {
+					source_ref = rm;
+					fprintf(stderr, " -> FETCH_HEAD");
+				}
+			}
+		}
+		fprintf(stderr, "\n\n");
+		if (source_ref) {
+			if (!strcmp(source_ref->name, "HEAD") ||
+				starts_with(source_ref->name, "refs/heads/")) {
+				install_branch_config(0, branch->name,
+							 transport->remote->name,
+							 source_ref->name);
+			} else if (starts_with(source_ref->name, "refs/remotes/")) {
+				warning(_("Not setting upstream for a remote remote-tracking branch"));
+			} else if (starts_with(source_ref->name, "refs/tags/")) {
+				warning(_("Tag upstream not set"));
+			} else {
+				warning(_("Unknown branch type"));
+			}
+		} else {
+			warning(_("No source branch found. \n You need to specify excatly "
+						"one branch with the set-upstream option."));
+		}
+	}
+ skip:
 	free_refs(ref_map);
 
 	/* if neither --no-tags nor --tags was specified, do automated tag
diff --git a/builtin/pull.c b/builtin/pull.c
index 701d1473d..06d7cddce 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -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);
diff --git a/t/t5553-set-upstream.sh b/t/t5553-set-upstream.sh
new file mode 100644
index 000000000..6126bb188
--- /dev/null
+++ b/t/t5553-set-upstream.sh
@@ -0,0 +1,142 @@
+#!/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() {
+	test_must_fail git config branch.$1.remote &&
+	test_must_fail git config branch.$1.merge
+}
+check_config_empty1() {
+	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
+}
+
+clear_config() {
+	git config --unset branch.$1.remote
+	git config --unset branch.$1.merge
+}
+
+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 upstream w/o branch' '
+	git checkout master &&
+	git fetch --set-upstream upstream &&
+	check_config_empty 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 &&
+	check_config master upstream refs/heads/other &&
+	check_config_empty other &&
+	check_config_empty other2
+'
+
+#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 master' '
+	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 &&
+	check_config master upstream refs/heads/other &&
+	check_config_empty other &&
+	check_config_empty other2 &&
+	check_config_empty three
+'
+
+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' '
+	clear_config master &&
+	git pull --set-upstream upstream master three &&
+	check_config_empty master &&
+	check_config_empty three
+'
+
+test_done
-- 
2.21.0-rc0


  reply	other threads:[~2019-04-17 16:02 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <d21d42228425408298da9e99b5877ac9@BPMBX2013-01.univ-lyon1.fr>
2019-04-04 15:43 ` [PATCH] [WIP/RFC] add git pull and git fetch --set-upstream Matthieu Moy
2019-04-09 12:52   ` Corentin BOMPARD
2019-04-17 16:01     ` Corentin BOMPARD [this message]
2019-04-18  1:35       ` Junio C Hamano
2019-04-19 16:00         ` Corentin BOMPARD
2019-04-19 18:42           ` Corentin BOMPARD
     [not found]           ` <f601baa2c2a04ddea4ba32ab25d0dd21@BPMBX2013-01.univ-lyon1.fr>
2019-04-22 10:38             ` Matthieu Moy
2019-08-14 13:46               ` [PATCH] pull, fetch: add --set-upstream option Matthieu Moy
2019-08-14 17:14                 ` Pratyush Yadav
2019-08-19  9:08                   ` Matthieu Moy
2019-08-19  9:11                     ` [PATCH v2] " Matthieu Moy
2019-08-14 17:38                 ` [PATCH] " Junio C Hamano
2019-08-19  9:07                   ` Matthieu Moy
2019-08-19 20:04                     ` Junio C Hamano
2019-08-20  8:09                       ` Matthieu Moy
     [not found]       ` <36559daca9d84f7a91933add734020cd@BPMBX2013-01.univ-lyon1.fr>
2019-04-18  9:51         ` [PATCH] [WIP/RFC] add git pull and git fetch --set-upstream Matthieu Moy
2019-04-19  4:46           ` Junio C Hamano
     [not found]           ` <04f23ebf83bd4aff90ee9ca88cec984e@BPMBX2013-01.univ-lyon1.fr>
2019-04-19  9:44             ` Matthieu Moy
     [not found]     ` <3d2ba75520b74c2e9e8251c41d6632ba@BPMBX2013-01.univ-lyon1.fr>
2019-04-18  9:56       ` Matthieu Moy
2019-04-04 12:22 Corentin BOMPARD

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190417160138.6114-1-corentin.bompard@etu.univ-lyon1.fr \
    --to=corentin.bompard@etu.univ-lyon1.fr \
    --cc=git@vger.kernel.org \
    --cc=matthieu.moy@univ-lyon1.fr \
    --cc=nathan.berbezier@etu.univ-lyon1.fr \
    --cc=pablo.chabanne@etu.univ-lyon1.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).