Skip to content

Commit 05e97b4

Browse files
adlternativeAone-Agent
authored andcommitted
commit: add --committer option
Add --committer option to git-commit, allowing users to override the committer identity similar to how --author works. This provides a more convenient alternative to setting GIT_COMMITTER_* environment variables. Signed-off-by: ZheNing Hu <adlternative@gmail.com> Co-authored-by: Aone-Agent <aone-agent@alibaba-inc.com>
1 parent 4badef0 commit 05e97b4

File tree

3 files changed

+144
-3
lines changed

3 files changed

+144
-3
lines changed

Documentation/git-commit.adoc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]
1212
[--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>]
1313
[-F <file> | -m <msg>] [--reset-author] [--allow-empty]
1414
[--allow-empty-message] [--no-verify] [-e] [--author=<author>]
15-
[--date=<date>] [--cleanup=<mode>] [--[no-]status]
15+
[--date=<date>] [--committer=<committer>] [--cleanup=<mode>] [--[no-]status]
1616
[-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
1717
[(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]
1818
[--] [<pathspec>...]
@@ -181,6 +181,13 @@ See linkgit:git-rebase[1] for details.
181181
`--date=<date>`::
182182
Override the author date used in the commit.
183183

184+
`--committer=<committer>`::
185+
Override the committer for the commit. Specify an explicit committer using the
186+
standard `A U Thor <committer@example.com>` format. Otherwise _<committer>_
187+
is assumed to be a pattern and is used to search for an existing
188+
commit by that author (i.e. `git rev-list --all -i --author=<committer>`);
189+
the commit author is then copied from the first such commit found.
190+
184191
`-m <msg>`::
185192
`--message=<msg>`::
186193
Use _<msg>_ as the commit message.

builtin/commit.c

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static const char * const builtin_commit_usage[] = {
4949
" [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>]\n"
5050
" [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
5151
" [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
52-
" [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
52+
" [--date=<date>] [--committer=<committer>] [--cleanup=<mode>] [--[no-]status]\n"
5353
" [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
5454
" [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
5555
" [--] [<pathspec>...]"),
@@ -112,6 +112,7 @@ static enum {
112112
} commit_style;
113113

114114
static const char *force_author;
115+
static const char *force_committer;
115116
static char *logfile;
116117
static char *template_file;
117118
/*
@@ -690,6 +691,48 @@ static void determine_author_info(struct strbuf *author_ident)
690691
free(date);
691692
}
692693

694+
static void determine_committer_info(struct strbuf *committer_ident)
695+
{
696+
char *name, *email, *date;
697+
struct ident_split committer;
698+
699+
name = xstrdup_or_null(getenv("GIT_COMMITTER_NAME"));
700+
email = xstrdup_or_null(getenv("GIT_COMMITTER_EMAIL"));
701+
date = xstrdup_or_null(getenv("GIT_COMMITTER_DATE"));
702+
703+
if (force_committer) {
704+
struct ident_split ident;
705+
706+
if (split_ident_line(&ident, force_committer, strlen(force_committer)) < 0)
707+
die(_("malformed --committer parameter"));
708+
set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin));
709+
set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin));
710+
711+
if (ident.date_begin) {
712+
struct strbuf date_buf = STRBUF_INIT;
713+
strbuf_addch(&date_buf, '@');
714+
strbuf_add(&date_buf, ident.date_begin, ident.date_end - ident.date_begin);
715+
strbuf_addch(&date_buf, ' ');
716+
strbuf_add(&date_buf, ident.tz_begin, ident.tz_end - ident.tz_begin);
717+
set_ident_var(&date, strbuf_detach(&date_buf, NULL));
718+
}
719+
}
720+
721+
if (force_date) {
722+
struct strbuf date_buf = STRBUF_INIT;
723+
if (parse_force_date(force_date, &date_buf))
724+
die(_("invalid date format: %s"), force_date);
725+
set_ident_var(&date, strbuf_detach(&date_buf, NULL));
726+
}
727+
728+
strbuf_addstr(committer_ident, fmt_ident(name, email, WANT_COMMITTER_IDENT, date,
729+
IDENT_STRICT));
730+
assert_split_ident(&committer, committer_ident);
731+
free(name);
732+
free(email);
733+
free(date);
734+
}
735+
693736
static int author_date_is_interesting(void)
694737
{
695738
return author_message || force_date;
@@ -1321,6 +1364,9 @@ static int parse_and_validate_options(int argc, const char *argv[],
13211364
if (force_author && renew_authorship)
13221365
die(_("options '%s' and '%s' cannot be used together"), "--reset-author", "--author");
13231366

1367+
if (force_committer && !strchr(force_committer, '>'))
1368+
force_committer = find_author_by_nickname(force_committer);
1369+
13241370
if (logfile || have_option_m || use_message)
13251371
use_editor = 0;
13261372

@@ -1709,6 +1755,7 @@ int cmd_commit(int argc,
17091755
OPT_FILENAME('F', "file", &logfile, N_("read message from file")),
17101756
OPT_STRING(0, "author", &force_author, N_("author"), N_("override author for commit")),
17111757
OPT_STRING(0, "date", &force_date, N_("date"), N_("override date for commit")),
1758+
OPT_STRING(0, "committer", &force_committer, N_("committer"), N_("override committer for commit")),
17121759
OPT_CALLBACK('m', "message", &message, N_("message"), N_("commit message"), opt_parse_m),
17131760
OPT_STRING('c', "reedit-message", &edit_message, N_("commit"), N_("reuse and edit message from specified commit")),
17141761
OPT_STRING('C', "reuse-message", &use_message, N_("commit"), N_("reuse message from specified commit")),
@@ -1785,6 +1832,7 @@ int cmd_commit(int argc,
17851832

17861833
struct strbuf sb = STRBUF_INIT;
17871834
struct strbuf author_ident = STRBUF_INIT;
1835+
struct strbuf committer_ident = STRBUF_INIT;
17881836
const char *index_file, *reflog_msg;
17891837
struct object_id oid;
17901838
struct commit_list *parents = NULL;
@@ -1930,8 +1978,13 @@ int cmd_commit(int argc,
19301978
append_merge_tag_headers(parents, &tail);
19311979
}
19321980

1981+
if (force_committer) {
1982+
determine_committer_info(&committer_ident);
1983+
}
1984+
19331985
if (commit_tree_extended(sb.buf, sb.len, &the_repository->index->cache_tree->oid,
1934-
parents, &oid, author_ident.buf, NULL,
1986+
parents, &oid, author_ident.buf,
1987+
force_committer ? committer_ident.buf : NULL,
19351988
sign_commit, extra)) {
19361989
rollback_index_files();
19371990
die(_("failed to write commit object"));
@@ -1980,6 +2033,7 @@ int cmd_commit(int argc,
19802033
free_commit_extra_headers(extra);
19812034
free_commit_list(parents);
19822035
strbuf_release(&author_ident);
2036+
strbuf_release(&committer_ident);
19832037
strbuf_release(&err);
19842038
strbuf_release(&sb);
19852039
free(logfile);

t/t7509-commit-authorship.sh

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ author_header () {
1212
sed -n -e '/^$/q' -e '/^author /p'
1313
}
1414

15+
committer_header () {
16+
git cat-file commit "$1" |
17+
sed -n -e '/^$/q' -e '/^committer /p'
18+
}
19+
1520
message_body () {
1621
git cat-file commit "$1" |
1722
sed -e '1,/^$/d'
@@ -171,4 +176,79 @@ test_expect_success '--reset-author with CHERRY_PICK_HEAD' '
171176
test_cmp expect actual
172177
'
173178

179+
test_expect_success '--committer option overrides committer' '
180+
git checkout Initial &&
181+
echo "Test --committer" >>foo &&
182+
test_tick &&
183+
git commit -a -m "test committer" --committer="Custom Committer <custom@committer.example>" &&
184+
committer_header HEAD >actual &&
185+
grep "Custom Committer <custom@committer.example>" actual
186+
'
187+
188+
test_expect_success '--committer with pattern search' '
189+
echo "Test committer pattern" >>foo &&
190+
test_tick &&
191+
git commit -a -m "test committer pattern" --committer="Frigate" &&
192+
committer_header HEAD >actual &&
193+
grep "Frigate <flying@over.world>" actual
194+
'
195+
196+
test_expect_success '--committer malformed parameter' '
197+
echo "Test malformed" >>foo &&
198+
test_tick &&
199+
test_must_fail git commit -a -m "test malformed" --committer="malformed committer"
200+
'
201+
202+
test_expect_success '--committer with --amend option' '
203+
git checkout -f Initial &&
204+
echo "Test committer with amend" >>foo &&
205+
test_tick &&
206+
git commit -a -m "initial commit for amend test" &&
207+
echo "Modified for amend" >>foo &&
208+
test_tick &&
209+
git commit -a --amend --no-edit \
210+
--author="Test Author <test@author.example>" \
211+
--committer="Test Committer <test@committer.example>" &&
212+
author_header HEAD >actual_author &&
213+
grep "Test Author <test@author.example>" actual_author &&
214+
committer_header HEAD >actual_committer &&
215+
grep "Test Committer <test@committer.example>" actual_committer
216+
'
217+
218+
test_expect_success 'GIT_COMMITTER_* environment variables' '
219+
git checkout -f Initial &&
220+
echo "Test env vars" >>foo &&
221+
test_tick &&
222+
GIT_COMMITTER_NAME="Env Committer" \
223+
GIT_COMMITTER_EMAIL="env@test.example" \
224+
git commit -a -m "test committer env vars" &&
225+
committer_header HEAD >actual &&
226+
grep "Env Committer <env@test.example>" actual
227+
'
228+
229+
test_expect_success '--committer overrides GIT_COMMITTER_* environment variables' '
230+
echo "Test override" >>foo &&
231+
test_tick &&
232+
GIT_COMMITTER_NAME="Env Committer" \
233+
GIT_COMMITTER_EMAIL="env@test.example" \
234+
git commit -a -m "test override" \
235+
--committer="Override Committer <override@test.example>" &&
236+
committer_header HEAD >actual &&
237+
grep "Override Committer <override@test.example>" actual
238+
'
239+
240+
test_expect_success '--date with --committer changes both author and committer dates' '
241+
git checkout -f Initial &&
242+
echo "Test date override" >>foo &&
243+
test_tick &&
244+
git commit -a -m "test date" \
245+
--author="Date Author <date@author.example>" \
246+
--committer="Date Committer <date@committer.example>" \
247+
--date="2024-06-15 10:30:00 +0800" &&
248+
git log -1 --format="%ai" >author_date &&
249+
git log -1 --format="%ci" >committer_date &&
250+
grep "2024-06-15 10:30:00 +0800" author_date &&
251+
grep "2024-06-15 10:30:00 +0800" committer_date
252+
'
253+
174254
test_done

0 commit comments

Comments
 (0)