[RFC PATCH] object-name: add @{upstreamhead} shorthand

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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





[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux