shithub: front

Download patch

ref: 7814ec46c39671d5c0721626c52c6d86c21cb311
parent: 35cab9b816dbf6eabe94d4ed3eff01ebff68a695
author: Jacob Moody <moody@posixcafe.org>
date: Sun Dec 22 16:06:53 EST 2024

git: make git/diff -s print relative file paths

This makes the output of git/diff -s plumbable
when the user is not within the root of the git repo.
This is implemented through adding a flag to git/walk
and having git/walk work out how many '..'s are needed.

Also includes a small piece of documentation regarding
the use of $editor in git/commit.

--- a/sys/man/1/git
+++ b/sys/man/1/git
@@ -183,6 +183,10 @@
 .I filters
 ]
 [
+.B -r
+.I rel
+]
+[
 .I file...
 ]
 
@@ -331,7 +335,14 @@
 .PP
 .B Git/commit
 creates a new commit consisting of all changes to the specified files.
-By default, an editor is opened to prepare the commit message.
+By default,
+.I $editor
+is opened to prepare the commit message.
+If
+.I $editor
+is undefined
+.IR hold (1)
+is used.
 The 
 .B -m
 flag supplies the commit message directly.
@@ -531,6 +542,10 @@
 The
 .B -q
 option suppresses all output.
+The
+.B -r
+option causes paths to be printed relative to the supplied directory
+.IR rel .
 The
 .B -f
 option filters files by status, and only matching items are printed.
--- a/sys/src/cmd/git/diff
+++ b/sys/src/cmd/git/diff
@@ -21,7 +21,7 @@
 
 branch=`{git/query -p $commit}
 if(~ $summarize 1 || ~ $uncommitted 1){
-	git/walk -f$filt $cparam $files
+	git/walk -r$gitrel -f$filt $cparam $files
 	exit
 }
 
--- a/sys/src/cmd/git/walk.c
+++ b/sys/src/cmd/git/walk.c
@@ -33,6 +33,9 @@
 Idxed	idxtab[NCACHE];
 char	repopath[1024];
 char	wdirpath[1024];
+char	relapath[1024];
+char	slashes[1024];
+int	nslash;
 char	*rstr	= "R ";
 char	*mstr	= "M ";
 char	*astr	= "A ";
@@ -347,15 +350,58 @@
 void
 show(Biobuf *o, int flg, char *str, char *path)
 {
+	char *pa, *pb, *suffix;
+	int ncommon = 0;
+
 	dirty |= flg;
-	if(!quiet && (printflg & flg))
-		Bprint(o, "%s%s\n", str, path);
+	if(!quiet && (printflg & flg)){
+		if(nslash){
+			suffix = path;
+			for(pa = relapath, pb = path; *pa && *pb; pa++, pb++){
+				if(*pa != *pb)
+					break;
+				if(*pa == '/'){
+					ncommon++;
+					suffix = pb+1;
+				}
+			}
+			Bprint(o, "%s%.*s%s\n", str, (nslash-ncommon)*3, slashes, suffix);
+		} else
+			Bprint(o, "%s%s\n", str, path);
+	}
 }
 
 void
+findslashes(char *path)
+{
+	char *s, *p;
+
+	p = cleanname(path);
+	if(p[0] == '.'){
+		if(p[1] == '\0')
+			return;
+		else if(p[1] == '.' && (p[2] == '/' || p[2] == '\0'))
+			sysfatal("relative path escapes git root");
+	}
+	
+	snprint(relapath, sizeof relapath, "%s/", p);
+	p = relapath;
+	if(*p == '/')
+		p++;
+
+	s = slashes;
+	for(; *p; p++){
+		if(*p != '/')
+			continue;
+		nslash++;
+		s = seprint(s, slashes + sizeof slashes, "../");
+	}
+}
+
+void
 usage(void)
 {
-	fprint(2, "usage: %s [-qbc] [-f filt] [-b base] [paths...]\n", argv0);
+	fprint(2, "usage: %s [-qbc] [-f filt] [-b base] [-r rel] [paths...]\n", argv0);
 	exits("usage");
 }
 
@@ -409,6 +455,9 @@
 		if(resolveref(&hd, "HEAD") == 0 && hasheq(&h, &hd))
 			useidx = 1;
 		bdir = smprint(".git/fs/object/%H/tree", h);
+		break;
+	case 'r':
+		findslashes(EARGF(usage()));
 		break;
 	default:
 		usage();
--