git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush
@ 2009-07-12 12:17 Paolo Bonzini
  2009-07-12 12:17 ` [PATCH 1/6] config: allow false and true values for branch.autosetuprebase Paolo Bonzini
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Paolo Bonzini @ 2009-07-12 12:17 UTC (permalink / raw)
  To: git

This patch series adds two features that are a step toward providing
consistent per-remote configuration of push behavior in addition
to merge (tracking) behavior.

In particular, the two features are:

1) per-remote configuration of automatic tracking setup.  This leads
to some nice refactoring of the code handling autosetup, where the
combination of autosetupmerge and autosetuprebase is consolidated in
a struct.

2) The ability to automatically setup push refspecs corresponding
to local branches tracking a remote.  This is false by default, since
we also have push.default---and actually, a generalized default of
true is probably not a good idea, unlike a per-remote setting.  In
the future, 'git remote add' might set the per-remote autosetuppush
to true if it gets some appropriate command-line argument.


Patch 1 is a somewhat tangential DWIM that I've meant to send for
a while.  It conflicts with this patch series, so I've included it.

Patches 2 and 3 include the refactorings in preparation for the new
remote.*.autosetup configuration, which is then implemented by
patch 4.

Patch 5 extracts some code to a function that will become more
complicated in patch 6.  Patch 6 implements autosetuppush by
automatically creating and deleting push refspecs upon branch
creation and deletion.

 config: allow false and true values for branch.autosetuprebase
 branch: install_branch_config and struct tracking refactoring
 introduce a struct tracking_config
 remote: add per-remote autosetupmerge and autosetuprebase configuration
 move deletion of merge configuration to branch.c
 branch, checkout: introduce autosetuppush

 Documentation/config.txt |   36 +++++++++++++++++-
 branch.c                 |   92 +++++++++++++++++++++++++++++++++++++--------
 branch.h                 |    5 ++-
 builtin-branch.c         |   10 +----
 builtin-checkout.c       |    2 +-
 builtin-clone.c          |    4 +-
 cache.h                  |   11 ++++-
 config.c                 |   48 +++++++++++++++++-------
 environment.c            |    7 ++-
 remote.c                 |    3 +
 remote.h                 |    1 +
 t/t3200-branch.sh        |   92 ++++++++++++++++++++++++++++++++++++++++++++-
 12 files changed, 259 insertions(+), 52 deletions(-)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/6] config: allow false and true values for branch.autosetuprebase
  2009-07-12 12:17 [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush Paolo Bonzini
@ 2009-07-12 12:17 ` Paolo Bonzini
  2009-07-12 12:17 ` [PATCH 2/6] branch: install_branch_config and struct tracking refactoring Paolo Bonzini
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Paolo Bonzini @ 2009-07-12 12:17 UTC (permalink / raw)
  To: git

Boolean values can be clearly DWIM'ed from false to never and
from true to always.  This is nicer to the user because autosetupmerge
allows boolean values.

Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
 Documentation/config.txt |    4 ++--
 config.c                 |   12 ++++++------
 t/t3200-branch.sh        |   15 ++++++++++++---
 3 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index cb6832b..1e37e33 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -479,12 +479,12 @@ branch.autosetuprebase::
 	When a new branch is created with 'git-branch' or 'git-checkout'
 	that tracks another branch, this variable tells git to set
 	up pull to rebase instead of merge (see "branch.<name>.rebase").
-	When `never`, rebase is never automatically set to true.
+	When `never` or `false`, rebase is never automatically set to true.
 	When `local`, rebase is set to true for tracked branches of
 	other local branches.
 	When `remote`, rebase is set to true for tracked branches of
 	remote branches.
-	When `always`, rebase will be set to true for all tracking
+	When `always` or `true`, rebase will be set to true for all tracking
 	branches.
 	See "branch.autosetupmerge" for details on how to set up a
 	branch to track another branch.
diff --git a/config.c b/config.c
index 1682273..b47a40e 100644
--- a/config.c
+++ b/config.c
@@ -557,17 +557,17 @@ static int git_default_branch_config(const char *var, const char *value)
 	}
 	if (!strcmp(var, "branch.autosetuprebase")) {
 		if (!value)
-			return config_error_nonbool(var);
-		else if (!strcmp(value, "never"))
-			autorebase = AUTOREBASE_NEVER;
+			value = "always";
+		autorebase = AUTOREBASE_NEVER;
+		if (!strcmp(value, "never"))
+			;
 		else if (!strcmp(value, "local"))
 			autorebase = AUTOREBASE_LOCAL;
 		else if (!strcmp(value, "remote"))
 			autorebase = AUTOREBASE_REMOTE;
-		else if (!strcmp(value, "always"))
+		else if (!strcmp(value, "always") ||
+			 git_config_bool (var, value))
 			autorebase = AUTOREBASE_ALWAYS;
-		else
-			return error("Malformed value for %s", var);
 		return 0;
 	}
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index d59a9b4..b14a3a9 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -461,11 +461,20 @@ test_expect_success 'detect misconfigured autosetuprebase (bad value)' '
 	test_must_fail git branch
 '
 
-test_expect_success 'detect misconfigured autosetuprebase (no value)' '
+test_expect_success 'boolean value (no value) for autosetuprebase' '
 	git config --unset branch.autosetuprebase &&
 	echo "[branch] autosetuprebase" >> .git/config &&
-	test_must_fail git branch &&
-	git config --unset branch.autosetuprebase
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git fetch local) &&
+	git branch --track myr21 local/master &&
+	git branch --track myr22 myr21 &&
+	test "$(git config branch.myr21.remote)" = local &&
+	test "$(git config branch.myr21.merge)" = refs/heads/master &&
+	test "z$(git config branch.myr21.rebase)" = ztrue &&
+	test "$(git config branch.myr22.remote)" = . &&
+	test "$(git config branch.myr22.merge)" = refs/heads/myr21 &&
+	test "z$(git config branch.myr22.rebase)" = ztrue
 '
 
 test_done
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/6] branch: install_branch_config and struct tracking refactoring
  2009-07-12 12:17 [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush Paolo Bonzini
  2009-07-12 12:17 ` [PATCH 1/6] config: allow false and true values for branch.autosetuprebase Paolo Bonzini
