Skip to content

Commit

Permalink
remote.c: fix handling of %(push:remoteref)
Browse files Browse the repository at this point in the history
Looking at the value of %(push:remoteref) only handles the case when an
explicit push refspec is passed. But it does not handle the fallback
cases of looking at the configuration value of `push.default`.

In particular, doing something like

    git config push.default current
    git for-each-ref --format='%(push)'
    git for-each-ref --format='%(push:remoteref)'

prints a useful tracking ref for the first for-each-ref, but an empty
string for the second.

Since the intention of %(push:remoteref), from 9700fae (for-each-ref:
let upstream/push report the remote ref name) is to get exactly which
branch `git push` will push to, even in the fallback cases, fix this.

To get the meaning of %(push:remoteref), `ref-filter.c` calls
`remote_ref_for_branch`. We simply add a new static helper function,
`branch_get_push_remoteref` that follows the logic of
`branch_get_push_1`, and call it from `remote_ref_for_branch`.

We also update t/6300-for-each-ref.sh to handle all `push.default`
strategies. This involves testing `push.default=simple` twice, once
where there is a matching upstream branch and once when there is none.

Signed-off-by: Damien Robert <damien.olivier.robert+git@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Damien Robert authored and gitster committed Apr 23, 2020
1 parent e870325 commit 812a588
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 27 deletions.
94 changes: 72 additions & 22 deletions remote.c
Expand Up @@ -516,28 +516,6 @@ const char *pushremote_for_branch(struct branch *branch, int *explicit)
return remote_for_branch(branch, explicit);
}

const char *remote_ref_for_branch(struct branch *branch, int for_push)
{
if (branch) {
if (!for_push) {
if (branch->merge_nr) {
return branch->merge_name[0];
}
} else {
const char *dst, *remote_name =
pushremote_for_branch(branch, NULL);
struct remote *remote = remote_get(remote_name);

if (remote && remote->push.nr &&
(dst = apply_refspecs(&remote->push,
branch->refname))) {
return dst;
}
}
}
return NULL;
}

static struct remote *remote_get_1(const char *name,
const char *(*get_default)(struct branch *, int *))
{
Expand Down Expand Up @@ -1656,6 +1634,64 @@ static const char *tracking_for_push_dest(struct remote *remote,
return ret;
}

/**
* Return the local name of the remote tracking branch, as in
* %(push:remoteref), that corresponds to the ref we would push to given a
* bare `git push` while `branch` is checked out.
* See also branch_get_push_1 below.
*/
static const char *branch_get_push_remoteref(struct branch *branch)
{
struct remote *remote;

remote = remote_get(pushremote_for_branch(branch, NULL));
if (!remote)
return NULL;

if (remote->push.nr) {
return apply_refspecs(&remote->push, branch->refname);
}

if (remote->mirror)
return branch->refname;

switch (push_default) {
case PUSH_DEFAULT_NOTHING:
return NULL;

case PUSH_DEFAULT_MATCHING:
case PUSH_DEFAULT_CURRENT:
return branch->refname;

case PUSH_DEFAULT_UPSTREAM:
if (branch && branch->merge && branch->merge[0] &&
branch->merge[0]->dst)
return branch->merge[0]->src;
else
return NULL;

case PUSH_DEFAULT_UNSPECIFIED:
case PUSH_DEFAULT_SIMPLE:
{
const char *up, *cur;

up = branch_get_upstream(branch, NULL);
cur = tracking_for_push_dest(remote, branch->refname, NULL);
if (up && cur && !strcmp(cur, up))
return branch->refname;
else
return NULL;

}
}
BUG("unhandled push situation");
}

/**
* Return the tracking branch, as in %(push), that corresponds to the ref we
* would push to given a bare `git push` while `branch` is checked out.
* See also branch_get_push_remoteref above.
*/
static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)
{
struct remote *remote;
Expand Down Expand Up @@ -1735,6 +1771,20 @@ static int ignore_symref_update(const char *refname)
return (flag & REF_ISSYMREF);
}

const char *remote_ref_for_branch(struct branch *branch, int for_push)
{
if (branch) {
if (!for_push) {
if (branch->merge_nr) {
return branch->merge_name[0];
}
} else {
return branch_get_push_remoteref(branch);
}
}
return NULL;
}

/*
* Create and return a list of (struct ref) consisting of copies of
* each remote_ref that matches refspec. refspec must be a pattern.
Expand Down
44 changes: 39 additions & 5 deletions t/t6300-for-each-ref.sh
Expand Up @@ -875,12 +875,46 @@ test_expect_success ':remotename and :remoteref' '
git for-each-ref --format="${pair%=*}" \
refs/heads/master >actual &&
test_cmp expect actual
done &&
git branch push-simple &&
git config branch.push-simple.pushRemote from &&
actual="$(git for-each-ref \
done
)
'

test_expect_success ':push:remoteref' '
git init push-tests &&
(
cd push-tests &&
test_commit initial &&
git remote add from fifth.coffee:blub &&
git config branch.master.remote from &&
actual="$(git -c push.default=simple for-each-ref \
--format="%(push:remotename),%(push:remoteref)" \
refs/heads/master)" &&
test from, = "$actual" &&
git config branch.master.merge refs/heads/master &&
actual="$(git -c push.default=simple for-each-ref \
--format="%(push:remotename),%(push:remoteref)" \
refs/heads/master)" &&
test from,refs/heads/master = "$actual" &&
git config branch.master.merge refs/heads/other &&
actual="$(git -c push.default=simple for-each-ref \
--format="%(push:remotename),%(push:remoteref)" \
refs/heads/master)" &&
test from, = "$actual" &&
actual="$(git -c push.default=upstream for-each-ref \
--format="%(push:remotename),%(push:remoteref)" \
refs/heads/master)" &&
test from,refs/heads/other = "$actual" &&
actual="$(git -c push.default=current for-each-ref \
--format="%(push:remotename),%(push:remoteref)" \
refs/heads/master)" &&
test from,refs/heads/master = "$actual" &&
actual="$(git -c push.default=matching for-each-ref \
--format="%(push:remotename),%(push:remoteref)" \
refs/heads/master)" &&
test from,refs/heads/master = "$actual" &&
actual="$(git -c push.default=nothing for-each-ref \
--format="%(push:remotename),%(push:remoteref)" \
refs/heads/push-simple)" &&
refs/heads/master)" &&
test from, = "$actual"
)
'
Expand Down

0 comments on commit 812a588

Please sign in to comment.