git: 9front

Download patch

ref: 60967087cee7443166af920594684b1ad3c8203b
parent: 7eef3745706ad785bbc5d8bcf6dd940bbe52ca67
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Apr 16 21:19:10 EDT 2022

git/send: fill in 'theirs' object, even if we miss it

When pushing, git/send would sometimes decide we had all the
objects that we'd need to update the remote, and would try
to pack and send the entire history of the repository. This
is because we only set the 'theirs' ref when we had the object.

If we didn't have the object, we would set a zero hash,
then when deciding if we needed to force, we would think
that we were updating a new branch and send everything,
which would fail to update the remote.

--- a/sys/src/cmd/git/send.c
+++ b/sys/src/cmd/git/send.c
@@ -134,8 +134,8 @@
 	nmap = nours;
 	map = eamalloc(nmap, sizeof(Map));
 	for(i = 0; i < nmap; i++){
-		map[i].ours = ours[i];
 		map[i].theirs = Zhash;
+		map[i].ours = ours[i];
 		map[i].ref = refs[i];
 	}
 	while(1){
@@ -155,9 +155,15 @@
 		theirs = earealloc(theirs, ntheirs+1, sizeof(Hash));
 		if(hparse(&theirs[ntheirs], sp[0]) == -1)
 			sysfatal("invalid hash %s", sp[0]);
+		if((idx = findkey(map, nmap, sp[1])) != -1)
+			map[idx].theirs = theirs[ntheirs];
+		/*
+		 * we only keep their ref if we can read the object to add it
+		 * to our reachability; otherwise, discard it; we only care
+		 * that we don't have it, so we can tell whether we need to
+		 * bail out of pushing.
+		 */
 		if((o = readobject(theirs[ntheirs])) != nil){
-			if((idx = findkey(map, nmap, sp[1])) != -1)
-				map[idx].theirs = theirs[ntheirs];
 			ntheirs++;
 			unref(o);
 		}
@@ -180,7 +186,7 @@
 			p = ancestor(a, b);
 		if(!force && !hasheq(&m->theirs, &Zhash) && (a == nil || p != a)){
 			fprint(2, "remote has diverged\n");
-			werrstr("force needed");
+			werrstr("remote diverged");
 			flushpkt(c);
 			return -1;
 		}
--