diff options
author | Felipe Contreras <felipe.contreras@gmail.com> | 2014-04-20 14:45:00 -0500 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2014-04-21 11:45:55 -0700 |
commit | bcf0d5482a6222aca7c858a4a17236b593d6c89d (patch) | |
tree | 466eb8af9bf10abc2f51009582923bbc08b8ff5a | |
parent | 67f9dc65f8ac6fcc717f7280e2d91d42d8b15c1c (diff) | |
download | git-bcf0d5482a6222aca7c858a4a17236b593d6c89d.tar.gz |
Add concept of 'publish' branch
The publish branch is the branch the user wants to push to, akin to the
upstream branch, which is the branch the user wants to use as a
baseline. It overrides other configurations, such as push.default, and
remote.<name>.push.
The upstream branch is:
branch.$name.remote
branch.$name.merge
The publish branch is:
branch.$name.pushremote
branch.$name.push
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | Documentation/config.txt | 7 | ||||
-rw-r--r-- | builtin/push.c | 9 | ||||
-rw-r--r-- | remote.c | 34 | ||||
-rw-r--r-- | remote.h | 4 | ||||
-rwxr-xr-x | t/t5516-fetch-push.sh | 48 |
5 files changed, 95 insertions, 7 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt index d8b6cc9654..168025b25c 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -763,6 +763,13 @@ branch.<name>.mergeoptions:: option values containing whitespace characters are currently not supported. +branch.<name>.push:: + Defines, together with branch.<name>.pushremote, the publish branch for + the given branch. It tells 'git push' which branch to push to, and + overrides any other configurations, such as push.default. It also tells + commands such as 'git status' and 'git branch' which remote branch to + use for tracking information (commits ahead and behind). + branch.<name>.rebase:: When true, rebase the branch <name> on top of the fetched branch, instead of merging the default branch from the default remote when diff --git a/builtin/push.c b/builtin/push.c index f8dfea41e1..31a4aa3396 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -424,7 +424,14 @@ static int do_push(const char *repo, int flags) } if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) { - if (remote->push_refspec_nr) { + struct branch *branch = branch_get(NULL); + /* Is there a publish branch */ + if (branch && branch->pushremote_name && !strcmp(remote->name, branch->pushremote_name) && + branch->push_name) { + struct strbuf refspec = STRBUF_INIT; + strbuf_addf(&refspec, "%s:%s", branch->name, branch->push_name); + add_refspec(refspec.buf); + } else if (remote->push_refspec_nr) { refspec = remote->push_refspec; refspec_nr = remote->push_refspec_nr; } else if (!(flags & TRANSPORT_PUSH_MIRROR)) @@ -352,13 +352,17 @@ static int handle_config(const char *key, const char *value, void *cb) explicit_default_remote_name = 1; } } else if (!strcmp(subkey, ".pushremote")) { + if (git_config_string(&branch->pushremote_name, key, value)) + return -1; if (branch == current_branch) - if (git_config_string(&branch_pushremote_name, key, value)) - return -1; + branch_pushremote_name = xstrdup(branch->pushremote_name); } else if (!strcmp(subkey, ".merge")) { if (!value) return config_error_nonbool(key); add_merge(branch, xstrdup(value)); + } else if (!strcmp(subkey, ".push")) { + if (git_config_string(&branch->push_name, key, value)) + return -1; } return 0; } @@ -1634,6 +1638,14 @@ struct branch *branch_get(const char *name) } } } + if (ret && ret->pushremote_name && ret->push_name) { + struct remote *pushremote; + pushremote = pushremote_get(ret->pushremote_name); + ret->push.src = xstrdup(ret->push_name); + if (remote_find_tracking(pushremote, &ret->push) + && !strcmp(ret->pushremote_name, ".")) + ret->push.dst = xstrdup(ret->push_name); + } return ret; } @@ -1843,6 +1855,15 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1) return found; } +static char *get_base(struct branch *branch) +{ + if (branch->push.dst) + return branch->push.dst; + if (branch->merge && branch->merge[0] && branch->merge[0]->dst) + return branch->merge[0]->dst; + return NULL; +} + /* * Compare a branch with its upstream, and save their differences (number * of commits) in *num_ours and *num_theirs. @@ -1860,12 +1881,13 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs) int rev_argc; /* Cannot stat unless we are marked to build on top of somebody else. */ - if (!branch || - !branch->merge || !branch->merge[0] || !branch->merge[0]->dst) + if (!branch) + return 0; + base = get_base(branch); + if (!base) return 0; /* Cannot stat if what we used to build on no longer exists */ - base = branch->merge[0]->dst; if (read_ref(base, sha1)) return -1; theirs = lookup_commit_reference(sha1); @@ -1941,7 +1963,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb) break; } - base = branch->merge[0]->dst; + base = get_base(branch); base = shorten_unambiguous_ref(base, 0); if (upstream_is_gone) { strbuf_addf(sb, @@ -205,6 +205,10 @@ struct branch { struct refspec **merge; int merge_nr; int merge_alloc; + + const char *pushremote_name; + const char *push_name; + struct refspec push; }; struct branch *branch_get(const char *name); diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index f4cf0dbd48..80a00e3b9f 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -1279,4 +1279,52 @@ EOF git push --no-thin --receive-pack="$rcvpck" no-thin/.git refs/heads/master:refs/heads/foo ' +mk_publish_test () { + mk_test up_repo heads/master && + mk_test down_repo heads/master && + test_config remote.up.url up_repo && + test_config remote.down.url down_repo && + test_config branch.master.pushremote down && + test_config branch.master.push for-john && + test_config branch.master.remote up && + test_config branch.master.merge master +} + +test_expect_success 'push with publish branch' ' + mk_publish_test && + git push && + check_push_result up_repo $the_first_commit heads/master && + check_push_result down_repo $the_commit heads/for-john +' + +test_expect_success 'push with publish branch for different remote' ' + mk_publish_test && + git push up && + check_push_result up_repo $the_commit heads/master && + check_push_result down_repo $the_first_commit heads/master +' + +test_expect_success 'push with publish branch with pushdefault' ' + mk_publish_test && + test_config remote.pushdefault up && + git push && + check_push_result up_repo $the_first_commit heads/master && + check_push_result down_repo $the_commit heads/for-john +' + +test_expect_success 'push with publish branch with remote refspec' ' + mk_publish_test && + test_config remote.down.push refs/heads/master:refs/heads/bad && + git push && + check_push_result up_repo $the_first_commit heads/master && + check_push_result down_repo $the_commit heads/for-john +' + +test_expect_success 'push with publish branch with manual refspec' ' + mk_publish_test && + git push down master:good && + check_push_result up_repo $the_first_commit heads/master && + check_push_result down_repo $the_commit heads/good +' + test_done |