[PATCH v2 1/2] fetch: allow asking for an explicit commit object by name

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

 



This teaches "git fetch" (hence "git pull") to accept an explicit commit
object name in the LHS of the refspec, as long as the named commit is at
the tip of an advertised ref. E.g.

    $ git pull origin 5738c9c21e53356ab5020912116e7f82fd2d428f
    $ git fetch origin 5738c9c21e53356ab5020912116e7f82fd2d428f:refs/remotes/origin

would behave exactly as if you asked

    $ git pull origin refs/heads/master
    $ git fetch origin refs/heads/master:refs/remotes/origin

when the output from "git ls-remote origin" said the remote side has the
commit object whose name is 5738c9c21e53356ab5020912116e7f82fd2d428f at
the tip of refs/heads/master branch ref.

This does not allow asking for a random object that may or may not exist
in the repository (this has been a longstanding security feature).

Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx>
---
 remote.c |   25 +++++++++++++++++++++++--
 1 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/remote.c b/remote.c
index ca42a12..76c2943 100644
--- a/remote.c
+++ b/remote.c
@@ -1387,6 +1387,25 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name)
 	return copy_ref(ref);
 }
 
+/*
+ * Allow fetching an explicitly-named commit from the command line,
+ * but only if it exactly matches the commit at the tip of one of the
+ * advertised refs.
+ */
+static struct ref *get_remote_commit(const struct ref *remote_refs, const char *hex)
+{
+	const struct ref *ref;
+	unsigned char sha1[20];
+
+	if (get_sha1_hex(hex, sha1) || hex[40])
+		return NULL;
+
+	for (ref = remote_refs; ref; ref = ref->next)
+		if (!strchr(ref->name, '^') && !hashcmp(sha1, ref->old_sha1))
+			return copy_ref(ref);
+	return NULL;
+}
+
 static struct ref *get_local_ref(const char *name)
 {
 	if (!name || name[0] == '\0')
@@ -1416,8 +1435,10 @@ int get_fetch_map(const struct ref *remote_refs,
 		const char *name = refspec->src[0] ? refspec->src : "HEAD";
 
 		ref_map = get_remote_ref(remote_refs, name);
-		if (!missing_ok && !ref_map)
-			die("Couldn't find remote ref %s", name);
+		if (!ref_map)
+			ref_map = get_remote_commit(remote_refs, name);
+		if (!ref_map && !missing_ok)
+			die("Couldn't find remote ref that matches %s", name);
 		if (ref_map) {
 			ref_map->peer_ref = get_local_ref(refspec->dst);
 			if (ref_map->peer_ref && refspec->force)
-- 
1.7.7.rc1.1.g1e5814

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[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]