shithub: git9

Download patch

ref: cb5eaa11386a1346a086e1672198854fdbebff3c
parent: f10ded757ffea343cf07e27cb0c504653444659f
author: Ori Bernstein <ori@eigenstate.org>
date: Tue Oct 15 22:33:10 EDT 2019

Speed up git/checkout: only copy changed files.

--- a/git.1
+++ b/git.1
@@ -131,6 +131,9 @@
 .B -f
 .I filters
 ]
+[
+.I [files...]
+]
 
 .SH DESCRIPTION
 .PP
--- a/pull
+++ b/pull
@@ -1,4 +1,4 @@
-#!/bin/rc -e
+#!/bin/rc -ex
 
 rfork en
 
@@ -6,45 +6,28 @@
 '
 
 fn update{
-	update=$1
-	branch=$2
-	upstream=$3
-	url=$4
-	dir=$5
+	branch=$1
+	upstream=$2
+	url=$3
+	dir=$4
 
 	fetch=`{git/fetch  -b $branch -u $upstream $url} |[2]  tr '\x0d' '\x0a'
 	st=$status
-	if(! ~ $st ''){
+	if(! ~ $st '|'){
 		echo fetch failed: $st
 		exit $st
 	}	
-	echo $fetch | awk -v 'update='^$update '
-		function writeref(ref, hash)
-		{
-			outfile = ".git/"ref
-			# we have local commits: nothing to do
-			if(system("~ `{git/query ''HEAD "hash" @''} `{git/query "hash"}") == 0)
-				exit("");
-			# we have local commits *and* remote commits: request a merge
-			if(system("~ `{git/query ''HEAD "hash" @''} `{git/query HEAD}") != 0){
-				printf("git/merge %s\n", hash) > "/fd/2";
-				exit("merge");
-			}
-			# we only have remote commits: update head
-			system("mkdir -p `{basename -d "outfile"}");
-			print hash > outfile;
-			close(outfile);
-		}
-
-		/^remote/{
-			if($2=="HEAD")
-				next
-
-			if(update)
-				writeref($2, $3)
-			gsub("^refs/heads", "refs/remotes/'$upstream'", $2)
-			writeref($2, $3)
-		}
+	echo $fetch | awk '
+	/^remote/{
+		if($2=="HEAD")
+			next
+		gsub("^refs/heads", "refs/remotes/'$upstream'", $2)
+		outfile = ".git/"ref
+		system("mkdir -p `{basename -d "outfile"}");
+		print hash > outfile;
+		print ref" => "hash > "/dev/fd/2"
+		close(outfile);
+	}
 	'
 }
 
@@ -55,11 +38,17 @@
 	exit usage
 }
 
-git/fs
 branch=`{awk '$1=="branch"{print $2}' < /mnt/git/ctl}
 remote=()
-update='true'
+checkout='true'
 upstream=origin
+
+if(! cd `{git/conf -r}){
+	echo 'not in git repository' >[1=2]
+	exit notgit
+}
+git/fs
+
 while(~ $1 -*){
 	switch($1){
 	case -u
@@ -70,7 +59,7 @@
 		branch=$2
 		shift
 	case -f
-		update=''
+		checkout=()
 	case *
 		usage
 	}
@@ -86,25 +75,35 @@
 	exit upstream
 }
 
-if(! cd `{git/conf -r})
-	exit 'not in git repository'
+update $branch $upstream $remote
+if (~ $#checkout 0)
+	exit
 
-dir=/mnt/git/branch/$branch/tree
-if(! ~ git/walk -q){
-	echo 'repository is dirty; commit before pulling' >[1=2]
-	exit 'dirty'
+local=`{git/branch}
+remote=`{git/branch | sed 's@^(refs/)?heads@remotes/'$upstream'@'}
+echo 'remote='$remote
+modified=`$nl{git/query -c HEAD $remote | grep '^[+~]' | sed 's/^..//'}
+deleted=`$nl{git/query -c HEAD $remote | grep '^-' | sed 's/^..//'}
+if(~ foo bar) { #! ~ $#modified 0 || ! ~ $#deleted 0){
+	if(! git/walk -q $modified $deleted){
+		echo remote changes would clobber local changes >[1=2]
+		exit dirty
+	}
 }
-oldfiles=`$nl{git/walk -cfT}
-update $update  $branch $upstream $remote $dir
-if(! ~ $update 0){
-	rm -f $oldfiles
-	tree=/mnt/git/HEAD/tree
-	@{builtin cd $tree && tar cif /fd/1 .} | @{tar xf /fd/0}
-	for(f in `$nl{walk -f $tree | sed 's@^'$tree'/*@@'}){
-		if(! ~ $#f 0){
-			idx=.git/index9/tracked/$f
-			mkdir -p `{basename -d $idx}
-			walk -eq $f > $idx
-		}
+
+
+cp .git/refs/$remote .git/refs/$local
+if(! ~ $#modified 0){
+	for(m in `{walk -f $modified}){
+		gm=/mnt/git/HEAD/tree/$m
+		d=`{basename -d $m}
+		mkdir -p $d
+		mkdir -p .git/index9/tracked/$d
+		cp  $gm $m
+		walk -eq $m > .git/index9/tracked/$m
 	}
+}
+if(! ~ $#deleted 0){
+	rm -f $deleted
+	rm -f .git/index9/tracked/$deleted
 }
--- a/walk.c
+++ b/walk.c
@@ -210,7 +210,7 @@
 void
 usage(void)
 {
-	fprint(2, "usage: %s [-qbc] [-f filt]\n", argv0);
+	fprint(2, "usage: %s [-qbc] [-f filt] [paths...]\n", argv0);
 	exits("usage");
 }
 
@@ -255,10 +255,20 @@
 		sysfatal("git/fs does not seem to be running");
 	if(printflg == 0)
 		printflg = Tflg | Aflg | Mflg | Rflg;
-	if(access(TDIR, AEXIST) == 0 && readpaths(&r, TDIR, "") == -1)
-		sysfatal("read tracked: %r");
-	if(access(RDIR, AEXIST) == 0 && readpaths(&r, RDIR, "") == -1)
-		sysfatal("read removed: %r");
+	if(argc == 0){
+		if(access(TDIR, AEXIST) == 0 && readpaths(&r, TDIR, "") == -1)
+			sysfatal("read tracked: %r");
+		if(access(RDIR, AEXIST) == 0 && readpaths(&r, RDIR, "") == -1)
+			sysfatal("read removed: %r");
+	}else{
+		r.path = emalloc(argc*sizeof(char*));
+		r.pathsz = argc;
+		for(i = 0; i < argc; i++){
+			snprint(tpath, sizeof(tpath), TDIR"/%s", argv[i]);
+			if(access(tpath, AEXIST) == 0)
+				r.path[r.npath++] = estrdup(argv[i]);
+		}
+	}		
 	dedup(&r);
 
 	for(i = 0; i < r.npath; i++){