Skip to content

rebase -r: support merge strategies other than recursive #294

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,6 @@
/git-range-diff
/git-read-tree
/git-rebase
/git-rebase--am
/git-rebase--common
/git-rebase--interactive
/git-rebase--preserve-merges
/git-receive-pack
/git-reflog
Expand Down
2 changes: 0 additions & 2 deletions Documentation/git-rebase.txt
Original file line number Diff line number Diff line change
Expand Up @@ -543,8 +543,6 @@ In addition, the following pairs of options are incompatible:
* --preserve-merges and --interactive
* --preserve-merges and --signoff
* --preserve-merges and --rebase-merges
* --rebase-merges and --strategy
* --rebase-merges and --strategy-option

BEHAVIORAL DIFFERENCES
-----------------------
Expand Down
2 changes: 0 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -624,8 +624,6 @@ SCRIPT_SH += git-web--browse.sh

SCRIPT_LIB += git-mergetool--lib
SCRIPT_LIB += git-parse-remote
SCRIPT_LIB += git-rebase--am
SCRIPT_LIB += git-rebase--common
SCRIPT_LIB += git-rebase--preserve-merges
SCRIPT_LIB += git-sh-setup
SCRIPT_LIB += git-sh-i18n
Expand Down
23 changes: 6 additions & 17 deletions builtin/rebase.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ struct rebase_options {
const char *onto_name;
const char *revisions;
const char *switch_to;
int root;
int root, root_with_onto;
struct object_id *squash_onto;
struct commit *restrict_revision;
int dont_finish_rebase;
Expand Down Expand Up @@ -374,6 +374,7 @@ static int run_rebase_interactive(struct rebase_options *opts,
flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;
flags |= opts->rebase_merges ? TODO_LIST_REBASE_MERGES : 0;
flags |= opts->rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;
flags |= opts->root_with_onto ? TODO_LIST_ROOT_WITH_ONTO : 0;
flags |= command == ACTION_SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0;

switch (command) {
Expand Down Expand Up @@ -1153,10 +1154,6 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action)
}

switch (opts->type) {
case REBASE_AM:
backend = "git-rebase--am";
backend_func = "git_rebase__am";
break;
case REBASE_PRESERVE_MERGES:
backend = "git-rebase--preserve-merges";
backend_func = "git_rebase__preserve_merges";
Expand All @@ -1167,8 +1164,7 @@ static int run_specific_rebase(struct rebase_options *opts, enum action action)
}

strbuf_addf(&script_snippet,
". git-sh-setup && . git-rebase--common &&"
" . %s && %s", backend, backend_func);
". git-sh-setup && . %s && %s", backend, backend_func);
argv[0] = script_snippet.buf;

status = run_command_v_opt(argv, RUN_USING_SHELL);
Expand Down Expand Up @@ -1816,15 +1812,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
"'--reschedule-failed-exec'"));
}

if (options.rebase_merges) {
if (strategy_options.nr)
die(_("cannot combine '--rebase-merges' with "
"'--strategy-option'"));
if (options.strategy)
die(_("cannot combine '--rebase-merges' with "
"'--strategy'"));
}

if (!options.root) {
if (argc < 1) {
struct branch *branch;
Expand Down Expand Up @@ -1855,7 +1842,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.squash_onto = &squash_onto;
options.onto_name = squash_onto_name =
xstrdup(oid_to_hex(&squash_onto));
}
} else
options.root_with_onto = 1;

options.upstream_name = NULL;
options.upstream = NULL;
if (argc > 1)
Expand Down
85 changes: 0 additions & 85 deletions git-rebase--am.sh

This file was deleted.

69 changes: 0 additions & 69 deletions git-rebase--common.sh

This file was deleted.

55 changes: 55 additions & 0 deletions git-rebase--preserve-merges.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,61 @@ rewritten_pending="$state_dir"/rewritten-pending
# and leaves CR at the end instead.
cr=$(printf "\015")

resolvemsg="
$(gettext 'Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".')
"

write_basic_state () {
echo "$head_name" > "$state_dir"/head-name &&
echo "$onto" > "$state_dir"/onto &&
echo "$orig_head" > "$state_dir"/orig-head &&
test t = "$GIT_QUIET" && : > "$state_dir"/quiet
test t = "$verbose" && : > "$state_dir"/verbose
test -n "$strategy" && echo "$strategy" > "$state_dir"/strategy
test -n "$strategy_opts" && echo "$strategy_opts" > \
"$state_dir"/strategy_opts
test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \
"$state_dir"/allow_rerere_autoupdate
test -n "$gpg_sign_opt" && echo "$gpg_sign_opt" > "$state_dir"/gpg_sign_opt
test -n "$signoff" && echo "$signoff" >"$state_dir"/signoff
test -n "$reschedule_failed_exec" && : > "$state_dir"/reschedule-failed-exec
}

