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`
|
(behind), "<>" (ahead and behind), or "=" (in sync). `:track`
|
||||||
also prints "[gone]" whenever unknown upstream ref is
|
also prints "[gone]" whenever unknown upstream ref is
|
||||||
encountered. Append `:track,nobracket` to show tracking
|
encountered. Append `:track,nobracket` to show tracking
|
||||||
information without brackets (i.e "ahead N, behind M"). Has
|
information without brackets (i.e "ahead N, behind M").
|
||||||
no effect if the ref does not have tracking information
|
+
|
||||||
associated with it. All the options apart from `nobracket`
|
For any remote-tracking branch `%(upstream)`, `%(upstream:remotename)`
|
||||||
are mutually exclusive, but if used together the last option
|
and `%(upstream:remoteref)` refer to the name of the remote and the
|
||||||
is selected.
|
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::
|
push::
|
||||||
The name of a local ref which represents the `@{push}`
|
The name of a local ref which represents the `@{push}`
|
||||||
location for the displayed ref. Respects `:short`, `:lstrip`,
|
location for the displayed ref. Respects `:short`, `:lstrip`,
|
||||||
`:rstrip`, `:track`, and `:trackshort` options as `upstream`
|
`:rstrip`, `:track`, `:trackshort`, `:remotename`, and `:remoteref`
|
||||||
does. Produces an empty string if no `@{push}` ref is
|
options as `upstream` does. Produces an empty string if no `@{push}`
|
||||||
configured.
|
ref is configured.
|
||||||
|
|
||||||
HEAD::
|
HEAD::
|
||||||
'*' if HEAD matches current ref (the checked out branch), ' '
|
'*' if HEAD matches current ref (the checked out branch), ' '
|
||||||
|
42
ref-filter.c
42
ref-filter.c
@ -76,9 +76,11 @@ static struct used_atom {
|
|||||||
char color[COLOR_MAXLEN];
|
char color[COLOR_MAXLEN];
|
||||||
struct align align;
|
struct align align;
|
||||||
struct {
|
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;
|
struct refname_atom refname;
|
||||||
unsigned int nobracket : 1;
|
unsigned int nobracket : 1, push : 1, push_remote : 1;
|
||||||
} remote_ref;
|
} remote_ref;
|
||||||
struct {
|
struct {
|
||||||
enum { C_BARE, C_BODY, C_BODY_DEP, C_LINES, C_SIG, C_SUB, C_TRAILERS } option;
|
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;
|
struct string_list params = STRING_LIST_INIT_DUP;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (!strcmp(atom->name, "push") || starts_with(atom->name, "push:"))
|
||||||
|
atom->u.remote_ref.push = 1;
|
||||||
|
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
atom->u.remote_ref.option = RR_REF;
|
atom->u.remote_ref.option = RR_REF;
|
||||||
refname_atom_parser_internal(&atom->u.remote_ref.refname,
|
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;
|
atom->u.remote_ref.option = RR_TRACKSHORT;
|
||||||
else if (!strcmp(s, "nobracket"))
|
else if (!strcmp(s, "nobracket"))
|
||||||
atom->u.remote_ref.nobracket = 1;
|
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;
|
atom->u.remote_ref.option = RR_REF;
|
||||||
refname_atom_parser_internal(&atom->u.remote_ref.refname,
|
refname_atom_parser_internal(&atom->u.remote_ref.refname,
|
||||||
arg, atom->name);
|
arg, atom->name);
|
||||||
@ -1268,6 +1279,25 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname,
|
|||||||
*s = ">";
|
*s = ">";
|
||||||
else
|
else
|
||||||
*s = "<>";
|
*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
|
} else
|
||||||
die("BUG: unhandled RR_* enum");
|
die("BUG: unhandled RR_* enum");
|
||||||
}
|
}
|
||||||
@ -1377,16 +1407,20 @@ static void populate_value(struct ref_array_item *ref)
|
|||||||
if (refname)
|
if (refname)
|
||||||
fill_remote_ref_details(atom, refname, branch, &v->s);
|
fill_remote_ref_details(atom, refname, branch, &v->s);
|
||||||
continue;
|
continue;
|
||||||
} else if (starts_with(name, "push")) {
|
} else if (atom->u.remote_ref.push) {
|
||||||
const char *branch_name;
|
const char *branch_name;
|
||||||
if (!skip_prefix(ref->refname, "refs/heads/",
|
if (!skip_prefix(ref->refname, "refs/heads/",
|
||||||
&branch_name))
|
&branch_name))
|
||||||
continue;
|
continue;
|
||||||
branch = branch_get(branch_name);
|
branch = branch_get(branch_name);
|
||||||
|
|
||||||
|
if (atom->u.remote_ref.push_remote)
|
||||||
|
refname = NULL;
|
||||||
|
else {
|
||||||
refname = branch_get_push(branch, NULL);
|
refname = branch_get_push(branch, NULL);
|
||||||
if (!refname)
|
if (!refname)
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
fill_remote_ref_details(atom, refname, branch, &v->s);
|
fill_remote_ref_details(atom, refname, branch, &v->s);
|
||||||
continue;
|
continue;
|
||||||
} else if (starts_with(name, "color:")) {
|
} 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);
|
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,
|
static struct remote *remote_get_1(const char *name,
|
||||||
const char *(*get_default)(struct branch *, int *))
|
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);
|
struct branch *branch_get(const char *name);
|
||||||
const char *remote_for_branch(struct branch *branch, int *explicit);
|
const char *remote_for_branch(struct branch *branch, int *explicit);
|
||||||
const char *pushremote_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_has_merge_config(struct branch *branch);
|
||||||
int branch_merge_matches(struct branch *, int n, const char *);
|
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_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
|
test_done
|
||||||
|
Loading…
x
Reference in New Issue
Block a user