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.
This commit is contained in:
parent
485b334608
commit
d9564c0642
7 changed files with 118 additions and 82 deletions
|
@ -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}' </adm/keys.who}
|
||||
if(~ $email '')
|
||||
email=`$nl{awk -F'|' '$1=="'$user'" {x=$5} END{print x}' </adm/keys.who}
|
||||
}
|
||||
if(~ $name '')
|
||||
name=glenda
|
||||
if(~ $email '')
|
||||
email=glenda@9front.local
|
||||
}
|
||||
|
||||
# merge1 out ours base theirs
|
||||
fn merge1 {@{
|
||||
rfork e
|
||||
n=$pid
|
||||
|
|
|
@ -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){
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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=''''
|
||||
'
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue