Once upon a time, I dreamt of an interactive rebase that would not
flatten branch structure, but instead recreate the commit topology
faithfully.
My original attempt was --preserve-merges, but that design was so
limited that I did not even enable it in interactive mode.
Subsequently, it *was* enabled in interactive mode, with the predictable
consequences: as the --preserve-merges design does not allow for
specifying the parents of merge commits explicitly, all the new commits'
parents are defined *implicitly* by the previous commit history, and
hence it is *not possible to even reorder commits*.
This design flaw cannot be fixed. Not without a complete re-design, at
least. This patch series offers such a re-design.
Think of --recreate-merges as "--preserve-merges done right". It
introduces new verbs for the todo list, `label`, `reset` and `merge`.
For a commit topology like this:
A - B - C
\ /
D
the generated todo list would look like this:
# branch D
pick 0123 A
label branch-point
pick 1234 D
label D
reset branch-point
pick 2345 B
merge -C 3456 D # C
There are more patches in the pipeline, based on this patch series, but
left for later in the interest of reviewable patch series: one mini
series to use the sequencer even for `git rebase -i --root`, and another
one to add support for octopus merges to --recreate-merges.
Changes since v3:
- (sorry for the broken iteration v4)
- fixed a grammar error in "introduce the `merge` command"'s commit message.
- fixed a couple of resource leaks in safe_append() and do_reset(), pointed
out by Eric Sunshine.
Johannes Schindelin (11):
sequencer: avoid using errno clobbered by rollback_lock_file()
sequencer: make rearrange_squash() a bit more obvious
sequencer: introduce new commands to reset the revision
sequencer: introduce the `merge` command
sequencer: fast-forward merge commits, if possible
rebase-helper --make-script: introduce a flag to recreate merges
rebase: introduce the --recreate-merges option
sequencer: make refs generated by the `label` command worktree-local
sequencer: handle post-rewrite for merge commands
pull: accept --rebase=recreate to recreate the branch topology
rebase -i: introduce --recreate-merges=[no-]rebase-cousins
Stefan Beller (1):
git-rebase--interactive: clarify arguments
Documentation/config.txt | 8 +
Documentation/git-pull.txt | 5 +-
Documentation/git-rebase.txt | 14 +-
builtin/pull.c | 14 +-
builtin/rebase--helper.c | 13 +-
builtin/remote.c | 2 +
contrib/completion/git-completion.bash | 4 +-
git-rebase--interactive.sh | 22 +-
git-rebase.sh | 16 +
refs.c | 3 +-
sequencer.c | 742 ++++++++++++++++++++++++++++++++-
sequencer.h | 7 +
t/t3430-rebase-recreate-merges.sh | 208 +++++++++
13 files changed, 1027 insertions(+), 31 deletions(-)
create mode 100755 t/t3430-rebase-recreate-merges.sh
base-commit: e3a80781f5932f5fea12a49eb06f3ade4ed8945c
Published-As: https://github.com/dscho/git/releases/tag/recreate-merges-v5
Fetch-It-Via: git fetch https://github.com/dscho/git recreate-merges-v5
Interdiff vs v4:
diff --git a/sequencer.c b/sequencer.c
index 63ae71a7512..b2bf63029d4 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2514,14 +2514,17 @@ static int safe_append(const char *filename, const
char *fmt, ...)
if (write_in_full(fd, buf.buf, buf.len) < 0) {
error_errno(_("could not write to '%s'"), filename);
+ strbuf_release(&buf);
rollback_lock_file(&lock);
return -1;
}
if (commit_lock_file(&lock) < 0) {
+ strbuf_release(&buf);
rollback_lock_file(&lock);
return error(_("failed to finalize '%s'"), filename);
}
+ strbuf_release(&buf);
return 0;
}
@@ -2601,8 +2604,11 @@ static int do_reset(const char *name, int len, struct
replay_opts *opts)
unpack_tree_opts.update = 1;
unpack_tree_opts.reset = 1;
- if (read_cache_unmerged())
+ if (read_cache_unmerged()) {
+ rollback_lock_file(&lock);
+ strbuf_release(&ref_name);
return error_resolve_conflict(_(action_name(opts)));
+ }
if (!fill_tree_descriptor(&desc, &oid)) {
error(_("failed to find tree of %s"), oid_to_hex(&oid));
--
2.16.1.windows.4