ref: 5add783e89fad10069df63ef4314affb6d002b61
parent: 9b86df709d4bca2a3ec5b342de04cadefe9e4192
author: Ori Bernstein <ori@eigenstate.org>
date: Sat Dec 5 12:51:20 EST 2020
git/send: smaller packfiles when pushing When pushing to a remote repository, we would pack at least all objects in one commit, even if the remote repository had most of them. This change prunes out all objects from the last commit that they have, which should drop the size of the generated pack file noticably for the common case of pushing a commit or that changes a small percentage of files in a larger repository.
--- a/git.h
+++ b/git.h
@@ -248,7 +248,7 @@
Object *clearedobject(Hash, int);
void parseobject(Object *);
int indexpack(char *, char *, Hash);
-int writepack(int, Object **, int, Hash*);
+int writepack(int, Hash*, int, Hash*, int, Hash*);
int hasheq(Hash *, Hash *);
Object *ref(Object *);
void unref(Object *);
--- a/pack.c
+++ b/pack.c
@@ -1167,10 +1167,15 @@
}
static void
-addmeta(Objmeta ***meta, int *nmeta, Object *o, char *path, vlong mtime)
+addmeta(Objmeta ***meta, int *nmeta, Objset *has, Object *o, char *path, vlong mtime)
{
Objmeta *m;
+ if(oshas(has, o->hash))
+ return;
+ osadd(has, o);
+ if(meta == nil)
+ return;
m = emalloc(sizeof(Objmeta));
m->obj = o;
m->path = estrdup(path);
@@ -1201,8 +1206,7 @@
return 0;
if((t = readobject(tree)) == nil)
return -1;
- osadd(has, t);
- addmeta(m, nm, t, dpath, mtime);
+ addmeta(m, nm, has, t, dpath, mtime);
for(i = 0; i < t->tree->nent; i++){
e = &t->tree->ent[i];
if(oshas(has, e->h))
@@ -1212,10 +1216,9 @@
k = (e->mode & DMDIR) ? GTree : GBlob;
o = clearedobject(e->h, k);
p = smprint("%s/%s", dpath, e->name);
- if(k == GBlob){
- osadd(has, o);
- addmeta(m, nm, o, p, mtime);
- }else if(loadtree(m, nm, has, e->h, p, mtime) == -1){
+ if(k == GBlob)
+ addmeta(m, nm, has, o, p, mtime);
+ else if(loadtree(m, nm, has, e->h, p, mtime) == -1){
free(p);
return -1;
}
@@ -1235,8 +1238,7 @@
return 0;
if((c = readobject(h)) == nil)
return -1;
- osadd(has, c);
- addmeta(m, nm, c, "", c->commit->ctime);
+ addmeta(m, nm, has, c, "", c->commit->ctime);
r = loadtree(m, nm, has, c->commit->tree, "", c->commit->ctime);
unref(c);
return r;
@@ -1243,23 +1245,32 @@
}
static int
-readmeta(Object **commits, int ncommits, Objmeta ***m)
+readmeta(Hash *theirs, int ntheirs, Hash *ours, int nours, Objmeta ***m)
{
+ Object **obj;
Objset has;
- int i, nm;
+ int i, nm, nobj;
*m = nil;
nm = 0;
osinit(&has);
- for(i = 0; i < ncommits; i++){
- dprint(2, "loading commit %H\n", commits[i]->hash);
- if(loadcommit(m, &nm, &has, commits[i]->hash) == -1){
- free(*m);
- return -1;
- }
- }
+ if(findtwixt(theirs, ntheirs, ours, nours, &obj, &nobj) == -1)
+ sysfatal("load twixt: %r");
+ if(nobj == 0)
+ return 0;
+ for(i = 0; i < nours; i++)
+ if(!hasheq(&ours[i], &Zhash))
+ if(loadcommit(nil, nil, &has, ours[i]) == -1)
+ goto out;
+ for(i = 0; i < nobj; i++)
+ if(loadcommit(m, &nm, &has, obj[i]->hash) == -1)
+ goto out;
osclear(&has);
return nm;
+out:
+ osclear(&has);
+ free(*m);
+ return -1;
}
static int
@@ -1281,12 +1292,14 @@
int i, j, x, nd, sz, pcnt, best;
pcnt = 0;
- fprint(2, "deltifying %d objects: 0%%", nmeta);
+ dprint(1, "picking deltas\n");
+ if(interactive)
+ fprint(2, "deltifying %d objects: 0%%", nmeta);
qsort(meta, nmeta, sizeof(Objmeta*), deltaordercmp);
for(i = 0; i < nmeta; i++){
m = meta[i];
x = (i*100) / nmeta;
- if(x > pcnt){
+ if(interactive && x > pcnt){
pcnt = x;
if(pcnt%10 == 0)
fprint(2, "\b\b\b\b%3d%%", pcnt);
@@ -1561,15 +1574,15 @@
}
int
-writepack(int fd, Object **obj, int nobj, Hash *h)
+writepack(int fd, Hash *theirs, int ntheirs, Hash *ours, int nours, Hash *h)
{
Objmeta **meta;
int i, r, nmeta;
- dprint(1, "reading meta\n");
- if((nmeta = readmeta(obj, nobj, &meta)) == -1)
+ if((nmeta = readmeta(theirs, ntheirs, ours, nours, &meta)) == -1)
return -1;
- dprint(1, "picking deltas\n");
+ if(nmeta == 0)
+ return 0;
pickdeltas(meta, nmeta);
dprint(1, "generating pack\n");
r = genpack(fd, meta, nmeta, h, 0);
--- a/repack.c
+++ b/repack.c
@@ -47,9 +47,8 @@
main(int argc, char **argv)
{
char path[128], **names;
- int fd, nobj, nrefs;
+ int fd, nrefs;
Hash *refs, h;
- Object **obj;
Dir rn;
ARGBEGIN{
@@ -64,13 +63,10 @@
refs = nil;
if((nrefs = listrefs(&refs, &names)) == -1)
sysfatal("load refs: %r");
- if(findtwixt(refs, nrefs, nil, 0, &obj, &nobj) == -1)
- sysfatal("load twixt: %r");
if((fd = create(TMPPATH("pack.tmp"), OWRITE, 0644)) == -1)
sysfatal("open %s: %r", TMPPATH("pack.tmp"));
- if(writepack(fd, obj, nobj, &h) == -1)
+ if(writepack(fd, refs, nrefs, nil, 0, &h) == -1)
sysfatal("writepack: %r");
- free(obj);
if(indexpack(TMPPATH("pack.tmp"), TMPPATH("idx.tmp"), h) == -1)
sysfatal("indexpack: %r");
close(fd);
--- a/send.c
+++ b/send.c
@@ -99,10 +99,10 @@
int
sendpack(Conn *c)
{
- int i, n, r, idx, nupd, nobj, nsp, send, first;
+ int i, n, r, idx, nupd, nsp, send, first;
char buf[Pktmax], *sp[3];
Hash h, *theirs, *ours;
- Object *a, *b, *p, **obj;
+ Object *a, *b, *p;
char **refs;
Capset cs;
@@ -187,9 +187,7 @@
if(!send)
print("nothing to send\n");
if(send){
- if(findtwixt(ours, nupd, theirs, nupd, &obj, &nobj) == -1)
- return -1;
- if(writepack(c->wfd, obj, nobj, &h) == -1)
+ if(writepack(c->wfd, ours, nupd, theirs, nupd, &h) == -1)
return -1;
if(cs.report && readphase(c) == -1)
return -1;
--- a/serve.c
+++ b/serve.c
@@ -138,17 +138,13 @@
servpack(Conn *c)
{
Hash *head, *tail, h;
- Object **obj;
- int nhead, ntail, nobj;
+ int nhead, ntail;
dprint(1, "negotiating pack\n");
if(servnegotiate(c, &head, &nhead, &tail, &ntail) == -1)
sysfatal("negotiate: %r");
- dprint(1, "finding twixt\n");
- if(findtwixt(head, nhead, tail, ntail, &obj, &nobj) == -1)
- sysfatal("twixt: %r");
dprint(1, "writing pack\n");
- if(nobj > 0 && writepack(c->wfd, obj, nobj, &h) == -1)
+ if(writepack(c->wfd, head, nhead, tail, ntail, &h) == -1)
sysfatal("send: %r");
return 0;
}