Skip to content

Commit 49ee2c2

Browse files
committed
Merge branch 'pw/rebase-cleanup-merge-strategy-option-handling' into seen
Clean-up of the code path that deals with merge strategy option handling in "git rebase". * pw/rebase-cleanup-merge-strategy-option-handling: rebase: remove a couple of redundant strategy tests rebase -m: fix serialization of strategy options rebase -m: cleanup --strategy-option handling rebase: stop reading and writing unnecessary strategy state
2 parents 1cb0656 + d7c3a76 commit 49ee2c2

File tree

6 files changed

+56
-132
lines changed

6 files changed

+56
-132
lines changed

builtin/rebase.c

Lines changed: 16 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ struct rebase_options {
117117
struct string_list exec;
118118
int allow_empty_message;
119119
int rebase_merges, rebase_cousins;
120-
char *strategy, *strategy_opts;
120+
char *strategy;
121+
struct string_list strategy_opts;
121122
struct strbuf git_format_patch_opt;
122123
int reschedule_failed_exec;
123124
int reapply_cherry_picks;
@@ -146,6 +147,7 @@ struct rebase_options {
146147
.config_rebase_merges = -1, \
147148
.update_refs = -1, \
148149
.config_update_refs = -1, \
150+
.strategy_opts = STRING_LIST_INIT_NODUP \
149151
}
150152

151153
static struct replay_opts get_replay_opts(const struct rebase_options *opts)
@@ -179,8 +181,14 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
179181
replay.default_strategy = NULL;
180182
}
181183

182-
if (opts->strategy_opts)
183-
parse_strategy_opts(&replay, opts->strategy_opts);
184+
if (opts->strategy_opts.nr) {
185+
ALLOC_ARRAY(replay.xopts, opts->strategy_opts.nr);
186+
replay.xopts_nr = opts->strategy_opts.nr;
187+
replay.xopts_alloc = opts->strategy_opts.nr;
188+
for (size_t i = 0; i < opts->strategy_opts.nr; i++)
189+
replay.xopts[i] =
190+
xstrdup(opts->strategy_opts.items[i].string);
191+
}
184192

185193
if (opts->squash_onto) {
186194
oidcpy(&replay.squash_onto, opts->squash_onto);
@@ -486,24 +494,6 @@ static int read_basic_state(struct rebase_options *opts)
486494
opts->gpg_sign_opt = xstrdup(buf.buf);
487495
}
488496

489-
if (file_exists(state_dir_path("strategy", opts))) {
490-
strbuf_reset(&buf);
491-
if (!read_oneliner(&buf, state_dir_path("strategy", opts),
492-
READ_ONELINER_WARN_MISSING))
493-
return -1;
494-
free(opts->strategy);
495-
opts->strategy = xstrdup(buf.buf);
496-
}
497-
498-
if (file_exists(state_dir_path("strategy_opts", opts))) {
499-
strbuf_reset(&buf);
500-
if (!read_oneliner(&buf, state_dir_path("strategy_opts", opts),
501-
READ_ONELINER_WARN_MISSING))
502-
return -1;
503-
free(opts->strategy_opts);
504-
opts->strategy_opts = xstrdup(buf.buf);
505-
}
506-
507497
strbuf_release(&buf);
508498

509499
return 0;
@@ -521,12 +511,6 @@ static int rebase_write_basic_state(struct rebase_options *opts)
521511
write_file(state_dir_path("quiet", opts), "%s", "");
522512
if (opts->flags & REBASE_VERBOSE)
523513
write_file(state_dir_path("verbose", opts), "%s", "");
524-
if (opts->strategy)
525-
write_file(state_dir_path("strategy", opts), "%s",
526-
opts->strategy);
527-
if (opts->strategy_opts)
528-
write_file(state_dir_path("strategy_opts", opts), "%s",
529-
opts->strategy_opts);
530514
if (opts->allow_rerere_autoupdate > 0)
531515
write_file(state_dir_path("allow_rerere_autoupdate", opts),
532516
"-%s-rerere-autoupdate",
@@ -1080,7 +1064,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
10801064
struct object_id branch_base;
10811065
int ignore_whitespace = 0;
10821066
const char *gpg_sign = NULL;
1083-
struct string_list strategy_options = STRING_LIST_INIT_NODUP;
10841067
struct object_id squash_onto;
10851068
char *squash_onto_name = NULL;
10861069
char *keep_base_onto_name = NULL;
@@ -1188,7 +1171,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
11881171
N_("use 'merge-base --fork-point' to refine upstream")),
11891172
OPT_STRING('s', "strategy", &options.strategy,
11901173
N_("strategy"), N_("use the given merge strategy")),
1191-
OPT_STRING_LIST('X', "strategy-option", &strategy_options,
1174+
OPT_STRING_LIST('X', "strategy-option", &options.strategy_opts,
11921175
N_("option"),
11931176
N_("pass the argument through to the merge "
11941177
"strategy")),
@@ -1491,23 +1474,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
14911474
} else {
14921475
/* REBASE_MERGE */
14931476
if (ignore_whitespace) {
1494-
string_list_append(&strategy_options,
1477+
string_list_append(&options.strategy_opts,
14951478
"ignore-space-change");
14961479
}
14971480
}
14981481

1499-
if (strategy_options.nr) {
1500-
int i;
1501-
1502-
if (!options.strategy)
1503-
options.strategy = "ort";
1504-
1505-
strbuf_reset(&buf);
1506-
for (i = 0; i < strategy_options.nr; i++)
1507-
strbuf_addf(&buf, " --%s",
1508-
strategy_options.items[i].string);
1509-
options.strategy_opts = xstrdup(buf.buf);
1510-
}
1482+
if (options.strategy_opts.nr && !options.strategy)
1483+
options.strategy = "ort";
15111484

15121485
if (options.strategy) {
15131486
options.strategy = xstrdup(options.strategy);
@@ -1889,10 +1862,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
18891862
free(options.gpg_sign_opt);
18901863
string_list_clear(&options.exec, 0);
18911864
free(options.strategy);
1892-
free(options.strategy_opts);
1865+
string_list_clear(&options.strategy_opts, 0);
18931866
strbuf_release(&options.git_format_patch_opt);
18941867
free(squash_onto_name);
18951868
free(keep_base_onto_name);
1896-
string_list_clear(&strategy_options, 0);
18971869
return !!ret;
18981870
}

sequencer.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2916,7 +2916,7 @@ static int populate_opts_cb(const char *key, const char *value, void *data)
29162916
return 0;
29172917
}
29182918

