[BUG] remote.pushdefault and branch.<name>.pushremote definition order

3 messages, 3 authors, 2016-06-15 · open the first message on its own page

[BUG] remote.pushdefault and branch.<name>.pushremote definition order

From: Jack Nagel <hidden>
Date: 2016-06-15 22:59:59

There seems to be a difference in the behavior of "git push" depending
on whether remote.pushdefault is defined before or after
branch.<name>.pushremote in .git/config.

If remote.pushdefault is defined to be "origin", and later in the
file, branch.master.pushremote is defined to be "upstream", then a
plain "git push" from master errors out because I haven't provided a
refspec or configured push.default. This makes sense.

However, if the order of the two in the file is reversed, then a plain
"git push" pushes to the "origin" repository, even though I have set
the pushremote for master to "upstream". This appears to be a bug.

I would expect the order that things are defined in the config file to
have no effect on the behavior of "git push".

I have reproduced this using git 1.9.0 and 1.8.3.4.

Thanks,
Jack

[PATCH] remote: handle pushremote config in any order order

From: Jeff King <hidden>
Date: 2016-06-15 22:59:59

On Mon, Feb 24, 2014 at 12:10:04AM -0500, Jack Nagel wrote:
There seems to be a difference in the behavior of "git push" depending
on whether remote.pushdefault is defined before or after
branch.<name>.pushremote in .git/config.
[...]
I would expect the order that things are defined in the config file to
have no effect on the behavior of "git push".
Yes, with a few exceptions, we usually try to make the ordering in the
config file irrelevant. This is a bug. The patch below should fix it.

-- >8 --
Subject: remote: handle pushremote config in any order

The remote we push can be defined either by
remote.pushdefault or by branch.*.pushremote for the current
branch. The order in which they appear in the config file
should not matter to precedence (which should be to prefer
the branch-specific config).

The current code parses the config linearly and uses a
single string to store both values, overwriting any
previous value. Thus, config like:

  [branch "master"]
  pushremote = foo
  [remote]
  pushdefault = bar

erroneously ends up pushing to "bar" from the master branch.

We can fix this by storing both values and resolving the
correct value after all config is read.

Signed-off-by: Jeff King <redacted>
---
 remote.c              |  7 ++++++-
 t/t5516-fetch-push.sh | 12 ++++++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/remote.c b/remote.c
index e41251e..7232a33 100644
--- a/remote.c
+++ b/remote.c
@@ -49,6 +49,7 @@ static int branches_nr;
 
 static struct branch *current_branch;
 static const char *default_remote_name;
+static const char *branch_pushremote_name;
 static const char *pushremote_name;
 static int explicit_default_remote_name;
 
@@ -352,7 +353,7 @@ static int handle_config(const char *key, const char *value, void *cb)
 			}
 		} else if (!strcmp(subkey, ".pushremote")) {
 			if (branch == current_branch)
-				if (git_config_string(&pushremote_name, key, value))
+				if (git_config_string(&branch_pushremote_name, key, value))
 					return -1;
 		} else if (!strcmp(subkey, ".merge")) {
 			if (!value)
@@ -492,6 +493,10 @@ static void read_config(void)
 			make_branch(head_ref + strlen("refs/heads/"), 0);
 	}
 	git_config(handle_config, NULL);
+	if (branch_pushremote_name) {
+		free(pushremote_name);
+		pushremote_name = branch_pushremote_name;
+	}
 	alias_all_urls();
 }
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 926e7f6..1309c4d 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -536,6 +536,18 @@ test_expect_success 'push with config branch.*.pushremote' '
 	check_push_result down_repo $the_commit heads/master
 '
 
+test_expect_success 'branch.*.pushremote config order is irrelevant' '
+	mk_test one_repo heads/master &&
+	mk_test two_repo heads/master &&
+	test_config remote.one.url one_repo &&
+	test_config remote.two.url two_repo &&
+	test_config branch.master.pushremote two_repo &&
+	test_config remote.pushdefault one_repo &&
+	git push &&
+	check_push_result one_repo $the_first_commit heads/master &&
+	check_push_result two_repo $the_commit heads/master
+'
+
 test_expect_success 'push with dry-run' '
 
 	mk_test testrepo heads/master &&
-- 
1.8.5.2.500.g8060133

Re: [PATCH] remote: handle pushremote config in any order order

From: Ramkumar Ramachandra <hidden>
Date: 2016-06-15 22:59:59

Jeff King wrote:
Thus, config like:

  [branch "master"]
  pushremote = foo
  [remote]
  pushdefault = bar

erroneously ends up pushing to "bar" from the master branch.
Oh, ouch. Thanks for fixing this.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help