@ 2009-07-12 12:17 ` Paolo Bonzini
  2009-07-12 12:17 ` [PATCH 3/6] introduce a struct tracking_config Paolo Bonzini
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Paolo Bonzini @ 2009-07-12 12:17 UTC (permalink / raw)
  To: git

This patch combines two small refactoring.  The first is to store
a struct remote into struct tracking.  The second is to pass a
struct remote instead of just the name to install_branch_config.

Together, these will allow to easily implement the new configuration
keys remote.*.autosetupmerge and remote.*.autosetuprebase.

Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
 branch.c        |   34 ++++++++++++++++++----------------
 branch.h        |    3 ++-
 builtin-clone.c |    4 ++--
 3 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/branch.c b/branch.c
index 05ef3f5..d17c5ec 100644
--- a/branch.c
+++ b/branch.c
@@ -7,7 +7,7 @@
 struct tracking {
 	struct refspec spec;
 	char *src;
-	const char *remote;
+	struct remote *remote;
 	int matches;
 };
 
@@ -18,7 +18,7 @@ static int find_tracked_branch(struct remote *remote, void *priv)
 	if (!remote_find_tracking(remote, &tracking->spec)) {
 		if (++tracking->matches == 1) {
 			tracking->src = tracking->spec.src;
-			tracking->remote = remote->name;
+			tracking->remote = remote;
 		} else {
 			free(tracking->spec.src);
 			if (tracking->src) {
@@ -32,7 +32,7 @@ static int find_tracked_branch(struct remote *remote, void *priv)
 	return 0;
 }
 
-static int should_setup_rebase(const char *origin)
+static int should_setup_rebase(struct remote *origin)
 {
 	switch (autorebase) {
 	case AUTOREBASE_NEVER:
@@ -47,17 +47,18 @@ static int should_setup_rebase(const char *origin)
 	return 0;
 }
 
-void install_branch_config(int flag, const char *local, const char *origin, const char *remote)
+void install_branch_config(int flag, const char *local, struct remote *remote,
+			   const char *merge)
 {
 	struct strbuf key = STRBUF_INIT;
-	int rebasing = should_setup_rebase(origin);
+	int rebasing = should_setup_rebase(remote);
 
 	strbuf_addf(&key, "branch.%s.remote", local);
-	git_config_set(key.buf, origin ? origin : ".");
+	git_config_set(key.buf, remote ? remote->name : ".");
 
 	strbuf_reset(&key);
 	strbuf_addf(&key, "branch.%s.merge", local);
-	git_config_set(key.buf, remote);
+	git_config_set(key.buf, merge);
 
 	if (rebasing) {
 		strbuf_reset(&key);
@@ -68,16 +69,15 @@ void install_branch_config(int flag, const char *local, const char *origin, cons
 	if (flag & BRANCH_CONFIG_VERBOSE) {
 		strbuf_reset(&key);
 
-		strbuf_addstr(&key, origin ? "remote" : "local");
+		strbuf_addstr(&key, remote ? "remote" : "local");
 
 		/* Are we tracking a proper "branch"? */
-		if (!prefixcmp(remote, "refs/heads/")) {
-			strbuf_addf(&key, " branch %s", remote + 11);
-			if (origin)
-				strbuf_addf(&key, " from %s", origin);
-		}
+		if (!prefixcmp(merge, "refs/heads/"))
+			strbuf_addf(&key, " branch %s", merge + 11);
 		else
-			strbuf_addf(&key, " ref %s", remote);
+			strbuf_addf(&key, " ref %s", merge);
+		if (remote)
+			strbuf_addf(&key, " from %s", remote->name);
 		printf("Branch %s set up to track %s%s.\n",
 		       local, key.buf,
 		       rebasing ? " by rebasing" : "");
@@ -117,9 +117,11 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
 		return error("Not tracking: ambiguous information for ref %s",
 				orig_ref);
 
-	install_branch_config(BRANCH_CONFIG_VERBOSE, new_ref, tracking.remote,
-			      tracking.src ? tracking.src : orig_ref);
+	if (!tracking.src)
+		tracking.src = xstrdup (orig_ref);
 
+	install_branch_config(BRANCH_CONFIG_VERBOSE, new_ref, tracking.remote,
+			      tracking.src);
 	free(tracking.src);
 	return 0;
 }
diff --git a/branch.h b/branch.h
index eed817a..f7c02c9 100644
--- a/branch.h
+++ b/branch.h
@@ -26,6 +26,7 @@ void remove_branch_state(void);
  * taken from origin "origin".
  */
 #define BRANCH_CONFIG_VERBOSE 01
-extern void install_branch_config(int flag, const char *local, const char *origin, const char *remote);
+struct remote;
+extern void install_branch_config(int flag, const char *local, struct remote *remote, const char *merge);
 
 #endif
diff --git a/builtin-clone.c b/builtin-clone.c
index 32dea74..552ddf6 100644
--- a/builtin-clone.c
+++ b/builtin-clone.c
@@ -527,7 +527,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 		remote_head = NULL;
 		option_no_checkout = 1;
 		if (!option_bare)
-			install_branch_config(0, "master", option_origin,
+			install_branch_config(0, "master", remote_get(option_origin),
 					      "refs/heads/master");
 	}
 
@@ -557,7 +557,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 				      head_points_at->peer_ref->name,
 				      reflog_msg.buf);
 
-			install_branch_config(0, head, option_origin,
+			install_branch_config(0, head, remote_get(option_origin),
 					      head_points_at->name);
 		}
 	} else if (remote_head) {
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/6] introduce a struct tracking_config
  2009-07-12 12:17 [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush Paolo Bonzini
  2009-07-12 12:17 ` [PATCH 1/6] config: allow false and true values for branch.autosetuprebase Paolo Bonzini
  2009-07-12 12:17 ` [PATCH 2/6] branch: install_branch_config and struct tracking refactoring Paolo Bonzini
@ 2009-07-12 12:17 ` Paolo Bonzini
  2009-07-12 12:17 ` [PATCH 4/6] remote: add per-remote autosetupmerge and autosetuprebase configuration Paolo Bonzini
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Paolo Bonzini @ 2009-07-12 12:17 UTC (permalink / raw)
  To: git

This struct groups together the settings for autosetupmerge and
autosetuprebase.

This refactoring will make it easier to add per-remote tracking
configuration, as well as making the addition of autosetuppush
more tidy.

Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
 branch.c           |    2 +-
 builtin-branch.c   |    2 +-
 builtin-checkout.c |    2 +-
 cache.h            |    9 +++++++--
 config.c           |   34 +++++++++++++++++++++++++---------
 environment.c      |    6 ++++--
 6 files changed, 39 insertions(+), 16 deletions(-)

diff --git a/branch.c b/branch.c
index d17c5ec..be683d9 100644
--- a/branch.c
+++ b/branch.c
@@ -34,7 +34,7 @@ static int find_tracked_branch(struct remote *remote, void *priv)
 
 static int should_setup_rebase(struct remote *origin)
 {
-	switch (autorebase) {
+	switch (git_branch_track.rebase) {
 	case AUTOREBASE_NEVER:
 		return 0;
 	case AUTOREBASE_LOCAL:
diff --git a/builtin-branch.c b/builtin-branch.c
index 5687d60..fdd6c05 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -595,7 +595,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (branch_use_color == -1)
 		branch_use_color = git_use_color_default;
 
-	track = git_branch_track;
+	track = git_branch_track.merge;
 
 	head = resolve_ref("HEAD", head_sha1, 0, NULL);
 	if (!head)
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 8a9a474..446cac7 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -624,7 +624,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 	}
 
 	if (opts.track == BRANCH_TRACK_UNSPECIFIED)
-		opts.track = git_branch_track;
+		opts.track = git_branch_track.merge;
 	if (conflict_style) {
 		opts.merge = 1; /* implied */
 		git_xmerge_config("merge.conflictstyle", conflict_style, NULL);
diff --git a/cache.h b/cache.h
index f1e5ede..2db4c3b 100644
--- a/cache.h
+++ b/cache.h
@@ -550,8 +550,12 @@ enum push_default_type {
 	PUSH_DEFAULT_CURRENT,
 };
 
-extern enum branch_track git_branch_track;
-extern enum rebase_setup_type autorebase;
+struct tracking_config {
+	enum branch_track merge;
+	enum rebase_setup_type rebase;
+};
+
+extern struct tracking_config git_branch_track;
 extern enum push_default_type push_default;
 
 enum object_creation_mode {
@@ -632,6 +636,7 @@ enum sharedrepo {
 	PERM_EVERYBODY      = 0664,
 };
 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 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 b47a40e..aa695d4 100644
--- a/config.c
+++ b/config.c
@@ -545,29 +545,30 @@ static int git_default_i18n_config(const char *var, const char *value)
 	return 0;
 }
 
-static int git_default_branch_config(const char *var, const char *value)
+int git_tracking_config(const char *var, const char *value, struct tracking_config *cfg)
 {
-	if (!strcmp(var, "branch.autosetupmerge")) {
+	var = strrchr (var, '.');
+	if (!strcmp(var, ".autosetupmerge")) {
 		if (value && !strcasecmp(value, "always")) {
-			git_branch_track = BRANCH_TRACK_ALWAYS;
+			cfg->merge = BRANCH_TRACK_ALWAYS;
 			return 0;
 		}
-		git_branch_track = git_config_bool(var, value);
+		cfg->merge = git_config_bool(var, value);
 		return 0;
 	}
-	if (!strcmp(var, "branch.autosetuprebase")) {
+	if (!strcmp(var, ".autosetuprebase")) {
 		if (!value)
 			value = "always";
-		autorebase = AUTOREBASE_NEVER;
+		cfg->rebase = AUTOREBASE_NEVER;
 		if (!strcmp(value, "never"))
 			;
 		else if (!strcmp(value, "local"))
-			autorebase = AUTOREBASE_LOCAL;
+			cfg->rebase = AUTOREBASE_LOCAL;
 		else if (!strcmp(value, "remote"))
-			autorebase = AUTOREBASE_REMOTE;
+			cfg->rebase = AUTOREBASE_REMOTE;
 		else if (!strcmp(value, "always") ||
 			 git_config_bool (var, value))
-			autorebase = AUTOREBASE_ALWAYS;
+			cfg->rebase = AUTOREBASE_ALWAYS;
 		return 0;
 	}
 
@@ -575,6 +576,21 @@ static int git_default_branch_config(const char *var, const char *value)
 	return 0;
 }
 
+static int git_default_branch_config(const char *var, const char *value)
+{
+	int result;
+
+	if (!prefixcmp(var, "branch.")
+	    && !strchr (var + 7, '.')) {
+		result = git_tracking_config (var, value, &git_branch_track);
+		if (result)
+			return result;
+	}
+
+	/* Add other config variables here and to Documentation/config.txt. */
+	return 0;
+}
+
 static int git_default_push_config(const char *var, const char *value)
 {
 	if (!strcmp(var, "push.default")) {
diff --git a/environment.c b/environment.c
index 801a005..049d269 100644
--- a/environment.c
+++ b/environment.c
@@ -40,8 +40,10 @@ const char *excludes_file;
 int auto_crlf = 0;	/* 1: both ways, -1: only when adding git objects */
 enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
 unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
-enum branch_track git_branch_track = BRANCH_TRACK_REMOTE;
-enum rebase_setup_type autorebase = AUTOREBASE_NEVER;
+struct tracking_config git_branch_track = {
+	BRANCH_TRACK_REMOTE,
+	AUTOREBASE_NEVER
+};
 enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
 #ifndef OBJECT_CREATION_MODE
 #define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/6] remote: add per-remote autosetupmerge and autosetuprebase configuration
  2009-07-12 12:17 [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush Paolo Bonzini
                   ` (2 preceding siblings ...)
  2009-07-12 12:17 ` [PATCH 3/6] introduce a struct tracking_config Paolo Bonzini
@ 2009-07-12 12:17 ` Paolo Bonzini
  2009-07-12 12:17 ` [PATCH 5/6] move deletion of merge configuration to branch.c Paolo Bonzini
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Paolo Bonzini @ 2009-07-12 12:17 UTC (permalink / raw)
  To: git

This is self-explanatory.  I chose to retain the full range of
possibilities for autosetuprebase, even though in practice only
never/false and always/true will make sense (local will be a
synonym of false, remote will be a synonym of true).

Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
 Documentation/config.txt |   13 +++++++++++++
 branch.c                 |    9 ++++++++-
 builtin-branch.c         |    4 +---
 cache.h                  |    1 +
 remote.c                 |    3 +++
 remote.h                 |    1 +
 t/t3200-branch.sh        |   41 +++++++++++++++++++++++++++++++++++++++++
 7 files changed, 68 insertions(+), 4 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 1e37e33..524a222 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1363,6 +1363,19 @@ remote.<name>.tagopt::
 	Setting this value to \--no-tags disables automatic tag following when
 	fetching from remote <name>
 
+remote.<name>.autosetupmerge::
+	Tells 'git-branch' and 'git-checkout' to setup new branches
+	so that linkgit:git-pull[1] will appropriately merge from the
+	starting point branch.  If present, this overrides the global
+	option branch.autosetupmerge, and can have the same settings.
+
+remote.<name>.autosetuprebase::
+	When a new branch is created with 'git-branch' or 'git-checkout'
+	that tracks another branch, this variable tells git to set
+	up pull to rebase instead of merge (see "branch.<name>.rebase").
+	If present, this overrides the global option
+	branch.autosetuprebase, and can have the same settings.
+
 remotes.<group>::
 	The list of remotes which are fetched by "git remote update
 	<group>".  See linkgit:git-remote[1].
diff --git a/branch.c b/branch.c
index be683d9..e427721 100644
--- a/branch.c
+++ b/branch.c
@@ -34,7 +34,7 @@ static int find_tracked_branch(struct remote *remote, void *priv)
 
 static int should_setup_rebase(struct remote *origin)
 {
-	switch (git_branch_track.rebase) {
+	switch (origin ? origin->track.rebase : git_branch_track.rebase) {
 	case AUTOREBASE_NEVER:
 		return 0;
 	case AUTOREBASE_LOCAL:
@@ -104,6 +104,13 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,
 	if (for_each_remote(find_tracked_branch, &tracking))
 		return 1;
 
+	if (track == BRANCH_TRACK_UNSPECIFIED) {
+		track = (tracking.remote
+			 ? tracking.remote->track.merge : git_branch_track.merge);
+		if (!track)
+			return 0;
+	}
+
 	if (!tracking.matches)
 		switch (track) {
 		case BRANCH_TRACK_ALWAYS:
diff --git a/builtin-branch.c b/builtin-branch.c
index fdd6c05..f045e16 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -540,7 +540,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	int delete = 0, rename = 0, force_create = 0;
 	int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
 	int reflog = 0;
-	enum branch_track track;
+	enum branch_track track = BRANCH_TRACK_UNSPECIFIED;
 	int kinds = REF_LOCAL_BRANCH;
 	struct commit_list *with_commit = NULL;
 
@@ -595,8 +595,6 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (branch_use_color == -1)
 		branch_use_color = git_use_color_default;
 
-	track = git_branch_track.merge;
-
 	head = resolve_ref("HEAD", head_sha1, 0, NULL);
 	if (!head)
 		die("Failed to resolve HEAD as a valid ref.");
diff --git a/cache.h b/cache.h
index 2db4c3b..703dc45 100644
--- a/cache.h
+++ b/cache.h
@@ -881,6 +881,7 @@ extern const char *packed_object_info_detail(struct packed_git *, off_t, unsigne
 extern int update_server_info(int);
 
 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(config_fn_t fn, void *);
diff --git a/remote.c b/remote.c
index c3ada2d..5e21da3 100644
--- a/remote.c
+++ b/remote.c
@@ -131,6 +131,7 @@ static struct remote *make_remote(const char *name, int len)
 		ret->name = xstrndup(name, len);
 	else
 		ret->name = xstrdup(name);
+	ret->track = git_branch_track;
 	return ret;
 }
 
@@ -375,6 +376,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 		return 0;
 	remote = make_remote(name, subkey - name);
 	remote->origin = REMOTE_CONFIG;
+	if (git_tracking_config(key, value, &remote->track))
+		return -1;
 	if (!strcmp(subkey, ".mirror"))
 		remote->mirror = git_config_bool(key, value);
 	else if (!strcmp(subkey, ".skipdefaultupdate"))
diff --git a/remote.h b/remote.h
index 5db8420..86b18dc 100644
--- a/remote.h
+++ b/remote.h
@@ -38,6 +38,7 @@ struct remote {
 	int fetch_tags;
 	int skip_default_update;
 	int mirror;
+	struct tracking_config track;
 
 	const char *receivepack;
 	const char *uploadpack;
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index b14a3a9..186ba56 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -476,5 +476,46 @@ test_expect_success 'boolean value (no value) for autosetuprebase' '
 	test "$(git config branch.myr22.merge)" = refs/heads/myr21 &&
 	test "z$(git config branch.myr22.rebase)" = ztrue
 '
+test_expect_success 'tracking remote with branch.autosetupmerge = false' '
+	git config remote.local.autosetupmerge true &&
+	git config branch.autosetupmerge false &&
+	git config remote.local.url . &&
+	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+	(git show-ref -q refs/remotes/local/master || git fetch local) &&
+	git branch myr23 local/master &&
+	test "$(git config branch.myr23.remote)" = local &&
+	test "$(git config branch.myr23.merge)" = refs/heads/master
+'
+
+test_expect_success 'non-tracking remote with branch.autosetupmerge = always' '
+	git config remote.local.autosetupmerge false &&
+	git config branch.autosetupmerge always &&
+	git branch myr24 local/master &&
+	test z"$(git config branch.myr24.remote)" = z &&
+	test z"$(git config branch.myr24.merge)" = z
+'
 
+test_expect_success 'tracking branch overriding remote configuration' '
+	git config remote.local.autosetupmerge false &&
+	git branch --track myr25 local/master &&
+	test "$(git config branch.myr25.remote)" = local &&
+	test "$(git config branch.myr25.merge)" = refs/heads/master
+'
+
+test_expect_success 'non-tracking branch overriding remote configuration' '
+	git config remote.local.autosetupmerge true &&
+	git branch --no-track myr26 local/master &&
+	test z"$(git config branch.myr26.remote)" = z &&
+	test z"$(git config branch.myr26.merge)" = z
+'
+
+test_expect_success '--no-track and multiple matches ' '
+	git config branch.autosetupmerge true &&
+	git config remote.local2.url . &&
+	git config remote.local2.fetch refs/heads/*:refs/remotes/local/* &&
+	git fetch local2 &&
+	git branch --no-track myr96 local/master
+	test z"$(git config branch.myr96.remote)" = z &&
+	test z"$(git config branch.myr96.merge)" = z
+'
 test_done
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 5/6] move deletion of merge configuration to branch.c
  2009-07-12 12:17 [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush Paolo Bonzini
                   ` (3 preceding siblings ...)
  2009-07-12 12:17 ` [PATCH 4/6] remote: add per-remote autosetupmerge and autosetuprebase configuration Paolo Bonzini
@ 2009-07-12 12:17 ` Paolo Bonzini
  2009-07-12 12:17 ` [PATCH 6/6] branch, checkout: introduce autosetuppush Paolo Bonzini
  2009-07-12 21:17 ` [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush Junio C Hamano
  6 siblings, 0 replies; 8+ messages in thread
From: Paolo Bonzini @ 2009-07-12 12:17 UTC (permalink / raw)
  To: git

In the next step, deletion of merge configuration will become more
complex, so we move it into a separate function.  Since the
configuration is installed with a function in branch.c, I'm placing
deletion there as well.

At the same time, the interface is changed to get the full ref name
including refs/heads/.  This makes no big difference for the caller.

Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
 branch.c         |   11 +++++++++++
 branch.h         |    2 ++
 builtin-branch.c |    6 +-----
 3 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/branch.c b/branch.c
index e427721..8d3e8d8 100644
--- a/branch.c
+++ b/branch.c
@@ -85,6 +85,17 @@ void install_branch_config(int flag, const char *local, struct remote *remote,
 	strbuf_release(&key);
 }
 
+void delete_branch_config (const char *name)
+{
+	struct strbuf buf = STRBUF_INIT;
+	if (prefixcmp(name, "refs/heads/"))
+		return;
+	strbuf_addf(&buf, "branch.%s", name + 11);
+	if (git_config_rename_section(buf.buf, NULL) < 0)
+		warning("Update of config-file failed");
+	strbuf_release(&buf);
+}
+
 /*
  * This is called when new_ref is branched off of orig_ref, and tries
  * to infer the settings for branch.<new_ref>.{remote,merge} from the
diff --git a/branch.h b/branch.h
index f7c02c9..efa4506 100644
--- a/branch.h
+++ b/branch.h
@@ -21,6 +21,8 @@ void create_branch(const char *head, const char *name, const char *start_name,
  */
 void remove_branch_state(void);
 
+void delete_branch_config(const char *name);
+
 /*
  * Configure local branch "local" to merge remote branch "remote"
  * taken from origin "origin".
diff --git a/builtin-branch.c b/builtin-branch.c
index f045e16..4469ea9 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -166,14 +166,10 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
 			      bname.buf);
 			ret = 1;
 		} else {
-			struct strbuf buf = STRBUF_INIT;
 			printf("Deleted %sbranch %s (was %s).\n", remote,
 			       bname.buf,
 			       find_unique_abbrev(sha1, DEFAULT_ABBREV));
-			strbuf_addf(&buf, "branch.%s", bname.buf);
-			if (git_config_rename_section(buf.buf, NULL) < 0)
-				warning("Update of config-file failed");
-			strbuf_release(&buf);
+			delete_branch_config (name);
 		}
 	}
 
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6/6] branch, checkout: introduce autosetuppush
  2009-07-12 12:17 [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush Paolo Bonzini
                   ` (4 preceding siblings ...)
  2009-07-12 12:17 ` [PATCH 5/6] move deletion of merge configuration to branch.c Paolo Bonzini
@ 2009-07-12 12:17 ` Paolo Bonzini
  2009-07-12 21:17 ` [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush Junio C Hamano
  6 siblings, 0 replies; 8+ messages in thread
From: Paolo Bonzini @ 2009-07-12 12:17 UTC (permalink / raw)
  To: git

The autosetuppush configuration arranges so that whenever
a merge configuration is setup, a push refspec is added for
the remote.

This is a step towards providing the functionality currently
enabled by push.default=tracking on a per-remote basis, and
without the restriction of pushing a single branch at a time.

Signed-off-by: Paolo Bonzini <bonzini@gnu.org>
---
 Documentation/config.txt |   19 +++++++++++++++++++
 branch.c                 |   38 ++++++++++++++++++++++++++++++++++++++
 cache.h                  |    1 +
 config.c                 |    4 ++++
 environment.c            |    3 ++-
 t/t3200-branch.sh        |   36 ++++++++++++++++++++++++++++++++++++
 6 files changed, 100 insertions(+), 1 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 524a222..4c27e9d 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -475,6 +475,15 @@ branch.autosetupmerge::
 	done when the starting point is either a local branch or remote
 	branch. This option defaults to true.
 
+branch.autosetuppush::
+	Tells 'git-branch' and 'git-checkout' to setup new branches
+	so that linkgit:git-push[1] will push into the starting point
+	branch.  Note that this option applies only to branches created
+	from a remote branch, and only if git is setting up merging
+	from the remote branch (via any one of branch.autosetupmerge,
+	remote.<name>.autosetupmerge, or `--track`).  This option defaults
+	to false.
+
 branch.autosetuprebase::
 	When a new branch is created with 'git-branch' or 'git-checkout'
 	that tracks another branch, this variable tells git to set
@@ -1369,6 +1378,16 @@ remote.<name>.autosetupmerge::
 	starting point branch.  If present, this overrides the global
 	option branch.autosetupmerge, and can have the same settings.
 
+remote.<name>.autosetuppush::
+	Tells 'git-branch' and 'git-checkout' to setup new branches
+	so that linkgit:git-push[1] will push into the starting point
+	branch.  If present, this overrides the global option
+	branch.autosetuppush, and can have the same settings.
+	Note that this option applies only if git is setting
+	up merging from the remote branch (via any one of
+	branch.autosetupmerge, remote.<name>.autosetupmerge, or
+	`--track`).
+
 remote.<name>.autosetuprebase::
 	When a new branch is created with 'git-branch' or 'git-checkout'
 	that tracks another branch, this variable tells git to set
diff --git a/branch.c b/branch.c
index 8d3e8d8..dfde568 100644
--- a/branch.c
+++ b/branch.c
@@ -51,6 +51,7 @@ void install_branch_config(int flag, const char *local, struct remote *remote,
 			   const char *merge)
 {
 	struct strbuf key = STRBUF_INIT;
+	struct strbuf value = STRBUF_INIT;
 	int rebasing = should_setup_rebase(remote);
 
 	strbuf_addf(&key, "branch.%s.remote", local);
@@ -60,6 +61,13 @@ void install_branch_config(int flag, const char *local, struct remote *remote,
 	strbuf_addf(&key, "branch.%s.merge", local);
 	git_config_set(key.buf, merge);
 
+	if (remote && remote->track.push) {
+		strbuf_reset(&key);
+		strbuf_addf(&key, "remote.%s.push", remote->name);
+		strbuf_addf(&value, "refs/heads/%s:%s", local, merge);
+		git_config_set_multivar(key.buf, value.buf, "^$", 0);
+	}
+
 	if (rebasing) {
 		strbuf_reset(&key);
 		strbuf_addf(&key, "branch.%s.rebase", local);
@@ -83,16 +91,46 @@ void install_branch_config(int flag, const char *local, struct remote *remote,
 		       rebasing ? " by rebasing" : "");
 	}
 	strbuf_release(&key);
+	strbuf_release(&value);
+}
+
+static void strbuf_addstr_escape_re (struct strbuf *buf, const char *add)
+{
+	const char *p = add;
+	while ((add = strpbrk(add, ".*?+^$(){}[]")) != NULL) {
+		strbuf_add(buf, p, add - p);
+		strbuf_addf(buf, "\\%c", *add++);
+		p = add;
+	}
+	strbuf_addstr(buf, p);
 }
 
 void delete_branch_config (const char *name)
 {
 	struct strbuf buf = STRBUF_INIT;
+	struct strbuf push_re = STRBUF_INIT;
+	struct branch *branch;
+
 	if (prefixcmp(name, "refs/heads/"))
 		return;
+
+	/* git config --unset-all remote.foo.push ^\+?refs/heads/bar:  */
+	branch = branch_get(name + 11);
+	strbuf_addf(&buf, "remote.%s.push", branch->remote_name);
+	strbuf_addstr(&push_re, "^\\+?");
+	strbuf_addstr_escape_re(&push_re, name);
+	strbuf_addch(&push_re, ':');
+	if (git_config_set_multivar(buf.buf, NULL, push_re.buf, 1) < 0) {
+		warning("Update of config-file failed");
+		goto fail;
+	}
+	strbuf_reset(&buf);
 	strbuf_addf(&buf, "branch.%s", name + 11);
 	if (git_config_rename_section(buf.buf, NULL) < 0)
 		warning("Update of config-file failed");
+
+fail:
+	strbuf_release(&push_re);
 	strbuf_release(&buf);
 }
 
diff --git a/cache.h b/cache.h
index 703dc45..2d9a864 100644
--- a/cache.h
+++ b/cache.h
@@ -553,6 +553,7 @@ enum push_default_type {
 struct tracking_config {
 	enum branch_track merge;
 	enum rebase_setup_type rebase;
+	int push;
 };
 
 extern struct tracking_config git_branch_track;
diff --git a/config.c b/config.c
index aa695d4..04380bb 100644
--- a/config.c
+++ b/config.c
@@ -556,6 +556,10 @@ int git_tracking_config(const char *var, const char *value, struct tracking_conf
 		cfg->merge = git_config_bool(var, value);
 		return 0;
 	}
+	if (!strcmp(var, ".autosetuppush")) {
+		cfg->push = git_config_bool(var, value);
+		return 0;
+	}
 	if (!strcmp(var, ".autosetuprebase")) {
 		if (!value)
 			value = "always";
diff --git a/environment.c b/environment.c
index 049d269..2b66ac6 100644
--- a/environment.c
+++ b/environment.c
@@ -42,7 +42,8 @@ enum safe_crlf safe_crlf = SAFE_CRLF_WARN;
 unsigned whitespace_rule_cfg = WS_DEFAULT_RULE;
 struct tracking_config git_branch_track = {
 	BRANCH_TRACK_REMOTE,
-	AUTOREBASE_NEVER
+	AUTOREBASE_NEVER,
+	0
 };
 enum push_default_type push_default = PUSH_DEFAULT_UNSPECIFIED;
 #ifndef OBJECT_CREATION_MODE
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 186ba56..5e23cf5 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -233,11 +233,47 @@ test_expect_success 'avoid ambiguous track' '
 	git branch all1 master &&
 	test -z "$(git config branch.all1.merge)"
 '
+test_expect_success 'test push setup' \
+    'git config branch.autosetupmerge true &&
+     git config branch.autosetuppush true &&
+     git config remote.local.url . &&
+     git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+     (git show-ref -q refs/remotes/local/master || git fetch local) &&
+     git branch my11 local/master &&
+     test $(git config branch.my11.remote) = local &&
+     test $(git config branch.my11.merge) = refs/heads/master
+     test $(git config remote.local.push) = refs/heads/my11:refs/heads/master
+'
+
+test_expect_success 'test multiple push setups' \
+    'git config remote.local.url . &&
+     git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+     (git show-ref -q refs/remotes/local/master || git fetch local) &&
+     git branch my12 local/master &&
+     test $(git config branch.my12.remote) = local &&
+     test $(git config branch.my12.merge) = refs/heads/master &&
+     (if git config remote.local.push; then exit 1; else test $? = 2; fi)
+'
+
+test_expect_success 'test push setup cleanup' \
+    'git config branch.autosetupmerge true &&
+     git config branch.autosetuppush true &&
+     git config remote.local.url . &&
+     git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
+     (git show-ref -q refs/remotes/local/master || git fetch local) &&
+     (git branch my11 local/master || :) &&
+     (git branch my12 local/master || :) &&
+     git branch -d my11 &&
+     test $(git config remote.local.push) = refs/heads/my12:refs/heads/master &&
+     git branch -d my12 &&
+     test z$(git config remote.local.push) = z
+'
 
 test_expect_success 'autosetuprebase local on a tracked local branch' '
 	git config remote.local.url . &&
 	git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
 	git config branch.autosetuprebase local &&
+	git config branch.autosetuppush false &&
 	(git show-ref -q refs/remotes/local/o || git fetch local) &&
 	git branch mybase &&
 	git branch --track myr1 mybase &&
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush
  2009-07-12 12:17 [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush Paolo Bonzini
                   ` (5 preceding siblings ...)
  2009-07-12 12:17 ` [PATCH 6/6] branch, checkout: introduce autosetuppush Paolo Bonzini
@ 2009-07-12 21:17 ` Junio C Hamano
  6 siblings, 0 replies; 8+ messages in thread
From: Junio C Hamano @ 2009-07-12 21:17 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: git

I haven't read any of these patches, other than applying them on top of
master and looking at the resulting diff in the t/ directory in the
aggregated form, and also noticing some style deviations in the C code.

The new tests not only check that the commands leave expected results in
the cases where these new variables are set (with or without command line
overrides), but also seem to have checks to see if the commands behave the
same way as before unless the new configuration variables are used.

It is very understandable for any developers (including me) to want to
demonstrate that their shiny new toys work as they specified, and writing
the positive tests (i.e. "does the feature kick in when the user does what
the manual says, and does it leave the expected result?") is a very good
discipline to protect the new features from future breakages.

But at the same time, we (again, including me) tend to forget the
importance about negative tests (e.g. "does the feature refrain from
kicking in when the user does not do what the additional part of the
manual says, iow, uses the traditional way of running the commands, and
does it leave the expected result without the new feature's effect?")
because (1) it is rather boring, and (2) we believe too much in ourselves'
ability not to break things.

So I already am liking the series even before reading a single line of
code.  Makes me hope that the changes are done with the same carefulness
as the tests ;-).

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2009-07-12 21:17 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-12 12:17 [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush Paolo Bonzini
2009-07-12 12:17 ` [PATCH 1/6] config: allow false and true values for branch.autosetuprebase Paolo Bonzini
2009-07-12 12:17 ` [PATCH 2/6] branch: install_branch_config and struct tracking refactoring Paolo Bonzini
2009-07-12 12:17 ` [PATCH 3/6] introduce a struct tracking_config Paolo Bonzini
2009-07-12 12:17 ` [PATCH 4/6] remote: add per-remote autosetupmerge and autosetuprebase configuration Paolo Bonzini
2009-07-12 12:17 ` [PATCH 5/6] move deletion of merge configuration to branch.c Paolo Bonzini
2009-07-12 12:17 ` [PATCH 6/6] branch, checkout: introduce autosetuppush Paolo Bonzini
2009-07-12 21:17 ` [PATCH 0/6] Tracking setup improvements: per-remote config, autosetuppush 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).