2919-
void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)
2919+
static void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)
29202920
{
29212921
int i;
29222922
int count;
@@ -2928,7 +2928,7 @@ void parse_strategy_opts(struct replay_opts *opts, char *raw_opts)
29282928
count = split_cmdline(strategy_opts_string,
29292929
(const char ***)&opts->xopts);
29302930
if (count < 0)
2931-
die(_("could not split '%s': %s"), strategy_opts_string,
2931+
BUG("could not split '%s': %s", strategy_opts_string,
29322932
split_cmdline_strerror(count));
29332933
opts->xopts_nr = count;
29342934
for (i = 0; i < opts->xopts_nr; i++) {
@@ -2944,7 +2944,6 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
29442944
strbuf_reset(buf);
29452945
if (!read_oneliner(buf, rebase_path_strategy(), 0))
29462946
return;
2947-
free(opts->strategy);
29482947
opts->strategy = strbuf_detach(buf, NULL);
29492948
if (!read_oneliner(buf, rebase_path_strategy_opts(), 0))
29502949
return;
@@ -3053,12 +3052,27 @@ static int read_populate_opts(struct replay_opts *opts)
30533052

30543053
static void write_strategy_opts(struct replay_opts *opts)
30553054
{
3056-
int i;
30573055
struct strbuf buf = STRBUF_INIT;
30583056

3059-
for (i = 0; i < opts->xopts_nr; ++i)
3060-
strbuf_addf(&buf, " --%s", opts->xopts[i]);
3057+
/*
3058+
* Quote strategy options so that they can be read correctly
3059+
* by split_cmdline().
3060+
*/
3061+
for (size_t i = 0; i < opts->xopts_nr; i++) {
3062+
char *arg = opts->xopts[i];
3063+
3064+
if (i)
3065+
strbuf_addch(&buf, ' ');
3066+
strbuf_addch(&buf, '"');
3067+
for (size_t j = 0; arg[j]; j++) {
3068+
const char c = arg[j];
30613069

3070+
if (c == '"' || c =='\\')
3071+
strbuf_addch(&buf, '\\');
3072+
strbuf_addch(&buf, c);
3073+
}
3074+
strbuf_addch(&buf, '"');
3075+
}
30623076
write_file(rebase_path_strategy_opts(), "%s\n", buf.buf);
30633077
strbuf_release(&buf);
30643078
}

sequencer.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,6 @@ int read_oneliner(struct strbuf *buf,
247247
const char *path, unsigned flags);
248248
int read_author_script(const char *path, char **name, char **email, char **date,
249249
int allow_missing);
250-
void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);
251250
int write_basic_state(struct replay_opts *opts, const char *head_name,
252251
struct commit *onto, const struct object_id *orig_head);
253252
void sequencer_post_commit_cleanup(struct repository *r, int verbose);

t/t3402-rebase-merge.sh

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -131,27 +131,6 @@ test_expect_success 'picking rebase' '
131131
esac
132132
'
133133

134-
test_expect_success 'rebase -s funny -Xopt' '
135-
test_when_finished "rm -fr test-bin funny.was.run" &&
136-
mkdir test-bin &&
137-
cat >test-bin/git-merge-funny <<-EOF &&
138-
#!$SHELL_PATH
139-
case "\$1" in --opt) ;; *) exit 2 ;; esac
140-
shift &&
141-
>funny.was.run &&
142-
exec git merge-recursive "\$@"
143-
EOF
144-
chmod +x test-bin/git-merge-funny &&
145-
git reset --hard &&
146-
git checkout -b test-funny main^ &&
147-
test_commit funny &&
148-
(
149-
PATH=./test-bin:$PATH &&
150-
git rebase -s funny -Xopt main
151-
) &&
152-
test -f funny.was.run
153-
'
154-
155134
test_expect_success 'rebase --skip works with two conflicts in a row' '
156135
git checkout second-side &&
157136
tr "[A-Z]" "[a-z]" <newfile >tmp &&

