From: Matthieu Moy <git@matthieu-moy.fr>
To: git@vger.kernel.org, matthieu.moy@univ-lyon1.fr
Cc: corentin.bompard@etu.univ-lyon1.fr, gitster@pobox.com,
nathan.berbezier@etu.univ-lyon1.fr,
pablo.chabanne@etu.univ-lyon1.fr,
Matthieu Moy <git@matthieu-moy.fr>
Subject: [PATCH] pull, fetch: add --set-upstream option
Date: Wed, 14 Aug 2019 15:46:29 +0200 [thread overview]
Message-ID: <20190814134629.21096-1-git@matthieu-moy.fr> (raw)
In-Reply-To: <86zhoil3yw.fsf@univ-lyon1.fr>
From: Corentin BOMPARD <corentin.bompard@etu.univ-lyon1.fr>
Add the --set-upstream option to git pull/fetch
which lets the user set the upstream configuration
(branch.<current-branch-name>.merge and
branch.<current-branch-name>.remote) for the current branch.
A typical use-case is:
git clone http://example.com/my-public-fork
git remote add main http://example.com/project-main-repo
git pull --set-upstream main master
or, instead of the last line:
git fetch --set-upstream main master
git merge # or git rebase
This functionality is analog to 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 <git@matthieu-moy.fr>
Patch-edited-by: Matthieu Moy <git@matthieu-moy.fr>
---
This is a followup on
https://public-inbox.org/git/86zhoil3yw.fsf@univ-lyon1.fr/. It's
initially a student project, but students didn't get time to complete
it. Still, I think the feature is interesting, and I finally get time
to fix the remarks made up to now. This now looks good to me, but
obviously needs other pairs of eyes.
Thanks,
Documentation/fetch-options.txt | 7 ++
builtin/fetch.c | 48 ++++++++-
builtin/pull.c | 6 ++
t/t5553-set-upstream.sh | 178 ++++++++++++++++++++++++++++++++
4 files changed, 238 insertions(+), 1 deletion(-)
create mode 100755 t/t5553-set-upstream.sh
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 3c9b4f9e09..99df1f3d4e 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -169,6 +169,13 @@ ifndef::git-pull[]
Disable recursive fetching of submodules (this has the same effect as
using the `--recurse-submodules=no` option).
+--set-upstream::
+ If the remote is fetched successfully, pull and add upstream
+ (tracking) reference, used by argument-less
+ linkgit:git-pull[1] and other commands. For more information,
+ see `branch.<name>.merge` and `branch.<name>.remote` 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 717dd14e89..5557ae1c04 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"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@@ -50,7 +51,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 enable_auto_gc = 1;
static int tags = TAGS_DEFAULT, unshallow, update_shallow, deepen;
@@ -123,6 +124,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"),
@@ -1367,6 +1370,49 @@ static int do_fetch(struct transport *transport,
retcode = 1;
goto cleanup;
}
+
+ 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 warning.
+ */
+ for (rm = ref_map; rm; rm = rm->next) {
+ if (!rm->peer_ref) {
+ if (source_ref) {
+ warning(_("multiple branch detected, incompatible with --set-upstream"));
+ goto skip;
+ } else {
+ source_ref = rm;
+ }
+ }
+ }
+ 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(_("not setting upstream for a remote tag"));
+ } else {
+ warning(_("unknown branch type"));
+ }
+ } else {
+ warning(_("no source branch found.\n"
+ "you need to specify exactly 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 f1eaf6e6ed..d25ff13a60 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -129,6 +129,7 @@ static char *opt_refmap;
static char *opt_ipv4;
static char *opt_ipv6;
static int opt_show_forced_updates = -1;
+static char *set_upstream;
static struct option pull_options[] = {
/* Shared options */
@@ -243,6 +244,9 @@ static struct option pull_options[] = {
PARSE_OPT_NOARG),
OPT_BOOL(0, "show-forced-updates", &opt_show_forced_updates,
N_("check for forced-updates on all updated branches")),
+ OPT_PASSTHRU(0, "set-upstream", &set_upstream, NULL,
+ N_("set upstream for git pull/fetch"),
+ PARSE_OPT_NOARG),
OPT_END()
};
@@ -556,6 +560,8 @@ static int run_fetch(const char *repo, const char **refspecs)
argv_array_push(&args, "--show-forced-updates");
else if (opt_show_forced_updates == 0)
argv_array_push(&args, "--no-show-forced-updates");
+ 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 100755
index 0000000000..bd1a94f494
--- /dev/null
+++ b/t/t5553-set-upstream.sh
@@ -0,0 +1,178 @@
+#!/bin/sh
+
+test_description='"git fetch/pull --set-upstream" basic tests.'
+. ./test-lib.sh
+
+check_config () {
+ printf "%s\n" "$2" "$3" >"expect.$1" &&
+ {
+ git config "branch.$1.remote" && git config "branch.$1.merge"
+ } >"actual.$1" &&
+ test_cmp "expect.$1" "actual.$1"
+}
+
+check_config_missing () {
+ test_expect_code 1 git config "branch.$1.remote" &&
+ test_expect_code 1 git config "branch.$1.merge"
+}
+
+clear_config () {
+ for branch in "$@"; do
+ test_might_fail git config --unset-all "branch.$branch.remote"
+ test_might_fail git config --unset-all "branch.$branch.merge"
+ done
+}
+
+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
+'
+
+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' '
+ clear_config master other &&
+ git checkout master &&
+ git fetch --set-upstream upstream &&
+ check_config_missing master &&
+ check_config_missing other
+'
+
+test_expect_success 'fetch --set-upstream upstream master sets branch master but not other' '
+ clear_config master other &&
+ git fetch --set-upstream upstream master &&
+ check_config master upstream refs/heads/master &&
+ check_config_missing other
+'
+
+test_expect_success 'fetch --set-upstream upstream other sets branch other' '
+ clear_config master other &&
+ git fetch --set-upstream upstream other &&
+ check_config master upstream refs/heads/other &&
+ check_config_missing other
+'
+
+test_expect_success 'fetch --set-upstream master:other does not set the branch other2' '
+ clear_config other2 &&
+ git fetch --set-upstream upstream master:other2 &&
+ check_config_missing other2
+'
+
+test_expect_success 'fetch --set-upstream http://nosuchdomain.example.com fails with invalid url' '
+ # master explicitly not cleared, we check that it is not touched from previous value
+ clear_config other other2 &&
+ test_must_fail git fetch --set-upstream http://nosuchdomain.example.com &&
+ check_config master upstream refs/heads/other &&
+ check_config_missing other &&
+ check_config_missing other2
+'
+
+test_expect_success 'fetch --set-upstream with valid URL sets upstream to URL' '
+ clear_config other other2 &&
+ url="file://'"$PWD"'" &&
+ git fetch --set-upstream "$url" &&
+ check_config master "$url" HEAD &&
+ check_config_missing other &&
+ check_config_missing 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' '
+ clear_config master other &&
+ git pull --set-upstream upstream master &&
+ check_config master upstream refs/heads/master &&
+ check_config_missing other
+'
+
+test_expect_success 'pull --set-upstream master:other2 does not set the branch other2' '
+ clear_config other2 &&
+ git pull --set-upstream upstream master:other2 &&
+ check_config_missing other2
+'
+
+test_expect_success 'pull --set-upstream upstream other sets branch master' '
+ clear_config master other &&
+ git pull --set-upstream upstream other &&
+ check_config master upstream refs/heads/other &&
+ check_config_missing other
+'
+
+test_expect_success 'pull --set-upstream upstream tag does not set the tag' '
+ clear_config three &&
+ git pull --tags --set-upstream upstream three &&
+ check_config_missing three
+'
+
+test_expect_success 'pull --set-upstream http://nosuchdomain.example.com fails with invalid url' '
+ # master explicitly not cleared, we check that it is not touched from previous value
+ clear_config other other2 three &&
+ test_must_fail git pull --set-upstream http://nosuchdomain.example.com &&
+ check_config master upstream refs/heads/other &&
+ check_config_missing other &&
+ check_config_missing other2 &&
+ check_config_missing three
+'
+
+test_expect_success 'pull --set-upstream upstream HEAD sets branch HEAD' '
+ clear_config master other &&
+ 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 three &&
+ git pull --set-upstream upstream master three &&
+ check_config_missing master &&
+ check_config_missing three
+'
+
+test_expect_success 'pull --set-upstream with valid URL sets upstream to URL' '
+ clear_config master other other2 &&
+ git checkout master &&
+ url="file://'"$PWD"'" &&
+ git pull --set-upstream "$url" &&
+ check_config master "$url" HEAD &&
+ check_config_missing other &&
+ check_config_missing other2
+'
+
+test_expect_success 'pull --set-upstream with valid URL and branch sets branch' '
+ clear_config master other other2 &&
+ git checkout master &&
+ url="file://'"$PWD"'" &&
+ git pull --set-upstream "$url" master &&
+ check_config master "$url" refs/heads/master &&
+ check_config_missing other &&
+ check_config_missing other2
+'
+
+test_done
--
2.20.1.98.gecbdaf0
next prev parent reply other threads:[~2019-08-14 14:06 UTC|newest]
Thread overview: 19+ 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
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 ` Matthieu Moy [this message]
2019-08-14 17:14 ` [PATCH] pull, fetch: add --set-upstream option 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
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=20190814134629.21096-1-git@matthieu-moy.fr \
--to=git@matthieu-moy.fr \
--cc=corentin.bompard@etu.univ-lyon1.fr \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--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).