The HEAD of the remote is useful in many situations, but currently one would need to know the name of the remote to perform something like "git log origin/HEAD..", which makes writing remote agnostic aliases complicated. Introduce the new shorthand "@{upstreamhead}" which returns <remote>/HEAD for the same <remote> "@{upstream}" would yield. Signed-off-by: Bence Ferdinandy <bence@xxxxxxxxxxxxxx> --- Notes: RFC v1: Testing and documentation is completely missing, I'll add those in a v2 if people think the patch has merit. object-name.c | 15 ++++++++++++++- remote.c | 36 ++++++++++++++++++++++++++++++++++++ remote.h | 8 ++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/object-name.c b/object-name.c index c892fbe80a..f40a226a57 100644 --- a/object-name.c +++ b/object-name.c @@ -936,6 +936,12 @@ static inline int push_mark(const char *string, int len) return at_mark(string, len, suffix, ARRAY_SIZE(suffix)); } +static inline int upstream_head_mark(const char *string, int len) +{ + const char *suffix[] = { "@{upstreamhead}", "@{uh}" }; + return at_mark(string, len, suffix, ARRAY_SIZE(suffix)); +} + static enum get_oid_result get_oid_1(struct repository *r, const char *name, int len, struct object_id *oid, unsigned lookup_flags); static int interpret_nth_prior_checkout(struct repository *r, const char *name, int namelen, struct strbuf *buf); @@ -985,7 +991,8 @@ static int get_oid_basic(struct repository *r, const char *str, int len, continue; } if (!upstream_mark(str + at, len - at) && - !push_mark(str + at, len - at)) { + !push_mark(str + at, len - at) && + !upstream_head_mark(str + at, len - at)) { reflog_len = (len-1) - (at+2); len = at; } @@ -1729,6 +1736,12 @@ int repo_interpret_branch_name(struct repository *r, options); if (len > 0) return len; + + len = interpret_branch_mark(r, name, namelen, at - name, buf, + upstream_head_mark, branch_get_upstream_head, + options); + if (len > 0) + return len; } return -1; diff --git a/remote.c b/remote.c index 10104d11e3..302f013a25 100644 --- a/remote.c +++ b/remote.c @@ -1980,6 +1980,42 @@ const char *branch_get_upstream(struct branch *branch, struct strbuf *err) return branch->merge[0]->dst; } +const char *branch_get_upstream_head(struct branch *branch, struct strbuf *err) +{ + struct strbuf retval = STRBUF_INIT, refstring = STRBUF_INIT; + struct string_list l = STRING_LIST_INIT_DUP; + + if (!branch) + return error_buf(err, _("HEAD does not point to a branch")); + + if (!branch->merge || !branch->merge[0]) { + /* + * no merge config; is it because the user didn't define any, + * or because it is not a real branch, and get_branch + * auto-vivified it? + */ + if (!refs_ref_exists(get_main_ref_store(the_repository), branch->refname)) + return error_buf(err, _("no such branch: '%s'"), + branch->name); + return error_buf(err, + _("no upstream configured for branch '%s'"), + branch->name); + } + + if (!branch->merge[0]->dst) + return error_buf(err, + _("upstream branch '%s' not stored as a remote-tracking branch"), + branch->merge[0]->src); + + string_list_split(&l, branch->merge[0]->dst, '/', -1); + strbuf_addf(&refstring, "refs/remotes/%s/HEAD", l.items[2].string); + + if (refs_read_symbolic_ref(get_main_ref_store(the_repository), refstring.buf, &retval)) + return error_buf(err, _("%s does not exist"), refstring.buf); + + return retval.buf; +} + static const char *tracking_for_push_dest(struct remote *remote, const char *refname, struct strbuf *err) diff --git a/remote.h b/remote.h index a7e5c4e07c..a1d0f44297 100644 --- a/remote.h +++ b/remote.h @@ -360,6 +360,14 @@ const char *branch_get_upstream(struct branch *branch, struct strbuf *err); */ const char *branch_get_push(struct branch *branch, struct strbuf *err); +/** + * Return the fully-qualified refname of the HEAD branch for the same remote + * that "branch@{upstream}" is on. + * + * The return value and `err` conventions match those of `branch_get_upstream`. + */ +const char *branch_get_upstream_head(struct branch *branch, struct strbuf *err); + /* Flags to match_refs. */ enum match_refs_flags { MATCH_REFS_NONE = 0, -- 2.47.0.94.gc947641c25