apply_autostash () {
if test -f "$state_dir/autostash"
then
stash_sha1=$(cat "$state_dir/autostash")
if git stash apply $stash_sha1 >/dev/null 2>&1
then
echo "$(gettext 'Applied autostash.')" >&2
else
git stash store -m "autostash" -q $stash_sha1 ||
die "$(eval_gettext "Cannot store \$stash_sha1")"
gettext 'Applying autostash resulted in conflicts.
Your changes are safe in the stash.
You can run "git stash pop" or "git stash drop" at any time.
' >&2
fi
fi
}

output () {
case "$verbose" in
'')
output=$("$@" 2>&1 )
status=$?
test $status != 0 && printf "%s\n" "$output"
return $status
;;
*)
"$@"
;;
esac
}

strategy_args=${strategy:+--strategy=$strategy}
test -n "$strategy_opts" &&
eval '
Expand Down
20 changes: 16 additions & 4 deletions sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ static int parse_key_value_squoted(char *buf, struct string_list *list)
* GIT_AUTHOR_DATE='$author_date'
*
* where $author_name, $author_email and $author_date are quoted. We are strict
* with our parsing, as the file was meant to be eval'd in the old
* with our parsing, as the file was meant to be eval'd in the now-removed
* git-am.sh/git-rebase--interactive.sh scripts, and thus if the file differs
* from what this function expects, it is better to bail out than to do
* something that the user does not expect.
Expand Down Expand Up @@ -3256,6 +3256,9 @@ static int do_merge(struct repository *r,
struct commit *head_commit, *merge_commit, *i;
struct commit_list *bases, *j, *reversed = NULL;
struct commit_list *to_merge = NULL, **tail = &to_merge;
const char *strategy = !opts->xopts_nr &&
(!opts->strategy || !strcmp(opts->strategy, "recursive")) ?
NULL : opts->strategy;
struct merge_options o;
int merge_arg_len, oneline_offset, can_fast_forward, ret, k;
static struct lock_file lock;
Expand Down Expand Up @@ -3404,7 +3407,7 @@ static int do_merge(struct repository *r,
goto leave_merge;
}

if (to_merge->next) {
if (strategy || to_merge->next) {
/* Octopus merge */
struct child_process cmd = CHILD_PROCESS_INIT;

Expand All @@ -3418,7 +3421,14 @@ static int do_merge(struct repository *r,
cmd.git_cmd = 1;
argv_array_push(&cmd.args, "merge");
argv_array_push(&cmd.args, "-s");
argv_array_push(&cmd.args, "octopus");
if (!strategy)
argv_array_push(&cmd.args, "octopus");
else {
argv_array_push(&cmd.args, strategy);
for (k = 0; k < opts->xopts_nr; k++)
argv_array_pushf(&cmd.args,
"-X%s", opts->xopts[k]);
}
argv_array_push(&cmd.args, "--no-edit");
argv_array_push(&cmd.args, "--no-ff");
argv_array_push(&cmd.args, "--no-log");
Expand Down Expand Up @@ -4430,6 +4440,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
{
int keep_empty = flags & TODO_LIST_KEEP_EMPTY;
int rebase_cousins = flags & TODO_LIST_REBASE_COUSINS;
int root_with_onto = flags & TODO_LIST_ROOT_WITH_ONTO;
struct strbuf buf = STRBUF_INIT, oneline = STRBUF_INIT;
struct strbuf label = STRBUF_INIT;
struct commit_list *commits = NULL, **tail = &commits, *iter;
Expand Down Expand Up @@ -4596,7 +4607,8 @@ static int make_script_with_merges(struct pretty_print_context *pp,

if (!commit)
strbuf_addf(out, "%s %s\n", cmd_reset,
rebase_cousins ? "onto" : "[new root]");
rebase_cousins || root_with_onto ?
"onto" : "[new root]");
else {
const char *to = NULL;

Expand Down
6 changes: 6 additions & 0 deletions sequencer.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ int sequencer_remove_state(struct replay_opts *opts);
*/
#define TODO_LIST_REBASE_COUSINS (1U << 4)
#define TODO_LIST_APPEND_TODO_HELP (1U << 5)
/*
* When generating a script that rebases merges with `--root` *and* with
* `--onto`, we do not want to re-generate the root commits.
*/
#define TODO_LIST_ROOT_WITH_ONTO (1U << 6)


int sequencer_make_script(struct repository *r, struct strbuf *out, int argc,
const char **argv, unsigned flags);
Expand Down
Loading