From cfebf83947550f3ae730cef4a9b1ab6bf6b8d4f7 Mon Sep 17 00:00:00 2001 From: Ori Bernstein Date: Tue, 17 Aug 2021 04:31:15 +0000 Subject: [PATCH] git: better handling of absolute paths, regex metachars Git currently gets a bit confused if you try to manipulate files by absolute path. There were also a number of places where user-controlled file paths ended up getting passed to regex interpretation, which could confuse things. This change mainly does 2 things: - Adds a 'drop' function which drops a non-regex prefix from a string, and uses that to manipulate paths, simplifies 'subst', and removes 'subst -g', which was only used with fixed regexes; sed does this job fine. - When getting a path from a user, we make it absolute and then strip out the head Along the way it cleans up a couple of stupids: - 'for(f in $list) if(! ~ $#f 0) use $f: $f can't be a nil list because of list flattening. - removes a useless substitution here: all=`$nl{{git/query -c $1 $2; git/query -c $2 $3} | sed 's/^..//' | \ gsubst '^('$ourbr'|'$basebr'|'$theirbr')/*' | sort | uniq} where git/query -c doesn't produce paths prefixed with the query. --- sys/lib/git/common.rc | 31 +++++++++++++++---------------- sys/src/cmd/git/add | 6 +++--- sys/src/cmd/git/clone | 14 ++++++-------- sys/src/cmd/git/merge | 5 ++--- sys/src/cmd/git/pull | 4 ++-- sys/src/cmd/git/revert | 4 ++-- 6 files changed, 30 insertions(+), 34 deletions(-) diff --git a/sys/lib/git/common.rc b/sys/lib/git/common.rc index b98987d75..787b5babd 100644 --- a/sys/lib/git/common.rc +++ b/sys/lib/git/common.rc @@ -11,23 +11,22 @@ fn usage{ exit 'usage' } -# subst [-g] this [that] -fn subst{ - awk 'BEGIN{ - global = 0 - for(i = 1; ARGV[i] ~ /^-/; i++){ - if(ARGV[i] == "-g") - global = 1 - ARGC-- - } - this = ARGV[i++]; ARGC-- - that = ARGV[i++]; ARGC-- - } +fn subst { + awk ' + BEGIN{ARGC=0} + {sub(ARGV[1], ARGV[2]); print} + ' $* +} + +fn drop { + awk ' + BEGIN{ARGC=0} { - if(global) gsub(this, that) - else sub(this, that) + if(index($0, ARGV[1]) == 1) + $0=substr($0, length(ARGV[1])+1) print - }' $* + } + ' $* } fn present { @@ -77,7 +76,7 @@ fn gitup{ if(~ $#gitroot 0) die 'not a git repository' gitfs=$gitroot/.git/fs - gitrel=`{pwd | subst '^'$"gitroot'/?'} + gitrel=`{pwd | drop $gitroot | sed 's@^/@@'} if(~ $#gitrel 0) gitrel='.' cd $gitroot diff --git a/sys/src/cmd/git/add b/sys/src/cmd/git/add index 53e24d933..b980d7dc8 100755 --- a/sys/src/cmd/git/add +++ b/sys/src/cmd/git/add @@ -16,11 +16,11 @@ if(~ $remove 1){ if(~ $#* 0) exec aux/usage -paths=`$nl{cleanname -d $gitrel $*} +paths=`$nl{cleanname -d $gitrel $* | drop $gitroot} if(~ $add tracked) - files=`$nl{walk -f $paths} + files=`$nl{walk -f ./$paths} if not - files=`$nl{cd .git/index9/tracked/ && walk -f $paths} + files=`$nl{cd .git/index9/tracked/ && walk -f ./$paths} for(f in $files){ if(! ~ `$nl{cleanname $f} .git/*){ diff --git a/sys/src/cmd/git/clone b/sys/src/cmd/git/clone index 47043d573..62b6036dc 100755 --- a/sys/src/cmd/git/clone +++ b/sys/src/cmd/git/clone @@ -7,7 +7,7 @@ eval `''{aux/getflags $*} || exec aux/usage if(~ $debug 1) debug=(-d) -remote=`{echo $1 | subst -g '/*$'} +remote=`{echo $1 | sed 's@/*$@@'} local=$2 if(~ $#remote 0) @@ -79,19 +79,17 @@ fn clone{ tree=.git/fs/HEAD/tree lbranch=`{git/branch} - rbranch=`{echo $lbranch | subst '^heads' 'remotes/origin'} + rbranch=`{echo $lbranch | subst 'heads' 'remotes/origin'} echo checking out repository... if(test -f .git/refs/$rbranch){ cp .git/refs/$rbranch .git/refs/$lbranch git/fs @ {builtin cd $tree && tar cif /fd/1 .} | @ {tar xf /fd/0} \ || die 'checkout failed:' $status - for(f in `$nl{walk -f $tree | subst '^'$tree'/*'}){ - if(! ~ $#f 0){ - idx=.git/index9/tracked/$f - mkdir -p `$nl{basename -d $idx} - walk -eq $f > $idx - } + for(f in `$nl{walk -f $tree | drop $tree}){ + idx=.git/index9/tracked/$f + mkdir -p `$nl{basename -d $idx} + walk -eq ./$f > $idx } } if not{ diff --git a/sys/src/cmd/git/merge b/sys/src/cmd/git/merge index 6e9791914..3d7a97a74 100755 --- a/sys/src/cmd/git/merge +++ b/sys/src/cmd/git/merge @@ -7,13 +7,12 @@ fn merge{ basebr=$gitfs/object/$2/tree theirbr=$gitfs/object/$3/tree - all=`$nl{{git/query -c $1 $2; git/query -c $2 $3} | sed 's/^..//' | \ - subst -g '^('$ourbr'|'$basebr'|'$theirbr')/*' | sort | uniq} + all=`$nl{{git/query -c $1 $2; git/query -c $2 $3} | sed 's/^..//' | sort | uniq} for(f in $all){ ours=$ourbr/$f base=$basebr/$f theirs=$theirbr/$f - merge1 $f $theirs $base $ours + merge1 ./$f $theirs $base $ours } } diff --git a/sys/src/cmd/git/pull b/sys/src/cmd/git/pull index 4dd7fe94e..189323f97 100755 --- a/sys/src/cmd/git/pull +++ b/sys/src/cmd/git/pull @@ -75,8 +75,8 @@ if(! ~ `{git/query HEAD $remote @} `{git/query HEAD}){ # The remote is directly ahead of the local, and we have # no local commits that need merging. if(~ $#quiet 0) - git/log -s -e $local'..'$remote >[1=2] + git/log -s -e $local'..'$remote echo -echo $remote':' `{git/query $local} '=>' `{git/query $remote} >[1=2] +echo $remote':' `{git/query $local} '=>' `{git/query $remote} git/branch -mnb $remote $local exit '' diff --git a/sys/src/cmd/git/revert b/sys/src/cmd/git/revert index a516e3a9d..c576af5c3 100644 --- a/sys/src/cmd/git/revert +++ b/sys/src/cmd/git/revert @@ -11,8 +11,8 @@ commit=$gitfs/HEAD if(~ $#query 1) commit=`{git/query -p $query} -files=`$nl{cleanname -d $gitrel $*} -for(f in `$nl{cd $commit/tree/ && walk -f $files}){ +files=`$nl{cleanname -d $gitrel $* | drop $gitroot} +for(f in `$nl{cd $commit/tree/ && walk -f ./$files}){ mkdir -p `{basename -d $f} cp -x -- $commit/tree/$f $f git/add $f -- 2.44.0