{"thread":{"id":"35123","subject":"[PATCH try2 0/8] Introduce publish tracking branch","startedAt":"2013-10-12T07:05:53Z","lastAt":"2013-10-13T10:15:42Z","messageCount":11,"participants":["Felipe Contreras","Eric Sunshine"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"228811","messageId":"1381561561-20459-1-git-send-email-felipe.contreras@gmail.com","threadId":"35123","inReplyTo":null,"subject":"[PATCH try2 0/8] Introduce publish tracking branch","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-10-12T07:05:53Z","receivedAt":"2013-10-12T07:05:53Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"As it has been discussed before, our support for triangular workflows is\nlacking, and the following patch series aims to improve that situation.\n\nWe have the concept of upstream branch (e.g. 'origin/master') which is to where\nour topic branches eventually should be merged to, so it makes sense that\n'git rebase' uses that as the destination, but most people would not push to\nsuch upstream branch, they would push to a publish branch\n(e.g.  'github/feature-a'). We could set our upstream to the place we push, and\n'git push' would be able to use that as default, and 'git branch --vv' would\nshow how ahead/behind we are in comparisson to that branch, but then 'git\nrebase' (or 'git merge') would be using the wrong branch.\n\nThis patch series adds:\n\n 1) git push --set-publish\n 2) git branch --set-publish\n 3) git branch -vv # uses and shows the publish branch when configured\n\nAfter this, it becomes much easier to track branches in a triangular workflow.\n\n  master          e230c56 [origin/master, gh/master] Git 1.8.4\n* fc/publish      0a105fd [master, gh/fc/publish: ahead 1] branch: display publish branch\n  fc/branch/fast  177dcad [master, gh/fc/branch/fast] branch: reorganize verbose options\n  fc/trivial      f289b9a [master: ahead 7] branch: trivial style fix\n  fc/leaks        d101af4 [master: ahead 2] read-cache: plug a possible leak\n  stable          e230c56 Git 1.8.4\n\nFelipe Contreras (8):\n  branch: trivial cleanup\n  branch: reorganize verbose options\n  push: trivial reorganization\n  Add concept of 'publish' branch\n  branch: allow configuring the publish branch\n  t: branch add publish branch tests\n  push: add --set-publish option\n  branch: display publish branch\n\n Documentation/git-branch.txt |  11 +++++\n Documentation/git-push.txt   |   9 +++-\n branch.c                     |  43 +++++++++++++++++\n branch.h                     |   2 +\n builtin/branch.c             | 107 +++++++++++++++++++++++++++++++++++++------\n builtin/push.c               |  52 +++++++++++++--------\n remote.c                     |  34 +++++++++++---\n remote.h                     |   4 ++\n t/t3200-branch.sh            |  76 ++++++++++++++++++++++++++++++\n t/t5529-push-publish.sh      |  70 ++++++++++++++++++++++++++++\n t/t6040-tracking-info.sh     |   8 ++--\n transport.c                  |  28 +++++++----\n transport.h                  |   1 +\n 13 files changed, 393 insertions(+), 52 deletions(-)\n create mode 100755 t/t5529-push-publish.sh\n\n-- \n1.8.4-fc\n"},{"id":"228817","messageId":"1381561561-20459-2-git-send-email-felipe.contreras@gmail.com","threadId":"35123","inReplyTo":"1381561561-20459-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH try2 7/8] push: add --set-publish option","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-10-12T07:05:54Z","receivedAt":"2013-10-12T07:05:54Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"To setup publish tracking branch, like 'git branch --set-publish'.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n Documentation/git-push.txt |  9 +++++-\n builtin/push.c             |  2 ++\n t/t5529-push-publish.sh    | 70 ++++++++++++++++++++++++++++++++++++++++++++++\n transport.c                | 28 +++++++++++++------\n transport.h                |  1 +\n 5 files changed, 100 insertions(+), 10 deletions(-)\n create mode 100755 t/t5529-push-publish.sh\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex f7dfe48..6f3885d 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -10,7 +10,8 @@ SYNOPSIS\n --------\n [verse]\n 'git push' [--all | --mirror | --tags] [--follow-tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>]\n-\t   [--repo=<repository>] [-f | --force] [--prune] [-v | --verbose] [-u | --set-upstream]\n+\t   [--repo=<repository>] [-f | --force] [--prune] [-v | --verbose]\n+\t   [-u | --set-upstream] [-p | --set-publish]\n \t   [--no-verify] [<repository> [<refspec>...]]\n \n DESCRIPTION\n@@ -171,6 +172,12 @@ useful if you write an alias or script around 'git push'.\n \tlinkgit:git-pull[1] and other commands. For more information,\n \tsee 'branch.<name>.merge' in linkgit:git-config[1].\n \n+-p::\n+--set-publish::\n+\tFor every branch that is up to date or successfully pushed, add\n+\tpublish branch tracking reference, used by argument-less\n+\tlinkgit:git-pull[1] and other commands.\n+\n --[no-]thin::\n \tThese options are passed to linkgit:git-send-pack[1]. A thin transfer\n \tsignificantly reduces the amount of sent data when the sender and\ndiff --git a/builtin/push.c b/builtin/push.c\nindex f2deddf..1c184b3 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -473,6 +473,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)\n \t\tOPT_STRING( 0 , \"exec\", &receivepack, \"receive-pack\", N_(\"receive pack program\")),\n \t\tOPT_BIT('u', \"set-upstream\", &flags, N_(\"set upstream for git pull/status\"),\n \t\t\tTRANSPORT_PUSH_SET_UPSTREAM),\n+\t\tOPT_BIT('p', \"set-publish\", &flags, N_(\"set publish for git pull/status\"),\n+\t\t\tTRANSPORT_PUSH_SET_PUBLISH),\n \t\tOPT_BOOL(0, \"progress\", &progress, N_(\"force progress reporting\")),\n \t\tOPT_BIT(0, \"prune\", &flags, N_(\"prune locally removed refs\"),\n \t\t\tTRANSPORT_PUSH_PRUNE),\ndiff --git a/t/t5529-push-publish.sh b/t/t5529-push-publish.sh\nnew file mode 100755\nindex 0000000..2037026\n--- /dev/null\n+++ b/t/t5529-push-publish.sh\n@@ -0,0 +1,70 @@\n+#!/bin/sh\n+\n+test_description='push with --set-publish'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'setup bare parent' '\n+\tgit init --bare parent &&\n+\tgit remote add publish parent\n+'\n+\n+test_expect_success 'setup local commit' '\n+\techo content >file &&\n+\tgit add file &&\n+\tgit commit -m one\n+'\n+\n+check_config() {\n+\t(echo $2; echo $3) >expect.$1\n+\t(git config branch.$1.pushremote\n+\t git config branch.$1.push) >actual.$1\n+\ttest_cmp expect.$1 actual.$1\n+}\n+\n+test_expect_success 'push -p master:master' '\n+\tgit push -p publish master:master &&\n+\tcheck_config master publish refs/heads/master\n+'\n+\n+test_expect_success 'push -u master:other' '\n+\tgit push -p publish master:other &&\n+\tcheck_config master publish refs/heads/other\n+'\n+\n+test_expect_success 'push -p --dry-run master:otherX' '\n+\tgit push -p --dry-run publish master:otherX &&\n+\tcheck_config master publish refs/heads/other\n+'\n+\n+test_expect_success 'push -p master2:master2' '\n+\tgit branch master2 &&\n+\tgit push -p publish master2:master2 &&\n+\tcheck_config master2 publish refs/heads/master2\n+'\n+\n+test_expect_success 'push -p master2:other2' '\n+\tgit push -p publish master2:other2 &&\n+\tcheck_config master2 publish refs/heads/other2\n+'\n+\n+test_expect_success 'push -p :master2' '\n+\tgit push -p publish :master2 &&\n+\tcheck_config master2 publish refs/heads/other2\n+'\n+\n+test_expect_success 'push -u --all' '\n+\tgit branch all1 &&\n+\tgit branch all2 &&\n+\tgit push -p --all &&\n+\tcheck_config all1 publish refs/heads/all1 &&\n+\tcheck_config all2 publish refs/heads/all2\n+'\n+\n+test_expect_success 'push -p HEAD' '\n+\tgit checkout -b headbranch &&\n+\tgit push -p publish HEAD &&\n+\tcheck_config headbranch publish refs/heads/headbranch\n+'\n+\n+test_done\ndiff --git a/transport.c b/transport.c\nindex e15db98..d796732 100644\n--- a/transport.c\n+++ b/transport.c\n@@ -140,8 +140,8 @@ static void insert_packed_refs(const char *packed_refs, struct ref **list)\n \t}\n }\n \n-static void set_upstreams(struct transport *transport, struct ref *refs,\n-\tint pretend)\n+static void set_tracking(struct transport *transport, struct ref *refs,\n+\tint pretend, int publish)\n {\n \tstruct ref *ref;\n \tfor (ref = refs; ref; ref = ref->next) {\n@@ -176,12 +176,18 @@ static void set_upstreams(struct transport *transport, struct ref *refs,\n \t\tif (!remotename || prefixcmp(remotename, \"refs/heads/\"))\n \t\t\tcontinue;\n \n-\t\tif (!pretend)\n-\t\t\tinstall_branch_config(BRANCH_CONFIG_VERBOSE,\n-\t\t\t\tlocalname + 11, transport->remote->name,\n-\t\t\t\tremotename);\n-\t\telse\n-\t\t\tprintf(\"Would set upstream of '%s' to '%s' of '%s'\\n\",\n+\t\tif (!pretend) {\n+\t\t\tif (publish)\n+\t\t\t\tinstall_branch_publish(localname + 11,\n+\t\t\t\t\t\ttransport->remote->name,\n+\t\t\t\t\t\tremotename);\n+\t\t\telse\n+\t\t\t\tinstall_branch_config(BRANCH_CONFIG_VERBOSE,\n+\t\t\t\t\tlocalname + 11, transport->remote->name,\n+\t\t\t\t\tremotename);\n+\t\t} else\n+\t\t\tprintf(\"Would set %s of '%s' to '%s' of '%s'\\n\",\n+\t\t\t\tpublish ? \"publish\" : \"upstream\",\n \t\t\t\tlocalname + 11, remotename + 11,\n \t\t\t\ttransport->remote->name);\n \t}\n@@ -1113,6 +1119,8 @@ int transport_push(struct transport *transport,\n \t\t/* Maybe FIXME. But no important transport uses this case. */\n \t\tif (flags & TRANSPORT_PUSH_SET_UPSTREAM)\n \t\t\tdie(\"This transport does not support using --set-upstream\");\n+\t\tif (flags & TRANSPORT_PUSH_SET_PUBLISH)\n+\t\t\tdie(\"This transport does not support using --set-publish\");\n \n \t\treturn transport->push(transport, refspec_nr, refspec, flags);\n \t} else if (transport->push_refs) {\n@@ -1181,7 +1189,9 @@ int transport_push(struct transport *transport,\n \t\t\t\t\treject_reasons);\n \n \t\tif (flags & TRANSPORT_PUSH_SET_UPSTREAM)\n-\t\t\tset_upstreams(transport, remote_refs, pretend);\n+\t\t\tset_tracking(transport, remote_refs, pretend, 0);\n+\t\tif (flags & TRANSPORT_PUSH_SET_PUBLISH)\n+\t\t\tset_tracking(transport, remote_refs, pretend, 1);\n \n \t\tif (!(flags & TRANSPORT_PUSH_DRY_RUN)) {\n \t\t\tstruct ref *ref;\ndiff --git a/transport.h b/transport.h\nindex ea70ea7..715e6d5 100644\n--- a/transport.h\n+++ b/transport.h\n@@ -108,6 +108,7 @@ struct transport {\n #define TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND 256\n #define TRANSPORT_PUSH_NO_HOOK 512\n #define TRANSPORT_PUSH_FOLLOW_TAGS 1024\n+#define TRANSPORT_PUSH_SET_PUBLISH 2048\n \n #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)\n #define TRANSPORT_SUMMARY(x) (int)(TRANSPORT_SUMMARY_WIDTH + strlen(x) - gettext_width(x)), (x)\n-- \n1.8.4-fc\n"},{"id":"228818","messageId":"1381561561-20459-3-git-send-email-felipe.contreras@gmail.com","threadId":"35123","inReplyTo":"1381561561-20459-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH try2 6/8] t: branch add publish branch tests","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-10-12T07:05:55Z","receivedAt":"2013-10-12T07:05:55Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n t/t3200-branch.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 file changed, 76 insertions(+)\n\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 44ec6a4..cd0b8e9 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -870,4 +870,80 @@ test_expect_success '--merged catches invalid object names' '\n \ttest_must_fail git branch --merged 0000000000000000000000000000000000000000\n '\n \n+test_expect_success '--set-publish-to fails on multiple branches' '\n+\ttest_must_fail git branch --set-publish-to master a b c\n+'\n+\n+test_expect_success '--set-publish-to fails on detached HEAD' '\n+\ttest_when_finished \"git checkout master\" &&\n+\tgit checkout master^{} &&\n+\ttest_must_fail git branch --set-publish-to master\n+'\n+\n+test_expect_success '--set-publish-to fails on a missing dst branch' '\n+\ttest_must_fail git branch --set-publish-to master does-not-exist\n+'\n+\n+test_expect_success '--set-publish-to fails on a missing src branch' '\n+\ttest_must_fail git branch --set-publish-to does-not-exist master\n+'\n+\n+test_expect_success '--set-publish-to fails on a non-ref' '\n+\ttest_must_fail git branch --set-publish-to HEAD^{}\n+'\n+\n+test_expect_success 'use --set-publish-to modify HEAD' '\n+\tgit checkout master &&\n+\ttest_config branch.master.pushremote foo &&\n+\ttest_config branch.master.push foo &&\n+\tgit branch -f test &&\n+\tgit branch --set-publish-to test &&\n+\ttest \"$(git config branch.master.pushremote)\" = \".\" &&\n+\ttest \"$(git config branch.master.push)\" = \"refs/heads/test\"\n+'\n+\n+test_expect_success 'use --set-publish-to modify a particular branch' '\n+\tgit branch -f test &&\n+\tgit branch -f test2 &&\n+\tgit branch --set-publish-to test2 test &&\n+\ttest \"$(git config branch.test.pushremote)\" = \".\" &&\n+\ttest \"$(git config branch.test.push)\" = \"refs/heads/test2\"\n+'\n+\n+test_expect_success '--unset-publish should fail if given a non-existent branch' '\n+\ttest_must_fail git branch --unset-publish i-dont-exist\n+'\n+\n+test_expect_success 'test --unset-publish on HEAD' '\n+\tgit checkout master &&\n+\tgit branch -f test &&\n+\ttest_config branch.master.pushremote foo &&\n+\ttest_config branch.master.push foo &&\n+\tgit branch --set-publish-to test &&\n+\tgit branch --unset-publish &&\n+\ttest_must_fail git config branch.master.pushremote &&\n+\ttest_must_fail git config branch.master.push &&\n+\t# fail for a branch without publish set\n+\ttest_must_fail git branch --unset-publish\n+'\n+\n+test_expect_success '--unset-publish should fail on multiple branches' '\n+\ttest_must_fail git branch --unset-publish a b c\n+'\n+\n+test_expect_success '--unset-publish should fail on detached HEAD' '\n+\ttest_when_finished \"git checkout -\" &&\n+\tgit checkout HEAD^{} &&\n+\ttest_must_fail git branch --unset-publish\n+'\n+\n+test_expect_success 'test --unset-publish on a particular branch' '\n+\tgit branch -f test &&\n+\tgit branch -f test2 &&\n+\tgit branch --set-publish-to test2 test &&\n+\tgit branch --unset-publish test &&\n+\ttest_must_fail git config branch.test2.pushremote &&\n+\ttest_must_fail git config branch.test2.push\n+'\n+\n test_done\n-- \n1.8.4-fc\n"},{"id":"228819","messageId":"1381561561-20459-4-git-send-email-felipe.contreras@gmail.com","threadId":"35123","inReplyTo":"1381561561-20459-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH try2 4/8] Add concept of 'publish' branch","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-10-12T07:05:56Z","receivedAt":"2013-10-12T07:05:56Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"The upstream branch is:\n\n  branch.$name.remote\n  branch.$name.merge\n\nThe publish branch is:\n\n  branch.$name.pushremote\n  branch.$name.push\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n builtin/push.c | 19 +++++++++++++++----\n remote.c       | 34 ++++++++++++++++++++++++++++------\n remote.h       |  4 ++++\n 3 files changed, 47 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/push.c b/builtin/push.c\nindex 5dc06a3..f2deddf 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -150,6 +150,20 @@ static void setup_push_current(struct remote *remote, struct branch *branch)\n \tadd_refspec(branch->name);\n }\n \n+static void setup_push_simple(struct remote *remote, struct branch *branch,\n+\t\t\t\tint triangular)\n+{\n+\tif (branch->push_name) {\n+\t\tstruct strbuf refspec = STRBUF_INIT;\n+\t\tstrbuf_addf(&refspec, \"%s:%s\", branch->name, branch->push_name);\n+\t\tadd_refspec(refspec.buf);\n+\t} else if (triangular) {\n+\t\tsetup_push_current(remote, branch);\n+\t} else {\n+\t\tsetup_push_upstream(remote, branch, triangular);\n+\t}\n+}\n+\n static char warn_unspecified_push_default_msg[] =\n N_(\"push.default is unset; its implicit value is changing in\\n\"\n    \"Git 2.0 from 'matching' to 'simple'. To squelch this message\\n\"\n@@ -210,10 +224,7 @@ static void setup_default_push_refspecs(struct remote *remote)\n \t\tbreak;\n \n \tcase PUSH_DEFAULT_SIMPLE:\n-\t\tif (triangular)\n-\t\t\tsetup_push_current(remote, get_current_branch(remote));\n-\t\telse\n-\t\t\tsetup_push_upstream(remote, get_current_branch(remote), triangular);\n+\t\tsetup_push_simple(remote, get_current_branch(remote), triangular);\n \t\tbreak;\n \n \tcase PUSH_DEFAULT_UPSTREAM:\ndiff --git a/remote.c b/remote.c\nindex efcba93..04c7ed9 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -350,13 +350,17 @@ static int handle_config(const char *key, const char *value, void *cb)\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 (git_config_string(&branch->pushremote_name, key, value))\n+\t\t\t\treturn -1;\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\t\tpushremote_name = xstrdup(branch->pushremote_name);\n \t\t} else if (!strcmp(subkey, \".merge\")) {\n \t\t\tif (!value)\n \t\t\t\treturn config_error_nonbool(key);\n \t\t\tadd_merge(branch, xstrdup(value));\n+\t\t} else if (!strcmp(subkey, \".push\")) {\n+\t\t\tif (git_config_string(&branch->push_name, key, value))\n+\t\t\t\treturn -1;\n \t\t}\n \t\treturn 0;\n \t}\n@@ -1492,6 +1496,14 @@ struct branch *branch_get(const char *name)\n \t\t\t}\n \t\t}\n \t}\n+\tif (ret && ret->pushremote_name) {\n+\t\tstruct remote *pushremote;\n+\t\tpushremote = pushremote_get(ret->pushremote_name);\n+\t\tret->push.src = xstrdup(ret->push_name);\n+\t\tif (remote_find_tracking(pushremote, &ret->push)\n+\t\t    && !strcmp(ret->pushremote_name, \".\"))\n+\t\t\tret->push.dst = xstrdup(ret->push_name);\n+\t}\n \treturn ret;\n }\n \n@@ -1694,6 +1706,15 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n \treturn found;\n }\n \n+static char *get_base(struct branch *branch)\n+{\n+\tif (branch->push.dst)\n+\t\treturn branch->push.dst;\n+\tif (branch->merge && branch->merge[0] && branch->merge[0]->dst)\n+\t\treturn branch->merge[0]->dst;\n+\treturn NULL;\n+}\n+\n /*\n  * Return true if there is anything to report, otherwise false.\n  */\n@@ -1710,15 +1731,16 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)\n \t * Nothing to report unless we are marked to build on top of\n \t * somebody else.\n \t */\n-\tif (!branch ||\n-\t    !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)\n+\tif (!branch)\n+\t\treturn 0;\n+\tbase = get_base(branch);\n+\tif (!base)\n \t\treturn 0;\n \n \t/*\n \t * If what we used to build on no longer exists, there is\n \t * nothing to report.\n \t */\n-\tbase = branch->merge[0]->dst;\n \tif (read_ref(base, sha1))\n \t\treturn 0;\n \ttheirs = lookup_commit_reference(sha1);\n@@ -1781,7 +1803,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \tif (!stat_tracking_info(branch, &num_ours, &num_theirs))\n \t\treturn 0;\n \n-\tbase = branch->merge[0]->dst;\n+\tbase = get_base(branch);\n \tbase = shorten_unambiguous_ref(base, 0);\n \tif (!num_theirs) {\n \t\tstrbuf_addf(sb,\ndiff --git a/remote.h b/remote.h\nindex cf56724..79e5adf 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -138,6 +138,10 @@ struct branch {\n \tstruct refspec **merge;\n \tint merge_nr;\n \tint merge_alloc;\n+\n+\tconst char *pushremote_name;\n+\tconst char *push_name;\n+\tstruct refspec push;\n };\n \n struct branch *branch_get(const char *name);\n-- \n1.8.4-fc\n"},{"id":"228866","messageId":"1381561561-20459-5-git-send-email-felipe.contreras@gmail.com","threadId":"35123","inReplyTo":"1381561561-20459-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH try2 1/8] branch: trivial cleanup","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-10-12T07:05:57Z","receivedAt":"2013-10-12T07:05:57Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"No functional changes.\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n builtin/branch.c | 19 +++++++++----------\n 1 file changed, 9 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0836890..ac17b18 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -425,16 +425,15 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tstruct strbuf fancy = STRBUF_INIT;\n \n \tif (!stat_tracking_info(branch, &ours, &theirs)) {\n-\t\tif (branch && branch->merge && branch->merge[0]->dst &&\n-\t\t    show_upstream_ref) {\n-\t\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n-\t\t\tif (want_color(branch_use_color))\n-\t\t\t\tstrbuf_addf(stat, \"[%s%s%s] \",\n-\t\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n-\t\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n-\t\t\telse\n-\t\t\t\tstrbuf_addf(stat, \"[%s] \", ref);\n-\t\t}\n+\t\tif (!branch || !branch->merge || !branch->merge[0]->dst || !show_upstream_ref)\n+\t\t\treturn;\n+\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n+\t\tif (want_color(branch_use_color))\n+\t\t\tstrbuf_addf(stat, \"[%s%s%s] \",\n+\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n+\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n+\t\telse\n+\t\t\tstrbuf_addf(stat, \"[%s] \", ref);\n \t\treturn;\n \t}\n \n-- \n1.8.4-fc\n"},{"id":"228816","messageId":"1381561561-20459-6-git-send-email-felipe.contreras@gmail.com","threadId":"35123","inReplyTo":"1381561561-20459-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH try2 2/8] branch: reorganize verbose options","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-10-12T07:05:58Z","receivedAt":"2013-10-12T07:05:58Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Showing the upstream tracking branch is more important than how many\ncommits are ahead/behind, so now 'git branch -v' shows the upstream, but\nnot the tracking info, and 'git branch -vv' shows all information (as\nbefore).\n\nSigned-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n builtin/branch.c         | 22 ++++++++++------------\n t/t6040-tracking-info.sh |  8 ++++----\n 2 files changed, 14 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex ac17b18..baa1d31 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -417,15 +417,15 @@ static int ref_cmp(const void *r1, const void *r2)\n }\n \n static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n-\t\tint show_upstream_ref)\n+\t\tint show_tracking)\n {\n \tint ours, theirs;\n \tchar *ref = NULL;\n \tstruct branch *branch = branch_get(branch_name);\n \tstruct strbuf fancy = STRBUF_INIT;\n \n-\tif (!stat_tracking_info(branch, &ours, &theirs)) {\n-\t\tif (!branch || !branch->merge || !branch->merge[0]->dst || !show_upstream_ref)\n+\tif (!show_tracking || !stat_tracking_info(branch, &ours, &theirs)) {\n+\t\tif (!branch || !branch->merge || !branch->merge[0]->dst)\n \t\t\treturn;\n \t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n \t\tif (want_color(branch_use_color))\n@@ -437,15 +437,13 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\treturn;\n \t}\n \n-\tif (show_upstream_ref) {\n-\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n-\t\tif (want_color(branch_use_color))\n-\t\t\tstrbuf_addf(&fancy, \"%s%s%s\",\n-\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n-\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n-\t\telse\n-\t\t\tstrbuf_addstr(&fancy, ref);\n-\t}\n+\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n+\tif (want_color(branch_use_color))\n+\t\tstrbuf_addf(&fancy, \"%s%s%s\",\n+\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n+\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n+\telse\n+\t\tstrbuf_addstr(&fancy, ref);\n \n \tif (!ours) {\n \t\tif (ref)\ndiff --git a/t/t6040-tracking-info.sh b/t/t6040-tracking-info.sh\nindex ec2b516..86e80eb 100755\n--- a/t/t6040-tracking-info.sh\n+++ b/t/t6040-tracking-info.sh\n@@ -36,10 +36,10 @@ test_expect_success setup '\n \n script='s/^..\\(b.\\)[\t 0-9a-f]*\\[\\([^]]*\\)\\].*/\\1 \\2/p'\n cat >expect <<\\EOF\n-b1 ahead 1, behind 1\n-b2 ahead 1, behind 1\n-b3 behind 1\n-b4 ahead 2\n+b1 origin/master\n+b2 origin/master\n+b3 origin/master\n+b4 origin/master\n EOF\n \n test_expect_success 'branch -v' '\n-- \n1.8.4-fc\n"},{"id":"228823","messageId":"1381561561-20459-7-git-send-email-felipe.contreras@gmail.com","threadId":"35123","inReplyTo":"1381561561-20459-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH try2 3/8] push: trivial reorganization","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-10-12T07:05:59Z","receivedAt":"2013-10-12T07:05:59Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n builtin/push.c | 35 +++++++++++++++++++----------------\n 1 file changed, 19 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/push.c b/builtin/push.c\nindex 04f0eaf..5dc06a3 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -113,20 +113,11 @@ static NORETURN int die_push_simple(struct branch *branch, struct remote *remote\n \t    remote->name, branch->name, advice_maybe);\n }\n \n-static const char message_detached_head_die[] =\n-\tN_(\"You are not currently on a branch.\\n\"\n-\t   \"To push the history leading to the current (detached HEAD)\\n\"\n-\t   \"state now, use\\n\"\n-\t   \"\\n\"\n-\t   \"    git push %s HEAD:<name-of-remote-branch>\\n\");\n-\n static void setup_push_upstream(struct remote *remote, struct branch *branch,\n \t\t\t\tint triangular)\n {\n \tstruct strbuf refspec = STRBUF_INIT;\n \n-\tif (!branch)\n-\t\tdie(_(message_detached_head_die), remote->name);\n \tif (!branch->merge_nr || !branch->merge || !branch->remote_name)\n \t\tdie(_(\"The current branch %s has no upstream branch.\\n\"\n \t\t    \"To push the current branch and set the remote as upstream, use\\n\"\n@@ -156,8 +147,6 @@ static void setup_push_upstream(struct remote *remote, struct branch *branch,\n \n static void setup_push_current(struct remote *remote, struct branch *branch)\n {\n-\tif (!branch)\n-\t\tdie(_(message_detached_head_die), remote->name);\n \tadd_refspec(branch->name);\n }\n \n@@ -191,9 +180,23 @@ static int is_workflow_triangular(struct remote *remote)\n \treturn (fetch_remote && fetch_remote != remote);\n }\n \n-static void setup_default_push_refspecs(struct remote *remote)\n+static const char message_detached_head_die[] =\n+\tN_(\"You are not currently on a branch.\\n\"\n+\t   \"To push the history leading to the current (detached HEAD)\\n\"\n+\t   \"state now, use\\n\"\n+\t   \"\\n\"\n+\t   \"    git push %s HEAD:<name-of-remote-branch>\\n\");\n+\n+static struct branch *get_current_branch(struct remote *remote)\n {\n \tstruct branch *branch = branch_get(NULL);\n+\tif (!branch)\n+\t\tdie(_(message_detached_head_die), remote->name);\n+\treturn branch;\n+}\n+\n+static void setup_default_push_refspecs(struct remote *remote)\n+{\n \tint triangular = is_workflow_triangular(remote);\n \n \tswitch (push_default) {\n@@ -208,17 +211,17 @@ static void setup_default_push_refspecs(struct remote *remote)\n \n \tcase PUSH_DEFAULT_SIMPLE:\n \t\tif (triangular)\n-\t\t\tsetup_push_current(remote, branch);\n+\t\t\tsetup_push_current(remote, get_current_branch(remote));\n \t\telse\n-\t\t\tsetup_push_upstream(remote, branch, triangular);\n+\t\t\tsetup_push_upstream(remote, get_current_branch(remote), triangular);\n \t\tbreak;\n \n \tcase PUSH_DEFAULT_UPSTREAM:\n-\t\tsetup_push_upstream(remote, branch, triangular);\n+\t\tsetup_push_upstream(remote, get_current_branch(remote), triangular);\n \t\tbreak;\n \n \tcase PUSH_DEFAULT_CURRENT:\n-\t\tsetup_push_current(remote, branch);\n+\t\tsetup_push_current(remote, get_current_branch(remote));\n \t\tbreak;\n \n \tcase PUSH_DEFAULT_NOTHING:\n-- \n1.8.4-fc\n"},{"id":"228865","messageId":"1381561561-20459-8-git-send-email-felipe.contreras@gmail.com","threadId":"35123","inReplyTo":"1381561561-20459-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH try2 8/8] branch: display publish branch","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-10-12T07:06:00Z","receivedAt":"2013-10-12T07:06:00Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n builtin/branch.c | 52 +++++++++++++++++++++++++++++++++++++++++++---------\n 1 file changed, 43 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex cf33e1c..9f15f7e 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -42,6 +42,7 @@ static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL,\t/* LOCAL */\n \tGIT_COLOR_GREEN,\t/* CURRENT */\n \tGIT_COLOR_BLUE,\t\t/* UPSTREAM */\n+\tGIT_COLOR_YELLOW,\t/* PUBLISH */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -49,7 +50,8 @@ enum color_branch {\n \tBRANCH_COLOR_REMOTE = 2,\n \tBRANCH_COLOR_LOCAL = 3,\n \tBRANCH_COLOR_CURRENT = 4,\n-\tBRANCH_COLOR_UPSTREAM = 5\n+\tBRANCH_COLOR_UPSTREAM = 5,\n+\tBRANCH_COLOR_PUBLISH = 6\n };\n \n static enum merge_filter {\n@@ -76,6 +78,8 @@ static int parse_branch_color_slot(const char *var, int ofs)\n \t\treturn BRANCH_COLOR_CURRENT;\n \tif (!strcasecmp(var+ofs, \"upstream\"))\n \t\treturn BRANCH_COLOR_UPSTREAM;\n+\tif (!strcasecmp(var+ofs, \"publish\"))\n+\t\treturn BRANCH_COLOR_PUBLISH;\n \treturn -1;\n }\n \n@@ -424,16 +428,35 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \tstruct branch *branch = branch_get(branch_name);\n \tstruct strbuf fancy = STRBUF_INIT;\n \n+\tif (!branch)\n+\t\treturn;\n+\n \tif (!show_tracking || !stat_tracking_info(branch, &ours, &theirs)) {\n-\t\tif (!branch || !branch->merge || !branch->merge[0]->dst)\n+\t\tif (branch->merge && branch->merge[0]->dst) {\n+\t\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n+\t\t\tif (want_color(branch_use_color))\n+\t\t\t\tstrbuf_addf(&fancy, \"%s%s%s\",\n+\t\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n+\t\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n+\t\t\telse\n+\t\t\t\tstrbuf_addstr(&fancy, ref);\n+\t\t}\n+\t\tif (branch->push.dst) {\n+\t\t\tref = shorten_unambiguous_ref(branch->push.dst, 0);\n+\t\t\tif (fancy.len)\n+\t\t\t\tstrbuf_addstr(&fancy, \", \");\n+\t\t\tif (want_color(branch_use_color))\n+\t\t\t\tstrbuf_addf(&fancy, \"%s%s%s\",\n+\t\t\t\t\t\tbranch_get_color(BRANCH_COLOR_PUBLISH),\n+\t\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n+\t\t\telse\n+\t\t\t\tstrbuf_addstr(&fancy, ref);\n+\t\t}\n+\t\tif (!fancy.len)\n \t\t\treturn;\n-\t\tref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);\n-\t\tif (want_color(branch_use_color))\n-\t\t\tstrbuf_addf(stat, \"[%s%s%s] \",\n-\t\t\t\t\tbranch_get_color(BRANCH_COLOR_UPSTREAM),\n-\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n-\t\telse\n-\t\t\tstrbuf_addf(stat, \"[%s] \", ref);\n+\t\tstrbuf_addf(stat, _(\"[%s]\"), fancy.buf);\n+\t\tstrbuf_release(&fancy);\n+\t\tstrbuf_addch(stat, ' ');\n \t\treturn;\n \t}\n \n@@ -444,6 +467,17 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,\n \t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n \telse\n \t\tstrbuf_addstr(&fancy, ref);\n+\tif (branch->push.dst) {\n+\t\tref = shorten_unambiguous_ref(branch->push.dst, 0);\n+\t\tif (fancy.len)\n+\t\t\tstrbuf_addstr(&fancy, \", \");\n+\t\tif (want_color(branch_use_color))\n+\t\t\tstrbuf_addf(&fancy, \"%s%s%s\",\n+\t\t\t\t\tbranch_get_color(BRANCH_COLOR_PUBLISH),\n+\t\t\t\t\tref, branch_get_color(BRANCH_COLOR_RESET));\n+\t\telse\n+\t\t\tstrbuf_addstr(&fancy, ref);\n+\t}\n \n \tif (!ours) {\n \t\tif (ref)\n-- \n1.8.4-fc\n"},{"id":"228821","messageId":"1381561561-20459-9-git-send-email-felipe.contreras@gmail.com","threadId":"35123","inReplyTo":"1381561561-20459-1-git-send-email-felipe.contreras@gmail.com","subject":"[PATCH try2 5/8] branch: allow configuring the publish branch","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-10-12T07:06:01Z","receivedAt":"2013-10-12T07:06:01Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>\n---\n Documentation/git-branch.txt | 11 +++++++++\n branch.c                     | 43 ++++++++++++++++++++++++++++++++++\n branch.h                     |  2 ++\n builtin/branch.c             | 56 ++++++++++++++++++++++++++++++++++++++++----\n 4 files changed, 108 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex b7cb625..1bf9b2a 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -14,7 +14,9 @@ SYNOPSIS\n \t[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]\n 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]\n 'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]\n+'git branch' (--set-publish-to=<publish> | -p <publish>) [<branchname>]\n 'git branch' --unset-upstream [<branchname>]\n+'git branch' --unset-publish [<branchname>]\n 'git branch' (-m | -M) [<oldbranch>] <newbranch>\n 'git branch' (-d | -D) [-r] <branchname>...\n 'git branch' --edit-description [<branchname>]\n@@ -189,6 +191,15 @@ start-point is either a local or remote-tracking branch.\n \tRemove the upstream information for <branchname>. If no branch\n \tis specified it defaults to the current branch.\n \n+-p <publish>::\n+--set-publish-to=<publish>::\n+\tSet up <branchname>'s publish tracking information. If no\n+\t<branchname> is specified, then it defaults to the current branch.\n+\n+--unset-publish::\n+\tRemove the publish information for <branchname>. If no branch\n+\tis specified it defaults to the current branch.\n+\n --edit-description::\n \tOpen an editor and edit the text to explain what the branch is\n \tfor, to be used by various other commands (e.g. `request-pull`).\ndiff --git a/branch.c b/branch.c\nindex c5c6984..02495e3 100644\n--- a/branch.c\n+++ b/branch.c\n@@ -144,6 +144,49 @@ static int setup_tracking(const char *new_ref, const char *orig_ref,\n \treturn 0;\n }\n \n+void install_branch_publish(const char *name, const char *remote, const char *remote_ref)\n+{\n+\tstruct strbuf key = STRBUF_INIT;\n+\n+\tif (!remote && !strcmp(name, remote_ref + 11) && !prefixcmp(remote_ref, \"refs/heads\")) {\n+\t\twarning(_(\"Not setting branch %s as its own publish branch.\"), name);\n+\t\treturn;\n+\t}\n+\n+\tstrbuf_addf(&key, \"branch.%s.pushremote\", name);\n+\tgit_config_set(key.buf, remote ? remote : \".\");\n+\n+\tstrbuf_reset(&key);\n+\tstrbuf_addf(&key, \"branch.%s.push\", name);\n+\tgit_config_set(key.buf, remote_ref);\n+\n+\tstrbuf_release(&key);\n+}\n+\n+int setup_publish(const char *name, const char *ref)\n+{\n+\tstruct tracking tracking;\n+\tconst char *remote, *remote_ref;\n+\n+\tmemset(&tracking, 0, sizeof(tracking));\n+\ttracking.spec.dst = (char*)ref;\n+\tif (for_each_remote(find_tracked_branch, &tracking))\n+\t\treturn 1;\n+\n+\tif (tracking.matches > 1)\n+\t\treturn error(_(\"Not tracking: ambiguous information for ref %s\"),\n+\t\t\t\tref);\n+\n+\tremote = tracking.remote;\n+\tremote_ref = tracking.src ? tracking.src : ref;\n+\n+\tinstall_branch_publish(name, remote, remote_ref);\n+\n+\tfree(tracking.src);\n+\n+\treturn 0;\n+}\n+\n struct branch_desc_cb {\n \tconst char *config_name;\n \tconst char *value;\ndiff --git a/branch.h b/branch.h\nindex 64173ab..c9b6aa9 100644\n--- a/branch.h\n+++ b/branch.h\n@@ -51,5 +51,7 @@ extern void install_branch_config(int flag, const char *local, const char *origi\n  * Read branch description\n  */\n extern int read_branch_desc(struct strbuf *, const char *branch_name);\n+extern int setup_publish(const char *name, const char *ref);\n+extern void install_branch_publish(const char *name, const char *remote, const char *remote_ref);\n \n #endif\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex baa1d31..cf33e1c 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -778,8 +778,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \tint delete = 0, rename = 0, force_create = 0, list = 0;\n \tint verbose = 0, abbrev = -1, detached = 0;\n \tint reflog = 0, edit_description = 0;\n-\tint quiet = 0, unset_upstream = 0;\n-\tconst char *new_upstream = NULL;\n+\tint quiet = 0, unset_upstream = 0, unset_publish = 0;\n+\tconst char *new_upstream = NULL, *publish = NULL;\n \tenum branch_track track;\n \tint kinds = REF_LOCAL_BRANCH;\n \tstruct commit_list *with_commit = NULL;\n@@ -794,7 +794,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tOPT_SET_INT( 0, \"set-upstream\",  &track, N_(\"change upstream info\"),\n \t\t\tBRANCH_TRACK_OVERRIDE),\n \t\tOPT_STRING('u', \"set-upstream-to\", &new_upstream, \"upstream\", \"change the upstream info\"),\n+\t\tOPT_STRING('p', \"set-publish-to\", &publish, \"publish\", \"change the publish info\"),\n \t\tOPT_BOOLEAN(0, \"unset-upstream\", &unset_upstream, \"Unset the upstream info\"),\n+\t\tOPT_BOOLEAN(0, \"unset-publish\", &unset_publish, \"Unset the publish info\"),\n \t\tOPT__COLOR(&branch_use_color, N_(\"use colored output\")),\n \t\tOPT_SET_INT('r', \"remotes\",     &kinds, N_(\"act on remote-tracking branches\"),\n \t\t\tREF_REMOTE_BRANCH),\n@@ -863,13 +865,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \targc = parse_options(argc, argv, prefix, options, builtin_branch_usage,\n \t\t\t     0);\n \n-\tif (!delete && !rename && !edit_description && !new_upstream && !unset_upstream && argc == 0)\n+\tif (!delete && !rename && !edit_description && !new_upstream && !publish &&\n+\t\t\t!unset_upstream && !unset_publish && argc == 0)\n \t\tlist = 1;\n \n \tif (with_commit || merge_filter != NO_FILTER)\n \t\tlist = 1;\n \n-\tif (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!unset_upstream > 1)\n+\tif (!!delete + !!rename + !!force_create + !!list + !!new_upstream + !!publish +\n+\t\t\t!!unset_upstream + !! unset_publish > 1)\n \t\tusage_with_options(builtin_branch_usage, options);\n \n \tif (abbrev == -1)\n@@ -975,6 +979,50 @@ int cmd_branch(int argc, const char **argv, const char *prefix)\n \t\tstrbuf_addf(&buf, \"branch.%s.merge\", branch->name);\n \t\tgit_config_set_multivar(buf.buf, NULL, NULL, 1);\n \t\tstrbuf_release(&buf);\n+\t} else if (publish) {\n+\t\tstruct branch *branch = branch_get(argv[0]);\n+\t\tchar *real_ref = NULL;\n+\t\tunsigned char sha1[20];\n+\n+\t\tif (argc > 1)\n+\t\t\tdie(_(\"too many branches to set new publish branch\"));\n+\n+\t\tif (!branch) {\n+\t\t\tif (!argc || !strcmp(argv[0], \"HEAD\"))\n+\t\t\t\tdie(_(\"could not set publish branch of HEAD when \"\n+\t\t\t\t      \"it does not point to any branch.\"));\n+\t\t\tdie(_(\"no such branch '%s'\"), argv[0]);\n+\t\t}\n+\n+\t\tif (!ref_exists(branch->refname))\n+\t\t\tdie(_(\"branch '%s' does not exist\"), branch->name);\n+\n+\t\tif (dwim_ref(publish, strlen(publish), sha1, &real_ref) != 1 ||\n+\t\t\t\tsetup_publish(branch->name, real_ref))\n+\t\t\tdie(_(\"Cannot setup publish branch to '%s'.\"), publish);\n+\t} else if (unset_publish) {\n+\t\tstruct branch *branch = branch_get(argv[0]);\n+\t\tstruct strbuf buf = STRBUF_INIT;\n+\n+\t\tif (argc > 1)\n+\t\t\tdie(_(\"too many branches to unset publish branch\"));\n+\n+\t\tif (!branch) {\n+\t\t\tif (!argc || !strcmp(argv[0], \"HEAD\"))\n+\t\t\t\tdie(_(\"could not unset publish branch of HEAD when \"\n+\t\t\t\t      \"it does not point to any branch.\"));\n+\t\t\tdie(_(\"no such branch '%s'\"), argv[0]);\n+\t\t}\n+\n+\t\tif (!branch->push_name)\n+\t\t\tdie(_(\"Branch '%s' has no publish information\"), branch->name);\n+\n+\t\tstrbuf_addf(&buf, \"branch.%s.pushremote\", branch->name);\n+\t\tgit_config_set_multivar(buf.buf, NULL, NULL, 1);\n+\t\tstrbuf_reset(&buf);\n+\t\tstrbuf_addf(&buf, \"branch.%s.push\", branch->name);\n+\t\tgit_config_set_multivar(buf.buf, NULL, NULL, 1);\n+\t\tstrbuf_release(&buf);\n \t} else if (argc > 0 && argc <= 2) {\n \t\tstruct branch *branch = branch_get(argv[0]);\n \t\tint branch_existed = 0, remote_tracking = 0;\n-- \n1.8.4-fc\n"},{"id":"228898","messageId":"CAPig+cQ=RkFWssANKQ=mca1jD6MGQuPxAV-SyM8rfHMLYoDHfA@mail.gmail.com","threadId":"35123","inReplyTo":"1381561561-20459-2-git-send-email-felipe.contreras@gmail.com","subject":"Re: [PATCH try2 7/8] push: add --set-publish option","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-10-13T10:03:04Z","receivedAt":"2013-10-13T10:03:04Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Oct 12, 2013 at 3:05 AM, Felipe Contreras\n<felipe.contreras@gmail.com> wrote:\n> diff --git a/t/t5529-push-publish.sh b/t/t5529-push-publish.sh\n> new file mode 100755\n> index 0000000..2037026\n> --- /dev/null\n> +++ b/t/t5529-push-publish.sh\n> @@ -0,0 +1,70 @@\n> +#!/bin/sh\n> +\n> +test_description='push with --set-publish'\n> +\n> +. ./test-lib.sh\n> +\n> +test_expect_success 'setup bare parent' '\n> +       git init --bare parent &&\n> +       git remote add publish parent\n> +'\n> +\n> +test_expect_success 'setup local commit' '\n> +       echo content >file &&\n> +       git add file &&\n> +       git commit -m one\n> +'\n> +\n> +check_config() {\n> +       (echo $2; echo $3) >expect.$1\n> +       (git config branch.$1.pushremote\n> +        git config branch.$1.push) >actual.$1\n> +       test_cmp expect.$1 actual.$1\n> +}\n\nDo you want to maintain &&-chain in this test?\n\n> +\n> +test_expect_success 'push -p master:master' '\n> +       git push -p publish master:master &&\n> +       check_config master publish refs/heads/master\n> +'\n> +\n> +test_expect_success 'push -u master:other' '\n> +       git push -p publish master:other &&\n> +       check_config master publish refs/heads/other\n> +'\n> +\n> +test_expect_success 'push -p --dry-run master:otherX' '\n> +       git push -p --dry-run publish master:otherX &&\n> +       check_config master publish refs/heads/other\n> +'\n> +\n> +test_expect_success 'push -p master2:master2' '\n> +       git branch master2 &&\n> +       git push -p publish master2:master2 &&\n> +       check_config master2 publish refs/heads/master2\n> +'\n> +\n> +test_expect_success 'push -p master2:other2' '\n> +       git push -p publish master2:other2 &&\n> +       check_config master2 publish refs/heads/other2\n> +'\n> +\n> +test_expect_success 'push -p :master2' '\n> +       git push -p publish :master2 &&\n> +       check_config master2 publish refs/heads/other2\n> +'\n> +\n> +test_expect_success 'push -u --all' '\n> +       git branch all1 &&\n> +       git branch all2 &&\n> +       git push -p --all &&\n> +       check_config all1 publish refs/heads/all1 &&\n> +       check_config all2 publish refs/heads/all2\n> +'\n> +\n> +test_expect_success 'push -p HEAD' '\n> +       git checkout -b headbranch &&\n> +       git push -p publish HEAD &&\n> +       check_config headbranch publish refs/heads/headbranch\n> +'\n> +\n> +test_done\n"},{"id":"228899","messageId":"CAMP44s2FihCyAJKLYqMzQSPOz7FgR_hh7EMwmS-socR0Zn8O_w@mail.gmail.com","threadId":"35123","inReplyTo":"CAPig+cQ=RkFWssANKQ=mca1jD6MGQuPxAV-SyM8rfHMLYoDHfA@mail.gmail.com","subject":"Re: [PATCH try2 7/8] push: add --set-publish option","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2013-10-13T10:15:42Z","receivedAt":"2013-10-13T10:15:42Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"On Sun, Oct 13, 2013 at 5:03 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Sat, Oct 12, 2013 at 3:05 AM, Felipe Contreras\n> <felipe.contreras@gmail.com> wrote:\n>> diff --git a/t/t5529-push-publish.sh b/t/t5529-push-publish.sh\n>> new file mode 100755\n>> index 0000000..2037026\n>> --- /dev/null\n>> +++ b/t/t5529-push-publish.sh\n>> @@ -0,0 +1,70 @@\n>> +#!/bin/sh\n>> +\n>> +test_description='push with --set-publish'\n>> +\n>> +. ./test-lib.sh\n>> +\n>> +test_expect_success 'setup bare parent' '\n>> +       git init --bare parent &&\n>> +       git remote add publish parent\n>> +'\n>> +\n>> +test_expect_success 'setup local commit' '\n>> +       echo content >file &&\n>> +       git add file &&\n>> +       git commit -m one\n>> +'\n>> +\n>> +check_config() {\n>> +       (echo $2; echo $3) >expect.$1\n>> +       (git config branch.$1.pushremote\n>> +        git config branch.$1.push) >actual.$1\n>> +       test_cmp expect.$1 actual.$1\n>> +}\n>\n> Do you want to maintain &&-chain in this test?\n\nAs much as we want to do it in t/t5523-push-upstream.sh, which has\nthis exact function.\n\n-- \nFelipe Contreras\n"}]}