summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sequencer.c36
-rwxr-xr-xt/t3404-rebase-interactive.sh18
2 files changed, 44 insertions, 10 deletions
diff --git a/sequencer.c b/sequencer.c
index c4e4418559..ba11fe5bca 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -636,7 +636,7 @@ missing_author:
else if (*message != '\'')
strbuf_addch(&buf, *(message++));
else
- strbuf_addf(&buf, "'\\\\%c'", *(message++));
+ strbuf_addf(&buf, "'\\%c'", *(message++));
strbuf_addstr(&buf, "'\nGIT_AUTHOR_EMAIL='");
while (*message && *message != '\n' && *message != '\r')
if (skip_prefix(message, "> ", &message))
@@ -644,19 +644,37 @@ missing_author:
else if (*message != '\'')
strbuf_addch(&buf, *(message++));
else
- strbuf_addf(&buf, "'\\\\%c'", *(message++));
+ strbuf_addf(&buf, "'\\%c'", *(message++));
strbuf_addstr(&buf, "'\nGIT_AUTHOR_DATE='@");
while (*message && *message != '\n' && *message != '\r')
if (*message != '\'')
strbuf_addch(&buf, *(message++));
else
- strbuf_addf(&buf, "'\\\\%c'", *(message++));
+ strbuf_addf(&buf, "'\\%c'", *(message++));
strbuf_addch(&buf, '\'');
res = write_message(buf.buf, buf.len, rebase_path_author_script(), 1);
strbuf_release(&buf);
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
* file) into an environment block. Returns -1 on error, 0 otherwise.
@@ -664,14 +682,18 @@ missing_author:
static int read_env_script(struct argv_array *env)
{
struct strbuf script = STRBUF_INIT;
- int i, count = 0;
- char *p, *p2;
+ int i, count = 0, sq_bug;
+ const char *p2;
+ char *p;
if (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)
return -1;
-
+ /* write_author_script() used to quote incorrectly */
+ sq_bug = quoting_is_broken(script.buf, script.len);
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);
else if (*p == '\'')
strbuf_splice(&script, p-- - script.buf, 1, "", 0);
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index b72167ecd5..834a124d60 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1382,9 +1382,21 @@ test_expect_success 'rebase -i --gpg-sign=<key-id> overrides commit.gpgSign' '
test_expect_success 'valid author header after --root swap' '
rebase_setup_and_clean author-header no-conflict-branch &&
set_fake_editor &&
- FAKE_LINES="2 1" git rebase -i --root &&
- git cat-file commit HEAD^ >out &&
- grep "^author ..*> [0-9][0-9]* [-+][0-9][0-9][0-9][0-9]$" out
+ git commit --amend --author="Au ${SQ}thor <author@example.com>" --no-edit &&
+ git cat-file commit HEAD | grep ^author >expected &&
+ 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