Merge branch 'js/for-each-ref-remote-name-and-ref'
The "--format=..." option "git for-each-ref" takes learned to show the name of the 'remote' repository and the ref at the remote side that is affected for 'upstream' and 'push' via "%(push:remotename)" and friends. * js/for-each-ref-remote-name-and-ref: for-each-ref: test :remotename and :remoteref for-each-ref: let upstream/push report the remote ref name for-each-ref: let upstream/push optionally report the remote name
This commit is contained in:
commit
093048b229
@ -145,18 +145,25 @@ upstream::
|
||||
(behind), "<>" (ahead and behind), or "=" (in sync). `:track`
|
||||
also prints "[gone]" whenever unknown upstream ref is
|
||||
encountered. Append `:track,nobracket` to show tracking
|
||||
information without brackets (i.e "ahead N, behind M"). Has
|
||||
no effect if the ref does not have tracking information
|
||||
associated with it. All the options apart from `nobracket`
|
||||
are mutually exclusive, but if used together the last option
|
||||
is selected.
|
||||
information without brackets (i.e "ahead N, behind M").
|
||||
+
|
||||
For any remote-tracking branch `%(upstream)`, `%(upstream:remotename)`
|
||||
and `%(upstream:remoteref)` refer to the name of the remote and the
|
||||
name of the tracked remote ref, respectively. In other words, the
|
||||
remote-tracking branch can be updated explicitly and individually by
|
||||
using the refspec `%(upstream:remoteref):%(upstream)` to fetch from
|
||||
`%(upstream:remotename)`.
|
||||
+
|
||||
Has no effect if the ref does not have tracking information associated
|
||||
with it. All the options apart from `nobracket` are mutually exclusive,
|
||||
but if used together the last option is selected.
|
||||
|
||||
push::
|
||||
The name of a local ref which represents the `@{push}`
|
||||
location for the displayed ref. Respects `:short`, `:lstrip`,
|
||||
`:rstrip`, `:track`, and `:trackshort` options as `upstream`
|
||||
does. Produces an empty string if no `@{push}` ref is
|
||||
configured.
|
||||
`:rstrip`, `:track`, `:trackshort`, `:remotename`, and `:remoteref`
|
||||
options as `upstream` does. Produces an empty string if no `@{push}`
|
||||
ref is configured.
|
||||
|
||||
HEAD::
|
||||
'*' if HEAD matches current ref (the checked out branch), ' '
|
||||
|
48
ref-filter.c
48
ref-filter.c
@ -76,9 +76,11 @@ static struct used_atom {
|
||||
char color[COLOR_MAXLEN];
|
||||
struct align align;
|
||||
struct {
|
||||
enum { RR_REF, RR_TRACK, RR_TRACKSHORT } option;
|
||||
enum {
|
||||
RR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME, RR_REMOTE_REF
|
||||
} option;
|
||||
struct refname_atom refname;
|
||||
unsigned int nobracket : 1;
|
||||
unsigned int nobracket : 1, push : 1, push_remote : 1;
|
||||
} remote_ref;
|
||||
struct {
|
||||
enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option;
|
||||
@ -138,6 +140,9 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_
|
||||
struct string_list params = STRING_LIST_INIT_DUP;
|
||||
int i;
|
||||
|
||||
if (!strcmp(atom->name, "push") || starts_with(atom->name, "push:"))
|
||||
atom->u.remote_ref.push = 1;
|
||||
|
||||
if (!arg) {
|
||||
atom->u.remote_ref.option = RR_REF;
|
||||
refname_atom_parser_internal(&atom->u.remote_ref.refname,
|
||||
@ -157,7 +162,13 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_
|
||||
atom->u.remote_ref.option = RR_TRACKSHORT;
|
||||
else if (!strcmp(s, "nobracket"))
|
||||
atom->u.remote_ref.nobracket = 1;
|
||||
else {
|
||||
else if (!strcmp(s, "remotename")) {
|
||||
atom->u.remote_ref.option = RR_REMOTE_NAME;
|
||||
atom->u.remote_ref.push_remote = 1;
|
||||
} else if (!strcmp(s, "remoteref")) {
|
||||
atom->u.remote_ref.option = RR_REMOTE_REF;
|
||||
atom->u.remote_ref.push_remote = 1;
|
||||
} else {
|
||||
atom->u.remote_ref.option = RR_REF;
|
||||
refname_atom_parser_internal(&atom->u.remote_ref.refname,
|
||||
arg, atom->name);
|
||||
@ -1268,6 +1279,25 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
|
||||
*s = ">";
|
||||
else
|
||||
*s = "<>";
|
||||
} else if (atom->u.remote_ref.option == RR_REMOTE_NAME) {
|
||||
int explicit;
|
||||
const char *remote = atom->u.remote_ref.push ?
|
||||
pushremote_for_branch(branch, &explicit) :
|
||||
remote_for_branch(branch, &explicit);
|
||||
if (explicit)
|
||||
*s = xstrdup(remote);
|
||||
else
|
||||
*s = "";
|
||||
} else if (atom->u.remote_ref.option == RR_REMOTE_REF) {
|
||||
int explicit;
|
||||
const char *merge;
|
||||
|
||||
merge = remote_ref_for_branch(branch, atom->u.remote_ref.push,
|
||||
&explicit);
|
||||
if (explicit)
|
||||
*s = xstrdup(merge);
|
||||
else
|
||||
*s = "";
|
||||
} else
|
||||
die("BUG: unhandled RR_* enum");
|
||||
}
|
||||
@ -1377,16 +1407,20 @@ static void populate_value(struct ref_array_item *ref)
|
||||
if (refname)
|
||||
fill_remote_ref_details(atom, refname, branch, &v->s);
|
||||
continue;
|
||||
} else if (starts_with(name, "push")) {
|
||||
} else if (atom->u.remote_ref.push) {
|
||||
const char *branch_name;
|
||||
if (!skip_prefix(ref->refname, "refs/heads/",
|
||||
&branch_name))
|
||||
continue;
|
||||
branch = branch_get(branch_name);
|
||||
|
||||
refname = branch_get_push(branch, NULL);
|
||||
if (!refname)
|
||||
continue;
|
||||
if (atom->u.remote_ref.push_remote)
|
||||
refname = NULL;
|
||||
else {
|
||||
refname = branch_get_push(branch, NULL);
|
||||
if (!refname)
|
||||
continue;
|
||||
}
|
||||
fill_remote_ref_details(atom, refname, branch, &v->s);
|
||||
continue;
|
||||
} else if (starts_with(name, "color:")) {
|
||||
|
30
remote.c
30
remote.c
@ -675,6 +675,36 @@ 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,
|
||||
int *explicit)
|
||||
{
|
||||
if (branch) {
|
||||
if (!for_push) {
|
||||
if (branch->merge_nr) {
|
||||
if (explicit)
|
||||
*explicit = 1;
|
||||
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_refspec_nr &&
|
||||
(dst = apply_refspecs(remote->push,
|
||||
remote->push_refspec_nr,
|
||||
branch->refname))) {
|
||||
if (explicit)
|
||||
*explicit = 1;
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (explicit)
|
||||
*explicit = 0;
|
||||
return "";
|
||||
}
|
||||
|
||||
static struct remote *remote_get_1(const char *name,
|
||||
const char *(*get_default)(struct branch *, int *))
|
||||
{
|
||||
|
2
remote.h
2
remote.h
@ -223,6 +223,8 @@ struct branch {
|
||||
struct branch *branch_get(const char *name);
|
||||
const char *remote_for_branch(struct branch *branch, int *explicit);
|
||||
const char *pushremote_for_branch(struct branch *branch, int *explicit);
|
||||
const char *remote_ref_for_branch(struct branch *branch, int for_push,
|
||||
int *explicit);
|
||||
|
||||
int branch_has_merge_config(struct branch *branch);
|
||||
int branch_merge_matches(struct branch *, int n, const char *);
|
||||
|
@ -766,4 +766,36 @@ test_expect_success 'Verify usage of %(symref:rstrip) atom' '
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success ':remotename and :remoteref' '
|
||||
git init remote-tests &&
|
||||
(
|
||||
cd remote-tests &&
|
||||
test_commit initial &&
|
||||
git remote add from fifth.coffee:blub &&
|
||||
git config branch.master.remote from &&
|
||||
git config branch.master.merge refs/heads/stable &&
|
||||
git remote add to southridge.audio:repo &&
|
||||
git config remote.to.push "refs/heads/*:refs/heads/pushed/*" &&
|
||||
git config branch.master.pushRemote to &&
|
||||
for pair in "%(upstream)=refs/remotes/from/stable" \
|
||||
"%(upstream:remotename)=from" \
|
||||
"%(upstream:remoteref)=refs/heads/stable" \
|
||||
"%(push)=refs/remotes/to/pushed/master" \
|
||||
"%(push:remotename)=to" \
|
||||
"%(push:remoteref)=refs/heads/pushed/master"
|
||||
do
|
||||
echo "${pair#*=}" >expect &&
|
||||
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 \
|
||||
--format="%(push:remotename),%(push:remoteref)" \
|
||||
refs/heads/push-simple)" &&
|
||||
test from, = "$actual"
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user