Skip to content

Commit 064e0b2

Browse files
committed
Merge branch 'pw/rebase-i-author-script-fix'
Recent "git rebase -i" update started to write bogusly formatted author-script, with a matching broken reading code. These are fixed. * pw/rebase-i-author-script-fix: sequencer: fix quoting in write_author_script sequencer: handle errors from read_author_ident()
2 parents 2f74393 + 4aa5ff9 commit 064e0b2

File tree

2 files changed

+53
-12
lines changed

2 files changed

+53
-12
lines changed

sequencer.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -639,42 +639,64 @@ static int write_author_script(const char *message)
639639
else if (*message != '\'')
640640
strbuf_addch(&buf, *(message++));
641641
else
642-
strbuf_addf(&buf, "'\\\\%c'", *(message++));
642+
strbuf_addf(&buf, "'\\%c'", *(message++));
643643
strbuf_addstr(&buf, "'\nGIT_AUTHOR_EMAIL='");
644644
while (*message && *message != '\n' && *message != '\r')
645645
if (skip_prefix(message, "> ", &message))
646646
break;
647647
else if (*message != '\'')
648648
strbuf_addch(&buf, *(message++));
649649
else
650-
strbuf_addf(&buf, "'\\\\%c'", *(message++));
650+
strbuf_addf(&buf, "'\\%c'", *(message++));
651651
strbuf_addstr(&buf, "'\nGIT_AUTHOR_DATE='@");
652652
while (*message && *message != '\n' && *message != '\r')
653653
if (*message != '\'')
654654
strbuf_addch(&buf, *(message++));
655655
else
656-
strbuf_addf(&buf, "'\\\\%c'", *(message++));
656+
strbuf_addf(&buf, "'\\%c'", *(message++));
657657
strbuf_addch(&buf, '\'');
658658
res = write_message(buf.buf, buf.len, rebase_path_author_script(), 1);
659659
strbuf_release(&buf);
660660
return res;
661661
}
662662

663+
664+
/*
665+
* write_author_script() used to fail to terminate the last line with a "'" and
666+
* also escaped "'" incorrectly as "'\\\\''" rather than "'\\''". We check for
667+
* the terminating "'" on the last line to see how "'" has been escaped in case
668+
* git was upgraded while rebase was stopped.
669+
*/
670+
static int quoting_is_broken(const char *s, size_t n)
671+
{
672+
/* Skip any empty lines in case the file was hand edited */
673+
while (n > 0 && s[--n] == '\n')
674+
; /* empty */
675+
if (n > 0 && s[n] != '\'')
676+
return 1;
677+
678+
return 0;
679+
}
680+
663681
/*
664682
* Read a list of environment variable assignments (such as the author-script
665683
* file) into an environment block. Returns -1 on error, 0 otherwise.
666684
*/
667685
static int read_env_script(struct argv_array *env)
668686
{
669687
struct strbuf script = STRBUF_INIT;
670-
int i, count = 0;
671-
char *p, *p2;
688+
int i, count = 0, sq_bug;
689+
const char *p2;
690+
char *p;
672691

673692
if (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)
674693
return -1;
675-
694+
/* write_author_script() used to quote incorrectly */
695+
sq_bug = quoting_is_broken(script.buf, script.len);
676696
for (p = script.buf; *p; p++)
677-
if (skip_prefix(p, "'\\\\''", (const char **)&p2))
697+
if (sq_bug && skip_prefix(p, "'\\\\''", &p2))
698+
strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
699+
else if (skip_prefix(p, "'\\''", &p2))
678700
strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
679701
else if (*p == '\'')
680702
strbuf_splice(&script, p-- - script.buf, 1, "", 0);
@@ -798,11 +820,18 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
798820

799821
if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
800822
struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
801-
const char *author = is_rebase_i(opts) ?
802-
read_author_ident(&script) : NULL;
823+
const char *author = NULL;
803824
struct object_id root_commit, *cache_tree_oid;
804825
int res = 0;
805826

827+
if (is_rebase_i(opts)) {
828+
author = read_author_ident(&script);
829+
if (!author) {
830+
strbuf_release(&script);
831+
return -1;
832+
}
833+
}
834+
806835
if (!defmsg)
807836
BUG("root commit without message");
808837

t/t3404-rebase-interactive.sh

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1426,9 +1426,21 @@ test_expect_success 'rebase -i --gpg-sign=<key-id> overrides commit.gpgSign' '
14261426
test_expect_success 'valid author header after --root swap' '
14271427
rebase_setup_and_clean author-header no-conflict-branch &&
14281428
set_fake_editor &&
1429-
FAKE_LINES="2 1" git rebase -i --root &&
1430-
git cat-file commit HEAD^ >out &&
1431-
grep "^author ..*> [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$" out
1429+
git commit --amend --author="Au ${SQ}thor <[email protected]>" --no-edit &&
1430+
git cat-file commit HEAD | grep ^author >expected &&
1431+
FAKE_LINES="5 1" git rebase -i --root &&
1432+
git cat-file commit HEAD^ | grep ^author >actual &&
1433+
test_cmp expected actual
1434+
'
1435+
1436+
test_expect_success 'valid author header when author contains single quote' '
1437+
rebase_setup_and_clean author-header no-conflict-branch &&
1438+
set_fake_editor &&
1439+
git commit --amend --author="Au ${SQ}thor <[email protected]>" --no-edit &&
1440+
git cat-file commit HEAD | grep ^author >expected &&
1441+
FAKE_LINES="2" git rebase -i HEAD~2 &&
1442+
git cat-file commit HEAD | grep ^author >actual &&
1443+
test_cmp expected actual
14321444
'
14331445

14341446
test_done

0 commit comments

Comments
 (0)