{"thread":{"id":"33320","subject":"[PATCH v4 0/6] Support triangular workflows","startedAt":"2013-03-28T13:26:36Z","lastAt":"2013-04-01T05:35:05Z","messageCount":18,"participants":["Ramkumar Ramachandra","Junio C Hamano","Jeff King"],"isPatch":true,"patchVersion":4,"patchTotal":6},"messages":[{"id":"212507","messageId":"1364477202-5742-1-git-send-email-artagnon@gmail.com","threadId":"33320","inReplyTo":null,"subject":"[PATCH v4 0/6] Support triangular workflows","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-28T13:26:36Z","receivedAt":"2013-03-28T13:26:36Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Hi,\n\nThe changes in this round are:\n\n1. Peff submitted a patch to squash into [3/6].  Since his patch\n   essentially reverts mine, I've blamed him for the change.\n\n2. Peff suggested a code movement in [5/6] to make things flow more\n   naturally.\n\n3. Jonathan suggested a better test description in [2/6].\n\n4. Junio suggested a minor documentation update in [6/6].\n\nMy build of git has had this feature for two weeks now (since the\nfirst iteration), and I'm very happy with it.\n\nJeff King (1):\n  t5516 (fetch-push): drop implicit arguments from helper functions\n\nRamkumar Ramachandra (5):\n  remote.c: simplify a bit of code using git_config_string()\n  t5516 (fetch-push): update test description\n  remote.c: introduce a way to have different remotes for fetch/push\n  remote.c: introduce remote.pushdefault\n  remote.c: introduce branch.<name>.pushremote\n\n Documentation/config.txt |  24 +++-\n builtin/push.c           |   2 +-\n remote.c                 |  41 ++++--\n remote.h                 |   1 +\n t/t5516-fetch-push.sh    | 316 +++++++++++++++++++++++++++--------------------\n 5 files changed, 238 insertions(+), 146 deletions(-)\n\n-- \n1.8.2.141.g3797f84\n"},{"id":"212509","messageId":"1364477202-5742-2-git-send-email-artagnon@gmail.com","threadId":"33320","inReplyTo":"1364477202-5742-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 1/6] remote.c: simplify a bit of code using git_config_string()","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-28T13:26:37Z","receivedAt":"2013-03-28T13:26:37Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"A small segment where handle_config() parses the branch.remote\nconfiguration variable can be simplified using git_config_string().\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n remote.c | 5 ++---\n 1 file changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 174e48e..02e6c4c 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -357,9 +357,8 @@ static int handle_config(const char *key, const char *value, void *cb)\n \t\t\treturn 0;\n \t\tbranch = make_branch(name, subkey - name);\n \t\tif (!strcmp(subkey, \".remote\")) {\n-\t\t\tif (!value)\n-\t\t\t\treturn config_error_nonbool(key);\n-\t\t\tbranch->remote_name = xstrdup(value);\n+\t\t\tif (git_config_string(&branch->remote_name, key, value))\n+\t\t\t\treturn -1;\n \t\t\tif (branch == current_branch) {\n \t\t\t\tdefault_remote_name = branch->remote_name;\n \t\t\t\texplicit_default_remote_name = 1;\n-- \n1.8.2.141.g3797f84\n"},{"id":"212508","messageId":"1364477202-5742-3-git-send-email-artagnon@gmail.com","threadId":"33320","inReplyTo":"1364477202-5742-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 2/6] t5516 (fetch-push): update test description","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-28T13:26:38Z","receivedAt":"2013-03-28T13:26:38Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"The file was originally created in bcdb34f (Test wildcard push/fetch,\n2007-06-08), and only contained tests that exercised wildcard\nfunctionality at the time.  In subsequent commits, many other tests\nunrelated to wildcards were added but the test description was never\nupdated.  Fix this.\n\nHelped-by: Jonathan Nieder <jrnieder@gmail.com>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n t/t5516-fetch-push.sh | 13 ++++++++++++-\n 1 file changed, 12 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 6fd125a..38f8fc0 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -1,6 +1,17 @@\n #!/bin/sh\n \n-test_description='fetching and pushing, with or without wildcard'\n+test_description='Basic fetch/push functionality.\n+\n+This test checks the following functionality:\n+\n+* command-line syntax\n+* refspecs\n+* fast-forward detection, and overriding it\n+* configuration\n+* hooks\n+* --porcelain output format\n+* hiderefs\n+'\n \n . ./test-lib.sh\n \n-- \n1.8.2.141.g3797f84\n"},{"id":"212510","messageId":"1364477202-5742-4-git-send-email-artagnon@gmail.com","threadId":"33320","inReplyTo":"1364477202-5742-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 3/6] t5516 (fetch-push): drop implicit arguments from helper functions","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-28T13:26:39Z","receivedAt":"2013-03-28T13:26:39Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nMany of the tests in t5516 look like:\n\n  mk_empty &&\n  git push testrepo ... &&\n  check_push_result $commit heads/master\n\nIt's reasonably easy to see what is being tested, with the\nexception that \"testrepo\" is a magic global name (it is\nimplicitly used in the helpers, but we have to name it\nexplicitly when calling git directly). Let's make it\nexplicit when call the helpers, too. This is slightly more\ntyping, but makes the test snippets read more naturally.\n\nIt also makes it easy for future tests to use an alternate\nor multiple repositories, without a proliferation of helper\nfunctions.\n\n[rr: fixed sloppy quoting]\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n t/t5516-fetch-push.sh | 276 ++++++++++++++++++++++++++------------------------\n 1 file changed, 142 insertions(+), 134 deletions(-)\n\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 38f8fc0..94e0189 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -18,10 +18,11 @@ This test checks the following functionality:\n D=`pwd`\n \n mk_empty () {\n-\trm -fr testrepo &&\n-\tmkdir testrepo &&\n+\trepo_name=\"$1\"\n+\trm -fr \"$repo_name\" &&\n+\tmkdir \"$repo_name\" &&\n \t(\n-\t\tcd testrepo &&\n+\t\tcd \"$repo_name\" &&\n \t\tgit init &&\n \t\tgit config receive.denyCurrentBranch warn &&\n \t\tmv .git/hooks .git/hooks-disabled\n@@ -29,16 +30,19 @@ mk_empty () {\n }\n \n mk_test () {\n-\tmk_empty &&\n+\trepo_name=\"$1\"\n+\tshift\n+\n+\tmk_empty \"$repo_name\" &&\n \t(\n \t\tfor ref in \"$@\"\n \t\tdo\n-\t\t\tgit push testrepo $the_first_commit:refs/$ref || {\n+\t\t\tgit push \"$repo_name\" $the_first_commit:refs/$ref || {\n \t\t\t\techo \"Oops, push refs/$ref failure\"\n \t\t\t\texit 1\n \t\t\t}\n \t\tdone &&\n-\t\tcd testrepo &&\n+\t\tcd \"$repo_name\" &&\n \t\tfor ref in \"$@\"\n \t\tdo\n \t\t\tr=$(git show-ref -s --verify refs/$ref) &&\n@@ -52,9 +56,10 @@ mk_test () {\n }\n \n mk_test_with_hooks() {\n+\trepo_name=$1\n \tmk_test \"$@\" &&\n \t(\n-\t\tcd testrepo &&\n+\t\tcd \"$repo_name\" &&\n \t\tmkdir .git/hooks &&\n \t\tcd .git/hooks &&\n \n@@ -86,13 +91,16 @@ mk_test_with_hooks() {\n }\n \n mk_child() {\n-\trm -rf \"$1\" &&\n-\tgit clone testrepo \"$1\"\n+\trm -rf \"$2\" &&\n+\tgit clone \"$1\" \"$2\"\n }\n \n check_push_result () {\n+\trepo_name=\"$1\"\n+\tshift\n+\n \t(\n-\t\tcd testrepo &&\n+\t\tcd \"$repo_name\" &&\n \t\tit=\"$1\" &&\n \t\tshift\n \t\tfor ref in \"$@\"\n@@ -124,7 +132,7 @@ test_expect_success setup '\n '\n \n test_expect_success 'fetch without wildcard' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \t(\n \t\tcd testrepo &&\n \t\tgit fetch .. refs/heads/master:refs/remotes/origin/master &&\n@@ -137,7 +145,7 @@ test_expect_success 'fetch without wildcard' '\n '\n \n test_expect_success 'fetch with wildcard' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \t(\n \t\tcd testrepo &&\n \t\tgit config remote.up.url .. &&\n@@ -152,7 +160,7 @@ test_expect_success 'fetch with wildcard' '\n '\n \n test_expect_success 'fetch with insteadOf' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \t(\n \t\tTRASH=$(pwd)/ &&\n \t\tcd testrepo &&\n@@ -169,7 +177,7 @@ test_expect_success 'fetch with insteadOf' '\n '\n \n test_expect_success 'fetch with pushInsteadOf (should not rewrite)' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \t(\n \t\tTRASH=$(pwd)/ &&\n \t\tcd testrepo &&\n@@ -186,7 +194,7 @@ test_expect_success 'fetch with pushInsteadOf (should not rewrite)' '\n '\n \n test_expect_success 'push without wildcard' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \n \tgit push testrepo refs/heads/master:refs/remotes/origin/master &&\n \t(\n@@ -199,7 +207,7 @@ test_expect_success 'push without wildcard' '\n '\n \n test_expect_success 'push with wildcard' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \n \tgit push testrepo \"refs/heads/*:refs/remotes/origin/*\" &&\n \t(\n@@ -212,7 +220,7 @@ test_expect_success 'push with wildcard' '\n '\n \n test_expect_success 'push with insteadOf' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \tTRASH=\"$(pwd)/\" &&\n \tgit config \"url.$TRASH.insteadOf\" trash/ &&\n \tgit push trash/testrepo refs/heads/master:refs/remotes/origin/master &&\n@@ -226,7 +234,7 @@ test_expect_success 'push with insteadOf' '\n '\n \n test_expect_success 'push with pushInsteadOf' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \tTRASH=\"$(pwd)/\" &&\n \tgit config \"url.$TRASH.pushInsteadOf\" trash/ &&\n \tgit push trash/testrepo refs/heads/master:refs/remotes/origin/master &&\n@@ -240,7 +248,7 @@ test_expect_success 'push with pushInsteadOf' '\n '\n \n test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf should not rewrite)' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \tTRASH=\"$(pwd)/\" &&\n \tgit config \"url.trash2/.pushInsteadOf\" trash/ &&\n \tgit config remote.r.url trash/wrong &&\n@@ -257,242 +265,242 @@ test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf\n \n test_expect_success 'push with matching heads' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit push testrepo &&\n-\tcheck_push_result $the_commit heads/master\n+\tcheck_push_result testrepo $the_commit heads/master\n \n '\n \n test_expect_success 'push with matching heads on the command line' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit push testrepo : &&\n-\tcheck_push_result $the_commit heads/master\n+\tcheck_push_result testrepo $the_commit heads/master\n \n '\n \n test_expect_success 'failed (non-fast-forward) push with matching heads' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit push testrepo : &&\n \tgit commit --amend -massaged &&\n \ttest_must_fail git push testrepo &&\n-\tcheck_push_result $the_commit heads/master &&\n+\tcheck_push_result testrepo $the_commit heads/master &&\n \tgit reset --hard $the_commit\n \n '\n \n test_expect_success 'push --force with matching heads' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit push testrepo : &&\n \tgit commit --amend -massaged &&\n \tgit push --force testrepo &&\n-\t! check_push_result $the_commit heads/master &&\n+\t! check_push_result testrepo $the_commit heads/master &&\n \tgit reset --hard $the_commit\n \n '\n \n test_expect_success 'push with matching heads and forced update' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit push testrepo : &&\n \tgit commit --amend -massaged &&\n \tgit push testrepo +: &&\n-\t! check_push_result $the_commit heads/master &&\n+\t! check_push_result testrepo $the_commit heads/master &&\n \tgit reset --hard $the_commit\n \n '\n \n test_expect_success 'push with no ambiguity (1)' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit push testrepo master:master &&\n-\tcheck_push_result $the_commit heads/master\n+\tcheck_push_result testrepo $the_commit heads/master\n \n '\n \n test_expect_success 'push with no ambiguity (2)' '\n \n-\tmk_test remotes/origin/master &&\n+\tmk_test testrepo remotes/origin/master &&\n \tgit push testrepo master:origin/master &&\n-\tcheck_push_result $the_commit remotes/origin/master\n+\tcheck_push_result testrepo $the_commit remotes/origin/master\n \n '\n \n test_expect_success 'push with colon-less refspec, no ambiguity' '\n \n-\tmk_test heads/master heads/t/master &&\n+\tmk_test testrepo heads/master heads/t/master &&\n \tgit branch -f t/master master &&\n \tgit push testrepo master &&\n-\tcheck_push_result $the_commit heads/master &&\n-\tcheck_push_result $the_first_commit heads/t/master\n+\tcheck_push_result testrepo $the_commit heads/master &&\n+\tcheck_push_result testrepo $the_first_commit heads/t/master\n \n '\n \n test_expect_success 'push with weak ambiguity (1)' '\n \n-\tmk_test heads/master remotes/origin/master &&\n+\tmk_test testrepo heads/master remotes/origin/master &&\n \tgit push testrepo master:master &&\n-\tcheck_push_result $the_commit heads/master &&\n-\tcheck_push_result $the_first_commit remotes/origin/master\n+\tcheck_push_result testrepo $the_commit heads/master &&\n+\tcheck_push_result testrepo $the_first_commit remotes/origin/master\n \n '\n \n test_expect_success 'push with weak ambiguity (2)' '\n \n-\tmk_test heads/master remotes/origin/master remotes/another/master &&\n+\tmk_test testrepo heads/master remotes/origin/master remotes/another/master &&\n \tgit push testrepo master:master &&\n-\tcheck_push_result $the_commit heads/master &&\n-\tcheck_push_result $the_first_commit remotes/origin/master remotes/another/master\n+\tcheck_push_result testrepo $the_commit heads/master &&\n+\tcheck_push_result testrepo $the_first_commit remotes/origin/master remotes/another/master\n \n '\n \n test_expect_success 'push with ambiguity' '\n \n-\tmk_test heads/frotz tags/frotz &&\n+\tmk_test testrepo heads/frotz tags/frotz &&\n \tif git push testrepo master:frotz\n \tthen\n \t\techo \"Oops, should have failed\"\n \t\tfalse\n \telse\n-\t\tcheck_push_result $the_first_commit heads/frotz tags/frotz\n+\t\tcheck_push_result testrepo $the_first_commit heads/frotz tags/frotz\n \tfi\n \n '\n \n test_expect_success 'push with colon-less refspec (1)' '\n \n-\tmk_test heads/frotz tags/frotz &&\n+\tmk_test testrepo heads/frotz tags/frotz &&\n \tgit branch -f frotz master &&\n \tgit push testrepo frotz &&\n-\tcheck_push_result $the_commit heads/frotz &&\n-\tcheck_push_result $the_first_commit tags/frotz\n+\tcheck_push_result testrepo $the_commit heads/frotz &&\n+\tcheck_push_result testrepo $the_first_commit tags/frotz\n \n '\n \n test_expect_success 'push with colon-less refspec (2)' '\n \n-\tmk_test heads/frotz tags/frotz &&\n+\tmk_test testrepo heads/frotz tags/frotz &&\n \tif git show-ref --verify -q refs/heads/frotz\n \tthen\n \t\tgit branch -D frotz\n \tfi &&\n \tgit tag -f frotz &&\n \tgit push -f testrepo frotz &&\n-\tcheck_push_result $the_commit tags/frotz &&\n-\tcheck_push_result $the_first_commit heads/frotz\n+\tcheck_push_result testrepo $the_commit tags/frotz &&\n+\tcheck_push_result testrepo $the_first_commit heads/frotz\n \n '\n \n test_expect_success 'push with colon-less refspec (3)' '\n \n-\tmk_test &&\n+\tmk_test testrepo &&\n \tif git show-ref --verify -q refs/tags/frotz\n \tthen\n \t\tgit tag -d frotz\n \tfi &&\n \tgit branch -f frotz master &&\n \tgit push testrepo frotz &&\n-\tcheck_push_result $the_commit heads/frotz &&\n+\tcheck_push_result testrepo $the_commit heads/frotz &&\n \ttest 1 = $( cd testrepo && git show-ref | wc -l )\n '\n \n test_expect_success 'push with colon-less refspec (4)' '\n \n-\tmk_test &&\n+\tmk_test testrepo &&\n \tif git show-ref --verify -q refs/heads/frotz\n \tthen\n \t\tgit branch -D frotz\n \tfi &&\n \tgit tag -f frotz &&\n \tgit push testrepo frotz &&\n-\tcheck_push_result $the_commit tags/frotz &&\n+\tcheck_push_result testrepo $the_commit tags/frotz &&\n \ttest 1 = $( cd testrepo && git show-ref | wc -l )\n \n '\n \n test_expect_success 'push head with non-existent, incomplete dest' '\n \n-\tmk_test &&\n+\tmk_test testrepo &&\n \tgit push testrepo master:branch &&\n-\tcheck_push_result $the_commit heads/branch\n+\tcheck_push_result testrepo $the_commit heads/branch\n \n '\n \n test_expect_success 'push tag with non-existent, incomplete dest' '\n \n-\tmk_test &&\n+\tmk_test testrepo &&\n \tgit tag -f v1.0 &&\n \tgit push testrepo v1.0:tag &&\n-\tcheck_push_result $the_commit tags/tag\n+\tcheck_push_result testrepo $the_commit tags/tag\n \n '\n \n test_expect_success 'push sha1 with non-existent, incomplete dest' '\n \n-\tmk_test &&\n+\tmk_test testrepo &&\n \ttest_must_fail git push testrepo `git rev-parse master`:foo\n \n '\n \n test_expect_success 'push ref expression with non-existent, incomplete dest' '\n \n-\tmk_test &&\n+\tmk_test testrepo &&\n \ttest_must_fail git push testrepo master^:branch\n \n '\n \n test_expect_success 'push with HEAD' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit checkout master &&\n \tgit push testrepo HEAD &&\n-\tcheck_push_result $the_commit heads/master\n+\tcheck_push_result testrepo $the_commit heads/master\n \n '\n \n test_expect_success 'push with HEAD nonexisting at remote' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit checkout -b local master &&\n \tgit push testrepo HEAD &&\n-\tcheck_push_result $the_commit heads/local\n+\tcheck_push_result testrepo $the_commit heads/local\n '\n \n test_expect_success 'push with +HEAD' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit checkout master &&\n \tgit branch -D local &&\n \tgit checkout -b local &&\n \tgit push testrepo master local &&\n-\tcheck_push_result $the_commit heads/master &&\n-\tcheck_push_result $the_commit heads/local &&\n+\tcheck_push_result testrepo $the_commit heads/master &&\n+\tcheck_push_result testrepo $the_commit heads/local &&\n \n \t# Without force rewinding should fail\n \tgit reset --hard HEAD^ &&\n \ttest_must_fail git push testrepo HEAD &&\n-\tcheck_push_result $the_commit heads/local &&\n+\tcheck_push_result testrepo $the_commit heads/local &&\n \n \t# With force rewinding should succeed\n \tgit push testrepo +HEAD &&\n-\tcheck_push_result $the_first_commit heads/local\n+\tcheck_push_result testrepo $the_first_commit heads/local\n \n '\n \n test_expect_success 'push HEAD with non-existent, incomplete dest' '\n \n-\tmk_test &&\n+\tmk_test testrepo &&\n \tgit checkout master &&\n \tgit push testrepo HEAD:branch &&\n-\tcheck_push_result $the_commit heads/branch\n+\tcheck_push_result testrepo $the_commit heads/branch\n \n '\n \n test_expect_success 'push with config remote.*.push = HEAD' '\n \n-\tmk_test heads/local &&\n+\tmk_test testrepo heads/local &&\n \tgit checkout master &&\n \tgit branch -f local $the_commit &&\n \t(\n@@ -504,8 +512,8 @@ test_expect_success 'push with config remote.*.push = HEAD' '\n \tgit config remote.there.push HEAD &&\n \tgit config branch.master.remote there &&\n \tgit push &&\n-\tcheck_push_result $the_commit heads/master &&\n-\tcheck_push_result $the_first_commit heads/local\n+\tcheck_push_result testrepo $the_commit heads/master &&\n+\tcheck_push_result testrepo $the_first_commit heads/local\n '\n \n # clean up the cruft left with the previous one\n@@ -514,12 +522,12 @@ git config --remove-section branch.master\n \n test_expect_success 'push with config remote.*.pushurl' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit checkout master &&\n \tgit config remote.there.url test2repo &&\n \tgit config remote.there.pushurl testrepo &&\n \tgit push there &&\n-\tcheck_push_result $the_commit heads/master\n+\tcheck_push_result testrepo $the_commit heads/master\n '\n \n # clean up the cruft left with the previous one\n@@ -527,19 +535,19 @@ git config --remove-section remote.there\n \n test_expect_success 'push with dry-run' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \t(\n \t\tcd testrepo &&\n \t\told_commit=$(git show-ref -s --verify refs/heads/master)\n \t) &&\n \tgit push --dry-run testrepo &&\n-\tcheck_push_result $old_commit heads/master\n+\tcheck_push_result testrepo $old_commit heads/master\n '\n \n test_expect_success 'push updates local refs' '\n \n-\tmk_test heads/master &&\n-\tmk_child child &&\n+\tmk_test testrepo heads/master &&\n+\tmk_child testrepo child &&\n \t(\n \t\tcd child &&\n \t\tgit pull .. master &&\n@@ -552,9 +560,9 @@ test_expect_success 'push updates local refs' '\n \n test_expect_success 'push updates up-to-date local refs' '\n \n-\tmk_test heads/master &&\n-\tmk_child child1 &&\n-\tmk_child child2 &&\n+\tmk_test testrepo heads/master &&\n+\tmk_child testrepo child1 &&\n+\tmk_child testrepo child2 &&\n \t(cd child1 && git pull .. master && git push) &&\n \t(\n \t\tcd child2 &&\n@@ -568,8 +576,8 @@ test_expect_success 'push updates up-to-date local refs' '\n \n test_expect_success 'push preserves up-to-date packed refs' '\n \n-\tmk_test heads/master &&\n-\tmk_child child &&\n+\tmk_test testrepo heads/master &&\n+\tmk_child testrepo child &&\n \t(\n \t\tcd child &&\n \t\tgit push &&\n@@ -580,8 +588,8 @@ test_expect_success 'push preserves up-to-date packed refs' '\n \n test_expect_success 'push does not update local refs on failure' '\n \n-\tmk_test heads/master &&\n-\tmk_child child &&\n+\tmk_test testrepo heads/master &&\n+\tmk_child testrepo child &&\n \tmkdir testrepo/.git/hooks &&\n \techo \"#!/no/frobnication/today\" >testrepo/.git/hooks/pre-receive &&\n \tchmod +x testrepo/.git/hooks/pre-receive &&\n@@ -597,7 +605,7 @@ test_expect_success 'push does not update local refs on failure' '\n \n test_expect_success 'allow deleting an invalid remote ref' '\n \n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \trm -f testrepo/.git/objects/??/* &&\n \tgit push testrepo :refs/heads/master &&\n \t(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)\n@@ -605,7 +613,7 @@ test_expect_success 'allow deleting an invalid remote ref' '\n '\n \n test_expect_success 'pushing valid refs triggers post-receive and post-update hooks' '\n-\tmk_test_with_hooks heads/master heads/next &&\n+\tmk_test_with_hooks testrepo heads/master heads/next &&\n \torgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&\n \tnewmaster=$(git show-ref -s --verify refs/heads/master) &&\n \torgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&\n@@ -641,7 +649,7 @@ test_expect_success 'pushing valid refs triggers post-receive and post-update ho\n '\n \n test_expect_success 'deleting dangling ref triggers hooks with correct args' '\n-\tmk_test_with_hooks heads/master &&\n+\tmk_test_with_hooks testrepo heads/master &&\n \trm -f testrepo/.git/objects/??/* &&\n \tgit push testrepo :refs/heads/master &&\n \t(\n@@ -670,7 +678,7 @@ test_expect_success 'deleting dangling ref triggers hooks with correct args' '\n '\n \n test_expect_success 'deletion of a non-existent ref is not fed to post-receive and post-update hooks' '\n-\tmk_test_with_hooks heads/master &&\n+\tmk_test_with_hooks testrepo heads/master &&\n \torgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&\n \tnewmaster=$(git show-ref -s --verify refs/heads/master) &&\n \tgit push testrepo master :refs/heads/nonexistent &&\n@@ -702,7 +710,7 @@ test_expect_success 'deletion of a non-existent ref is not fed to post-receive a\n '\n \n test_expect_success 'deletion of a non-existent ref alone does trigger post-receive and post-update hooks' '\n-\tmk_test_with_hooks heads/master &&\n+\tmk_test_with_hooks testrepo heads/master &&\n \tgit push testrepo :refs/heads/nonexistent &&\n \t(\n \t\tcd testrepo/.git &&\n@@ -722,7 +730,7 @@ test_expect_success 'deletion of a non-existent ref alone does trigger post-rece\n '\n \n test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks with correct input' '\n-\tmk_test_with_hooks heads/master heads/next heads/pu &&\n+\tmk_test_with_hooks testrepo heads/master heads/next heads/pu &&\n \torgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&\n \tnewmaster=$(git show-ref -s --verify refs/heads/master) &&\n \torgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&\n@@ -768,14 +776,14 @@ test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks w\n '\n \n test_expect_success 'allow deleting a ref using --delete' '\n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \t(cd testrepo && git config receive.denyDeleteCurrent warn) &&\n \tgit push testrepo --delete master &&\n \t(cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)\n '\n \n test_expect_success 'allow deleting a tag using --delete' '\n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \tgit tag -a -m dummy_message deltag heads/master &&\n \tgit push testrepo --tags &&\n \t(cd testrepo && git rev-parse --verify -q refs/tags/deltag) &&\n@@ -784,17 +792,17 @@ test_expect_success 'allow deleting a tag using --delete' '\n '\n \n test_expect_success 'push --delete without args aborts' '\n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \ttest_must_fail git push testrepo --delete\n '\n \n test_expect_success 'push --delete refuses src:dest refspecs' '\n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \ttest_must_fail git push testrepo --delete master:foo\n '\n \n test_expect_success 'warn on push to HEAD of non-bare repository' '\n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \t(\n \t\tcd testrepo &&\n \t\tgit checkout master &&\n@@ -805,7 +813,7 @@ test_expect_success 'warn on push to HEAD of non-bare repository' '\n '\n \n test_expect_success 'deny push to HEAD of non-bare repository' '\n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \t(\n \t\tcd testrepo &&\n \t\tgit checkout master &&\n@@ -815,7 +823,7 @@ test_expect_success 'deny push to HEAD of non-bare repository' '\n '\n \n test_expect_success 'allow push to HEAD of bare repository (bare)' '\n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \t(\n \t\tcd testrepo &&\n \t\tgit checkout master &&\n@@ -827,7 +835,7 @@ test_expect_success 'allow push to HEAD of bare repository (bare)' '\n '\n \n test_expect_success 'allow push to HEAD of non-bare repository (config)' '\n-\tmk_test heads/master &&\n+\tmk_test testrepo heads/master &&\n \t(\n \t\tcd testrepo &&\n \t\tgit checkout master &&\n@@ -838,7 +846,7 @@ test_expect_success 'allow push to HEAD of non-bare repository (config)' '\n '\n \n test_expect_success 'fetch with branches' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \tgit branch second $the_first_commit &&\n \tgit checkout second &&\n \techo \"..\" > testrepo/.git/branches/branch1 &&\n@@ -853,7 +861,7 @@ test_expect_success 'fetch with branches' '\n '\n \n test_expect_success 'fetch with branches containing #' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \techo \"..#second\" > testrepo/.git/branches/branch2 &&\n \t(\n \t\tcd testrepo &&\n@@ -866,7 +874,7 @@ test_expect_success 'fetch with branches containing #' '\n '\n \n test_expect_success 'push with branches' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \tgit checkout second &&\n \techo \"testrepo\" > .git/branches/branch1 &&\n \tgit push branch1 &&\n@@ -879,7 +887,7 @@ test_expect_success 'push with branches' '\n '\n \n test_expect_success 'push with branches containing #' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \techo \"testrepo#branch3\" > .git/branches/branch2 &&\n \tgit push branch2 &&\n \t(\n@@ -892,9 +900,9 @@ test_expect_success 'push with branches containing #' '\n '\n \n test_expect_success 'push into aliased refs (consistent)' '\n-\tmk_test heads/master &&\n-\tmk_child child1 &&\n-\tmk_child child2 &&\n+\tmk_test testrepo heads/master &&\n+\tmk_child testrepo child1 &&\n+\tmk_child testrepo child2 &&\n \t(\n \t\tcd child1 &&\n \t\tgit branch foo &&\n@@ -914,9 +922,9 @@ test_expect_success 'push into aliased refs (consistent)' '\n '\n \n test_expect_success 'push into aliased refs (inconsistent)' '\n-\tmk_test heads/master &&\n-\tmk_child child1 &&\n-\tmk_child child2 &&\n+\tmk_test testrepo heads/master &&\n+\tmk_child testrepo child1 &&\n+\tmk_child testrepo child2 &&\n \t(\n \t\tcd child1 &&\n \t\tgit branch foo &&\n@@ -941,9 +949,9 @@ test_expect_success 'push into aliased refs (inconsistent)' '\n '\n \n test_expect_success 'push requires --force to update lightweight tag' '\n-\tmk_test heads/master &&\n-\tmk_child child1 &&\n-\tmk_child child2 &&\n+\tmk_test testrepo heads/master &&\n+\tmk_child testrepo child1 &&\n+\tmk_child testrepo child2 &&\n \t(\n \t\tcd child1 &&\n \t\tgit tag Tag &&\n@@ -962,7 +970,7 @@ test_expect_success 'push requires --force to update lightweight tag' '\n '\n \n test_expect_success 'push --porcelain' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \techo >.git/foo  \"To testrepo\" &&\n \techo >>.git/foo \"*\trefs/heads/master:refs/remotes/origin/master\t[new branch]\"  &&\n \techo >>.git/foo \"Done\" &&\n@@ -977,13 +985,13 @@ test_expect_success 'push --porcelain' '\n '\n \n test_expect_success 'push --porcelain bad url' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \ttest_must_fail git push >.git/bar --porcelain asdfasdfasd refs/heads/master:refs/remotes/origin/master &&\n \ttest_must_fail grep -q Done .git/bar\n '\n \n test_expect_success 'push --porcelain rejected' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \tgit push testrepo refs/heads/master:refs/remotes/origin/master &&\n \t(cd testrepo &&\n \t\tgit reset --hard origin/master^\n@@ -997,7 +1005,7 @@ test_expect_success 'push --porcelain rejected' '\n '\n \n test_expect_success 'push --porcelain --dry-run rejected' '\n-\tmk_empty &&\n+\tmk_empty testrepo &&\n \tgit push testrepo refs/heads/master:refs/remotes/origin/master &&\n \t(cd testrepo &&\n \t\tgit reset --hard origin/master\n@@ -1012,25 +1020,25 @@ test_expect_success 'push --porcelain --dry-run rejected' '\n '\n \n test_expect_success 'push --prune' '\n-\tmk_test heads/master heads/second heads/foo heads/bar &&\n+\tmk_test testrepo heads/master heads/second heads/foo heads/bar &&\n \tgit push --prune testrepo &&\n-\tcheck_push_result $the_commit heads/master &&\n-\tcheck_push_result $the_first_commit heads/second &&\n-\t! check_push_result $the_first_commit heads/foo heads/bar\n+\tcheck_push_result testrepo $the_commit heads/master &&\n+\tcheck_push_result testrepo $the_first_commit heads/second &&\n+\t! check_push_result testrepo $the_first_commit heads/foo heads/bar\n '\n \n test_expect_success 'push --prune refspec' '\n-\tmk_test tmp/master tmp/second tmp/foo tmp/bar &&\n+\tmk_test testrepo tmp/master tmp/second tmp/foo tmp/bar &&\n \tgit push --prune testrepo \"refs/heads/*:refs/tmp/*\" &&\n-\tcheck_push_result $the_commit tmp/master &&\n-\tcheck_push_result $the_first_commit tmp/second &&\n-\t! check_push_result $the_first_commit tmp/foo tmp/bar\n+\tcheck_push_result testrepo $the_commit tmp/master &&\n+\tcheck_push_result testrepo $the_first_commit tmp/second &&\n+\t! check_push_result testrepo $the_first_commit tmp/foo tmp/bar\n '\n \n for configsection in transfer receive\n do\n \ttest_expect_success \"push to update a ref hidden by $configsection.hiderefs\" '\n-\t\tmk_test heads/master hidden/one hidden/two hidden/three &&\n+\t\tmk_test testrepo heads/master hidden/one hidden/two hidden/three &&\n \t\t(\n \t\t\tcd testrepo &&\n \t\t\tgit config $configsection.hiderefs refs/hidden\n@@ -1038,32 +1046,32 @@ do\n \n \t\t# push to unhidden ref succeeds normally\n \t\tgit push testrepo master:refs/heads/master &&\n-\t\tcheck_push_result $the_commit heads/master &&\n+\t\tcheck_push_result testrepo $the_commit heads/master &&\n \n \t\t# push to update a hidden ref should fail\n \t\ttest_must_fail git push testrepo master:refs/hidden/one &&\n-\t\tcheck_push_result $the_first_commit hidden/one &&\n+\t\tcheck_push_result testrepo $the_first_commit hidden/one &&\n \n \t\t# push to delete a hidden ref should fail\n \t\ttest_must_fail git push testrepo :refs/hidden/two &&\n-\t\tcheck_push_result $the_first_commit hidden/two &&\n+\t\tcheck_push_result testrepo $the_first_commit hidden/two &&\n \n \t\t# idempotent push to update a hidden ref should fail\n \t\ttest_must_fail git push testrepo $the_first_commit:refs/hidden/three &&\n-\t\tcheck_push_result $the_first_commit hidden/three\n+\t\tcheck_push_result testrepo $the_first_commit hidden/three\n \t'\n done\n \n test_expect_success 'fetch exact SHA1' '\n-\tmk_test heads/master hidden/one &&\n+\tmk_test testrepo heads/master hidden/one &&\n \tgit push testrepo master:refs/hidden/one &&\n \t(\n \t\tcd testrepo &&\n \t\tgit config transfer.hiderefs refs/hidden\n \t) &&\n-\tcheck_push_result $the_commit hidden/one &&\n+\tcheck_push_result testrepo $the_commit hidden/one &&\n \n-\tmk_child child &&\n+\tmk_child testrepo child &&\n \t(\n \t\tcd child &&\n \n-- \n1.8.2.141.g3797f84\n"},{"id":"212512","messageId":"1364477202-5742-5-git-send-email-artagnon@gmail.com","threadId":"33320","inReplyTo":"1364477202-5742-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 4/6] remote.c: introduce a way to have different remotes for fetch/push","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-28T13:26:40Z","receivedAt":"2013-03-28T13:26:40Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Currently, do_push() in push.c calls remote_get(), which gets the\nconfigured remote for fetching and pushing.  Replace this call with a\ncall to pushremote_get() instead, a new function that will return the\nremote configured specifically for pushing.  This function tries to\nwork with the string pushremote_name, before falling back to the\ncodepath of remote_get().  This patch has no visible impact, but\nserves to enable future patches to introduce configuration variables\nto set pushremote_name.  For example, you can now do the following in\nhandle_config():\n\n    if (!strcmp(key, \"remote.pushdefault\"))\n       git_config_string(&pushremote_name, key, value);\n\nThen, pushes will automatically go to the remote specified by\nremote.pushdefault.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n builtin/push.c |  2 +-\n remote.c       | 25 +++++++++++++++++++++----\n remote.h       |  1 +\n 3 files changed, 23 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/push.c b/builtin/push.c\nindex 42b129d..d447a80 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -322,7 +322,7 @@ static int push_with_options(struct transport *transport, int flags)\n static int do_push(const char *repo, int flags)\n {\n \tint i, errs;\n-\tstruct remote *remote = remote_get(repo);\n+\tstruct remote *remote = pushremote_get(repo);\n \tconst char **url;\n \tint url_nr;\n \ndiff --git a/remote.c b/remote.c\nindex 02e6c4c..b733aec 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -49,6 +49,7 @@ static int branches_nr;\n \n static struct branch *current_branch;\n static const char *default_remote_name;\n+static const char *pushremote_name;\n static int explicit_default_remote_name;\n \n static struct rewrites rewrites;\n@@ -670,17 +671,21 @@ static int valid_remote_nick(const char *name)\n \treturn !strchr(name, '/'); /* no slash */\n }\n \n-struct remote *remote_get(const char *name)\n+static struct remote *remote_get_1(const char *name, const char *pushremote_name)\n {\n \tstruct remote *ret;\n \tint name_given = 0;\n \n-\tread_config();\n \tif (name)\n \t\tname_given = 1;\n \telse {\n-\t\tname = default_remote_name;\n-\t\tname_given = explicit_default_remote_name;\n+\t\tif (pushremote_name) {\n+\t\t\tname = pushremote_name;\n+\t\t\tname_given = 1;\n+\t\t} else {\n+\t\t\tname = default_remote_name;\n+\t\t\tname_given = explicit_default_remote_name;\n+\t\t}\n \t}\n \n \tret = make_remote(name, 0);\n@@ -699,6 +704,18 @@ struct remote *remote_get(const char *name)\n \treturn ret;\n }\n \n+struct remote *remote_get(const char *name)\n+{\n+\tread_config();\n+\treturn remote_get_1(name, NULL);\n+}\n+\n+struct remote *pushremote_get(const char *name)\n+{\n+\tread_config();\n+\treturn remote_get_1(name, pushremote_name);\n+}\n+\n int remote_is_configured(const char *name)\n {\n \tint i;\ndiff --git a/remote.h b/remote.h\nindex f7b08f1..5fe5f53 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -51,6 +51,7 @@ struct remote {\n };\n \n struct remote *remote_get(const char *name);\n+struct remote *pushremote_get(const char *name);\n int remote_is_configured(const char *name);\n \n typedef int each_remote_fn(struct remote *remote, void *priv);\n-- \n1.8.2.141.g3797f84\n"},{"id":"212513","messageId":"1364477202-5742-6-git-send-email-artagnon@gmail.com","threadId":"33320","inReplyTo":"1364477202-5742-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 5/6] remote.c: introduce remote.pushdefault","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-28T13:26:41Z","receivedAt":"2013-03-28T13:26:41Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"This new configuration variable defines the default remote to push to,\nand overrides `branch.<name>.remote` for all branches.  It is useful\nin the typical triangular-workflow setup, where the remote you're\nfetching from is different from the remote you're pushing to.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Documentation/config.txt | 13 ++++++++++---\n remote.c                 |  7 +++++++\n t/t5516-fetch-push.sh    | 12 ++++++++++++\n 3 files changed, 29 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex c1f435f..dd78171 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -727,9 +727,12 @@ branch.autosetuprebase::\n \tThis option defaults to never.\n \n branch.<name>.remote::\n-\tWhen in branch <name>, it tells 'git fetch' and 'git push' which\n-\tremote to fetch from/push to.  It defaults to `origin` if no remote is\n-\tconfigured. `origin` is also used if you are not on any branch.\n+\tWhen on branch <name>, it tells 'git fetch' and 'git push'\n+\twhich remote to fetch from/push to.  The remote to push to\n+\tmay be overridden with `remote.pushdefault` (for all branches).\n+\tIf no remote is configured, or if you are not on any branch,\n+\tit defaults to `origin` for fetching and `remote.pushdefault`\n+\tfor pushing.\n \n branch.<name>.merge::\n \tDefines, together with branch.<name>.remote, the upstream branch\n@@ -1898,6 +1901,10 @@ receive.updateserverinfo::\n \tIf set to true, git-receive-pack will run git-update-server-info\n \tafter receiving data from git-push and updating refs.\n \n+remote.pushdefault::\n+\tThe remote to push to by default.  Overrides\n+\t`branch.<name>.remote` for all branches.\n+\n remote.<name>.url::\n \tThe URL of a remote repository.  See linkgit:git-fetch[1] or\n \tlinkgit:git-push[1].\ndiff --git a/remote.c b/remote.c\nindex b733aec..49c4b8b 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -389,9 +389,16 @@ static int handle_config(const char *key, const char *value, void *cb)\n \t\t\tadd_instead_of(rewrite, xstrdup(value));\n \t\t}\n \t}\n+\n \tif (prefixcmp(key,  \"remote.\"))\n \t\treturn 0;\n \tname = key + 7;\n+\n+\t/* Handle remote.* variables */\n+\tif (!strcmp(name, \"pushdefault\"))\n+\t\treturn git_config_string(&pushremote_name, key, value);\n+\n+\t/* Handle remote.<name>.* variables */\n \tif (*name == '/') {\n \t\twarning(\"Config remote shorthand cannot begin with '/': %s\",\n \t\t\tname);\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 94e0189..ac1ec9d 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -520,6 +520,18 @@ test_expect_success 'push with config remote.*.push = HEAD' '\n git config --remove-section remote.there\n git config --remove-section branch.master\n \n+test_expect_success 'push with remote.pushdefault' '\n+\tmk_test up_repo heads/frotz &&\n+\tmk_test down_repo heads/master &&\n+\ttest_config remote.up.url up_repo &&\n+\ttest_config remote.down.url down_repo &&\n+\ttest_config branch.master.remote up &&\n+\ttest_config remote.pushdefault down &&\n+\tgit push &&\n+\ttest_must_fail check_push_result up_repo $the_commit heads/master &&\n+\tcheck_push_result down_repo $the_commit heads/master\n+'\n+\n test_expect_success 'push with config remote.*.pushurl' '\n \n \tmk_test testrepo heads/master &&\n-- \n1.8.2.141.g3797f84\n"},{"id":"212511","messageId":"1364477202-5742-7-git-send-email-artagnon@gmail.com","threadId":"33320","inReplyTo":"1364477202-5742-1-git-send-email-artagnon@gmail.com","subject":"[PATCH 6/6] remote.c: introduce branch.<name>.pushremote","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-28T13:26:42Z","receivedAt":"2013-03-28T13:26:42Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"This new configuration variable overrides `remote.pushdefault` and\n`branch.<name>.remote` for pushes.  When you pull from one\nplace (e.g. your upstream) and push to another place (e.g. your own\npublishing repository), you would want to set `remote.pushdefault` to\nspecify the remote to push to for all branches, and use this option to\noverride it for a specific branch.\n\nSigned-off-by: Ramkumar Ramachandra <artagnon@gmail.com>\n---\n Documentation/config.txt | 19 +++++++++++++++----\n remote.c                 |  4 ++++\n t/t5516-fetch-push.sh    | 15 +++++++++++++++\n 3 files changed, 34 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex dd78171..ec579c5 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -730,9 +730,19 @@ branch.<name>.remote::\n \tWhen on branch <name>, it tells 'git fetch' and 'git push'\n \twhich remote to fetch from/push to.  The remote to push to\n \tmay be overridden with `remote.pushdefault` (for all branches).\n-\tIf no remote is configured, or if you are not on any branch,\n-\tit defaults to `origin` for fetching and `remote.pushdefault`\n-\tfor pushing.\n+\tThe remote to push to, for the current branch, may be further\n+\toverridden by `branch.<name>.pushremote`.  If no remote is\n+\tconfigured, or if you are not on any branch, it defaults to\n+\t`origin` for fetching and `remote.pushdefault` for pushing.\n+\n+branch.<name>.pushremote::\n+\tWhen on branch <name>, it overrides `branch.<name>.remote` for\n+\tpushing.  It also overrides `remote.pushdefault` for pushing\n+\tfrom branch <name>.  When you pull from one place (e.g. your\n+\tupstream) and push to another place (e.g. your own publishing\n+\trepository), you would want to set `remote.pushdefault` to\n+\tspecify the remote to push to for all branches, and use this\n+\toption to override it for a specific branch.\n \n branch.<name>.merge::\n \tDefines, together with branch.<name>.remote, the upstream branch\n@@ -1903,7 +1913,8 @@ receive.updateserverinfo::\n \n remote.pushdefault::\n \tThe remote to push to by default.  Overrides\n-\t`branch.<name>.remote` for all branches.\n+\t`branch.<name>.remote` for all branches, and is overridden by\n+\t`branch.<name>.pushremote` for specific branches.\n \n remote.<name>.url::\n \tThe URL of a remote repository.  See linkgit:git-fetch[1] or\ndiff --git a/remote.c b/remote.c\nindex 49c4b8b..e89b1b7 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -364,6 +364,10 @@ static int handle_config(const char *key, const char *value, void *cb)\n \t\t\t\tdefault_remote_name = branch->remote_name;\n \t\t\t\texplicit_default_remote_name = 1;\n \t\t\t}\n+\t\t} else if (!strcmp(subkey, \".pushremote\")) {\n+\t\t\tif (branch == current_branch)\n+\t\t\t\tif (git_config_string(&pushremote_name, key, value))\n+\t\t\t\t\treturn -1;\n \t\t} else if (!strcmp(subkey, \".merge\")) {\n \t\t\tif (!value)\n \t\t\t\treturn config_error_nonbool(key);\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex ac1ec9d..13028a4 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -542,6 +542,21 @@ test_expect_success 'push with config remote.*.pushurl' '\n \tcheck_push_result testrepo $the_commit heads/master\n '\n \n+test_expect_success 'push with config branch.*.pushremote' '\n+\tmk_test up_repo heads/frotz &&\n+\tmk_test side_repo heads/quux &&\n+\tmk_test down_repo heads/master &&\n+\ttest_config remote.up.url up_repo &&\n+\ttest_config remote.pushdefault side_repo &&\n+\ttest_config remote.down.url down_repo &&\n+\ttest_config branch.master.remote up &&\n+\ttest_config branch.master.pushremote down &&\n+\tgit push &&\n+\ttest_must_fail check_push_result up_repo $the_commit heads/master &&\n+\ttest_must_fail check_push_result side_repo $the_commit heads/master &&\n+\tcheck_push_result down_repo $the_commit heads/master\n+'\n+\n # clean up the cruft left with the previous one\n git config --remove-section remote.there\n \n-- \n1.8.2.141.g3797f84\n"},{"id":"212525","messageId":"7vppyjworw.fsf@alter.siamese.dyndns.org","threadId":"33320","inReplyTo":"1364477202-5742-1-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-28T15:02:43Z","receivedAt":"2013-03-28T15:02:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> The changes in this round are:\n>\n> 1. Peff submitted a patch to squash into [3/6].  Since his patch\n>    essentially reverts mine, I've blamed him for the change.\n>\n> 2. Peff suggested a code movement in [5/6] to make things flow more\n>    naturally.\n>\n> 3. Jonathan suggested a better test description in [2/6].\n>\n> 4. Junio suggested a minor documentation update in [6/6].\n>\n> My build of git has had this feature for two weeks now (since the\n> first iteration), and I'm very happy with it.\n\nWill take a look; thanks for a reroll.\n\nWe may need a bit of adjustment to the longer term plan for the\npush.default topic, as I expect we will have this feature a lot\nsooner (e.g. perhaps in 1.8.4) than we will switch the push default\nto \"simple\".  The description of simple and upstream still is\nwritten around the \"you push to and pull from the same place\", and\nmay need to be updated to explain \"what happens if you are employing\na triangular workflow?\"  Or it could turn out that triangular people may be better\nserved by a push.default different from simple or upstream.\n\nOr it may turn out that we do not need any change to what is queued\non the push-2.0-default-to-simple topic (I haven't thought things\nthrough).\n\nIt is not urgent, but please start thinking about how you can help,\nnow you introduced the triangular stuff.\n\nThanks.\n\n> Jeff King (1):\n>   t5516 (fetch-push): drop implicit arguments from helper functions\n>\n> Ramkumar Ramachandra (5):\n>   remote.c: simplify a bit of code using git_config_string()\n>   t5516 (fetch-push): update test description\n>   remote.c: introduce a way to have different remotes for fetch/push\n>   remote.c: introduce remote.pushdefault\n>   remote.c: introduce branch.<name>.pushremote\n>\n>  Documentation/config.txt |  24 +++-\n>  builtin/push.c           |   2 +-\n>  remote.c                 |  41 ++++--\n>  remote.h                 |   1 +\n>  t/t5516-fetch-push.sh    | 316 +++++++++++++++++++++++++++--------------------\n>  5 files changed, 238 insertions(+), 146 deletions(-)\n"},{"id":"212530","messageId":"20130328153547.GA3337@sigill.intra.peff.net","threadId":"33320","inReplyTo":"1364477202-5742-1-git-send-email-artagnon@gmail.com","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2013-03-28T15:35:47Z","receivedAt":"2013-03-28T15:35:47Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Mar 28, 2013 at 06:56:36PM +0530, Ramkumar Ramachandra wrote:\n\n> Jeff King (1):\n>   t5516 (fetch-push): drop implicit arguments from helper functions\n> \n> Ramkumar Ramachandra (5):\n>   remote.c: simplify a bit of code using git_config_string()\n>   t5516 (fetch-push): update test description\n>   remote.c: introduce a way to have different remotes for fetch/push\n>   remote.c: introduce remote.pushdefault\n>   remote.c: introduce branch.<name>.pushremote\n\nThanks, this iteration looks pretty good. I have one minor nit, which is\nthat the tests in patches 5 and 6 do things like:\n\n> +\tgit push &&\n> +\ttest_must_fail check_push_result up_repo $the_commit heads/master &&\n> +\tcheck_push_result down_repo $the_commit heads/master\n\nUsing test_must_fail here caught my eye, because usually it is meant to\ncheck failure of a single git command. When it (or \"!\", for that matter)\nis used with a compound function, you end up losing robustness in corner\ncases.\n\nFor example, imagine your function is:\n\n  check_foo() {\n          cd \"$1\" &&\n          git foo\n  }\n\nand you expect in some cases that \"git foo\" will succeed and in some\ncases it will fail. In the affirmative case (running \"check_foo\"), this\nis robust; if any of the steps fails, the test fails.\n\nBut if you run the negative case (\"test_must_fail check_foo\"), you will\nalso fail if any of the preparatory steps fail. I.e., you wanted to say:\n\n  cd \"$1\" && test_must_fail git foo\n\nbut you actually said (applying De Morgan's laws):\n\n  test_must_fail cd \"$1\" || test_must_fail git foo\n\nNow we probably don't expect the \"cd\" to fail here, but of course the\nother steps can be more complicated, too. In your case, I think the\neffect you are looking for is that \"heads/master != $the_commit\". But\nnote that we would also fail if \"git fsck\" fails in the pushed\nrepository, which is not what we want.\n\nSometimes it's annoyingly verbose to break down a compound function. But\nI think in this case, you can make your tests more robust by just\nchecking the affirmative that the ref is still where we expect it to be,\nlike:\n\n  check_push_result up_repo $the_first_commit heads/master\n\nSorry if that was a bit long-winded. I think that practically speaking,\nit is not a likely source of problems in this case. But it's an\nanti-pattern in our tests that I think is worth mentioning.\n\n-Peff\n"},{"id":"212556","messageId":"7vhajvv51f.fsf@alter.siamese.dyndns.org","threadId":"33320","inReplyTo":"20130328153547.GA3337@sigill.intra.peff.net","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-03-28T16:54:20Z","receivedAt":"2013-03-28T16:54:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Sometimes it's annoyingly verbose to break down a compound function. But\n> I think in this case, you can make your tests more robust by just\n> checking the affirmative that the ref is still where we expect it to be,\n> like:\n>\n>   check_push_result up_repo $the_first_commit heads/master\n>\n> Sorry if that was a bit long-winded. I think that practically speaking,\n> it is not a likely source of problems in this case. But it's an\n> anti-pattern in our tests that I think is worth mentioning.\n\nThanks.  That is one of the reasons why we do not want to see too\nmany custom test helper functions.\n"},{"id":"212753","messageId":"CALkWK0=a0wmUe-rjK8Gg8izc0FdXYzChSrgp+W-JNsECsDf+yA@mail.gmail.com","threadId":"33320","inReplyTo":"20130328153547.GA3337@sigill.intra.peff.net","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-31T20:51:22Z","receivedAt":"2013-03-31T20:51:22Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Jeff King wrote:\n> [...]\n\nSo, you're saying: don't test compound statements for failure, since\nanything in the chain could fail and propagate failure.  I should only\ntest simple git-foo commands for failure?\n\n> Sometimes it's annoyingly verbose to break down a compound function. But\n> I think in this case, you can make your tests more robust by just\n> checking the affirmative that the ref is still where we expect it to be,\n> like:\n>\n>   check_push_result up_repo $the_first_commit heads/master\n\nDoesn't that change the meaning of the test though?  I really like how\nthe original tests read.\n"},{"id":"212754","messageId":"CALkWK0=+7ctiiYJSs3SQvV8aywT4tvwGLZ02KLozP8zjU-LQ2g@mail.gmail.com","threadId":"33320","inReplyTo":"7vhajvv51f.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Ramkumar Ramachandra","fromEmail":"artagnon@gmail.com","sentAt":"2013-03-31T20:54:16Z","receivedAt":"2013-03-31T20:54:16Z","isPatch":true,"sender":{"key":"r@artagnon.com","avatar":"https://avatars.githubusercontent.com/u/37226?v=4"},"body":"Junio C Hamano wrote:\n> Jeff King <peff@peff.net> writes:\n>> [...]\n> Thanks.  That is one of the reasons why we do not want to see too\n> many custom test helper functions.\n\nI noticed that you queued my original series without modification in\nrr/triangle.  Should I submit a re-roll with Peff's suggestion\nincorporated?\n"},{"id":"212756","messageId":"20130331214318.GA24646@sigill.intra.peff.net","threadId":"33320","inReplyTo":"CALkWK0=a0wmUe-rjK8Gg8izc0FdXYzChSrgp+W-JNsECsDf+yA@mail.gmail.com","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2013-03-31T21:43:18Z","receivedAt":"2013-03-31T21:43:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Apr 01, 2013 at 02:21:22AM +0530, Ramkumar Ramachandra wrote:\n\n> Jeff King wrote:\n> > [...]\n> \n> So, you're saying: don't test compound statements for failure, since\n> anything in the chain could fail and propagate failure.  I should only\n> test simple git-foo commands for failure?\n\nRight.\n\n> > Sometimes it's annoyingly verbose to break down a compound function. But\n> > I think in this case, you can make your tests more robust by just\n> > checking the affirmative that the ref is still where we expect it to be,\n> > like:\n> >\n> >   check_push_result up_repo $the_first_commit heads/master\n> \n> Doesn't that change the meaning of the test though?  I really like how\n> the original tests read.\n\nDoes it? I thought the original was:\n\n  test_must_fail check_push_result up_repo $the_commit heads/master\n\nwhich is checking that we did _not_ push $the_commit to up_repo.\nChecking that without a negative means confirming that what _used_ to be\nthere is still there, which is $the_first_commit.\n\nBut I didn't actually run it, so I might be wrong about what is supposed\nto be there after the (lack of) push.\n\n-Peff\n"},{"id":"212767","messageId":"7vli93nhnw.fsf@alter.siamese.dyndns.org","threadId":"33320","inReplyTo":"20130331214318.GA24646@sigill.intra.peff.net","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-01T01:50:11Z","receivedAt":"2013-04-01T01:50:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Mon, Apr 01, 2013 at 02:21:22AM +0530, Ramkumar Ramachandra wrote:\n>\n>> Jeff King wrote:\n>> > [...]\n>> \n>> So, you're saying: don't test compound statements for failure, since\n>> anything in the chain could fail and propagate failure.  I should only\n>> test simple git-foo commands for failure?\n>\n> Right.\n\nI think another thing to keep in mind is that \"test_must_fail\" is\nused only to check for an expected failure from git-foo commands,\nnot for a random command (or sequence of commands).\n\nThe primary point of test_must_fail is not to declare _any_ failure\nas \"Oh, good, I wanted see it to fail and it returned non-zero exit\nstatus so I am happy\", but exclude uncontrolled failures, by saying\n\"Yuck, it returned non-zero exit status, but it died by signal\n(e.g. SEGV), which is not the way I wanted to see it die\".\n"},{"id":"212768","messageId":"7vhajrnhco.fsf@alter.siamese.dyndns.org","threadId":"33320","inReplyTo":"CALkWK0=+7ctiiYJSs3SQvV8aywT4tvwGLZ02KLozP8zjU-LQ2g@mail.gmail.com","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-01T01:56:55Z","receivedAt":"2013-04-01T01:56:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ramkumar Ramachandra <artagnon@gmail.com> writes:\n\n> Junio C Hamano wrote:\n>> Jeff King <peff@peff.net> writes:\n>>> [...]\n>> Thanks.  That is one of the reasons why we do not want to see too\n>> many custom test helper functions.\n>\n> I noticed that you queued my original series without modification in\n> rr/triangle.  Should I submit a re-roll with Peff's suggestion\n> incorporated?\n\nIf you want the topic to make progress, yes.\n\nThe only reason a topic is queued in 'pu' is to let me not pay\nattention to it, without risking to forget about it completely ;-).\n\nThe topics on 'pu' have potential to be a useful change even though\nthey are far from ready for 'next'.  By queuing on 'pu', rather than\njust letting them sit in the mail archive and relying on the author\nto send follow-ups, I can send out \"what happened to this topic?\"\ninquiries from time to time, without paying constant attention to\nthem.\n"},{"id":"212777","messageId":"7v7gkmncpz.fsf@alter.siamese.dyndns.org","threadId":"33320","inReplyTo":"7vhajrnhco.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-01T03:36:56Z","receivedAt":"2013-04-01T03:36:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> The only reason a topic is queued in 'pu' is to let me not pay\n> attention to it, without risking to forget about it completely ;-).\n>\n> The topics on 'pu' have potential to be a useful change even though\n> they are far from ready for 'next'.\n\nThat's not \"even though\" but should have been \"even when\".\nSometimes when I feel a topic is already of 'next' quality, the\nauthor suggests that a reroll is coming, and I hold such a topic\noff.\n\nAlso, inverse is not true, as always.  Some topics may not be queued\nin 'pu' when I push a day's integration results out, but that does\nnot mean they do not have potential to be useful.  They may not be\nin 'pu' because I didn't have enough time to get around to them, or\nbecause there was discussion ongoing and I saw the author was\nactively responding to the comments, relieving me from having to\nkeep an eye on the topic at all until the dust settled without even\nqueueing it on 'pu'.\n"},{"id":"212781","messageId":"7vppyeltz7.fsf@alter.siamese.dyndns.org","threadId":"33320","inReplyTo":"7vhajrnhco.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-01T05:07:08Z","receivedAt":"2013-04-01T05:07:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n>\n>> Junio C Hamano wrote:\n>>> Jeff King <peff@peff.net> writes:\n>>>> [...]\n>>> Thanks.  That is one of the reasons why we do not want to see too\n>>> many custom test helper functions.\n>>\n>> I noticed that you queued my original series without modification in\n>> rr/triangle.  Should I submit a re-roll with Peff's suggestion\n>> incorporated?\n>\n> If you want the topic to make progress, yes.\n\nBy the way, this series seems to break a few tests in the test\nsuite, both as a standalone topic branch and as part of the 'pu'.\n"},{"id":"212784","messageId":"7vhajqlsom.fsf@alter.siamese.dyndns.org","threadId":"33320","inReplyTo":"7vppyeltz7.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v4 0/6] Support triangular workflows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-04-01T05:35:05Z","receivedAt":"2013-04-01T05:35:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Ramkumar Ramachandra <artagnon@gmail.com> writes:\n>>\n>>> Junio C Hamano wrote:\n>>>> Jeff King <peff@peff.net> writes:\n>>>>> [...]\n>>>> Thanks.  That is one of the reasons why we do not want to see too\n>>>> many custom test helper functions.\n>>>\n>>> I noticed that you queued my original series without modification in\n>>> rr/triangle.  Should I submit a re-roll with Peff's suggestion\n>>> incorporated?\n>>\n>> If you want the topic to make progress, yes.\n>\n> By the way, this series seems to break a few tests in the test\n> suite,...\n\nI suspect this could be interaction with push-default change near\nthe tip of 'pu'.  Setting push.default explicitly to matching in the\ntest may be necessary.\n\nAlso the t5516 is involved in in-flight churns, so there could be\nsome merge mixups.\n"}]}