From d9564c0642b9a8280f8e4dfe9ff15a2c65b6d93d Mon Sep 17 00:00:00 2001 From: Ori Bernstein Date: Fri, 3 Sep 2021 02:47:18 +0000 Subject: [PATCH] git: separate author and committer Git has the ability to track the person who creates a commit separately from the person who wrote the commit. For git9, we ignored this feature. However, as we start using git/import more, it will be useful to figure out who imported a commit, as well as who wrote it. This change adds support for seeing this information in git, as well as setting the author and committer separately in git/import. --- sys/lib/git/common.rc | 17 ++++++++++- sys/src/cmd/git/commit | 17 +---------- sys/src/cmd/git/fs.c | 68 +++++++++++++++++++++++------------------- sys/src/cmd/git/import | 28 +++++++++-------- sys/src/cmd/git/log.c | 3 ++ sys/src/cmd/git/merge | 2 +- sys/src/cmd/git/save.c | 65 +++++++++++++++++++++++++++------------- 7 files changed, 118 insertions(+), 82 deletions(-) diff --git a/sys/lib/git/common.rc b/sys/lib/git/common.rc index 787b5babd..653d6bfb1 100644 --- a/sys/lib/git/common.rc +++ b/sys/lib/git/common.rc @@ -38,7 +38,22 @@ fn present { status=() } -# merge1 out theirs base ours +fn whoami{ + name=`$nl{git/conf user.name} + email=`$nl{git/conf user.email} + if(test -f /adm/keys.who){ + if(~ $name '') + name=`$nl{awk -F'|' '$1=="'$user'" {x=$3} END{print x}' 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: diff --git a/sys/src/cmd/git/import b/sys/src/cmd/git/import index 1ce614a20..d8470dd01 100755 --- a/sys/src/cmd/git/import +++ b/sys/src/cmd/git/import @@ -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); + aname=$0; + amail=$0; + sub(/[ \t]*<.*$/, "", aname); + 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='''' ' diff --git a/sys/src/cmd/git/log.c b/sys/src/cmd/git/log.c index 2a0692aba..af9b90504 100644 --- a/sys/src/cmd/git/log.c +++ b/sys/src/cmd/git/log.c @@ -153,6 +153,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; diff --git a/sys/src/cmd/git/merge b/sys/src/cmd/git/merge index 3d7a97a74..051e22483 100755 --- a/sys/src/cmd/git/merge +++ b/sys/src/cmd/git/merge @@ -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 } } diff --git a/sys/src/cmd/git/save.c b/sys/src/cmd/git/save.c index d6062769c..08a1a50cf 100644 --- a/sys/src/cmd/git/save.c +++ b/sys/src/cmd/git/save.c @@ -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); }