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()
This commit is contained in:
47
sequencer.c
47
sequencer.c
@ -639,7 +639,7 @@ missing_author:
|
|||||||
else if (*message != '\'')
|
else if (*message != '\'')
|
||||||
strbuf_addch(&buf, *(message++));
|
strbuf_addch(&buf, *(message++));
|
||||||
else
|
else
|
||||||
strbuf_addf(&buf, "'\\\\%c'", *(message++));
|
strbuf_addf(&buf, "'\\%c'", *(message++));
|
||||||
strbuf_addstr(&buf, "'\nGIT_AUTHOR_EMAIL='");
|
strbuf_addstr(&buf, "'\nGIT_AUTHOR_EMAIL='");
|
||||||
while (*message && *message != '\n' && *message != '\r')
|
while (*message && *message != '\n' && *message != '\r')
|
||||||
if (skip_prefix(message, "> ", &message))
|
if (skip_prefix(message, "> ", &message))
|
||||||
@ -647,19 +647,37 @@ missing_author:
|
|||||||
else if (*message != '\'')
|
else if (*message != '\'')
|
||||||
strbuf_addch(&buf, *(message++));
|
strbuf_addch(&buf, *(message++));
|
||||||
else
|
else
|
||||||
strbuf_addf(&buf, "'\\\\%c'", *(message++));
|
strbuf_addf(&buf, "'\\%c'", *(message++));
|
||||||
strbuf_addstr(&buf, "'\nGIT_AUTHOR_DATE='@");
|
strbuf_addstr(&buf, "'\nGIT_AUTHOR_DATE='@");
|
||||||
while (*message && *message != '\n' && *message != '\r')
|
while (*message && *message != '\n' && *message != '\r')
|
||||||
if (*message != '\'')
|
if (*message != '\'')
|
||||||
strbuf_addch(&buf, *(message++));
|
strbuf_addch(&buf, *(message++));
|
||||||
else
|
else
|
||||||
strbuf_addf(&buf, "'\\\\%c'", *(message++));
|
strbuf_addf(&buf, "'\\%c'", *(message++));
|
||||||
strbuf_addch(&buf, '\'');
|
strbuf_addch(&buf, '\'');
|
||||||
res = write_message(buf.buf, buf.len, rebase_path_author_script(), 1);
|
res = write_message(buf.buf, buf.len, rebase_path_author_script(), 1);
|
||||||
strbuf_release(&buf);
|
strbuf_release(&buf);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* write_author_script() used to fail to terminate the last line with a "'" and
|
||||||
|
* also escaped "'" incorrectly as "'\\\\''" rather than "'\\''". We check for
|
||||||
|
* the terminating "'" on the last line to see how "'" has been escaped in case
|
||||||
|
* git was upgraded while rebase was stopped.
|
||||||
|
*/
|
||||||
|
static int quoting_is_broken(const char *s, size_t n)
|
||||||
|
{
|
||||||
|
/* Skip any empty lines in case the file was hand edited */
|
||||||
|
while (n > 0 && s[--n] == '\n')
|
||||||
|
; /* empty */
|
||||||
|
if (n > 0 && s[n] != '\'')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read a list of environment variable assignments (such as the author-script
|
* Read a list of environment variable assignments (such as the author-script
|
||||||
* file) into an environment block. Returns -1 on error, 0 otherwise.
|
* file) into an environment block. Returns -1 on error, 0 otherwise.
|
||||||
@ -667,14 +685,18 @@ missing_author:
|
|||||||
static int read_env_script(struct argv_array *env)
|
static int read_env_script(struct argv_array *env)
|
||||||
{
|
{
|
||||||
struct strbuf script = STRBUF_INIT;
|
struct strbuf script = STRBUF_INIT;
|
||||||
int i, count = 0;
|
int i, count = 0, sq_bug;
|
||||||
char *p, *p2;
|
const char *p2;
|
||||||
|
char *p;
|
||||||
|
|
||||||
if (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)
|
if (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
/* write_author_script() used to quote incorrectly */
|
||||||
|
sq_bug = quoting_is_broken(script.buf, script.len);
|
||||||
for (p = script.buf; *p; p++)
|
for (p = script.buf; *p; p++)
|
||||||
if (skip_prefix(p, "'\\\\''", (const char **)&p2))
|
if (sq_bug && skip_prefix(p, "'\\\\''", &p2))
|
||||||
|
strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
|
||||||
|
else if (skip_prefix(p, "'\\''", &p2))
|
||||||
strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
|
strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
|
||||||
else if (*p == '\'')
|
else if (*p == '\'')
|
||||||
strbuf_splice(&script, p-- - script.buf, 1, "", 0);
|
strbuf_splice(&script, p-- - script.buf, 1, "", 0);
|
||||||
@ -798,11 +820,18 @@ static int run_git_commit(const char *defmsg, struct replay_opts *opts,
|
|||||||
|
|
||||||
if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
|
if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) {
|
||||||
struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
|
struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT;
|
||||||
const char *author = is_rebase_i(opts) ?
|
const char *author = NULL;
|
||||||
read_author_ident(&script) : NULL;
|
|
||||||
struct object_id root_commit, *cache_tree_oid;
|
struct object_id root_commit, *cache_tree_oid;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
|
if (is_rebase_i(opts)) {
|
||||||
|
author = read_author_ident(&script);
|
||||||
|
if (!author) {
|
||||||
|
strbuf_release(&script);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!defmsg)
|
if (!defmsg)
|
||||||
BUG("root commit without message");
|
BUG("root commit without message");
|
||||||
|
|
||||||
|
@ -1426,9 +1426,21 @@ test_expect_success 'rebase -i --gpg-sign=<key-id> overrides commit.gpgSign' '
|
|||||||
test_expect_success 'valid author header after --root swap' '
|
test_expect_success 'valid author header after --root swap' '
|
||||||
rebase_setup_and_clean author-header no-conflict-branch &&
|
rebase_setup_and_clean author-header no-conflict-branch &&
|
||||||
set_fake_editor &&
|
set_fake_editor &&
|
||||||
FAKE_LINES="2 1" git rebase -i --root &&
|
git commit --amend --author="Au ${SQ}thor <author@example.com>" --no-edit &&
|
||||||
git cat-file commit HEAD^ >out &&
|
git cat-file commit HEAD | grep ^author >expected &&
|
||||||
grep "^author ..*> [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$" out
|
FAKE_LINES="5 1" git rebase -i --root &&
|
||||||
|
git cat-file commit HEAD^ | grep ^author >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'valid author header when author contains single quote' '
|
||||||
|
rebase_setup_and_clean author-header no-conflict-branch &&
|
||||||
|
set_fake_editor &&
|
||||||
|
git commit --amend --author="Au ${SQ}thor <author@example.com>" --no-edit &&
|
||||||
|
git cat-file commit HEAD | grep ^author >expected &&
|
||||||
|
FAKE_LINES="2" git rebase -i HEAD~2 &&
|
||||||
|
git cat-file commit HEAD | grep ^author >actual &&
|
||||||
|
test_cmp expected actual
|
||||||
'
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Reference in New Issue
Block a user