* [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push'
@ 2009-07-20 17:49 Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 1/8] reintroduce PUSH_DEFAULT_UNSPECIFIED Paolo Bonzini
` (8 more replies)
0 siblings, 9 replies; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 17:49 UTC (permalink / raw)
To: git
I post as an initial RFC the third series in the push.default saga.
This is on top of origin/next and even then it requires the
"push --current" patches to be fully functional. Even without it,
however, it will create correct configuration.
The series adds --push options to "git remote add" and "git clone".
These accept a push strategy of the same kind as "push.default",
and will use it to create push configuration and refspecs. These
will then override push.default.
The argument is optional, in which case it will be taken from the
"push.default" config key itself. In this case, since the user explicitly
requested something they did not configure, a warning is emitted similar
to the one of 1.6.3. If --push is used appropriately, in a non-specified
future "git push" might not use push.default anymore and thus require
a push refspec. (Or more realistically, it would look at push.default,
but only to suggest the user commands that do the transition).
This patch is a bit harder to justify than the others so far, since
it may as well look like a feature in search of a use case. To this,
my reply is that this is just a step towards a more polished (IMO)
implementation of the existing "push.default" feature. Actually, the
patch is big but it is mostly builtin-remote.c and tests. And you
will have to put up with this for only another series or two.
Patch 1 is just taken from the push --current series. Patch 2 adds
a new value for `push.default', so that it's easier to map --mirror
to a --push suboption.
Patches 3 and 4 add the option to "git remote add" (refactoring
first, adding the feature later).
Patches 5 to 8 add the option to "git clone". The first two share
the code for the config setup between "git remote add" and "git clone".
The third adds a new function to get just the global configuration
(not the repository one), for usage in "git clone" before the repository
is actually created. The final one finally adds the new option,
which is little more than tweaking the call into "git remote add".
That's it for now. I'll post the final version of this series when I
get comments *and* once both autosetuppush and push --current have been
committed to next. In the meanwhile, opinions, reviews and flames are
welcome as usual.
Paolo Bonzini (8):
reintroduce PUSH_DEFAULT_UNSPECIFIED
push: add push.default = mirror
git remote add: refactor configuration
git remote add: add --push option
clone: refactoring of building the fetch refspec
clone: use setup_remote_config
config: add git_config_norepo
clone: add --push option
Documentation/config.txt | 2 +
Documentation/git-clone.txt | 13 +++-
Documentation/git-remote.txt | 13 ++--
builtin-clone.c | 133 +++++++++++++++---------------
builtin-push.c | 13 +++-
builtin-remote.c | 188 ++++++++++++++++++++++++++++++++++--------
cache.h | 5 +
config.c | 74 +++++++++++-----
environment.c | 2 +-
remote.h | 3 +
t/t5505-remote.sh | 73 ++++++++++++++++
t/t5517-push-mirror.sh | 22 +++++-
t/t5601-clone.sh | 78 +++++++++++++++++
13 files changed, 486 insertions(+), 133 deletions(-)
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH RFC 1/8] reintroduce PUSH_DEFAULT_UNSPECIFIED
2009-07-20 17:49 [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Paolo Bonzini
@ 2009-07-20 17:49 ` Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 2/8] push: add push.default = mirror Paolo Bonzini
` (7 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 17:49 UTC (permalink / raw)
To: git
This is just the first patch from the push --current series. It
is the only one needed as a prerequisite for these patches, at
least to get as far as writing the configuration in .git/config.
Not-signed-off-for-this-rfc-by: Paolo Bonzini <bonzini@gnu.org>
---
builtin-push.c | 1 +
cache.h | 1 +
environment.c | 2 +-
3 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/builtin-push.c b/builtin-push.c
index 1d92e22..e678a9d 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -69,6 +69,7 @@ static void setup_default_push_refspecs(void)
git_config(git_default_config, NULL);
switch (push_default) {
default:
+ case PUSH_DEFAULT_UNSPECIFIED:
case PUSH_DEFAULT_MATCHING:
add_refspec(":");
break;
diff --git a/cache.h b/cache.h
index dbe460c..f10513f 100644
--- a/cache.h
+++ b/cache.h
@@ -544,6 +544,7 @@ enum rebase_setup_type {
};
enum push_default_type {
+ PUSH_DEFAULT_UNSPECIFIED = -1,
PUSH_DEFAULT_NOTHING = 0,
PUSH_DEFAULT_MATCHING,
PUSH_DEFAULT_TRACKING,
diff --git a/environment.c b/environment.c
index 95aa8a6..4b68109 100644
--- a/environment.c
+++ b/environment.c
@@ -46,7 +46,7 @@ struct tracking_config git_branch_track = {
AUTOREBASE_NEVER,
0
};
-enum push_default_type push_default = PUSH_DEFAULT_MATCHING;
+enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
#ifndef OBJECT_CREATION_MODE
#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
#endif
--
1.6.2.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC 2/8] push: add push.default = mirror
2009-07-20 17:49 [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 1/8] reintroduce PUSH_DEFAULT_UNSPECIFIED Paolo Bonzini
@ 2009-07-20 17:49 ` Paolo Bonzini
2009-07-20 20:46 ` Junio C Hamano
2009-07-20 17:49 ` [PATCH RFC 3/8] git remote add: refactor configuration Paolo Bonzini
` (6 subsequent siblings)
8 siblings, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 17:49 UTC (permalink / raw)
To: git
This patch adds a new value for push.default. The aim of the series is
to support all push.default values as arguments to `--push' in git-clone
and git-remote, and if push.default=mirror works it is easy to make
`--mirror' a synonym for `--push=mirror' in those comments.
Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
Documentation/config.txt | 2 ++
builtin-push.c | 12 ++++++++++--
cache.h | 1 +
config.c | 4 +++-
4 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 4c27e9d..fa5eb76 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1290,6 +1290,8 @@ push.default::
* `matching` push all matching branches.
All branches having the same name in both ends are considered to be
matching. This is the default.
+* `mirror` pushes all branches forcing non fast-forward updates and
+ deletes branches that do not exist anymore locally.
* `tracking` push the current branch to its upstream branch.
* `current` push the current branch to a branch of the same name.
diff --git a/builtin-push.c b/builtin-push.c
index e678a9d..8a312a3 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -66,7 +66,6 @@ static void setup_push_tracking(void)
static void setup_default_push_refspecs(void)
{
- git_config(git_default_config, NULL);
switch (push_default) {
default:
case PUSH_DEFAULT_UNSPECIFIED:
@@ -74,6 +73,10 @@ static void setup_default_push_refspecs(void)
add_refspec(":");
break;
+ case PUSH_DEFAULT_MIRROR:
+ add_refspec("+refs/*:refs/*");
+ break;
+
case PUSH_DEFAULT_TRACKING:
setup_push_tracking();
break;
@@ -126,8 +129,12 @@ static int do_push(const char *repo, int flags)
if (remote->push_refspec_nr) {
refspec = remote->push_refspec;
refspec_nr = remote->push_refspec_nr;
- } else if (!(flags & TRANSPORT_PUSH_MIRROR))
+ } else if (!(flags & TRANSPORT_PUSH_MIRROR)
+ || push_default == PUSH_DEFAULT_MIRROR) {
+ if (push_default == PUSH_DEFAULT_MIRROR)
+ flags |= TRANSPORT_PUSH_MIRROR;
setup_default_push_refspecs();
+ }
}
errs = 0;
if (remote->pushurl_nr) {
@@ -184,6 +191,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
OPT_END()
};
+ git_config(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
if (tags)
diff --git a/cache.h b/cache.h
index f10513f..172d36c 100644
--- a/cache.h
+++ b/cache.h
@@ -549,6 +549,7 @@ enum push_default_type {
PUSH_DEFAULT_MATCHING,
PUSH_DEFAULT_TRACKING,
PUSH_DEFAULT_CURRENT,
+ PUSH_DEFAULT_MIRROR,
};
struct tracking_config {
diff --git a/config.c b/config.c
index 04380bb..4db5c6d 100644
--- a/config.c
+++ b/config.c
@@ -604,6 +604,8 @@ static int git_default_push_config(const char *var, const char *value)
push_default = PUSH_DEFAULT_NOTHING;
else if (!strcmp(value, "matching"))
push_default = PUSH_DEFAULT_MATCHING;
+ else if (!strcmp(value, "mirror"))
+ push_default = PUSH_DEFAULT_MIRROR;
else if (!strcmp(value, "tracking"))
push_default = PUSH_DEFAULT_TRACKING;
else if (!strcmp(value, "current"))
@@ -611,7 +613,7 @@ static int git_default_push_config(const char *var, const char *value)
else {
error("Malformed value for %s: %s", var, value);
return error("Must be one of nothing, matching, "
- "tracking or current.");
+ "mirror, tracking or current.");
}
return 0;
}
--
1.6.2.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC 3/8] git remote add: refactor configuration
2009-07-20 17:49 [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 1/8] reintroduce PUSH_DEFAULT_UNSPECIFIED Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 2/8] push: add push.default = mirror Paolo Bonzini
@ 2009-07-20 17:49 ` Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 4/8] git remote add: add --push option Paolo Bonzini
` (5 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 17:49 UTC (permalink / raw)
To: git
This moves the configuration setup of git remote add to
a separate function. The next patch will add more
configuration options in setup_remote_config.
Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
builtin-remote.c | 74 ++++++++++++++++++++++++++++++++----------------------
1 files changed, 44 insertions(+), 30 deletions(-)
diff --git a/builtin-remote.c b/builtin-remote.c
index 008abfe..c30fbb7 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -36,6 +36,49 @@ static inline int postfixcmp(const char *string, const char *postfix)
return strcmp(string + len1 - len2, postfix);
}
+static int setup_remote_config(const char *name, const char *url, int mirror, struct string_list *track)
+{
+ struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
+ int i;
+
+ if (mirror) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "remote.%s.mirror", name);
+ if (git_config_set(buf.buf, "true"))
+ return 1;
+ }
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "remote.%s.url", name);
+ if (git_config_set(buf.buf, url))
+ return 1;
+
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "remote.%s.fetch", name);
+
+ if (track->nr == 0)
+ string_list_append("*", track);
+
+ for (i = 0; i < track->nr; i++) {
+ struct string_list_item *item = track->items + i;
+
+ strbuf_reset(&buf2);
+ if (mirror)
+ strbuf_addf(&buf2, "+refs/%s:refs/%s",
+ item->string, item->string);
+ else
+ strbuf_addf(&buf2, "+refs/heads/%s:refs/remotes/%s/%s",
+ item->string, name, item->string);
+ if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
+ return 1;
+ }
+
+ strbuf_release(&buf);
+ strbuf_release(&buf2);
+ return 0;
+}
+
+
static int opt_parse_track(const struct option *opt, const char *arg, int not)
{
struct string_list *list = opt->value;
@@ -67,7 +110,6 @@ static int add(int argc, const char **argv)
struct remote *remote;
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
const char *name, *url;
- int i;
struct option options[] = {
OPT_GROUP("add specific options"),
@@ -97,37 +139,9 @@ static int add(int argc, const char **argv)
if (!valid_fetch_refspec(buf2.buf))
die("'%s' is not a valid remote name", name);
- strbuf_addf(&buf, "remote.%s.url", name);
- if (git_config_set(buf.buf, url))
+ if (setup_remote_config(name, url, mirror, &track))
return 1;
- strbuf_reset(&buf);
- strbuf_addf(&buf, "remote.%s.fetch", name);
-
- if (track.nr == 0)
- string_list_append("*", &track);
- for (i = 0; i < track.nr; i++) {
- struct string_list_item *item = track.items + i;
-
- strbuf_reset(&buf2);
- strbuf_addch(&buf2, '+');
- if (mirror)
- strbuf_addf(&buf2, "refs/%s:refs/%s",
- item->string, item->string);
- else
- strbuf_addf(&buf2, "refs/heads/%s:refs/remotes/%s/%s",
- item->string, name, item->string);
- if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
- return 1;
- }
-
- if (mirror) {
- strbuf_reset(&buf);
- strbuf_addf(&buf, "remote.%s.mirror", name);
- if (git_config_set(buf.buf, "true"))
- return 1;
- }
-
if (fetch && fetch_remote(name))
return 1;
--
1.6.2.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC 4/8] git remote add: add --push option
2009-07-20 17:49 [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Paolo Bonzini
` (2 preceding siblings ...)
2009-07-20 17:49 ` [PATCH RFC 3/8] git remote add: refactor configuration Paolo Bonzini
@ 2009-07-20 17:49 ` Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 5/8] clone: refactoring of building the fetch refspec Paolo Bonzini
` (4 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 17:49 UTC (permalink / raw)
To: git
This patch makes `git remote add' able to setup push refspecs,
as well as options controlling the behavior of git-push. Remotes
created with this option will not be subject to the "push.default"
configuration setting, because they have a push refspec.
This plans ahead for a future transition to "push.default = nothing"
being the default, while being a worthwhile addition in case the
transition never materializes.
Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
Documentation/git-remote.txt | 13 +++--
builtin-remote.c | 119 +++++++++++++++++++++++++++++++++++++++--
cache.h | 4 +-
config.c | 39 ++++++++------
t/t5505-remote.sh | 73 ++++++++++++++++++++++++++
t/t5517-push-mirror.sh | 22 +++++++-
6 files changed, 240 insertions(+), 30 deletions(-)
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 9e2b4ea..5f1bda3 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -10,7 +10,7 @@ SYNOPSIS
--------
[verse]
'git remote' [-v | --verbose]
-'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>
+'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror | --push=<strategy>] <name> <url>
'git remote rename' <old> <new>
'git remote rm' <name>
'git remote set-head' <name> [-a | -d | <branch>]
@@ -56,11 +56,12 @@ multiple branches without grabbing all branches.
With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set
up to point at remote's `<master>` branch. See also the set-head command.
+
-In mirror mode, enabled with `\--mirror`, the refs will not be stored
-in the 'refs/remotes/' namespace, but in 'refs/heads/'. This option
-only makes sense in bare repositories. If a remote uses mirror
-mode, furthermore, `git push` will always behave as if `\--mirror`
-was passed.
+The remote's behavior upon `git push` can also be set up by
+`git remote add`. Valid values for `\--push` are 'matching', 'mirror,
+'tracking', 'current', and `nothing'. Their meanings are the same as
+for the `push.default` configuration key. `\--mirror` is a synonym for
+`\--push=mirror`.
+
'rename'::
diff --git a/builtin-remote.c b/builtin-remote.c
index c30fbb7..23ab24b 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -9,7 +9,7 @@
static const char * const builtin_remote_usage[] = {
"git remote [-v | --verbose]",
- "git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>",
+ "git remote add [-t <branch>] [-m <master>] [-f] [--push=<strategy>] [--mirror] <name> <url>",
"git remote rename <old> <new>",
"git remote rm <name>",
"git remote set-head <name> [-a | -d | <branch>]",
@@ -36,17 +36,92 @@ static inline int postfixcmp(const char *string, const char *postfix)
return strcmp(string + len1 - len2, postfix);
}
-static int setup_remote_config(const char *name, const char *url, int mirror, struct string_list *track)
+static const char *warn_unconfigured_push_msg[] = {
+ "You did not specify any argument to --push, and 'push.default'",
+ "is not defined in your configuration. The default action in this",
+ "case will be to push all matching refspecs, that is, all branches",
+ "that exist both locally and remotely will be updated. This may",
+ "not necessarily be what you want to happen.",
+ "",
+ "You can specify what action you want to take in this case, and",
+ "avoid seeing this message again, by configuring 'push.default' to:",
+ " 'matching' : Push all matching branches (default)",
+ " 'mirror' : Push all branches and delete non-existing ones",
+ " 'tracking' : Push the current branch to whatever it is tracking",
+ " 'current' : Push the current branch"
+};
+
+static void warn_unconfigured_push()
{
- struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
int i;
+ for (i = 0; i < ARRAY_SIZE(warn_unconfigured_push_msg); i++)
+ warning("%s", warn_unconfigured_push_msg[i]);
+}
+
+
+static int setup_default_remote_config(const char *name, const char *url, int push, struct string_list *track)
+{
+ struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT;
+ const char *refspec = NULL;
+ int mirror = 0;
+ int current = 0;
+ int autosetuppush = 0;
+ int setup_push_refspecs = 0;
+ int i;
+
+ switch (push) {
+ case PUSH_DEFAULT_UNSPECIFIED:
+ warn_unconfigured_push();
+ /* fallthrough */
+
+ case PUSH_DEFAULT_MATCHING:
+ refspec = ":";
+ break;
+
+ case PUSH_DEFAULT_MIRROR:
+ refspec = "+refs/*:refs/*";
+ mirror = 1;
+ break;
+
+ case PUSH_DEFAULT_TRACKING:
+ current = 1;
+ autosetuppush = 1;
+ setup_push_refspecs = (track->nr > 0);
+ break;
+
+ case PUSH_DEFAULT_CURRENT:
+ refspec = "HEAD";
+ current = 1;
+ break;
+
+ case PUSH_DEFAULT_NOTHING:
+ break;
+ }
+ if (refspec) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "remote.%s.push", name);
+ if (git_config_set(buf.buf, refspec))
+ return 1;
+ }
+ if (autosetuppush) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "remote.%s.autosetuppush", name);
+ if (git_config_set(buf.buf, "true"))
+ return 1;
+ }
if (mirror) {
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.mirror", name);
if (git_config_set(buf.buf, "true"))
return 1;
}
+ if (current) {
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "remote.%s.pushHeadOnly", name);
+ if (git_config_set(buf.buf, "true"))
+ return 1;
+ }
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.url", name);
@@ -55,6 +130,8 @@ static int setup_remote_config(const char *name, const char *url, int mirror, st
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", name);
+ strbuf_reset(&buf3);
+ strbuf_addf(&buf3, "remote.%s.push", name);
if (track->nr == 0)
string_list_append("*", track);
@@ -62,8 +139,16 @@ static int setup_remote_config(const char *name, const char *url, int mirror, st
for (i = 0; i < track->nr; i++) {
struct string_list_item *item = track->items + i;
+ if (setup_push_refspecs) {
+ strbuf_reset(&buf2);
+ strbuf_addf(&buf2, "refs/heads/%s:refs/heads/%s",
+ item->string, item->string);
+ if (git_config_set_multivar(buf3.buf, buf2.buf, "^$", 0))
+ return 1;
+ }
+
strbuf_reset(&buf2);
- if (mirror)
+ if (push == PUSH_DEFAULT_MIRROR)
strbuf_addf(&buf2, "+refs/%s:refs/%s",
item->string, item->string);
else
@@ -75,10 +160,24 @@ static int setup_remote_config(const char *name, const char *url, int mirror, st
strbuf_release(&buf);
strbuf_release(&buf2);
+ strbuf_release(&buf3);
return 0;
}
+static int opt_parse_push(const struct option *opt, const char *arg, int not)
+{
+ int *value = opt->value;
+ if (not)
+ *value = PUSH_DEFAULT_NOTHING;
+ else if (!arg)
+ *value = push_default;
+ else
+ return git_parse_push_default("--push", arg, value);
+
+ return 0;
+}
+
static int opt_parse_track(const struct option *opt, const char *arg, int not)
{
struct string_list *list = opt->value;
@@ -104,7 +203,7 @@ static int fetch_remote(const char *name)
static int add(int argc, const char **argv)
{
- int fetch = 0, mirror = 0;
+ int fetch = 0, push = PUSH_DEFAULT_UNKNOWN, mirror = 0;
struct string_list track = { NULL, 0, 0 };
const char *master = NULL;
struct remote *remote;
@@ -117,10 +216,13 @@ static int add(int argc, const char **argv)
OPT_CALLBACK('t', "track", &track, "branch",
"branch(es) to track", opt_parse_track),
OPT_STRING('m', "master", &master, "branch", "master branch"),
+ { OPTION_CALLBACK, 0, "push", &push, "strategy",
+ "how to setup pushing", PARSE_OPT_OPTARG, opt_parse_push },
OPT_BOOLEAN(0, "mirror", &mirror, "no separate remotes"),
OPT_END()
};
+ git_config(git_default_config, NULL);
argc = parse_options(argc, argv, NULL, options, builtin_remote_usage,
0);
@@ -130,6 +232,11 @@ static int add(int argc, const char **argv)
name = argv[0];
url = argv[1];
+ if (push == PUSH_DEFAULT_UNKNOWN)
+ push = mirror ? PUSH_DEFAULT_MIRROR : PUSH_DEFAULT_NOTHING;
+ else if (mirror && push != PUSH_DEFAULT_MIRROR)
+ die ("--mirror and --push are incompatible");
+
remote = remote_get(name);
if (remote && (remote->url_nr > 1 || strcmp(name, remote->url[0]) ||
remote->fetch_refspec_nr))
@@ -139,7 +246,7 @@ static int add(int argc, const char **argv)
if (!valid_fetch_refspec(buf2.buf))
die("'%s' is not a valid remote name", name);
- if (setup_remote_config(name, url, mirror, &track))
+ if (setup_remote_config(name, url, push, &track))
return 1;
if (fetch && fetch_remote(name))
diff --git a/cache.h b/cache.h
index 172d36c..a46bfe6 100644
--- a/cache.h
+++ b/cache.h
@@ -544,7 +544,8 @@ enum rebase_setup_type {
};
enum push_default_type {
- PUSH_DEFAULT_UNSPECIFIED = -1,
+ PUSH_DEFAULT_UNKNOWN = -2, /* command line: use push.default */
+ PUSH_DEFAULT_UNSPECIFIED = -1, /* config key absent */
PUSH_DEFAULT_NOTHING = 0,
PUSH_DEFAULT_MATCHING,
PUSH_DEFAULT_TRACKING,
@@ -640,6 +641,7 @@ enum sharedrepo {
};
int git_config_perm(const char *var, const char *value);
int git_config_tracking(const char *var, const char *value, struct tracking_config *cfg);
+int git_parse_push_default(const char *var, const char *value, int *result);
int set_shared_perm(const char *path, int mode);
#define adjust_shared_perm(path) set_shared_perm((path), 0)
int safe_create_leading_directories(char *path);
diff --git a/config.c b/config.c
index 4db5c6d..37d95a4 100644
--- a/config.c
+++ b/config.c
@@ -580,6 +580,27 @@ int git_tracking_config(const char *var, const char *value, struct tracking_conf
return 0;
}
+int git_parse_push_default(const char *var, const char *value, int *result)
+{
+ if (!strcmp(value, "nothing"))
+ *result = PUSH_DEFAULT_NOTHING;
+ else if (!strcmp(value, "matching"))
+ *result = PUSH_DEFAULT_MATCHING;
+ else if (!strcmp(value, "mirror"))
+ *result = PUSH_DEFAULT_MIRROR;
+ else if (!strcmp(value, "tracking"))
+ *result = PUSH_DEFAULT_TRACKING;
+ else if (!strcmp(value, "current"))
+ *result = PUSH_DEFAULT_CURRENT;
+ else {
+ error("Malformed value for %s: %s", var, value);
+ return error("Must be one of nothing, matching, "
+ "mirror, tracking or current.");
+ }
+
+ return 0;
+}
+
static int git_default_branch_config(const char *var, const char *value)
{
int result;
@@ -600,22 +621,8 @@ static int git_default_push_config(const char *var, const char *value)
if (!strcmp(var, "push.default")) {
if (!value)
return config_error_nonbool(var);
- else if (!strcmp(value, "nothing"))
- push_default = PUSH_DEFAULT_NOTHING;
- else if (!strcmp(value, "matching"))
- push_default = PUSH_DEFAULT_MATCHING;
- else if (!strcmp(value, "mirror"))
- push_default = PUSH_DEFAULT_MIRROR;
- else if (!strcmp(value, "tracking"))
- push_default = PUSH_DEFAULT_TRACKING;
- else if (!strcmp(value, "current"))
- push_default = PUSH_DEFAULT_CURRENT;
- else {
- error("Malformed value for %s: %s", var, value);
- return error("Must be one of nothing, matching, "
- "mirror, tracking or current.");
- }
- return 0;
+ else
+ return git_parse_push_default (var, value, &push_default);
}
/* Add other config variables here and to Documentation/config.txt. */
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 852ccb5..a411eef 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -77,6 +77,79 @@ test_expect_success 'add another remote' '
)
'
+test_expect_success 'configuration for --push=mirror' '
+(
+ git clone one test2 &&
+ cd test2 &&
+ git remote add push-mirror --push=mirror ../two &&
+ git config --bool remote.push-mirror.mirror &&
+ ! git config --bool remote.push-mirror.pushHeadOnly &&
+ ! git config --bool remote.push-mirror.autosetuppush &&
+ test $(git config remote.push-mirror.push) = "+refs/*:refs/*"
+)
+'
+
+test_expect_success 'configuration for --push=current' '
+(
+ cd test2 &&
+ git remote add push-current --push=current ../two &&
+ ! git config --bool remote.push-current.mirror &&
+ git config --bool remote.push-current.pushHeadOnly &&
+ ! git config --bool remote.push-current.autosetuppush &&
+ test $(git config remote.push-current.push) = HEAD
+)
+'
+
+test_expect_success 'configuration for --push=matching' '
+(
+ cd test2 &&
+ git remote add -f push-matching --push=matching ../two &&
+ ! git config --bool remote.push-matching.mirror &&
+ ! git config --bool remote.push-matching.pushHeadOnly &&
+ ! git config --bool remote.push-matching.autosetuppush &&
+ test $(git config remote.push-matching.push) = :
+)
+'
+
+test_expect_success 'configuration for --push=tracking' '
+(
+ git clone one test3 &&
+ cd test3 &&
+ git remote add -f push-tracking --push=tracking ../two &&
+ ! git config --bool remote.push-tracking.tracking &&
+ git config --bool remote.push-tracking.pushHeadOnly &&
+ git config --bool remote.push-tracking.autosetuppush &&
+ ! test $(git config remote.push-tracking.push) &&
+ git checkout -b myother push-tracking/another &&
+ test $(git config remote.push-tracking.push) = "refs/heads/myother:refs/heads/another"
+)
+'
+
+test_expect_success 'configuration for --push -t (push.default = tracking)' '
+(
+ git clone one test4 &&
+ cd test4 &&
+ git config push.default tracking &&
+ git remote add -f push-tracking2 -t another --push ../two &&
+ ! git config --bool remote.push-tracking2.mirror &&
+ git config --bool remote.push-tracking2.pushHeadOnly &&
+ git config --bool remote.push-tracking2.autosetuppush &&
+ test $(git config remote.push-tracking2.push) = "refs/heads/another:refs/heads/another"
+)
+'
+
+test_expect_success 'configuration for --push -t (push.default = matching)' '
+(
+ cd test4 &&
+ git config push.default matching
+ git remote add -f push-matching2 -t side --push ../two &&
+ ! git config --bool remote.push-matching2.mirror &&
+ ! git config --bool remote.push-matching2.pushHeadOnly &&
+ ! git config --bool remote.push-matching2.autosetuppush &&
+ test $(git config remote.push-matching2.push) = :
+)
+'
+
test_expect_success 'remote forces tracking branches' '
(
cd test &&
diff --git a/t/t5517-push-mirror.sh b/t/t5517-push-mirror.sh
index ea49ded..7a0ff99 100755
--- a/t/t5517-push-mirror.sh
+++ b/t/t5517-push-mirror.sh
@@ -225,7 +225,7 @@ test_expect_success 'push mirror adds, updates and removes tags together' '
'
-test_expect_success 'remote.foo.mirror adds and removes branches' '
+test_expect_success 'git remote add --mirror adds and removes branches' '
mk_repo_pair --mirror &&
(
@@ -245,6 +245,26 @@ test_expect_success 'remote.foo.mirror adds and removes branches' '
'
+test_expect_success 'git remote add --push=mirror adds and removes branches' '
+
+ mk_repo_pair --push=mirror &&
+ (
+ cd master &&
+ echo one >foo && git add foo && git commit -m one &&
+ git branch keep master &&
+ git branch remove master &&
+ git push up &&
+ git branch -D remove
+ git push up
+ ) &&
+ (
+ cd mirror &&
+ git show-ref -s --verify refs/heads/keep &&
+ invert git show-ref -s --verify refs/heads/remove
+ )
+
+'
+
test_expect_success 'remote.foo.mirror=no has no effect' '
mk_repo_pair &&
--
1.6.2.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC 5/8] clone: refactoring of building the fetch refspec
2009-07-20 17:49 [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Paolo Bonzini
` (3 preceding siblings ...)
2009-07-20 17:49 ` [PATCH RFC 4/8] git remote add: add --push option Paolo Bonzini
@ 2009-07-20 17:49 ` Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 6/8] clone: use setup_remote_config Paolo Bonzini
` (3 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 17:49 UTC (permalink / raw)
To: git
In builtin-clone.c, two variables (src_ref_prefix and branch_top.buf)
were used to represent basically two parts of a refspec. Since a
refspec is built anyway later, we can drop these variables and
use refspec->dst when we need it.
Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
builtin-clone.c | 21 ++++++++++-----------
1 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/builtin-clone.c b/builtin-clone.c
index 552ddf6..345101a 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -349,9 +349,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int dest_exists;
const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
- struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
+ struct strbuf reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
- char *src_ref_prefix = "refs/heads/";
int err = 0;
struct refspec *refspec;
@@ -452,20 +451,21 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_bare) {
if (option_mirror)
- src_ref_prefix = "refs/";
- strbuf_addstr(&branch_top, src_ref_prefix);
+ fetch_pattern = "+refs/*:refs/*";
+ else
+ fetch_pattern = "+refs/heads/*:refs/heads/*";
git_config_set("core.bare", "true");
} else {
- strbuf_addf(&branch_top, "refs/remotes/%s/", option_origin);
+ strbuf_addf(&value, "+refs/heads/*:refs/remotes/%s/*:*",
+ option_origin);
+ fetch_pattern = value.buf;
}
- strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top.buf);
-
if (option_mirror || !option_bare) {
/* Configure the remote */
strbuf_addf(&key, "remote.%s.fetch", option_origin);
- git_config_set_multivar(key.buf, value.buf, "^$", 0);
+ git_config_set_multivar(key.buf, fetch_pattern, "^$", 0);
strbuf_reset(&key);
if (option_mirror) {
@@ -479,7 +479,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
strbuf_reset(&key);
}
- fetch_pattern = value.buf;
refspec = parse_fetch_refspec(1, &fetch_pattern);
strbuf_reset(&value);
@@ -549,7 +548,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
head_points_at->old_sha1,
NULL, 0, DIE_ON_ERR);
- strbuf_addstr(&head_ref, branch_top.buf);
+ strbuf_addstr(&head_ref, refspec->dst);
+ strbuf_setlen(&head_ref, head_ref.len - 1);
strbuf_addstr(&head_ref, "HEAD");
/* Remote branch link */
@@ -611,7 +611,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
strbuf_release(&reflog_msg);
- strbuf_release(&branch_top);
strbuf_release(&key);
strbuf_release(&value);
junk_pid = 0;
--
1.6.2.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC 6/8] clone: use setup_remote_config
2009-07-20 17:49 [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Paolo Bonzini
` (4 preceding siblings ...)
2009-07-20 17:49 ` [PATCH RFC 5/8] clone: refactoring of building the fetch refspec Paolo Bonzini
@ 2009-07-20 17:49 ` Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 7/8] config: add git_config_norepo Paolo Bonzini
` (2 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 17:49 UTC (permalink / raw)
To: git
We can now use setup_remote_config in builtin-clone.c and remove
duplicated computation of remote.*.fetch contents.
The three cases to consider are:
1) !option_bare. This is the easy case when setup_remote_config just
works and a normal refs/heads/*:refs/remotes/origin/* refspec is created.
This only requires a small new feature in setup_remote_config to pass
the refspec back to builtin-clone.c; setup_remote_config will simply store
it in the util field of the stringlist items.
2) option_bare && option_mirror. Again, setup_remote_config is used.
Passing PUSH_DEFAULT_MIRROR to option_mirror will use +refs/*:refs/*
for the refspec. There is a change from before, in that a remote.*.push
refspec will be setup as well.
3) option_bare && !option_mirror. In this case, no fetch refspec will
be configured (just as before), and setup_remote_config is not used.
Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
builtin-clone.c | 46 ++++++++++++++--------------------------------
builtin-remote.c | 5 +++--
remote.h | 3 +++
3 files changed, 20 insertions(+), 34 deletions(-)
diff --git a/builtin-clone.c b/builtin-clone.c
index 345101a..68d8a68 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -19,6 +19,7 @@
#include "strbuf.h"
#include "dir.h"
#include "pack-refs.h"
+#include "string-list.h"
#include "sigchain.h"
#include "branch.h"
#include "remote.h"
@@ -348,7 +349,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
char *path, *dir;
int dest_exists;
const struct ref *refs, *head_points_at, *remote_head, *mapped_refs;
- struct strbuf key = STRBUF_INIT, value = STRBUF_INIT;
struct strbuf reflog_msg = STRBUF_INIT;
struct transport *transport = NULL;
int err = 0;
@@ -449,40 +449,24 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
git_config(git_default_config, NULL);
- if (option_bare) {
- if (option_mirror)
- fetch_pattern = "+refs/*:refs/*";
- else
- fetch_pattern = "+refs/heads/*:refs/heads/*";
-
+ if (option_bare)
git_config_set("core.bare", "true");
- } else {
- strbuf_addf(&value, "+refs/heads/*:refs/remotes/%s/*:*",
- option_origin);
- fetch_pattern = value.buf;
- }
if (option_mirror || !option_bare) {
- /* Configure the remote */
- strbuf_addf(&key, "remote.%s.fetch", option_origin);
- git_config_set_multivar(key.buf, fetch_pattern, "^$", 0);
- strbuf_reset(&key);
-
- if (option_mirror) {
- strbuf_addf(&key, "remote.%s.mirror", option_origin);
- git_config_set(key.buf, "true");
- strbuf_reset(&key);
- }
-
- strbuf_addf(&key, "remote.%s.url", option_origin);
- git_config_set(key.buf, repo);
- strbuf_reset(&key);
+ struct string_list track = { NULL, 0, 0 };
+ setup_remote_config (option_origin, repo,
+ option_mirror
+ ? PUSH_DEFAULT_MIRROR
+ : PUSH_DEFAULT_NOTHING,
+ &track);
+ fetch_pattern = track.items[0].util;
+ refspec = parse_fetch_refspec(1, &fetch_pattern);
+ string_list_clear(&track, 1);
+ } else {
+ fetch_pattern = "+refs/heads/*:refs/heads/*";
+ refspec = parse_fetch_refspec(1, &fetch_pattern);
}
- refspec = parse_fetch_refspec(1, &fetch_pattern);
-
- strbuf_reset(&value);
-
if (path && !is_bundle)
refs = clone_local(path, git_dir);
else {
@@ -611,8 +595,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
}
strbuf_release(&reflog_msg);
- strbuf_release(&key);
- strbuf_release(&value);
junk_pid = 0;
return err;
}
diff --git a/builtin-remote.c b/builtin-remote.c
index 23ab24b..99c06bc 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -59,7 +59,7 @@ static void warn_unconfigured_push()
}
-static int setup_default_remote_config(const char *name, const char *url, int push, struct string_list *track)
+int setup_remote_config(const char *name, const char *url, int push, struct string_list *track)
{
struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT;
const char *refspec = NULL;
@@ -154,6 +154,7 @@ static int setup_default_remote_config(const char *name, const char *url, int pu
else
strbuf_addf(&buf2, "+refs/heads/%s:refs/remotes/%s/%s",
item->string, name, item->string);
+ item->util = xstrdup (buf2.buf);
if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
return 1;
}
@@ -265,7 +266,7 @@ static int add(int argc, const char **argv)
strbuf_release(&buf);
strbuf_release(&buf2);
- string_list_clear(&track, 0);
+ string_list_clear(&track, 1);
return 0;
}
diff --git a/remote.h b/remote.h
index 86b18dc..64f4d58 100644
--- a/remote.h
+++ b/remote.h
@@ -115,6 +115,9 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name);
*/
int remote_find_tracking(struct remote *remote, struct refspec *refspec);
+struct string_list;
+int setup_remote_config(const char *name, const char *url, int push, struct string_list *track);
+
struct branch {
const char *name;
const char *refname;
--
1.6.2.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC 7/8] config: add git_config_norepo
2009-07-20 17:49 [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Paolo Bonzini
` (5 preceding siblings ...)
2009-07-20 17:49 ` [PATCH RFC 6/8] clone: use setup_remote_config Paolo Bonzini
@ 2009-07-20 17:49 ` Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 8/8] clone: add --push option Paolo Bonzini
2009-07-20 22:15 ` [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Junio C Hamano
8 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 17:49 UTC (permalink / raw)
To: git
This function will be needed to read the configuration in git-clone
before the new repository is created.
Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
cache.h | 1 +
config.c | 37 ++++++++++++++++++++++++++++---------
2 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/cache.h b/cache.h
index a46bfe6..c349cd1 100644
--- a/cache.h
+++ b/cache.h
@@ -893,6 +893,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *);
extern int git_tracking_config(const char *, const char *, struct tracking_config *);
extern int git_default_config(const char *, const char *, void *);
extern int git_config_from_file(config_fn_t fn, const char *, void *);
+extern int git_config_norepo(config_fn_t fn, void *);
extern int git_config(config_fn_t fn, void *);
extern int git_parse_ulong(const char *, unsigned long *);
extern int git_config_int(const char *, const char *);
diff --git a/config.c b/config.c
index 37d95a4..d50a261 100644
--- a/config.c
+++ b/config.c
@@ -709,19 +709,14 @@ int git_config_global(void)
return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
}
-int git_config(config_fn_t fn, void *data)
+static int git_config_extra_repo(config_fn_t fn, void *data, int *found)
{
- int ret = 0, found = 0;
- char *repo_config = NULL;
+ int ret = 0;
const char *home = NULL;
-
- /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
- if (config_exclusive_filename)
- return git_config_from_file(fn, config_exclusive_filename, data);
if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
ret += git_config_from_file(fn, git_etc_gitconfig(),
data);
- found += 1;
+ *found += 1;
}
home = getenv("HOME");
@@ -729,11 +724,35 @@ int git_config(config_fn_t fn, void *data)
char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
if (!access(user_config, R_OK)) {
ret += git_config_from_file(fn, user_config, data);
- found += 1;
+ *found += 1;
}
free(user_config);
}
+ return ret;
+}
+
+int git_config_norepo(config_fn_t fn, void *data)
+{
+ int ret, found = 0;
+
+ /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
+ if (config_exclusive_filename)
+ return git_config_from_file(fn, config_exclusive_filename, data);
+ ret = git_config_extra_repo (fn, data, &found);
+ if (found == 0)
+ return -1;
+ return ret;
+}
+int git_config(config_fn_t fn, void *data)
+{
+ int ret, found = 0;
+ char *repo_config;
+
+ /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
+ if (config_exclusive_filename)
+ return git_config_from_file(fn, config_exclusive_filename, data);
+ ret = git_config_extra_repo (fn, data, &found);
repo_config = git_pathdup("config");
if (!access(repo_config, R_OK)) {
ret += git_config_from_file(fn, repo_config, data);
--
1.6.2.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH RFC 8/8] clone: add --push option
2009-07-20 17:49 [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Paolo Bonzini
` (6 preceding siblings ...)
2009-07-20 17:49 ` [PATCH RFC 7/8] config: add git_config_norepo Paolo Bonzini
@ 2009-07-20 17:49 ` Paolo Bonzini
2009-07-20 22:15 ` [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Junio C Hamano
8 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 17:49 UTC (permalink / raw)
To: git
This patch completes the series by supporting --push within
git clone as well.
The bulk of the patch actually is just moving the options struct
for builtin-clone as late as possible to make it possible to use
OPT_CALLBACK. The actual implementation of --push is essentially
reusing setup_remote_config, and actually simplifies the code.
Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
Documentation/git-clone.txt | 13 ++++++-
builtin-clone.c | 90 ++++++++++++++++++++++++++-----------------
t/t5601-clone.sh | 78 +++++++++++++++++++++++++++++++++++++
3 files changed, 145 insertions(+), 36 deletions(-)
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index b14de6c..d5753c4 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -27,6 +27,9 @@ all the remote-tracking branches, and a `git pull` without
arguments will in addition merge the remote master branch into the
current master branch, if any.
+Optionally, `git clone` can also set up the behavior upon `git push`.
+This will be done only if the `--push` option is provided.
+
This default configuration is achieved by creating references to
the remote branch heads under `$GIT_DIR/refs/remotes/origin` and
by initializing `remote.origin.url` and `remote.origin.fetch`
@@ -111,8 +114,16 @@ then the cloned repository will become corrupt.
used, neither remote-tracking branches nor the related
configuration variables are created.
+--push=<strategy>::
+ Set up the clone's behavior upon `git push`. Valid values
+ for `\--push` are `matching`, `mirror, `tracking`, `current`
+ and `nothing`. The meanings are the same as for the
+ `push.default` configuration key. If no strategy is
+ specified, the contents of `push.default` will be used.
+
--mirror::
- Set up a mirror of the remote repository. This implies --bare.
+ Set up a mirror of the remote repository. This is the
+ same as `\--push=mirror --bare`.
--origin <name>::
-o <name>::
diff --git a/builtin-clone.c b/builtin-clone.c
index 68d8a68..b9f2f16 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -40,40 +40,12 @@ static const char * const builtin_clone_usage[] = {
static int option_quiet, option_no_checkout, option_bare, option_mirror;
static int option_local, option_no_hardlinks, option_shared;
+static int option_push = PUSH_DEFAULT_UNKNOWN;
static char *option_template, *option_reference, *option_depth;
static char *option_origin = NULL;
static char *option_upload_pack = "git-upload-pack";
static int option_verbose;
-static struct option builtin_clone_options[] = {
- OPT__QUIET(&option_quiet),
- OPT__VERBOSE(&option_verbose),
- OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
- "don't create a checkout"),
- OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
- OPT_BOOLEAN(0, "naked", &option_bare, "create a bare repository"),
- OPT_BOOLEAN(0, "mirror", &option_mirror,
- "create a mirror repository (implies bare)"),
- OPT_BOOLEAN('l', "local", &option_local,
- "to clone from a local repository"),
- OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks,
- "don't use local hardlinks, always copy"),
- OPT_BOOLEAN('s', "shared", &option_shared,
- "setup as shared repository"),
- OPT_STRING(0, "template", &option_template, "path",
- "path the template repository"),
- OPT_STRING(0, "reference", &option_reference, "repo",
- "reference repository"),
- OPT_STRING('o', "origin", &option_origin, "branch",
- "use <branch> instead of 'origin' to track upstream"),
- OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
- "path to git-upload-pack on the remote"),
- OPT_STRING(0, "depth", &option_depth, "depth",
- "create a shallow clone of that depth"),
-
- OPT_END()
-};
-
static char *get_repo_path(const char *repo, int *is_bundle)
{
static char *suffix[] = { "/.git", ".git", "" };
@@ -341,6 +313,50 @@ static struct ref *write_remote_refs(const struct ref *refs,
return local_refs;
}
+static int opt_parse_push(const struct option *opt, const char *arg, int not)
+{
+ int *value = opt->value;
+ if (not)
+ *value = PUSH_DEFAULT_NOTHING;
+ else if (!arg)
+ *value = push_default;
+ else
+ return git_parse_push_default("--push", arg, value);
+
+ return 0;
+}
+
+static struct option builtin_clone_options[] = {
+ OPT__QUIET(&option_quiet),
+ OPT__VERBOSE(&option_verbose),
+ OPT_BOOLEAN('n', "no-checkout", &option_no_checkout,
+ "don't create a checkout"),
+ OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
+ OPT_BOOLEAN(0, "naked", &option_bare, "create a bare repository"),
+ { OPTION_CALLBACK, 0, "push", &option_push, "strategy",
+ "how to setup pushing", PARSE_OPT_OPTARG, opt_parse_push },
+ OPT_BOOLEAN(0, "mirror", &option_mirror,
+ "create a mirror repository (implies --bare and --push=mirror)"),
+ OPT_BOOLEAN('l', "local", &option_local,
+ "to clone from a local repository"),
+ OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks,
+ "don't use local hardlinks, always copy"),
+ OPT_BOOLEAN('s', "shared", &option_shared,
+ "setup as shared repository"),
+ OPT_STRING(0, "template", &option_template, "path",
+ "path the template repository"),
+ OPT_STRING(0, "reference", &option_reference, "repo",
+ "reference repository"),
+ OPT_STRING('o', "origin", &option_origin, "branch",
+ "use <branch> instead of 'origin' to track upstream"),
+ OPT_STRING('u', "upload-pack", &option_upload_pack, "path",
+ "path to git-upload-pack on the remote"),
+ OPT_STRING(0, "depth", &option_depth, "depth",
+ "create a shallow clone of that depth"),
+
+ OPT_END()
+};
+
int cmd_clone(int argc, const char **argv, const char *prefix)
{
int is_bundle = 0;
@@ -358,14 +374,22 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
junk_pid = getpid();
+ git_config_norepo(git_default_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_clone_options,
builtin_clone_usage, 0);
if (argc == 0)
die("You must specify a repository to clone.");
- if (option_mirror)
+ if (option_push == PUSH_DEFAULT_UNKNOWN)
+ option_push = (option_mirror
+ ? PUSH_DEFAULT_MIRROR
+ : PUSH_DEFAULT_NOTHING);
+ if (option_mirror) {
option_bare = 1;
+ if (option_push != PUSH_DEFAULT_MIRROR)
+ die ("--mirror and --push are incompatible");
+ }
if (option_bare) {
if (option_origin)
@@ -454,11 +478,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (option_mirror || !option_bare) {
struct string_list track = { NULL, 0, 0 };
- setup_remote_config (option_origin, repo,
- option_mirror
- ? PUSH_DEFAULT_MIRROR
- : PUSH_DEFAULT_NOTHING,
- &track);
+ setup_remote_config(option_origin, repo, option_push, &track);
fetch_pattern = track.items[0].util;
refspec = parse_fetch_refspec(1, &fetch_pattern);
string_list_clear(&track, 1);
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 2335d8b..6445dad 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -83,11 +83,89 @@ test_expect_success 'clone --mirror' '
test ! -f mirror/file &&
FETCH="$(cd mirror && git config remote.origin.fetch)" &&
test "+refs/*:refs/*" = "$FETCH" &&
+ PUSH="$(cd mirror && git config remote.origin.push)" &&
+ test "+refs/*:refs/*" = "$PUSH" &&
MIRROR="$(cd mirror && git config --bool remote.origin.mirror)" &&
test "$MIRROR" = true
'
+test_expect_success 'clone --push=mirror' '
+
+ git clone --push=mirror src mirrorx &&
+ test -f mirrorx/.git/HEAD &&
+ test -f mirrorx/file &&
+ FETCH="$(cd mirrorx && git config remote.origin.fetch)" &&
+ test "+refs/*:refs/*" = "$FETCH" &&
+ PUSH="$(cd mirrorx && git config remote.origin.push)" &&
+ test "+refs/*:refs/*" = "$PUSH" &&
+ MIRROR="$(cd mirrorx && git config --bool remote.origin.mirror)" &&
+ test "$MIRROR" = true
+
+'
+
+test_expect_success 'clone --push=current' '
+
+ git clone --push=current src current &&
+ test -f current/.git/HEAD &&
+ test -f current/file &&
+ ! (cd current/.git && git config --bool remote.origin.mirror) &&
+ (cd current/.git && git config --bool remote.origin.pushHeadOnly) &&
+ ! (cd current/.git && git config --bool remote.origin.autosetuppush) &&
+ test "+refs/heads/*:refs/remotes/origin/*" = \
+ "$(cd current && git config remote.origin.fetch)" &&
+ test HEAD = "$(cd current && git config remote.origin.push)"
+
+'
+
+test_expect_success 'clone --push' '
+
+ HOME=$(pwd) &&
+ export HOME &&
+ test_config="$HOME/.gitconfig" &&
+ unset GIT_CONFIG_NOGLOBAL &&
+ echo "[push] default=current" > $test_config
+ git clone --push src default &&
+ test -f default/.git/HEAD &&
+ test -f default/file &&
+ ! (cd default/.git && git config --bool remote.origin.mirror) &&
+ (cd default/.git && git config --bool remote.origin.pushHeadOnly) &&
+ ! (cd default/.git && git config --bool remote.origin.autosetuppush) &&
+ test "+refs/heads/*:refs/remotes/origin/*" = \
+ "$(cd default && git config remote.origin.fetch)" &&
+ test HEAD = "$(cd default && git config remote.origin.push)"
+
+'
+
+test_expect_success 'clone --push=tracking' '
+
+ git clone --push=tracking src tracking &&
+ test -f tracking/.git/HEAD &&
+ test -f tracking/file &&
+ ! (cd tracking && git config --bool remote.origin.mirror) &&
+ (cd tracking && git config --bool remote.origin.pushHeadOnly) &&
+ (cd tracking && git config --bool remote.origin.autosetuppush) &&
+ test "+refs/heads/*:refs/remotes/origin/*" = \
+ "$(cd tracking && git config remote.origin.fetch)" &&
+ test refs/heads/master:refs/heads/master = \
+ "$(cd tracking && git config remote.origin.push)"
+
+'
+
+test_expect_success 'clone --push=matching' '
+
+ git clone --push=matching src matching &&
+ test -f matching/.git/HEAD &&
+ test -f matching/file &&
+ ! (cd matching && git config --bool remote.origin.mirror) &&
+ ! (cd matching && git config --bool remote.origin.pushHeadOnly) &&
+ ! (cd matching && git config --bool remote.origin.autosetuppush) &&
+ test "+refs/heads/*:refs/remotes/origin/*" = \
+ "$(cd matching && git config remote.origin.fetch)" &&
+ test : = "$(cd matching && git config remote.origin.push)"
+
+'
+
test_expect_success 'clone --bare names the local repository <name>.git' '
git clone --bare src &&
--
1.6.2.5
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 2/8] push: add push.default = mirror
2009-07-20 17:49 ` [PATCH RFC 2/8] push: add push.default = mirror Paolo Bonzini
@ 2009-07-20 20:46 ` Junio C Hamano
2009-07-20 21:14 ` Paolo Bonzini
0 siblings, 1 reply; 16+ messages in thread
From: Junio C Hamano @ 2009-07-20 20:46 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: git
Paolo Bonzini <bonzini@gnu.org> writes:
> This patch adds a new value for push.default. The aim of the series is
> to support all push.default values as arguments to `--push' in git-clone
> and git-remote, and if push.default=mirror works it is easy to make
> `--mirror' a synonym for `--push=mirror' in those comments.
>
> Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
> ---
> Documentation/config.txt | 2 ++
> builtin-push.c | 12 ++++++++++--
> cache.h | 1 +
> config.c | 4 +++-
> 4 files changed, 16 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/config.txt b/Documentation/config.txt
> index 4c27e9d..fa5eb76 100644
> --- a/Documentation/config.txt
> +++ b/Documentation/config.txt
> @@ -1290,6 +1290,8 @@ push.default::
> * `matching` push all matching branches.
> All branches having the same name in both ends are considered to be
> matching. This is the default.
> +* `mirror` pushes all branches forcing non fast-forward updates and
> + deletes branches that do not exist anymore locally.
> * `tracking` push the current branch to its upstream branch.
> * `current` push the current branch to a branch of the same name.
I think this patch alone (regardless of the rest which I haven't read)
probably makes sense.
Except that I think the part below contradicts with the --mirror push
semantics (see remote.c::match_refs()).
> diff --git a/builtin-push.c b/builtin-push.c
> index e678a9d..8a312a3 100644
> --- a/builtin-push.c
> +++ b/builtin-push.c
> @@ -74,6 +73,10 @@ static void setup_default_push_refspecs(void)
> add_refspec(":");
> break;
>
> + case PUSH_DEFAULT_MIRROR:
> + add_refspec("+refs/*:refs/*");
> + break;
> +
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 2/8] push: add push.default = mirror
2009-07-20 20:46 ` Junio C Hamano
@ 2009-07-20 21:14 ` Paolo Bonzini
2009-07-20 21:34 ` Junio C Hamano
0 siblings, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 21:14 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Paolo Bonzini, git
> I think this patch alone (regardless of the rest which I haven't read)
> probably makes sense.
>
> Except that I think the part below contradicts with the --mirror push
> semantics (see remote.c::match_refs()).
if (!send_mirror && prefixcmp(src->name, "refs/heads/"))
continue;
The way I read this, send_mirror will send everything, even if it's
outside refs/heads/*. So refs/*.
If we agree on the semantics, would you harvest it separately or should
I resubmit?
Paolo
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 2/8] push: add push.default = mirror
2009-07-20 21:14 ` Paolo Bonzini
@ 2009-07-20 21:34 ` Junio C Hamano
2009-07-20 21:36 ` Paolo Bonzini
0 siblings, 1 reply; 16+ messages in thread
From: Junio C Hamano @ 2009-07-20 21:34 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: Paolo Bonzini, git
Paolo Bonzini <paolo.bonzini@gmail.com> writes:
>> I think this patch alone (regardless of the rest which I haven't read)
>> probably makes sense.
>>
>> Except that I think the part below contradicts with the --mirror push
>> semantics (see remote.c::match_refs()).
>
> if (!send_mirror && prefixcmp(src->name, "refs/heads/"))
> continue;
>
> The way I read this, send_mirror will send everything, even if it's
> outside refs/heads/*. So refs/*.
Ah, ok, thanks.
> If we agree on the semantics, would you harvest it separately or
> should I resubmit?
I do not expect the rest of the series to be near 'next' before 1.6.4, and
it is likely that I'll forget about this patch by the time 1.6.4 finally
ships.
But I realize that without the rest of the series, being able to say
push.default = mirror does not add much value. A replacement commit log
message I wrote for this patch stand-alone is:
Instead "git push --mirror $over_there", you can say "git push" after
setting up push.default to "mirror".
But the thing is, you can already do that with "remote add --mirror".
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 2/8] push: add push.default = mirror
2009-07-20 21:34 ` Junio C Hamano
@ 2009-07-20 21:36 ` Paolo Bonzini
0 siblings, 0 replies; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-20 21:36 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Paolo Bonzini, git
>> If we agree on the semantics, would you harvest it separately or
>> should I resubmit?
>
> I do not expect the rest of the series to be near 'next' before 1.6.4, and
> it is likely that I'll forget about this patch by the time 1.6.4 finally
> ships.
Okay, let's keep it out of the way for now. It doesn't add much.
Paolo
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push'
2009-07-20 17:49 [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Paolo Bonzini
` (7 preceding siblings ...)
2009-07-20 17:49 ` [PATCH RFC 8/8] clone: add --push option Paolo Bonzini
@ 2009-07-20 22:15 ` Junio C Hamano
2009-07-21 10:33 ` Paolo Bonzini
8 siblings, 1 reply; 16+ messages in thread
From: Junio C Hamano @ 2009-07-20 22:15 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: git, Finn Arne Gangstad
Paolo Bonzini <bonzini@gnu.org> writes:
> I post as an initial RFC the third series in the push.default saga.
> This is on top of origin/next and even then it requires the
> "push --current" patches to be fully functional. Even without it,
> however, it will create correct configuration.
>
> The series adds --push options to "git remote add" and "git clone".
> These accept a push strategy of the same kind as "push.default",
> and will use it to create push configuration and refspecs. These
> will then override push.default.
Let's step back a bit.
If I have a local branch X, is it conceivable that if I ever want to push
it out to elsewhere on a regular basis, I would likely to push it to the
same branch at the same remote?
I think the answer to the above question is yes, and partly because that
is because the precondition of the question is qualified with "on a
regular basis".
Now, I regularly push my 'master' to four repositories (k.org, repo.or.cz,
sf.net and sourceforge.jp), and I could be pushing it out to a different
branch at each of these remotes, but we could loosen the above statement
somewhat and still keep the main point.
If I have a local branch X that want to push it out to another
repository R on a regular basis, I would very likely to push it to the
same branch Y at that remote.
Now, how do (X,R) and Y related with each other? I think there are three
workflows that want different settings (and one is actually a special case
of another one, so essentially there are only two).
* X tracks Y from R, iow, branch.X.remote = R, branch.X.merge = Y;
push.default = tracking helps pushing out X when X is the current
branch, but it does not help pushing all such X out.
* X is Y; push.default = matching helps pushing all such X out. This is
a special case of the above.
* X tracks Y from R, but there are other X' that also track Y from R and
pushing all of them is nonsense. push.default = tracking helps pushing
X when it is the current branch. This is the case where you fork your
topic(s) directly from remote integration branch
Are these all? What I am trying to get at is if we can tweak the rules
without introducing too much configuration variables to cover all these
cases.
Traditionally, we said:
$ git push $there $ref
is _always_ a shorthand for
$ git push $there $ref:$ref
This favors the second case in that if for whatever reason you cannot
afford to push all of them in matching, but as long as your (X,R) -> Y
mapping is X==Y (i.e. matching), then you do not have to say colon to
duplicate refname. You can say "git push origin master next" to push only
these two without pushing out 'pu', for example. If we somehow tweak
this "$ref is a shorthand for $ref:$ref" rule to account for the tracking
branch.*.merge gives us, perhaps we can make the push easier to use.
If the conjecture "no matter what your workflow is, (X,R) -> Y is a
function, not a one-to-many-mapping" holds, perhaps we may instead want to
say something like:
(1) "git push R" pushes out the refs according to remote.R.push refspec
rules (this is also the same as the current set of rules). Absense
of such configured refspec rules used to always trigger "matching"
rule, but now it can optionally use "tracking" rule for all the local
branches.
(2) "git push R $ref" is *NOT* same as "git push R $ref:$ref" anymore.
Because for a given (R,X) we can say what (R,X) -> Y function yields,
we should map the given ref to where the user wants to put it. If X
tracks Y, "git push R X" should become "git push R X:Y" without any
funky configuration.
(3) "git push $ref" used to be illegal, but when it is unambiguous that
$ref cannot name a remote, we look at branch.$ref.remote = R to find
that the push is a shorthand for "git push R $ref". The mapping rules
of (2) also applies.
(4) "git push" is a synonym for "git push R" where R is the value of
branch.X.remote, or "origin" if there is no such configuration. This
will in turn trigger rule (1) above.
We could optionally make it a synonym for "git push X" (where X is
the name of the current branch), which would invoke rule (3) above,
which in turn would invoke rule (2) above. Perhaps "push only the
current branch" option in the configuration, or "git push HEAD" from
the command line, would trigger this alternate behaviour.
I think one of the workflows quoted as the original motivation of Finn
Arne's series that added push.default also falls naturally out of this.
When you interact with more than one remote, you may track the 'master'
branch from remote R1 as your local R1-master while tracking the 'master'
branch from remote R2 as your local R2-master.
Then
$ git push
while on R1-master, with the optional setting of rule (4) above, will be
the same as
$ git push R1-master
both of which would mean
$ git push R1 R1-master:master
Also
$ git push R1
will trigger rule (1) and would push whatever is configured in
remote.R1.push. Optionally, without remote.R1.push, it can inspect local
branches and find ones that track branches from R1, and push them to
corresponding places (this would match "matching" ref behaviour but with
the renaming expressed by branch.*.merge).
Jut thinking aloud.
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push'
2009-07-20 22:15 ` [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Junio C Hamano
@ 2009-07-21 10:33 ` Paolo Bonzini
2009-07-21 21:00 ` Junio C Hamano
0 siblings, 1 reply; 16+ messages in thread
From: Paolo Bonzini @ 2009-07-21 10:33 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Finn Arne Gangstad
> If I have a local branch X, is it conceivable that if I ever want to push
> it out to elsewhere on a regular basis, I would likely to push it to the
> same branch at the same remote?
Yes. The exception could be if you push to multiple remotes---but in
that case, you have to issue multiple push commands anyway. X -> (R,Y)
is not a function, but (X,R) -> Y is.
> Are these all? What I am trying to get at is if we can tweak the rules
> without introducing too much configuration variables to cover all these
> cases.
>
> Traditionally, we said:
>
> $ git push $there $ref
>
> is _always_ a shorthand for
>
> $ git push $there $ref:$ref
>
> If we somehow tweak
> this "$ref is a shorthand for $ref:$ref" rule to account for the tracking
> branch.*.merge gives us, perhaps we can make the push easier to use.
This is nice indeed. My questions are:
1) can we assume backwards compatibility is not a problem? Or, in other
words, would this be 1.6.5 or 1.7.0 material? In the past, the list has
usually been very cautious about that, but if there's good reasons I
guess the answer can be "yes".
> (4) "git push" is a synonym for "git push R" where R is the value of
> branch.X.remote, or "origin" if there is no such configuration. This
> will in turn trigger rule (1) above.
>
> We could optionally make it a synonym for "git push X" (where X is
> the name of the current branch), which would invoke rule (3) above,
> which in turn would invoke rule (2) above. Perhaps "push only the
> current branch" option in the configuration, or "git push HEAD" from
> the command line, would trigger this alternate behaviour.
[i.e., looking up branch.*.remote for the current branch].
2) if I understand correctly, then "git push HEAD" would behave like
push.default=tracking rather than push.default=current. If so, how do
you provide push.default=current behavior? (Or maybe you don't care).
Would this apply to remote.*.push = HEAD too? (I think so). Are the
backward compatibility issues stronger in this case? (I also think so).
3) if the previous item turns out to be a problem, should we invent a
new kind of refspec? "HEAD:" is free to use, is it a good idea? (I
don't like it).
4) From an implementation point of view, how well will it fit the
existing code, or rather will it have to be special-cased all over the
place? I already didn't like the single special case I have in the "git
push --current" patch, though I think it's unavoidable.
> I think one of the workflows quoted as the original motivation of Finn
> Arne's series that added push.default also falls naturally out of this.
That's true, and I actually liked the idea very much. The fact that it
raises many questions is not necessarily a point down---adding new
configuration keys is definitely simpler to flesh out, but it may be
that it only reaches a local maximum of simplicity/expressiveness. In
my case the combination refspec/autosetuppush/pushHeadOnly is very
expressive, but it requires to be wrapped by porcelain "git remote
add"/"git clone" for the average user.
In the past I've seen the development of git follow the line of adding
more knobs to allow the experts to tweak them, but that could also be a
byproduct of the audience that this ML reaches.
In this case, I think the choice depends on how much effort can be
invested in answering the above questions.
Paolo
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push'
2009-07-21 10:33 ` Paolo Bonzini
@ 2009-07-21 21:00 ` Junio C Hamano
0 siblings, 0 replies; 16+ messages in thread
From: Junio C Hamano @ 2009-07-21 21:00 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: git, Finn Arne Gangstad
Paolo Bonzini <bonzini@gnu.org> writes:
>> If I have a local branch X, is it conceivable that if I ever want to push
>> it out to elsewhere on a regular basis, I would likely to push it to the
>> same branch at the same remote?
>
> Yes. The exception could be if you push to multiple remotes---but in
> that case, you have to issue multiple push commands anyway. X ->
> (R,Y) is not a function, but (X,R) -> Y is.
>
>> Are these all? What I am trying to get at is if we can tweak the rules
>> without introducing too much configuration variables to cover all these
>> cases.
>>
>> Traditionally, we said:
>>
>> $ git push $there $ref
>>
>> is _always_ a shorthand for
>>
>> $ git push $there $ref:$ref
>>
>> If we somehow tweak
>> this "$ref is a shorthand for $ref:$ref" rule to account for the tracking
>> branch.*.merge gives us, perhaps we can make the push easier to use.
>
> This is nice indeed. My questions are:
>
> 1) can we assume backwards compatibility is not a problem? Or, in
> other words, would this be 1.6.5 or 1.7.0 material? In the past, the
> list has usually been very cautious about that, but if there's good
> reasons I guess the answer can be "yes".
I do not think this is an 1.6.X material. We _do_ plan a backward
incompatible changes in 1.7.0 (a few series queued in 'pu') in the area,
so if a redesign along these lines is preferable, 1.7.0 would be the
milestone to do so.
I have a suspicion that the compatibility might not even be a huge issue
for this particular change.
* If I say "git push k.org master", I always mean "git push k.org
master:master", but I would never have forked my master from something
else over there to begin with, and looking up branch.master.merge will
yield master and there is no change in behaviour. Note that in this
paragraph, "I" is figurative---for anybody who uses local branch X as a
local integration branch to be pushed back to the remote X, the end
result will not change, even though the mechanism may be different.
* For somebody who uses local branch Y to track branch X from the remote,
branch.X.merge would say Y. The above change will not be backward
compatible in that:
$ git push $there X
would start pushing X to Y (currently X is pushed to X).
But I suspect that people in this camp would already consider the
current behaviour a misfeature, and they are always doing:
$ git push $there X:Y
when they want to push a single branch out, and loathing it (we can be
reasonably sure about this when we realize that push.default = tracking
was an attempt to lose :Y from this command line).
The change would be an improvement for them. Of course when they
really mean it, they can say:
$ git push $there X:X
> 2) if I understand correctly, then "git push HEAD" would behave like
> push.default=tracking rather than push.default=current. If so, how do
> you provide push.default=current behavior? (Or maybe you don't care).
>
> Would this apply to remote.*.push = HEAD too? (I think so). Are the
> backward compatibility issues stronger in this case? (I also think
> so).
In either case, one assumption I did not spell out in the message you are
replying to is that in a sane workflow the mapping branch.X.merge = Y
gives us is enough and the (implicit) mapping remote.R.push gives to X is
redundant information. I.e. if branch.X.merge = Y, branch.X.remote = R,
then remote.R.push would never map local X to anything but remote Y.
But that is just an assumption. While I do not think of a sane workflow
for which that assumption does not hold, it is not a proof that the
assumption is universally true.
"git push HEAD" would behave like either tracking or current after this
change, but the distinction does not matter in practice exactly for the
same reason as the answer to the item 1) above in your list.
> 3) if the previous item turns out to be a problem, should we invent a
> new kind of refspec? "HEAD:" is free to use, is it a good idea? (I
> don't like it).
Likewise, if it is inconvenient that "git push HEAD" follows
branch.X.merge while on branch X, you can say "git push HEAD:HEAD" to be
more explicit.
> 4) From an implementation point of view, how well will it fit the
> existing code, or rather will it have to be special-cased all over the
> place? I already didn't like the single special case I have in the
> "git push --current" patch, though I think it's unavoidable.
I actually have no idea, as I haven't looked at the code nor tried to
remember how it currently does its thing, while writing the message you
are replying to.
That was why I said "let's step back a bit". I wanted to see if it is a
good time to start thinking what a design that is easier to use purely
from the end-user standpoint should look like, without being constrained
by the current implementation. Piling more knobs after knobs may allow
experts who know which knobs to turn and what combination of knobs to
avoid in order to get the desired effect, but it is suboptimal if the end
result is unusable to ordinary users.
> That's true, and I actually liked the idea very much. The fact that
> it raises many questions is not necessarily a point down---adding new
> configuration keys is definitely simpler to flesh out, but it may be
> that it only reaches a local maximum of simplicity/expressiveness.
Yes, the simplification (of the end user experience, anyway) I outlined
crucially depends on that one assumption that remote.R.push is more or
less redundant information when branch.X.merge is properly used.
I do not know if that is true.
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2009-07-21 21:00 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-20 17:49 [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 1/8] reintroduce PUSH_DEFAULT_UNSPECIFIED Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 2/8] push: add push.default = mirror Paolo Bonzini
2009-07-20 20:46 ` Junio C Hamano
2009-07-20 21:14 ` Paolo Bonzini
2009-07-20 21:34 ` Junio C Hamano
2009-07-20 21:36 ` Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 3/8] git remote add: refactor configuration Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 4/8] git remote add: add --push option Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 5/8] clone: refactoring of building the fetch refspec Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 6/8] clone: use setup_remote_config Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 7/8] config: add git_config_norepo Paolo Bonzini
2009-07-20 17:49 ` [PATCH RFC 8/8] clone: add --push option Paolo Bonzini
2009-07-20 22:15 ` [PATCH RFC 0/8] introduce 'git remote add --push' and 'git clone --push' Junio C Hamano
2009-07-21 10:33 ` Paolo Bonzini
2009-07-21 21:00 ` Junio C Hamano
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 NNTP newsgroup(s).