shithub: git9

Download patch

ref: 26b0b7a8d040c802af32e57184df45b9eaaa4491
parent: ee592df0ef72455aa2250bfaeb17291e908c9b50
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Oct 12 02:11:12 EDT 2019

Allow querying for tree changes between revisions.

--- a/query.c
+++ b/query.c
@@ -3,9 +3,76 @@
 
 #include "git.h"
 
+#pragma	varargck	type	"P"	void
+
 int fullpath;
+int changes;
+char *path[128];
+int npath;
 
+int
+Pfmt(Fmt *f)
+{
+	int i, n;
+
+	n = 0;
+	for(i = 0; i < npath; i++)
+		n += fmtprint(f, "%s/", path[i]);
+	return n;
+}
+
 void
+difftrees(Hash ah, Hash bh)
+{
+	Dirent *ap, *bp, *ae, *be;
+	Object *a, *b;
+	int c;
+
+	if((a = readobject(ah)) == nil)
+		sysfatal("bad hash %H", ah);
+	if((b = readobject(bh)) == nil)
+		sysfatal("bad hash %H", bh);
+	if(a->type != b->type)
+		return;
+	switch(a->type){
+	case GCommit:
+		difftrees(a->commit->tree, b->commit->tree);
+		break;
+	case GTree:
+		ap = a->tree->ent;
+		ae = ap + a->tree->nent;
+		bp = b->tree->ent;
+		be = bp + b->tree->nent;
+		while(ap != ae && bp != be){
+			c = strcmp(ap->name, bp->name);
+			if(c == 0){
+				if(ap->mode != bp->mode || !hasheq(&ap->h, &bp->h)) {
+					if(!(ap->mode & DMDIR) || !(bp->mode & DMDIR))
+						print("~ %P%s\n", ap->name);
+					if(ap->mode & DMDIR || bp->mode & DMDIR){
+						if(npath >= nelem(path))
+						sysfatal("path too deep");
+						path[npath++] = ap->name;
+						difftrees(ap->h, bp->h);
+						npath--;
+					}
+				}
+				ap++;
+				bp++;
+			}else if(c < 0){
+				print("- %P%s\n", ap->name);
+				ap++;
+			}else if(c > 0){
+				print("+ %P%s\n", bp->name);
+				bp++;
+			}
+		}
+		break;
+	}
+}
+
+
+void
 usage(void)
 {
 	fprint(2, "usage: %s [-p]\n", argv0);
@@ -17,21 +84,29 @@
 {
 	int i, j, n;
 	Hash *h;
+	char *p;
 
 	ARGBEGIN{
 	case 'p':	fullpath++;	break;
+	case 'c':	changes++;	break;
 	default:	usage();	break;
 	}ARGEND;
 
 	gitinit();
+	fmtinstall('P', Pfmt);
 	for(i = 0; i < argc; i++){
 		if((n = resolverefs(&h, argv[i])) == -1)
 			sysfatal("resolve %s: %r", argv[i]);
-		for(j = 0; j < n; j++)
-			if(fullpath)
-				print("/mnt/git/object/%H\n", h[j]);
-			else
-				print("%H\n", h[j]);
+		if(changes){
+			if(n != 2)
+				sysfatal("diff: need 2 commits, got %d\n", n);
+			difftrees(h[0], h[1]);
+		}else{
+			p = (fullpath ? "/mnt/git/object/" : "");
+			for(j = 0; j < n; j++)
+				print("%s%H\n", p, h[j]);
+		}
 	}
 	exits(nil);
 }
+