git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH] object-name: add @{upstreamhead} shorthand
@ 2024-10-20 20:24 Bence Ferdinandy
  2024-10-20 20:40 ` Kristoffer Haugsbakk
  0 siblings, 1 reply; 14+ messages in thread
From: Bence Ferdinandy @ 2024-10-20 20:24 UTC (permalink / raw)
  To: git; +Cc: Bence Ferdinandy

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@ferdinandy.com>
---

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


^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2024-10-28  5:33 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-20 20:24 [RFC PATCH] object-name: add @{upstreamhead} shorthand Bence Ferdinandy
2024-10-20 20:40 ` Kristoffer Haugsbakk
2024-10-20 21:42   ` Bence Ferdinandy
2024-10-21 19:14     ` Jeff King
2024-10-21 20:09       ` Bence Ferdinandy
2024-10-21 20:35         ` Taylor Blau
2024-10-23 21:56         ` Jeff King
2024-10-24 18:48           ` Bence Ferdinandy
2024-10-25  6:24             ` Jeff King
2024-10-27 22:07               ` Bence Ferdinandy
2024-10-27 23:45                 ` Taylor Blau
2024-10-28  5:33                 ` Jeff King
2024-10-21 19:45     ` Taylor Blau
2024-10-21 20:11       ` Bence Ferdinandy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).