diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index 39f50bd53e..174af2c0ec 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -142,8 +142,12 @@ upstream:: encountered. Append `:track,nobracket` to show tracking information without brackets (i.e "ahead N, behind M"). + -Also respects `:remotename` to state the name of the *remote* instead of -the ref. +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, @@ -152,9 +156,9 @@ 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`, `:trackshort` and `:remotename` 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), ' ' diff --git a/ref-filter.c b/ref-filter.c index 4819707d03..2259563e73 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -77,7 +77,7 @@ static struct used_atom { struct align align; struct { enum { - RR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME + RR_REF, RR_TRACK, RR_TRACKSHORT, RR_REMOTE_NAME, RR_REMOTE_REF } option; struct refname_atom refname; unsigned int nobracket : 1, push : 1, push_remote : 1; @@ -164,6 +164,9 @@ static void remote_ref_atom_parser(const struct ref_format *format, struct used_ 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, @@ -1262,6 +1265,16 @@ static void fill_remote_ref_details(struct used_atom *atom, const char *refname, *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"); } diff --git a/remote.c b/remote.c index b220f0dfc6..2bdcfc280c 100644 --- a/remote.c +++ b/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 *)) { diff --git a/remote.h b/remote.h index 2ecf4c8c74..1f6611be21 100644 --- a/remote.h +++ b/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 *);