M commit => commit +2 -17
@@ 2,21 2,6 @@
rfork ne
. /sys/lib/git/common.rc
-fn whoami{
- name=`{git/conf user.name}
- email=`{git/conf user.email}
- if(test -f /adm/keys.who){
- if(~ $name '')
- name=`{awk -F'|' '$1=="'$user'" {x=$3} END{print x}' </adm/keys.who}
- if(~ $email '')
- email=`{awk -F'|' '$1=="'$user'" {x=$5} END{print x}' </adm/keys.who}
- }
- if(~ $name '')
- name=glenda
- if(~ $email '')
- email=glenda@9front.local
-}
-
fn findbranch{
branch=`{git/branch}
if(test -e $gitfs/branch/$branch/tree){
@@ 58,7 43,7 @@ fn editmsg{
echo '#'
for(p in $parents)
echo '# parent:' $p
- git/walk -fAMR $files | subst -g '^' '# '
+ git/walk -fAMR $files | subst '^' '# '
echo '#'
echo '# Commit message:'
}
@@ 92,7 77,7 @@ fn commit{
msg=`''{cat $msgfile}
if(! ~ $#parents 0)
pflags='-p'^$parents
- hash=`{git/save -n $"name -e $"email -m $"msg $pflags $files || die $status}
+ hash=`{git/save -n $"name -e $"email -m $"msg $pflags $files || die $status}
rm -f .git/index9/merge-parents
}
M common.rc => common.rc +4 -4
@@ 39,13 39,13 @@ fn present {
}
fn whoami{
- name=`{git/conf user.name}
- email=`{git/conf user.email}
+ name=`$nl{git/conf user.name}
+ email=`$nl{git/conf user.email}
if(test -f /adm/keys.who){
if(~ $name '')
- name=`{awk -F'|' '$1=="'$user'" {x=$3} END{print x}' </adm/keys.who}
+ name=`$nl{awk -F'|' '$1=="'$user'" {x=$3} END{print x}' </adm/keys.who}
if(~ $email '')
- email=`{awk -F'|' '$1=="'$user'" {x=$5} END{print x}' </adm/keys.who}
+ email=`$nl{awk -F'|' '$1=="'$user'" {x=$5} END{print x}' </adm/keys.who}
}
if(~ $name '')
name=glenda
M compat => compat +10 -0
@@ 125,6 125,15 @@ fn cmd_remote{
}
}
+fn cmd_ls-remote{
+ if(~ $1 -q)
+ shift
+ remote=`$nl{git/conf 'remote "'$1'".url'}
+ if(~ $#remote 0)
+ remote=$1
+ git/fetch -l $remote | awk '/^remote/{print $3"\t"$2}'
+}
+
fn cmd_version{
echo git version 2.2.0
}
@@ 154,5 163,6 @@ if(! test -f '/env/fn#cmd_'$1)
if(! ~ $1 init && ! ~ $1 clone)
gitroot=`{git/conf -r} || die repo
+echo $* >/tmp/gitlog
cmd_$1 $*(2-)
exit ''
M diff => diff +16 -6
@@ 26,12 26,22 @@ fn lsdirty {
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}){
- orig=$branch/tree/$f
- if(! test -f $orig)
- orig=/dev/null
- if(! test -f $f)
- f=/dev/null
- diff -u $orig $f
+ if(~ $#showed 0){
+ echo diff `{git/query $commit} uncommitted
+ showed=1
+ }
+ cd /mnt/scratch
+ a=a/$f
+ b=b/$f
+ if(! test -f a/$f)
+ a=/dev/null
+ if(! test -f b/$f)
+ b=/dev/null
+ diff -u $a $b
}
exit ''
M fs.c => fs.c +38 -30
@@ 12,12 12,13 @@ enum {
Qhead,
Qbranch,
Qcommit,
- Qcommitmsg,
- Qcommitparent,
- Qcommittree,
- Qcommitdata,
- Qcommithash,
- Qcommitauthor,
+ Qmsg,
+ Qparent,
+ Qtree,
+ Qcdata,
+ Qhash,
+ Qauthor,
+ Qcommitter,
Qobject,
Qctl,
Qmax,
@@ 284,23 285,23 @@ gcommitgen(int i, Dir *d, void *p)
d->mode = 0755 | DMDIR;
d->name = estrdup9p("tree");
d->qid.type = QTDIR;
- d->qid.path = qpath(c, i, o->id, Qcommittree);
+ d->qid.path = qpath(c, i, o->id, Qtree);
break;
case 1:
d->name = estrdup9p("parent");
- d->qid.path = qpath(c, i, o->id, Qcommitparent);
+ d->qid.path = qpath(c, i, o->id, Qparent);
break;
case 2:
d->name = estrdup9p("msg");
- d->qid.path = qpath(c, i, o->id, Qcommitmsg);
+ d->qid.path = qpath(c, i, o->id, Qmsg);
break;
case 3:
d->name = estrdup9p("hash");
- d->qid.path = qpath(c, i, o->id, Qcommithash);
+ d->qid.path = qpath(c, i, o->id, Qhash);
break;
case 4:
d->name = estrdup9p("author");
- d->qid.path = qpath(c, i, o->id, Qcommitauthor);
+ d->qid.path = qpath(c, i, o->id, Qauthor);
break;
default:
return -1;
@@ 491,18 492,20 @@ objwalk1(Qid *q, Object *o, Crumb *p, Crumb *c, char *name, vlong qdir, Gitaux *
q->type = 0;
c->mtime = o->commit->mtime;
c->mode = 0644;
- assert(qdir == Qcommit || qdir == Qobject || qdir == Qcommittree || qdir == Qhead);
+ assert(qdir == Qcommit || qdir == Qobject || qdir == Qtree || qdir == Qhead || qdir == Qcommitter);
if(strcmp(name, "msg") == 0)
- q->path = qpath(p, 0, o->id, Qcommitmsg);
+ q->path = qpath(p, 0, o->id, Qmsg);
else if(strcmp(name, "parent") == 0)
- q->path = qpath(p, 1, o->id, Qcommitparent);
+ q->path = qpath(p, 1, o->id, Qparent);
else if(strcmp(name, "hash") == 0)
- q->path = qpath(p, 2, o->id, Qcommithash);
+ q->path = qpath(p, 2, o->id, Qhash);
else if(strcmp(name, "author") == 0)
- q->path = qpath(p, 3, o->id, Qcommitauthor);
+ q->path = qpath(p, 3, o->id, Qauthor);
+ else if(strcmp(name, "committer") == 0)
+ q->path = qpath(p, 3, o->id, Qcommitter);
else if(strcmp(name, "tree") == 0){
q->type = QTDIR;
- q->path = qpath(p, 4, o->id, Qcommittree);
+ q->path = qpath(p, 4, o->id, Qtree);
unref(c->obj);
c->mode = DMDIR | 0755;
c->obj = readobject(o->commit->tree);
@@ 640,14 643,15 @@ gitwalk1(Fid *fid, char *name, Qid *q)
case Qcommit:
e = objwalk1(q, o->obj, o, c, name, Qcommit, aux);
break;
- case Qcommittree:
- e = objwalk1(q, o->obj, o, c, name, Qcommittree, aux);
+ case Qtree:
+ e = objwalk1(q, o->obj, o, c, name, Qtree, aux);
break;
- case Qcommitparent:
- case Qcommitmsg:
- case Qcommitdata:
- case Qcommithash:
- case Qcommitauthor:
+ case Qparent:
+ case Qmsg:
+ case Qcdata:
+ case Qhash:
+ case Qauthor:
+ case Qcommitter:
case Qctl:
return Enodir;
default:
@@ 760,20 764,24 @@ gitread(Req *r)
else
dirread9p(r, objgen, aux);
break;
- case Qcommitmsg:
+ case Qmsg:
readbuf(r, o->commit->msg, o->commit->nmsg);
break;
- case Qcommitparent:
+ case Qparent:
readcommitparent(r, o);
break;
- case Qcommithash:
+ case Qhash:
snprint(buf, sizeof(buf), "%H\n", o->hash);
readstr(r, buf);
break;
- case Qcommitauthor:
+ case Qauthor:
snprint(buf, sizeof(buf), "%s\n", o->commit->author);
readstr(r, buf);
break;
+ case Qcommitter:
+ snprint(buf, sizeof(buf), "%s\n", o->commit->committer);
+ readstr(r, buf);
+ break;
case Qctl:
e = readctl(r);
break;
@@ 785,8 793,8 @@ gitread(Req *r)
objread(r, aux);
break;
case Qcommit:
- case Qcommittree:
- case Qcommitdata:
+ case Qtree:
+ case Qcdata:
objread(r, aux);
break;
default:
M import => import +15 -13
@@ 7,11 7,13 @@ fn sigexit {
rm -f $diffpath
}
+
fn apply @{
git/fs
- email=''
- name=''
+ amail=''
+ aname=''
msg=''
+ whoami
parents='-p'^`{git/query HEAD}
branch=`{git/branch}
if(test -e $gitfs/branch/$branch/tree)
@@ 26,11 28,11 @@ fn apply @{
}
state=="headers" && /^From:/ {
sub(/^From:[ \t]*/, "", $0);
- name=$0;
- email=$0;
- sub(/[ \t]*<.*$/, "", name);
- sub(/.*</, "", email);
- sub(/>/, "", email);
+ aname=$0;
+ amail=$0;
+ sub(/[ \t]*<.*$/, "", aname);
+ sub(/^[^<]*</, "", amail);
+ sub(/>[^>]*$/, "", amail);
}
state=="headers" && /^Date:/{
sub(/^Date:[ \t]*/, "", $0)
@@ 45,7 47,7 @@ fn apply @{
state="body"
next
}
- (state=="headers" || state=="body") && (/^diff/ || /^---[ ]*$/){
+ (state=="headers" || state=="body") && (/^diff / || /^---( |$)/){
state="diff"
}
state=="body" {
@@ 57,10 59,10 @@ fn apply @{
END{
if(state != "diff")
exit("malformed patch: " state);
- if(name == "" || email == "" || date == "" || gotmsg == "")
+ if(aname == "" || amail == "" || date == "" || gotmsg == "")
exit("missing headers");
- printf "%s", name > "/env/name"
- printf "%s", email > "/env/email"
+ printf "%s", aname > "/env/aname"
+ printf "%s", amail > "/env/amail"
printf "%s", date > "/env/date"
}
' || die 'could not import:' $status
@@ 79,8 81,8 @@ fn apply @{
}
git/walk -fRMA $files
if(~ $#nocommit 0){
- hash=`{git/save -n $name -e $email -m $msg -d $date $parents $files}
- echo $hash > $refpath
+ if(hash=`{git/save -n $aname -e $amail -N $name -E $email -m $msg -d $date $parents $files})
+ echo $hash > $refpath
}
status=''''
'
M log.c => log.c +16 -67
@@ 15,10 15,8 @@ char *queryexpr;
char *commitid;
int shortlog;
-Object **heap;
-int nheap;
-int heapsz;
Objset done;
+Objq objq;
Pfilt *pathfilt;
void
@@ 153,6 151,9 @@ show(Object *o)
tmtime(&tm, o->commit->mtime, tzload("local"));
Bprint(out, "Hash:\t%H\n", o->hash);
Bprint(out, "Author:\t%s\n", o->commit->author);
+ if(o->commit->committer != nil
+ && strcmp(o->commit->author, o->commit->committer) != 0)
+ Bprint(out, "Commiter:\t%s\n", o->commit->committer);
Bprint(out, "Date:\t%Ï„\n", tmfmt(&tm, "WW MMM D hh:mm:ss z YYYY"));
Bprint(out, "\n");
p = o->commit->msg;
@@ 189,64 190,10 @@ showquery(char *q)
}
static void
-qput(Object *o)
-{
- Object *p;
- int i;
-
- if(oshas(&done, o->hash))
- return;
- osadd(&done, o);
- if(nheap == heapsz){
- heapsz *= 2;
- heap = earealloc(heap, heapsz, sizeof(Object*));
- }
- heap[nheap++] = o;
- for(i = nheap - 1; i > 0; i = (i-1)/2){
- o = heap[i];
- p = heap[(i-1)/2];
- if(o->commit->mtime < p->commit->mtime)
- break;
- heap[i] = p;
- heap[(i-1)/2] = o;
- }
-}
-
-static Object*
-qpop(void)
-{
- Object *o, *t;
- int i, l, r, m;
-
- if(nheap == 0)
- return nil;
-
- i = 0;
- o = heap[0];
- t = heap[--nheap];
- heap[0] = t;
- while(1){
- m = i;
- l = 2*i+1;
- r = 2*i+2;
- if(l < nheap && heap[m]->commit->mtime < heap[l]->commit->mtime)
- m = l;
- if(r < nheap && heap[m]->commit->mtime < heap[r]->commit->mtime)
- m = r;
- else
- break;
- t = heap[m];
- heap[m] = heap[i];
- heap[i] = t;
- i = m;
- }
- return o;
-}
-
-static void
showcommits(char *c)
{
Object *o, *p;
+ Qelt e;
int i;
Hash h;
@@ 256,18 203,20 @@ showcommits(char *c)
sysfatal("resolve %s: %r", c);
if((o = readobject(h)) == nil)
sysfatal("load %H: %r", h);
- heapsz = 8;
- heap = eamalloc(heapsz, sizeof(Object*));
+ qinit(&objq);
osinit(&done);
- qput(o);
- while((o = qpop()) != nil){
- show(o);
- for(i = 0; i < o->commit->nparent; i++){
- if((p = readobject(o->commit->parent[i])) == nil)
+ qput(&objq, o, 0, 0);
+ while(qpop(&objq, &e)){
+ show(e.o);
+ for(i = 0; i < e.o->commit->nparent; i++){
+ if(oshas(&done, e.o->commit->parent[i]))
+ continue;
+ if((p = readobject(e.o->commit->parent[i])) == nil)
sysfatal("load %H: %r", o->commit->parent[i]);
- qput(p);
+ osadd(&done, p);
+ qput(&objq, p, 0, 0);
}
- unref(o);
+ unref(e.o);
}
}
M merge => merge +1 -1
@@ 12,7 12,7 @@ fn merge{
ours=$ourbr/$f
base=$basebr/$f
theirs=$theirbr/$f
- merge1 ./$f $theirs $base $ours
+ merge1 ./$f $ours $base $theirs
}
}
M mkfile => mkfile +6 -0
@@ 51,6 51,12 @@ install:V:
mk $MKFLAGS $i.install
for (i in $RC)
mk $MKFLAGS $i.rcinstall
+ cp git.1.man /sys/man/1/git
+ cp gitfs.4.man /sys/man/4/gitfs
+ cp common.rc /sys/lib/git/common.rc
+
+uninstall:V:
+ rm -rf $BIN /sys/lib/git /sys/man/1/git /sys/man/4/gitfs
%.rcinstall:V:
cp $stem $BIN/$stem
M query.c => query.c +1 -0
@@ 158,6 158,7 @@ main(int argc, char **argv)
char query[2048], repo[512];
ARGBEGIN{
+ case 'd': chattygit++; break;
case 'p': fullpath++; break;
case 'c': changes++; break;
case 'r': reverse ^= 1; break;
M ref.c => ref.c +166 -248
@@ 5,8 5,20 @@
#include "git.h"
typedef struct Eval Eval;
-typedef struct XObject XObject;
-typedef struct Objq Objq;
+typedef struct Lcaq Lcaq;
+
+struct Lcaq {
+ Objq;
+
+ Hash *head;
+ Hash *tail;
+ int nhead;
+ int ntail;
+
+ Object *best;
+ int dist;
+};
+
enum {
Blank,
@@ 22,17 34,10 @@ struct Eval {
int stksz;
};
-struct XObject {
- Object *obj;
- Object *mark;
- XObject *queue;
- XObject *next;
-};
-
-struct Objq {
- Objq *next;
- Object *o;
- int color;
+static char *colors[] = {
+[Keep] "keep",
+[Drop] "drop",
+[Blank] "blank",
};
static Object zcommit = {
@@ 128,213 133,98 @@ take(Eval *ev, char *m)
return 1;
}
-XObject*
-hnode(XObject *ht[], Object *o)
-{
- XObject *h;
- int hh;
-
- hh = o->hash.h[0] & 0xff;
- for(h = ht[hh]; h; h = h->next)
- if(hasheq(&o->hash, &h->obj->hash))
- return h;
-
- h = emalloc(sizeof(*h));
- h->obj = o;
- h->mark = nil;
- h->queue = nil;
- h->next = ht[hh];
- ht[hh] = h;
- return h;
-}
-
-Object*
-ancestor(Object *a, Object *b)
+static int
+pickbest(Lcaq *q, Qelt *e, int color)
{
- Object *o, *p, *r;
- XObject *ht[256];
- XObject *h, *q, *q1, *q2;
- int i;
-
- if(a == b)
- return a;
- if(a == nil || b == nil)
- return nil;
- r = nil;
- memset(ht, 0, sizeof(ht));
- q1 = nil;
-
- h = hnode(ht, a);
- h->mark = a;
- h->queue = q1;
- q1 = h;
+ int i, best, exact;
- h = hnode(ht, b);
- h->mark = b;
- h->queue = q1;
- q1 = h;
-
- while(1){
- q2 = nil;
- while(q = q1){
- q1 = q->queue;
- q->queue = nil;
- o = q->obj;
- for(i = 0; i < o->commit->nparent; i++){
- p = readobject(o->commit->parent[i]);
- if(p == nil)
- goto err;
- h = hnode(ht, p);
- if(h->mark != nil){
- if(h->mark != q->mark){
- r = h->obj;
- goto done;
- }
- } else {
- h->mark = q->mark;
- h->queue = q2;
- q2 = h;
- }
- }
- }
- if(q2 == nil){
-err:
- werrstr("no common ancestor");
- break;
- }
- q1 = q2;
+ best = 0;
+ exact = 0;
+ if(color == Blank || e->color == color)
+ return 0;
+ if(e->dist < q->dist){
+ dprint(1, "found best (dist %d < %d): %H\n", e->dist, q->dist, e->o->hash);
+ best = 1;
}
-done:
- for(i=0; i<nelem(ht); i++){
- while(h = ht[i]){
- ht[i] = h->next;
- free(h);
+ for(i = 0; i < q->nhead; i++)
+ if(hasheq(&q->head[i], &e->o->hash)){
+ dprint(1, "found best (exact head): %H\n", e->o->hash);
+ best = 1;
+ exact = 1;
}
+ for(i = 0; i < q->ntail; i++)
+ if(hasheq(&q->tail[i], &e->o->hash)){
+ dprint(1, "found best (exact tail): %H\n", e->o->hash);
+ best = 1;
+ exact = 1;
+ }
+ if(best){
+ q->best = e->o;
+ q->dist = e->dist;
}
- return r;
-}
-
-int
-lca(Eval *ev)
-{
- Object *a, *b, *o;
-
- if(ev->nstk < 2){
- werrstr("ancestor needs 2 objects");
- return -1;
- }
- a = pop(ev);
- b = pop(ev);
- o = ancestor(a, b);
- if(o == nil)
- return -1;
- push(ev, o);
- return 0;
+ return exact;
}
-int
-parentof(Eval *ev)
+static int
+repaint(Lcaq *lcaq, Objset *keep, Objset *drop, Object *o, int dist, int ancestor)
{
- Objq *q, *n, *e;
- Object *p, *c;
- Objset seen;
- int i, r;
+ Lcaq objq;
+ Qelt e;
+ Object *p;
+ int i;
- print("parentof\n");
- if(ev->nstk < 2){
- werrstr("parentof needs 2 objects");
+ qinit(&objq);
+ if((o = readobject(o->hash)) == nil)
return -1;
- }
- osinit(&seen);
- r = 0;
- p = pop(ev);
- c = pop(ev);
- q = emalloc(sizeof(Objq));
- q->o = ref(p);
- e = q;
- if(p->type != GCommit || c->type != GCommit){
- werrstr("object is not commit");
- return -1;
- }
- while(q != nil){
- if(oshas(&seen, q->o->hash))
- goto next;
- osadd(&seen, q->o);
- if(hasheq(&q->o->hash, &c->hash)){
- push(ev, c);
+ qput(&objq, o, Drop, dist);
+ while(qpop(&objq, &e)){
+ o = e.o;
+ if(oshas(drop, o->hash))
+ continue;
+ if(ancestor && pickbest(lcaq, &e, Keep))
goto out;
+ if(!oshas(keep, o->hash)){
+ dprint(2, "repaint: blank => drop %H\n", o->hash);
+ osadd(drop, o);
+ continue;
}
- for(i = 0; i < q->o->commit->nparent; i++){
- if((c = readobject(q->o->commit->parent[i])) == nil){
- r = -1;
- goto out;
- }
- if(c->type != GCommit){
- fprint(2, "warning: %H does not point at commit\n", c->hash);
- unref(c);
+ for(i = 0; i < o->commit->nparent; i++){
+ if(oshas(drop, o->commit->parent[i]))
continue;
+ if((p = readobject(o->commit->parent[i])) == nil)
+ goto out;
+ if(p->type != GCommit){
+ fprint(2, "hash %H not commit\n", p->hash);
+ unref(p);
}
- n = emalloc(sizeof(Objq));
- n->next = nil;
- n->o = c;
- e->next = n;
- e = n;
- unref(c);
+ qput(&objq, p, Drop, e.dist+1);
}
-next:
- n = q->next;
- free(q);
- q = n;
+ unref(e.o);
}
out:
- osclear(&seen);
- for(; q != nil; q = n) {
- n = q->next;
- free(q);
- }
- return r;
-}
-
-static int
-repaint(Objset *keep, Objset *drop, Object *o)
-{
- Object *p;
- int i;
-
- if(!oshas(keep, o->hash) && !oshas(drop, o->hash)){
- dprint(2, "repaint: blank => drop %H\n", o->hash);
- osadd(drop, o);
- return 0;
- }
- if(oshas(keep, o->hash))
- dprint(2, "repaint: keep => drop %H\n", o->hash);
- osadd(drop, o);
- for(i = 0; i < o->commit->nparent; i++){
- if((p = readobject(o->commit->parent[i])) == nil)
- return -1;
- if(repaint(keep, drop, p) == -1)
- return -1;
- unref(p);
- }
+ qclear(&objq);
return 0;
}
-int
-findtwixt(Hash *head, int nhead, Hash *tail, int ntail, Object ***res, int *nres)
+static int
+paint(Hash *head, int nhead, Hash *tail, int ntail, Object ***res, int *nres, int ancestor)
{
- Objq *q, *e, *n, **p;
+ Qelt e;
+ Lcaq objq;
Objset keep, drop;
Object *o, *c;
int i, ncolor;
- e = nil;
- q = nil;
- p = &q;
osinit(&keep);
osinit(&drop);
+ qinit(&objq);
+ objq.head = head;
+ objq.nhead = nhead;
+ objq.tail = tail;
+ objq.ntail = ntail;
+ objq.dist = 1<<30;
+
for(i = 0; i < nhead; i++){
- if(hasheq(&head[i], &Zhash))
- continue;
if((o = readobject(head[i])) == nil){
fprint(2, "warning: %H does not point at commit\n", o->hash);
werrstr("read head %H: %r", head[i]);
@@ 345,17 235,11 @@ findtwixt(Hash *head, int nhead, Hash *tail, int ntail, Object ***res, int *nres
unref(o);
continue;
}
- dprint(1, "twixt init: keep %H\n", o->hash);
- e = emalloc(sizeof(Objq));
- e->o = o;
- e->color = Keep;
- *p = e;
- p = &e->next;
+ dprint(1, "init: keep %H\n", o->hash);
+ qput(&objq, o, Keep, 0);
unref(o);
}
for(i = 0; i < ntail; i++){
- if(hasheq(&tail[i], &Zhash))
- continue;
if((o = readobject(tail[i])) == nil){
werrstr("read tail %H: %r", tail[i]);
return -1;
@@ 366,78 250,117 @@ findtwixt(Hash *head, int nhead, Hash *tail, int ntail, Object ***res, int *nres
continue;
}
dprint(1, "init: drop %H\n", o->hash);
- e = emalloc(sizeof(Objq));
- e->o = o;
- e->color = Drop;
- *p = e;
- p = &e->next;
+ qput(&objq, o, Drop, 0);
unref(o);
}
dprint(1, "finding twixt commits\n");
- while(q != nil){
- if(oshas(&drop, q->o->hash))
+ while(qpop(&objq, &e)){
+ if(oshas(&drop, e.o->hash))
ncolor = Drop;
- else if(oshas(&keep, q->o->hash))
+ else if(oshas(&keep, e.o->hash))
ncolor = Keep;
else
ncolor = Blank;
- if(ncolor == Drop || ncolor == Keep && q->color == Keep)
- goto next;
- if(ncolor == Keep && q->color == Drop){
- if(repaint(&keep, &drop, q->o) == -1)
+ if(ancestor && pickbest(&objq, &e, ncolor))
+ goto exactlca;
+ if(ncolor == Keep && e.color == Keep || ncolor == Drop)
+ continue;
+ if(ncolor == Keep && e.color == Drop){
+ if(repaint(&objq, &keep, &drop, e.o, e.dist, ancestor) == -1)
goto error;
}else if (ncolor == Blank) {
- dprint(2, "visit: %s %H\n", q->color == Keep ? "keep" : "drop", q->o->hash);
- if(q->color == Keep)
- osadd(&keep, q->o);
+ if(e.color == Keep)
+ osadd(&keep, e.o);
else
- osadd(&drop, q->o);
- for(i = 0; i < q->o->commit->nparent; i++){
- if((c = readobject(q->o->commit->parent[i])) == nil)
+ osadd(&drop, e.o);
+ o = readobject(e.o->hash);
+ for(i = 0; i < o->commit->nparent; i++){
+ if((c = readobject(e.o->commit->parent[i])) == nil)
goto error;
if(c->type != GCommit){
fprint(2, "warning: %H does not point at commit\n", c->hash);
unref(c);
continue;
}
- dprint(2, "enqueue: %s %H\n", q->color == Keep ? "keep" : "drop", c->hash);
- n = emalloc(sizeof(Objq));
- n->color = q->color;
- n->next = nil;
- n->o = c;
- e->next = n;
- e = n;
+ dprint(2, "\tenqueue: %s %H\n", colors[e.color], c->hash);
+ qput(&objq, c, e.color, e.dist+1);
unref(c);
}
- }else{
- sysfatal("oops");
+ unref(o);
}
-next:
- n = q->next;
- unref(q->o);
- free(q);
- q = n;
}
- *res = eamalloc(keep.nobj, sizeof(Object*));
- *nres = 0;
- for(i = 0; i < keep.sz; i++){
- if(keep.obj[i] != nil && !oshas(&drop, keep.obj[i]->hash)){
- (*res)[*nres] = keep.obj[i];
- (*nres)++;
+exactlca:
+ if(ancestor){
+ dprint(1, "found ancestor\n");
+ if(objq.best == nil){
+ *nres = 0;
+ *res = nil;
+ }else{
+ *nres = 1;
+ *res = eamalloc(1, sizeof(Object*));
+ (*res)[0] = objq.best;
+ }
+ }else{
+ dprint(1, "found twixt\n");
+ *res = eamalloc(keep.nobj, sizeof(Object*));
+ *nres = 0;
+ for(i = 0; i < keep.sz; i++){
+ if(keep.obj[i] != nil && !oshas(&drop, keep.obj[i]->hash)){
+ (*res)[*nres] = keep.obj[i];
+ (*nres)++;
+ }
}
}
osclear(&keep);
osclear(&drop);
return 0;
error:
- for(; q != nil; q = n) {
- n = q->next;
- free(q);
- }
+ dprint(1, "twixt error: %r\n");
+ free(objq.heap);
return -1;
}
+int
+findtwixt(Hash *head, int nhead, Hash *tail, int ntail, Object ***res, int *nres)
+{
+ return paint(head, nhead, tail, ntail, res, nres, 0);
+}
+
+Object*
+ancestor(Object *a, Object *b)
+{
+ Object **o, *r;
+ int n;
+
+ if(paint(&a->hash, 1, &b->hash, 1, &o, &n, 1) == -1 || n == 0)
+ return nil;
+ r = o[0];
+ free(o);
+ return ref(r);
+}
+
+int
+lca(Eval *ev)
+{
+ Object *a, *b, **o;
+ int n;
+
+ if(ev->nstk < 2){
+ werrstr("ancestor needs 2 objects");
+ return -1;
+ }
+ n = 0;
+ b = pop(ev);
+ a = pop(ev);
+ paint(&a->hash, 1, &b->hash, 1, &o, &n, 1);
+ if(n == 0)
+ return -1;
+ push(ev, *o);
+ free(o);
+ return 0;
+}
+
static int
parent(Eval *ev)
{
@@ 609,18 532,13 @@ evalpostfix(Eval *ev)
while(1){
eatspace(ev);
- switch(*ev->p){
+ switch(ev->p[0]){
case '^':
case '~':
ev->p++;
if(parent(ev) == -1)
return -1;
break;
- case '<':
- ev->p++;
- if(parentof(ev) == -1)
- return -1;
- break;
case '@':
ev->p++;
if(lca(ev) == -1)
M save.c => save.c +44 -21
@@ 14,6 14,14 @@ enum {
Maxparents = 16,
};
+char *authorname;
+char *authoremail;
+char *committername;
+char *committeremail;
+char *commitmsg;
+Hash parents[Maxparents];
+int nparents;
+
int
gitmode(Dirent *e)
{
@@ 299,7 307,7 @@ err:
void
-mkcommit(Hash *c, char *msg, char *name, char *email, vlong date, Hash *parents, int nparents, Hash tree)
+mkcommit(Hash *c, vlong date, Hash tree)
{
char *s, h[64];
int ns, nh, i;
@@ 309,10 317,10 @@ mkcommit(Hash *c, char *msg, char *name, char *email, vlong date, Hash *parents,
fmtprint(&f, "tree %H\n", tree);
for(i = 0; i < nparents; i++)
fmtprint(&f, "parent %H\n", parents[i]);
- fmtprint(&f, "author %s <%s> %lld +0000\n", name, email, date);
- fmtprint(&f, "committer %s <%s> %lld +0000\n", name, email, date);
+ fmtprint(&f, "author %s <%s> %lld +0000\n", authorname, authoremail, date);
+ fmtprint(&f, "committer %s <%s> %lld +0000\n", committername, committeremail, date);
fmtprint(&f, "\n");
- fmtprint(&f, "%s", msg);
+ fmtprint(&f, "%s", commitmsg);
s = fmtstrflush(&f);
ns = strlen(s);
@@ 346,9 354,9 @@ usage(void)
void
main(int argc, char **argv)
{
- Hash th, ch, parents[Maxparents];
- char *msg, *name, *email, *dstr, cwd[1024];
- int i, r, ncwd, nparents;
+ Hash th, ch;
+ char *dstr, cwd[1024];
+ int i, r, ncwd;
vlong date;
Object *t;
@@ 357,19 365,29 @@ main(int argc, char **argv)
sysfatal("could not find git repo: %r");
if(getwd(cwd, sizeof(cwd)) == nil)
sysfatal("getcwd: %r");
- msg = nil;
- name = nil;
- email = nil;
dstr = nil;
date = time(nil);
- nparents = 0;
ncwd = strlen(cwd);
ARGBEGIN{
- case 'm': msg = EARGF(usage()); break;
- case 'n': name = EARGF(usage()); break;
- case 'e': email = EARGF(usage()); break;
- case 'd': dstr = EARGF(usage()); break;
+ case 'm':
+ commitmsg = EARGF(usage());
+ break;
+ case 'n':
+ authorname = EARGF(usage());
+ break;
+ case 'e':
+ authoremail = EARGF(usage());
+ break;
+ case 'N':
+ committername = EARGF(usage());
+ break;
+ case 'E':
+ committeremail = EARGF(usage());
+ break;
+ case 'd':
+ dstr = EARGF(usage());
+ break;
case 'p':
if(nparents >= Maxparents)
sysfatal("too many parents");
@@ 378,21 396,26 @@ main(int argc, char **argv)
break;
default:
usage();
+ break;
}ARGEND;
- if(!msg)
+ if(commitmsg == nil)
sysfatal("missing message");
- if(!name)
+ if(authorname == nil)
sysfatal("missing name");
- if(!email)
+ if(authoremail == nil)
sysfatal("missing email");
+ if((committername == nil) != (committeremail == nil))
+ sysfatal("partially specified committer");
+ if(committername == nil && committeremail == nil){
+ committername = authorname;
+ committeremail = authoremail;
+ }
if(dstr){
date=strtoll(dstr, &dstr, 10);
if(strlen(dstr) != 0)
sysfatal("could not parse date %s", dstr);
}
- if(msg == nil || name == nil)
- usage();
for(i = 0; i < argc; i++){
cleanname(argv[i]);
if(*argv[i] == '/' && strncmp(argv[i], cwd, ncwd) == 0)
@@ 405,7 428,7 @@ main(int argc, char **argv)
r = treeify(t, argv, argv + argc, 0, &th);
if(r == -1)
sysfatal("could not commit: %r\n");
- mkcommit(&ch, msg, name, email, date, parents, nparents, th);
+ mkcommit(&ch, date, th);
print("%H\n", ch);
exits(nil);
}
M serve.c => serve.c +1 -1
@@ 34,7 34,7 @@ showrefs(Conn *c)
refs = nil;
names = nil;
if(resolveref(&head, "HEAD") != -1)
- if(fmtpkt(c, "%H HEAD", head) == -1)
+ if(fmtpkt(c, "%H HEAD\n", head) == -1)
goto error;
if((nrefs = listrefs(&refs, &names)) == -1)
M util.c => util.c +71 -0
@@ 321,3 321,74 @@ showprogress(int x, int pct)
}
return pct;
}
+
+void
+qinit(Objq *q)
+{
+ memset(q, 0, sizeof(Objq));
+ q->nheap = 0;
+ q->heapsz = 8;
+ q->heap = eamalloc(q->heapsz, sizeof(Qelt));
+}
+
+void
+qclear(Objq *q)
+{
+ free(q->heap);
+}
+
+void
+qput(Objq *q, Object *o, int color, int dist)
+{
+ Qelt t;
+ int i;
+
+ if(q->nheap == q->heapsz){
+ q->heapsz *= 2;
+ q->heap = earealloc(q->heap, q->heapsz, sizeof(Qelt));
+ }
+ q->heap[q->nheap].o = o;
+ q->heap[q->nheap].color = color;
+ q->heap[q->nheap].dist = dist;
+ q->heap[q->nheap].mtime = o->commit->mtime;
+ for(i = q->nheap; i > 0; i = (i-1)/2){
+ if(q->heap[i].mtime < q->heap[(i-1)/2].mtime)
+ break;
+ t = q->heap[i];
+ q->heap[i] = q->heap[(i-1)/2];
+ q->heap[(i-1)/2] = t;
+ }
+ q->nheap++;
+}
+
+int
+qpop(Objq *q, Qelt *e)
+{
+ int i, l, r, m;
+ Qelt t;
+
+ if(q->nheap == 0)
+ return 0;
+ *e = q->heap[0];
+ if(--q->nheap == 0)
+ return 1;
+
+ i = 0;
+ q->heap[0] = q->heap[q->nheap];
+ while(1){
+ m = i;
+ l = 2*i+1;
+ r = 2*i+2;
+ if(l < q->nheap && q->heap[m].mtime < q->heap[l].mtime)
+ m = l;
+ if(r < q->nheap && q->heap[m].mtime < q->heap[r].mtime)
+ m = r;
+ if(m == i)
+ break;
+ t = q->heap[m];
+ q->heap[m] = q->heap[i];
+ q->heap[i] = t;
+ i = m;
+ }
+ return 1;
+}