t/t3418-rebase-continue.sh

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -62,61 +62,39 @@ test_expect_success 'rebase --continue remembers merge strategy and options' '
6262
rm -fr .git/rebase-* &&
6363
git reset --hard commit-new-file-F2-on-topic-branch &&
6464
test_commit "commit-new-file-F3-on-topic-branch" F3 32 &&
65-
test_when_finished "rm -fr test-bin funny.was.run" &&
65+
test_when_finished "rm -fr test-bin" &&
6666
mkdir test-bin &&
67-
cat >test-bin/git-merge-funny <<-EOF &&
68-
#!$SHELL_PATH
69-
case "\$1" in --opt) ;; *) exit 2 ;; esac
70-
shift &&
71-
>funny.was.run &&
72-
exec git merge-recursive "\$@"
67+
68+
write_script test-bin/git-merge-funny <<-\EOF &&
69+
printf "[%s]\n" $# "$1" "$2" "$3" "$5" >actual
70+
shift 3 &&
71+
exec git merge-recursive "$@"
7372
EOF
74-
chmod +x test-bin/git-merge-funny &&
75-
(
76-
PATH=./test-bin:$PATH &&
77-
test_must_fail git rebase -s funny -Xopt main topic
78-
) &&
79-
test -f funny.was.run &&
80-
rm funny.was.run &&
81-
echo "Resolved" >F2 &&
82-
git add F2 &&
83-
(
84-
PATH=./test-bin:$PATH &&
85-
git rebase --continue
86-
) &&
87-
test -f funny.was.run
88-
'
8973
90-
test_expect_success 'rebase -i --continue handles merge strategy and options' '
91-
rm -fr .git/rebase-* &&
92-
git reset --hard commit-new-file-F2-on-topic-branch &&
93-
test_commit "commit-new-file-F3-on-topic-branch-for-dash-i" F3 32 &&
94-
test_when_finished "rm -fr test-bin funny.was.run funny.args" &&
95-
mkdir test-bin &&
96-
cat >test-bin/git-merge-funny <<-EOF &&
97-
#!$SHELL_PATH
98-
echo "\$@" >>funny.args
99-
case "\$1" in --opt) ;; *) exit 2 ;; esac
100-
case "\$2" in --foo) ;; *) exit 2 ;; esac
101-
case "\$4" in --) ;; *) exit 2 ;; esac
102-
shift 2 &&
103-
>funny.was.run &&
104-
exec git merge-recursive "\$@"
74+
cat >expect <<-\EOF &&
75+
[7]
76+
[--option=arg with space]
77+
[--op"tion\]
78+
[--new
79+
line ]
80+
[--]
10581
EOF
106-
chmod +x test-bin/git-merge-funny &&
82+
83+
rm -f actual &&
10784
(
10885
PATH=./test-bin:$PATH &&
109-
test_must_fail git rebase -i -s funny -Xopt -Xfoo main topic
86+
test_must_fail git rebase -s funny -X"option=arg with space" \
87+
-Xop\"tion\\ -X"new${LF}line " main topic
11088
) &&
111-
test -f funny.was.run &&
112-
rm funny.was.run &&
89+
test_cmp expect actual &&
90+
rm actual &&
11391
echo "Resolved" >F2 &&
11492
git add F2 &&
11593
(
11694
PATH=./test-bin:$PATH &&
11795
git rebase --continue
11896
) &&
119-
test -f funny.was.run
97+
test_cmp expect actual
12098
'
12199

122100
test_expect_success 'rebase -r passes merge strategy options correctly' '

t/t3436-rebase-more-options.sh

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,6 @@ test_expect_success 'setup' '
4040
EOF
4141
'
4242

43-
test_expect_success 'bad -X <strategy-option> arguments: unclosed quote' '
44-
cat >expect <<-\EOF &&
45-
fatal: could not split '\''--bad'\'': unclosed quote
46-
EOF
47-
test_expect_code 128 git rebase -X"bad argument\"" side main >out 2>actual &&
48-
test_must_be_empty out &&
49-
test_cmp expect actual
50-
'
51-
52-
test_expect_success 'bad -X <strategy-option> arguments: bad escape' '
53-
cat >expect <<-\EOF &&
54-
fatal: could not split '\''--bad'\'': cmdline ends with \
55-
EOF
56-
test_expect_code 128 git rebase -X"bad escape \\" side main >out 2>actual &&
57-
test_must_be_empty out &&
58-
test_cmp expect actual
59-
'
60-
6143
test_expect_success '--ignore-whitespace works with apply backend' '
6244
test_must_fail git rebase --apply main side &&
6345
git rebase --abort &&

0 commit comments

Comments
 (0)