summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Contreras <felipe.contreras@gmail.com>2014-04-20 14:45:00 -0500
committerJunio C Hamano <gitster@pobox.com>2014-04-21 11:45:55 -0700
commitbcf0d5482a6222aca7c858a4a17236b593d6c89d (patch)
tree466eb8af9bf10abc2f51009582923bbc08b8ff5a
parent67f9dc65f8ac6fcc717f7280e2d91d42d8b15c1c (diff)
downloadgit-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.txt7
-rw-r--r--builtin/push.c9
-rw-r--r--remote.c34
-rw-r--r--remote.h4
-rwxr-xr-xt/t5516-fetch-push.sh48
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))
diff --git a/remote.c b/remote.c
index eea2c8de45..e04efdc393 100644
--- a/remote.c
+++ b/remote.c
@@ -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,
diff --git a/remote.h b/remote.h
index 917d383a80..bf2a040e7f 100644
--- a/remote.h
+++ b/remote.h
@@ -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