ref: e4c68a3b4caef3e61db35966e8f7d096648e0345
parent: 768963687f66b324a6442ec46e1d9939944ed37a
author: Ori Bernstein <ori@eigenstate.org>
date: Thu Nov 26 20:01:14 EST 2020
git/send: use pack deltification code Since git/serve landed, git9 has had support for generating deltified pack files. However, out of caution, git/send had been left untouched, using the naïve packfile generation. This change has been applied locally for a while, and the code generating the deltas has been working fine in git/serve, so it's well tested enough.
--- a/import
+++ b/import
@@ -74,7 +74,8 @@
rc -c '
echo applying $msg | sed 1q
date=`{seconds $date}
- files=`$nl{ape/patch -Ep1 < $diffpath | sed ''s/^patching file `(.*)''''/\1/''}
+ if(! files=`$nl{ape/patch -Ep1 < $diffpath | sed ''s/^patching file `(.*)''''/\1/''})
+ die 'patch failed'
for(f in $files){
if(test -e $f)
git/add $f
--- a/push
+++ b/push
@@ -25,7 +25,7 @@
upstream=origin
remotes=`$nl{git/conf -a 'remote "'$upstream'".url'}
-if(~ $#remote 0)
+if(~ $#remotes 0)
remotes=$upstream
branch=-b^$branch
if(! ~ $#remove 0)
--- a/ref.c
+++ b/ref.c
@@ -262,8 +262,12 @@
osinit(&keep);
osinit(&drop);
for(i = 0; i < nhead; i++){
- if((o = readobject(head[i])) == nil)
- sysfatal("read head %H: %r", head[i]);
+ if(hasheq(&head[i], &Zhash))
+ continue;
+ if((o = readobject(head[i])) == nil){
+ werrstr("read head %H: %r", head[i]);
+ return -1;
+ }
dprint(1, "twixt init: keep %H\n", o->hash);
e = emalloc(sizeof(Objq));
e->o = o;
@@ -273,8 +277,12 @@
unref(o);
}
for(i = 0; i < ntail; i++){
- if((o = readobject(tail[i])) == nil)
- sysfatal("read tail %H: %r", tail[i]);
+ if(hasheq(&tail[i], &Zhash))
+ continue;
+ if((o = readobject(tail[i])) == nil){
+ werrstr("read tail %H: %r", tail[i]);
+ return -1;
+ }
dprint(1, "init: drop %H\n", o->hash);
e = emalloc(sizeof(Objq));
e->o = o;
--- a/send.c
+++ b/send.c
@@ -3,34 +3,8 @@
#include "git.h"
-typedef struct Objq Objq;
-typedef struct Buf Buf;
-typedef struct Compout Compout;
-typedef struct Update Update;
typedef struct Capset Capset;
-struct Buf {
- int off;
- int sz;
- uchar *data;
-};
-
-struct Compout {
- int fd;
- DigestState *st;
-};
-
-struct Objq {
- Objq *next;
- Object *obj;
-};
-
-struct Update {
- char ref[128];
- Hash theirs;
- Hash ours;
-};
-
struct Capset {
int sideband;
int sideband64k;
@@ -46,229 +20,32 @@
int npacked;
int nsent;
-static int
-hwrite(int fd, void *buf, int nbuf, DigestState **st)
-{
- if(write(fd, buf, nbuf) != nbuf)
- return -1;
- *st = sha1(buf, nbuf, nil, *st);
- return nbuf;
-}
-
-void
-pack(Objset *send, Objset *skip, Object *o)
-{
- Dirent *e;
- Object *s;
- int i;
-
- if(oshas(send, o->hash) || oshas(skip, o->hash))
- return;
- osadd(send, o);
- switch(o->type){
- case GCommit:
- if((s = readobject(o->commit->tree)) == nil)
- sysfatal("could not read tree %H: %r", o->hash);
- pack(send, skip, s);
- unref(s);
- break;
- case GTree:
- for(i = 0; i < o->tree->nent; i++){
- e = &o->tree->ent[i];
- if ((s = readobject(e->h)) == nil)
- sysfatal("could not read entry %H: %r", e->h);
- pack(send, skip, s);
- unref(s);
- }
- break;
- default:
- break;
- }
-}
-
int
-compread(void *p, void *dst, int n)
+findref(char **r, int nr, char *ref)
{
- Buf *b;
-
- b = p;
- if(n > b->sz - b->off)
- n = b->sz - b->off;
- memcpy(dst, b->data + b->off, n);
- b->off += n;
- return n;
-}
-
-int
-compwrite(void *p, void *buf, int n)
-{
- Compout *o;
-
- o = p;
- o->st = sha1(buf, n, nil, o->st);
- return write(o->fd, buf, n);
-}
-
-int
-compress(int fd, void *buf, int sz, DigestState **st)
-{
- int r;
- Buf b ={
- .off=0,
- .data=buf,
- .sz=sz,
- };
- Compout o = {
- .fd = fd,
- .st = *st,
- };
-
- r = deflatezlib(&o, compwrite, &b, compread, 6, 0);
- *st = o.st;
- return r;
-}
-
-int
-writeobject(int fd, Object *o, DigestState **st)
-{
- char hdr[8];
- uvlong sz;
int i;
- i = 1;
- sz = o->size;
- hdr[0] = o->type << 4;
- hdr[0] |= sz & 0xf;
- if(sz >= (1 << 4)){
- hdr[0] |= 0x80;
- sz >>= 4;
-
- for(i = 1; i < sizeof(hdr); i++){
- hdr[i] = sz & 0x7f;
- if(sz <= 0x7f){
- i++;
- break;
- }
- hdr[i] |= 0x80;
- sz >>= 7;
- }
- }
-
- if(hwrite(fd, hdr, i, st) != i)
- return -1;
- if(compress(fd, o->data, o->size, st) == -1)
- return -1;
- return 0;
+ for(i = 0; i < nr; i++)
+ if(strcmp(r[i], ref) == 0)
+ break;
+ return i;
}
int
-writepackdata(Conn *c, Update *upd, int nupd)
+readours(Hash **tailp, char ***refp)
{
- Objset send, skip;
- Object *o, *p;
- Objq *q, *n, *e;
- DigestState *st;
- Update *u;
- char buf[4];
- Hash h;
- int i;
+ int nu, i, idx;
+ char *r, *pfx, **ref;
+ Hash *tail;
- osinit(&send);
- osinit(&skip);
- for(i = 0; i < nupd; i++){
- u = &upd[i];
- if(hasheq(&u->theirs, &Zhash))
- continue;
- if((o = readobject(u->theirs)) != nil)
- pack(&skip, &skip, o);
- if(!force && o == nil)
- sysfatal("could not read %H", u->theirs);
- unref(o);
- }
-
- q = nil;
- e = nil;
- for(i = 0; i < nupd; i++){
- u = &upd[i];
- if((o = readobject(u->ours)) == nil){
- if(!force)
- sysfatal("could not read object %H", u->ours);
- continue;
- }
- n = emalloc(sizeof(Objq));
- n->obj = o;
- unref(o);
- if(!q){
- q = n;
- e = n;
- }else{
- e->next = n;
- }
- }
-
- for(n = q; n; n = n->next)
- e = n;
- for(; q; q = n){
- o = q->obj;
- if(oshas(&skip, o->hash) || oshas(&send, o->hash))
- goto iter;
- pack(&send, &skip, o);
- for(i = 0; i < o->commit->nparent; i++){
- if((p = readobject(o->commit->parent[i])) == nil)
- sysfatal("could not read parent of %H", o->hash);
- e->next = emalloc(sizeof(Objq));
- e->next->obj = p;
- e = e->next;
- }
-iter:
- n = q->next;
- free(q);
- }
-
- st = nil;
- PUTBE32(buf, send.nobj);
- if(hwrite(c->wfd, "PACK\0\0\0\02", 8, &st) != 8)
- return -1;
- if(hwrite(c->wfd, buf, 4, &st) == -1)
- return -1;
- for(i = 0; i < send.sz; i++){
- if(!send.obj[i])
- continue;
- o = readobject(send.obj[i]->hash);
- if(writeobject(c->wfd, o, &st) == -1)
- return -1;
- unref(o);
- }
- sha1(nil, 0, h.h, st);
- if(write(c->wfd, h.h, sizeof(h.h)) == -1)
- return -1;
- return 0;
-}
-
-Update*
-findref(Update *u, int nu, char *ref)
-{
- int i;
-
- for(i = 0; i < nu; i++)
- if(strcmp(u[i].ref, ref) == 0)
- return &u[i];
- return nil;
-}
-
-int
-readours(Update **ret)
-{
- Update *u, *r;
- int nu, i;
- char *pfx;
- Hash *h;
-
+ if(sendall)
+ return listrefs(tailp, refp);
nu = 0;
- u = emalloc((nremoved + nbranch)*sizeof(Update));
+ tail = emalloc((nremoved + nbranch)*sizeof(Hash));
+ ref = emalloc((nremoved + nbranch)*sizeof(char*));
for(i = 0; i < nbranch; i++){
- snprint(u[nu].ref, sizeof(u[nu].ref), "%s", branch[i]);
- if(resolveref(&u[nu].ours, branch[i]) == -1)
+ ref[nu] = estrdup(branch[i]);
+ if(resolveref(&tail[nu], branch[i]) == -1)
sysfatal("broken branch %s", branch[i]);
nu++;
}
@@ -278,16 +55,16 @@
pfx = "refs/";
if(strstr(removed[i], "refs/heads/") == removed[i])
pfx = "";
- snprint(u[nu].ref, sizeof(u[nu].ref), "%s%s", pfx, removed[i]);
- h = &u[nu].ours;
- if((r = findref(u, nu, u[nu].ref)) != nil)
- h = &r->ours;
+ if((r = smprint("%s%s", pfx, removed[i])) == nil)
+ sysfatal("smprint: %r");
+ if((idx = findref(ref, nu, r)) == nu)
+ nu = idx;
else
- nu++;
- memcpy(h, &Zhash, sizeof(Hash));
+ free(r);
+ memcpy(&tail[idx], &Zhash, sizeof(Hash));
}
-
- *ret = u;
+ *tailp = tail;
+ *refp = ref;
return nu;
}
@@ -322,14 +99,16 @@
int
sendpack(Conn *c)
{
- int i, n, r, nupd, nsp, send, first;
+ int i, n, r, idx, nupd, nobj, nsp, send, first;
char buf[Pktmax], *sp[3];
- Update *upd, *u;
- Object *a, *b, *p;
+ Hash h, *theirs, *ours;
+ Object *a, *b, *p, **obj;
+ char **refs;
Capset cs;
first = 1;
- nupd = readours(&upd);
+ nupd = readours(&ours, &refs);
+ theirs = emalloc(nupd*sizeof(Hash));
while(1){
n = readpkt(c, buf, sizeof(buf));
if(n == -1)
@@ -344,11 +123,10 @@
if(getfields(buf, sp, nelem(sp), 1, " \t\r\n") != 2)
sysfatal("invalid ref line %.*s", utfnlen(buf, n), buf);
- if((u = findref(upd, nupd, sp[1])) == nil)
+ if((idx = findref(refs, nupd, sp[1])) == -1)
continue;
- if(hparse(&u->theirs, sp[0]) == -1)
+ if(hparse(&theirs[idx], sp[0]) == -1)
sysfatal("invalid hash %s", sp[0]);
- snprint(u->ref, sizeof(u->ref), sp[1]);
}
if(writephase(c) == -1)
@@ -356,13 +134,12 @@
r = 0;
send = 0;
for(i = 0; i < nupd; i++){
- u = &upd[i];
- a = readobject(u->theirs);
- b = readobject(u->ours);
+ a = readobject(theirs[i]);
+ b = readobject(ours[i]);
p = nil;
- if(a && b)
+ if(a != nil && b != nil)
p = ancestor(a, b);
- if(!force && !hasheq(&u->theirs, &Zhash) && (a == nil || p != a)){
+ if(!force && !hasheq(&theirs[i], &Zhash) && (a == nil || p != a)){
fprint(2, "remote has diverged\n");
werrstr("force needed");
send=0;
@@ -372,16 +149,16 @@
unref(a);
unref(b);
unref(p);
- if(hasheq(&u->ours, &Zhash)){
- print("removed %s\n", u->ref);
+ if(hasheq(&ours[i], &Zhash)){
+ print("removed %s\n", refs[i]);
continue;
}
- if(hasheq(&u->theirs, &u->ours)){
- print("uptodate %s\n", u->ref);
+ if(hasheq(&theirs[i], &ours[i])){
+ print("uptodate %s\n", refs[i]);
continue;
}
- print("update %s %H %H\n", u->ref, u->theirs, u->ours);
- n = snprint(buf, sizeof(buf), "%H %H %s", u->theirs, u->ours, u->ref);
+ print("update %s %H %H\n", refs[i], theirs[i], ours[i]);
+ n = snprint(buf, sizeof(buf), "%H %H %s", theirs[i], ours[i], refs[i]);
/*
* Workaround for github.
@@ -410,8 +187,9 @@
if(!send)
print("nothing to send\n");
if(send){
- dprint(1, "sending pack...\n");
- if(writepackdata(c, upd, nupd) == -1)
+ if(findtwixt(ours, nupd, theirs, nupd, &obj, &nobj) == -1)
+ return -1;
+ if(writepack(c->wfd, obj, nobj, &h) == -1)
return -1;
if(cs.report && readphase(c) == -1)
return -1;