ref: 4fecf55b94bb8a2c8648784fca2e00c85bfe2526
parent: 45001b2700f817cc4a3609574031437040de393e
author: Ori Bernstein <[email protected]>
date: Mon May 27 15:09:53 EDT 2024
git: sync with 9front
--- a/add
+++ b/add
@@ -7,32 +7,13 @@
flagfmt='r:remove'; args='file ...'
eval `''{aux/getflags $*} || exec aux/usage
-add='tracked'
-del='removed'
-if(~ $remove 1){
- add='removed'
- del='tracked'
-}
+s=A
+if(~ $remove 1)
+ s=R
if(~ $#* 0)
exec aux/usage
paths=`$nl{cleanname -d $gitrel $* | drop $gitroot}
-if(~ $add tracked)
- files=`$nl{walk -f ./$paths}
-if not
- files=`$nl{cd .git/index9/tracked/ && walk -f ./$paths}
-
-for(f in $files){
- if(! ~ `$nl{cleanname $f} .git/*){
- addpath=.git/index9/$add/$f
- delpath=.git/index9/$del/$f
- mkdir -p `$nl{basename -d $addpath}
- mkdir -p `$nl{basename -d $delpath}
- # We don't want a matching qid, so that
- # git/walk doesn't think this came from
- # a checkout.
- echo -n > $addpath
- rm -f $delpath
- }
-}
+walk -f ./$paths | grep -v '^(./)?.git/' | \
+ sed 's/^/'$s' NOQID 0 /' >> .git/INDEX9
exit ''
--- a/branch
+++ b/branch
@@ -4,7 +4,7 @@
gitup
-flagfmt='a:listall, b:baseref ref, d:delete, n:newbr, s:stay, m:merge'
+flagfmt='a:listall, b:baseref ref, d:delete, n:newbr, s:stay, m:merge, M:nomod'
args='[branch]'
eval `''{aux/getflags $*} || exec aux/usage
@@ -48,8 +48,11 @@
modified=`$nl{git/query -c HEAD $base | grep '^[^-]' | subst '^..'}
deleted=`$nl{git/query -c HEAD $base | grep '^-' | subst '^..'}
+# if we delete the current branch without switching, bad things happen
+if(~ $delete 1 && ~ `{git/query HEAD} `{git/query $branch})
+ die 'cannot delete current branch'
# if we're not merging, don't clobber existing changes.
-if(~ $#merge 0){
+if(~ $#merge 0 && ~ $#delete 0){
if(! ~ $#modified 0 || ! ~ $#deleted 0){
git/walk -fRMA $modified $deleted ||
die 'uncommitted changes would be clobbered'
@@ -84,7 +87,6 @@
for(m in $cleanpaths){
d=`$nl{basename -d $m}
mkdir -p $d
- mkdir -p .git/index9/tracked/$d
# Modifications can turn a file into
# a directory, or vice versa, so we
# need to delete and copy the files
@@ -97,11 +99,11 @@
b=file
if(! ~ $a $b){
rm -rf $m
- rm -rf .git/index9/tracked/$m
+ echo R NOQID 0 $m >> .git/INDEX9
}
if(~ $b file){
cp -x -- $basedir/tree/$m $m
- walk -eq $m > .git/index9/tracked/$m
+ echo T NOQID 0 $m >> .git/INDEX9
touch $m
}
}
@@ -112,9 +114,11 @@
merge1 $ours $ours $common $theirs
}
-if(! ~ $#deleted 0){
- rm -f $deleted
- rm -f .git/index9/tracked/$deleted
+for(d in $deleted){
+ if(! test -d $d){
+ rm -f $d
+ echo R NOQID 0 $d >> .git/INDEX9
+ }
}
echo ref: $new > .git/HEAD
--- a/clone
+++ b/clone
@@ -17,8 +17,8 @@
if(~ $#branch 1)
branchflag=(-b $branch)
-if(test -e $local)
- die 'repository already exists:' $local
+if(test -e $local && ~ `{ls $local | sed 1q | wc -l} 1)
+ die 'destination already exists:' $local
fn clone{
flag +e
@@ -67,7 +67,7 @@
refdir = headref;
gsub("/?[^/]*/?$", "", refdir)
gsub("^refs/remotes/origin", "refs/heads", headref)
- system("mkdir -p .git/"refdir);
+ system("mkdir -p `{basename -d .git/"headref"}");
system("cp .git/" remote " .git/" headref)
print "ref: " headref > ".git/HEAD"
}else if(headhash != ""){
@@ -82,15 +82,13 @@
rbranch=`{echo $lbranch | subst 'heads' 'remotes/origin'}
echo checking out repository...
if(test -f .git/refs/$rbranch){
+ mkdir -p `{basename -d .git/refs/$lbranch}
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 | drop $tree}){
- idx=.git/index9/tracked/$f
- mkdir -p `$nl{basename -d $idx}
- walk -eq ./$f > $idx
- }
+ {for(f in `$nl{cd $tree && walk -f})
+ echo 'T NOQID 0 '$f} > .git/INDEX9
}
if not{
echo no default branch >[1=2]
@@ -100,6 +98,7 @@
fn sigint {
echo cancelled clone $remote: cleaning $local >[1=2]
+ unmount $local/.git/fs >[2]/dev/null
rm -rf $local
exit interrupted
}
@@ -108,6 +107,7 @@
st=$status
if(! ~ $st ''){
echo failed to clone $remote: cleaning $local >[1=2]
+ unmount $local/.git/fs >[2]/dev/null
rm -rf $local
exit $st
}
--- a/commit
+++ b/commit
@@ -65,8 +65,8 @@
fn parents{
if(! ~ $#revise 0)
parents=`{cat $gitfs/HEAD/parent}
- if not if(test -f .git/index9/merge-parents)
- parents=`{cat .git/index9/merge-parents | sort | uniq}
+ if not if(test -f .git/merge-parents)
+ parents=`{cat .git/merge-parents | sort | uniq}
if not if(~ $initial true)
parents=()
if not
@@ -78,7 +78,7 @@
if(! ~ $#parents 0)
pflags='-p'^$parents
hash=`{git/save -n $"name -e $"email -m $"msg $pflags $files || die $status}
- rm -f .git/index9/merge-parents
+ rm -f .git/merge-parents
}
fn update{
@@ -89,14 +89,10 @@
echo $branch: $hash
echo $hash > $refpath
for(f in $files){
- if(test -e .git/index9/removed/$f || ! test -e $f){
- rm -f .git/index9/removed/$f
- rm -f .git/index9/tracked/$f
- }
- if not{
- mkdir -p `{basename -d $f}
- walk -eq $f > .git/index9/tracked/$f
- }
+ if(! test -e $f && ! test -e .git/object/$hash/tree/$f)
+ echo R NOQID 0 $f >> .git/INDEX9
+ if not
+ echo T NOQID 0 $f >> .git/INDEX9
}
}
@@ -120,10 +116,12 @@
}
files=()
+if(test -f .git/merge-parents)
+ files=`$nl{git/query -c `{cat .git/merge-parents} | sed 's/^..//'}
if(! ~ $#* 0)
- files=`$nl{git/walk -c `$nl{cleanname -d $gitrel $*}}
-if(~ $status '' || ~ $#files 0 && ! test -f .git/index9/merge-parents && ~ $#revise 0)
- die 'nothing to commit' $status
+ files=($files `$nl{git/walk -c `$nl{cleanname -d $gitrel $*}})
+if(~ $status '' || ~ $#files 0 && ! test -f .git/merge-parents && ~ $#revise 0)
+ die 'nothing to commit'
@{
flag e +
whoami
--- a/common.rc
+++ b/common.rc
@@ -84,10 +84,11 @@
base=/dev/null
if(! test -f $theirs)
theirs=/dev/null
- if(! ape/diff3 -3 -m $ours $base $theirs > $tmp)
- echo merge needed: $out >[1=2]
if(mergeperm $ours $base $theirs){
+ mkdir -p `{basename -d $tmp}
+ if(! ape/diff3 -3 -m $ours $base $theirs > $tmp)
+ echo merge needed: $out >[1=2]
mv $tmp $out
git/add $out
chmod $mergedperms $out
@@ -99,9 +100,14 @@
}}
fn gitup{
- gitroot=`{git/conf -r >[2]/dev/null}
+ gitroot=`$nl{git/conf -r >[2]/dev/null}
if(~ $#gitroot 0)
die 'not a git repository'
+ gitwork=`$nl{git/conf work.dir}
+ if(~ $#gitwork 1)
+ bind -c $gitwork/objects $gitroot/.git/objects
+ if(~ $#workdir 1)
+ bind $workdir .git/objects
gitfs=$gitroot/.git/fs
gitrel=`{pwd | drop $gitroot | sed 's@^/@@'}
if(~ $#gitrel 0)
--- a/diff
+++ b/diff
@@ -4,33 +4,32 @@
gitup
-flagfmt='c:commit branch, s:summarize'; args='[file ...]'
+flagfmt='c:commit branch, s:summarize, u:uncommitted'; args='[file ...]'
eval `''{aux/getflags $*} || exec aux/usage
-if(~ $#commit 0)
+if(~ $#commit 0){
commit=HEAD
+ cparam=()
+}
files=()
+filt=MAR
+if(~ $#uncommitted 1)
+ filt=MARU
if(! ~ $#* 0)
files=`{cleanname -d $gitrel $*}
branch=`{git/query -p $commit}
-if(~ $summarize 1){
- git/walk -fMAR $files
+if(~ $summarize 1 || ~ $uncommitted 1){
+ git/walk -f$filt $cparam $files
exit
}
-fn lsdirty {
- git/walk -c -fRMA $files
- if(! ~ $commit HEAD)
- git/query -c $commit HEAD | subst '^..'
-}
-
showed=()
mntgen /mnt/scratch
bind $branch/tree/ /mnt/scratch/a
bind . /mnt/scratch/b
-for(f in `$nl{lsdirty | sort | uniq}){
+for(f in `$nl{git/walk -c -f$filt $cparam $files}){
if(~ $#showed 0){
echo diff `{git/query $commit} uncommitted
showed=1
--- a/get.c
+++ b/get.c
@@ -219,8 +219,6 @@
return -1;
if(n == 0)
break;
- if(strncmp(buf, "ERR ", 4) == 0)
- sysfatal("%s", buf + 4);
if(first && n > strlen(buf))
handlecaps(buf + strlen(buf) + 1);
--- a/git.h
+++ b/git.h
@@ -10,7 +10,6 @@
typedef struct Delta Delta;
typedef struct Cinfo Cinfo;
typedef struct Tinfo Tinfo;
-typedef struct Ginfo Ginfo;
typedef struct Object Object;
typedef struct Objset Objset;
typedef struct Pack Pack;
@@ -130,7 +129,6 @@
union {
Cinfo *commit;
Tinfo *tree;
- Ginfo *tag;
};
};
@@ -147,18 +145,6 @@
Hash tree;
char *author;
char *committer;
- char *msg;
- int nmsg;
- vlong ctime;
- vlong mtime;
-};
-
-struct Ginfo {
- /* Tag */
- Hash object;
- char *tagger;
- char *type;
- char *tag;
char *msg;
int nmsg;
vlong ctime;
--- a/import
+++ b/import
@@ -98,7 +98,8 @@
if(~ $#nocommit 0){
if(hash=`{git/save -n $aname -e $amail -N $name -E $email -m $msg -d $date $parents $files}){
echo $hash > $refpath
- rm -f .git/index9/removed/$files
+ for(f in $files)
+ echo T NOQID 0 $f >> .git/INDEX9
}
}
status=''''
--- a/init
+++ b/init
@@ -31,7 +31,7 @@
echo '[branch "'$branch'"]'
echo ' remote = origin'
}
-
+>$dir/.git/INDEX9
>$dir/.git/HEAD {
echo ref: refs/heads/$branch
}
--- a/merge
+++ b/merge
@@ -38,8 +38,8 @@
git/revert .
exit ''
}
-echo $ours >> .git/index9/merge-parents
-echo $theirs >> .git/index9/merge-parents
+echo $ours >> .git/merge-parents
+echo $theirs >> .git/merge-parents
merge $ours $base $theirs
>[1=2] echo 'merge complete: remember to commit'
--- a/pack.c
+++ b/pack.c
@@ -908,46 +908,6 @@
}
static void
-parsetag(Object *o)
-{
- char *p, buf[128];
- int np;
-
- p = o->data;
- np = o->size;
- o->tag = emalloc(sizeof(Ginfo));
- while(1){
- if(scanword(&p, &np, buf, sizeof(buf)) == -1)
- break;
- if(strcmp(buf, "object") == 0){
- if(scanword(&p, &np, buf, sizeof(buf)) == -1)
- sysfatal("invalid commit: tree missing");
- if(hparse(&o->tag->object, buf) == -1)
- sysfatal("invalid commit: garbled tree");
- }else if(strcmp(buf, "tagger") == 0){
- parseauthor(&p, &np, &o->commit->author, &o->tag->mtime);
- }else if(strcmp(buf, "type") == 0){
- if(scanword(&p, &np, buf, sizeof(buf)) == -1)
- sysfatal("bad tag type");
- if((o->tag->type = strdup(buf)) == nil)
- sysfatal("strdup: %r");
- }else if(strcmp(buf, "tag") == 0){
- if(scanword(&p, &np, buf, sizeof(buf)) == -1)
- sysfatal("bad tag type");
- if((o->tag->type = strdup(buf)) == nil)
- sysfatal("strdup: %r");
- }
- nextline(&p, &np);
- }
- while (np && isspace(*p)) {
- p++;
- np--;
- }
- o->commit->msg = p;
- o->commit->nmsg = np;
-}
-
-static void
parsetree(Object *o)
{
int m, a, entsz, nent;
@@ -1001,6 +961,12 @@
o->tree->ent = ent;
o->tree->nent = nent;
}
+
+static void
+parsetag(Object *)
+{
+}
+
void
parseobject(Object *o)
{
--- a/proto.c
+++ b/proto.c
@@ -75,6 +75,12 @@
sysfatal("pktline: undersize buffer");
if(readn(c->rfd, buf, n) != n)
return -1;
+ if(n > 4 && strncmp(buf, "ERR ", 4) == 0){
+ if((e = strrchr(buf, '\n')) != nil)
+ *e = '\0';
+ werrstr("%s", buf + 4);
+ return -1;
+ }
buf[n] = 0;
tracepkt(1, "=r=>", buf, n);
return n;
--- a/revert
+++ b/revert
@@ -8,12 +8,12 @@
if (! eval `''{aux/getflags $*} || ~ $#* 0)
exec aux/usage
-commit=$gitfs/HEAD
-if(~ $#query 1)
- commit=`{git/query -p $query}
+if(~ $#query 0)
+ query=HEAD
+commit=`{git/query -p $query}
files=`$nl{cleanname -d $gitrel $* | drop $gitroot}
-for(f in `$nl{cd $commit/tree/ && walk -f ./$files}){
+for(f in `$nl{git/walk -c -fRM -b $query $files}){
mkdir -p `{basename -d $f}
cp -x -- $commit/tree/$f $f
touch $f
--- a/send.c
+++ b/send.c
@@ -149,8 +149,6 @@
if(first && n > strlen(buf))
parsecaps(buf + strlen(buf) + 1, &cs);
first = 0;
- if(strncmp(buf, "ERR ", 4) == 0)
- sysfatal("%s", buf + 4);
if(getfields(buf, sp, nelem(sp), 1, " \t\r\n") != 2)
sysfatal("invalid ref line %.*s", utfnlen(buf, n), buf);
--- a/serve.c
+++ b/serve.c
@@ -8,6 +8,19 @@
char *pathpfx = nil;
int allowwrite;
+_Noreturn static void
+fail(Conn *c, char *fmt, ...)
+{
+ char msg[ERRMAX];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprint(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ fmtpkt(c, "ERR %s\n", msg);
+ sysfatal("%s", msg);
+}
+
int
showrefs(Conn *c)
{
@@ -24,7 +37,7 @@
goto error;
if((nrefs = listrefs(&refs, &names)) == -1)
- sysfatal("listrefs: %r");
+ fail(c, "listrefs: %r");
for(i = 0; i < nrefs; i++){
if(strncmp(names[i], "heads/", strlen("heads/")) != 0)
continue;
@@ -128,10 +141,10 @@
dprint(1, "negotiating pack\n");
if(servnegotiate(c, &head, &nhead, &tail, &ntail) == -1)
- sysfatal("negotiate: %r");
+ fail(c, "negotiate: %r");
dprint(1, "writing pack\n");
if(writepack(c->wfd, head, nhead, tail, ntail, &h) == -1)
- sysfatal("send: %r");
+ fail(c, "send: %r");
return 0;
}
@@ -138,6 +151,7 @@
int
validref(char *s)
{
+ cleanname(s);
if(strncmp(s, "refs/", 5) != 0)
return 0;
for(; *s != '\0'; s++)
@@ -149,7 +163,7 @@
int
recvnegotiate(Conn *c, Hash **cur, Hash **upd, char ***ref, int *nupd)
{
- char pkt[Pktmax], *sp[4];
+ char pkt[Pktmax], refpath[512], *sp[4];
Hash old, new;
int n, i;
@@ -186,6 +200,16 @@
(*cur)[*nupd] = old;
(*upd)[*nupd] = new;
(*ref)[*nupd] = estrdup(sp[2]);
+ n = snprint(refpath, sizeof(refpath), ".git/%s", sp[2]);
+ if(n >= sizeof(refpath)-1){
+ fmtpkt(c, "ERR invalid ref %s\n", sp[2]);
+ goto error;
+ }
+ if(access(refpath, AWRITE) == -1
+ && access(refpath, AEXIST) == 0){
+ fmtpkt(c, "ERR read-only ref %s\n", sp[2]);
+ goto error;
+ }
*nupd += 1;
}
return 0;
@@ -446,8 +470,10 @@
char **ref;
int nupd;
+ if(!allowwrite)
+ fail(c, "read-only repo");
if(recvnegotiate(c, &cur, &upd, &ref, &nupd) == -1)
- sysfatal("negotiate refs: %r");
+ fail(c, "negotiate refs: %r");
if(nupd != 0 && updatepack(c) == -1)
sysfatal("update pack: %r");
if(nupd != 0 && updaterefs(c, cur, upd, ref, nupd) == -1)
@@ -520,20 +546,18 @@
repo = parsecmd(buf, cmd, sizeof(cmd));
cleanname(repo);
if(strncmp(repo, "../", 3) == 0)
- sysfatal("invalid path %s\n", repo);
- if(bind(repo, "/", MREPL) == -1){
- fmtpkt(&c, "ERR no repo %r\n");
- sysfatal("enter %s: %r", repo);
- }
+ fail(&c, "invalid path %s\n", repo);
+ if(bind(repo, "/", MREPL) == -1)
+ fail(&c, "no such repo", repo);
if(chdir("/") == -1)
- sysfatal("chdir: %r");
+ fail(&c, "no such repo");
if(access(".git", AREAD) == -1)
- sysfatal("no git repository");
- if(strcmp(cmd, "git-receive-pack") == 0 && allowwrite)
+ fail(&c, "no such repo");
+ if(strcmp(cmd, "git-receive-pack") == 0)
recvpack(&c);
else if(strcmp(cmd, "git-upload-pack") == 0)
servpack(&c);
else
- sysfatal("unsupported command '%s'", cmd);
+ fail(&c, "unsupported command '%s'", cmd);
exits(nil);
}