From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS31976 209.132.180.0/23 X-Spam-Status: No, score=-2.6 required=3.0 tests=AWL,BAYES_00, FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS, RCVD_IN_DNSWL_HI,T_RP_MATCHES_RCVD shortcircuit=no autolearn=no autolearn_force=no version=3.4.0 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by dcvr.yhbt.net (Postfix) with ESMTP id 496BF1FAE2 for ; Mon, 29 Jan 2018 22:54:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751803AbeA2Wyq (ORCPT ); Mon, 29 Jan 2018 17:54:46 -0500 Received: from mout.gmx.net ([212.227.15.18]:59741 "EHLO mout.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751547AbeA2Wyo (ORCPT ); Mon, 29 Jan 2018 17:54:44 -0500 Received: from MININT-KR8J64V.europe.corp.microsoft.com ([37.201.193.1]) by mail.gmx.com (mrgmx002 [212.227.17.190]) with ESMTPSA (Nemesis) id 0Ldq55-1f5hAf28Ad-00j1fl; Mon, 29 Jan 2018 23:54:34 +0100 Date: Mon, 29 Jan 2018 23:54:32 +0100 (STD) From: Johannes Schindelin X-X-Sender: virtualbox@MININT-6BKU6QN.europe.corp.microsoft.com To: git@vger.kernel.org cc: Junio C Hamano , Jacob Keller , Stefan Beller , Philip Oakley , Eric Sunshine , Phillip Wood Subject: [PATCH v2 00/10] rebase -i: offer to recreate merge commits In-Reply-To: Message-ID: References: User-Agent: Alpine 2.21.1 (DEB 209 2017-03-23) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-Provags-ID: V03:K0:mH7xUJOQ8bZ0Xl5jUR+ymFEmUFKUnfYMosYscyeLY6+40WaLYe5 mglc5u8Lwg+f2GJj3oPqV9KlP/oJPEVbSt/M62Gjo20z3sj7Gwjgk2b3f9J8vGHCWd/neoE NyTzNrZwpymYJCWp6gktf7jXpZf9RLmGSceORpfj2IzREZJDI9iQD/orOXcD0+iO8J1qnlI GsPAhOyuuRN4Su3Awulpg== X-UI-Out-Filterresults: notjunk:1;V01:K0:uI5FZeBAjmw=:UyST0V47+HyVZ5sifEiHcT d8hLkl7gzVB7uOQxHZy98sCp/njqddNOzYhMSMv24uJNut+V7zQ8XbmKOaNfnubrBxoab+l6R Ht614jpExzjs4Qwghy5Jc5IE1Nkca4udZXHZz3UwWOgZszZYtF/5Ss3L5LgREsdyXXNLPOrrk E1q2TFSL6o0W/BwoVXQ4Ys6EHM31Xgj4P11SqfWX8kjX/5ScuyqDY/XVLfFDI+qhlPImleM7d D1yj75voi0sYnNyvfBbuaCiT1aMRBgPZbcXQvy7QEtT4AkXHgkQbaqWrynl1CC+CoTczSREY4 8kYq0MQSJwt7Wr28iVfrn25RVD31Er0vvA5DZ7TXKdiBIjC6EISBm2FxXDfGkEKmCvIezyu51 2vlxUn8sE6om+TPVNZEXwpWbplt1ftYU7BpzdFSulh0dEhK0JSL40CoViIhmwFUgsRg3I+nFe +fhepp1YHj6GRs1OcwNI3OT6ngwiefXT1sMBEkHnOLSr/78cq+alLBb0moQpECC4NueQgwdbL b88OuJmmebRepBn3K/qYEjtXY2FfGjCEvOGo+7e/5O5cxw132IGKXAsdnvlnpaiU80PcXK/vH zbM27O+LC+goNsr2DX1qMl82ZMT6yAdDekZPKL39DQesXYuUAo3yg2QiFJuynXoDNrYHdLOxq oqaohdUgW0LPeZxME+GV/oaakXolzlmZmdV3PvV9x13/7Iy/5zyZM5FOWgWc3+NUvoMbBg0R5 tbD31I0QuAmeVonvMyF6U27w2kDDZIPU/cDZ/5laxgGtHZMyENZpTwx4+CaAYFBt4IMZXdFPM BgiHIKd8uBzt6MxFxhCHHRkmWEzUicOKuCs1eyqrLrHiDQDxLo3BAXOxFJxfZIBZ96kzP6J Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org 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 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 v1: - reintroduced "sequencer: make refs generated by the `label` command worktree-local" (which was squashed into "sequencer: handle autosquash and post-rewrite for merge commands" by accident) - got rid of the universally-hated `bud` command - as per Stefan's suggestion, the help blurb at the end of the todo list now lists the syntax - the no-rebase-cousins mode was made the default; This not only reflects the experience won from those years of using the Git garden shears, but was also deemed the better default in the discussion on the PR at https://github.com/git/git/pull/447 - I tried to clarify the role of the `onto` label in the commit message of `rebase-helper --make-script: introduce a flag to recreate merges` - fixed punctuation at the end of error(...) messages, and incorrect upper-case at the start - changed the generated todo lists to separate the label and the oneline in the `reset` command with a `#`, for readability - dropped redundant paragraph in the commit message that talked about support for octopus merges - avoided empty error message when HEAD could not be read during do_label() - merge commits are fast-forwarded only unless --force-rebase was passed - do_merge() now errors out a lot earlier when HEAD could not be parsed - the one-letter variables to hold either abbreviated or full todo list instructions in make_script_recreating_merges() were renamed to clearer names - The description of rebase's --recreate-merge option has been reworded; Hopefully it is a lot more clear now. Johannes Schindelin (9): 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 autosquash and 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 | 699 ++++++++++++++++++++++++++++++++- sequencer.h | 7 + t/t3430-rebase-recreate-merges.sh | 208 ++++++++++ 13 files changed, 988 insertions(+), 27 deletions(-) create mode 100755 t/t3430-rebase-recreate-merges.sh base-commit: 5be1f00a9a701532232f57958efab4be8c959a29 Published-As: https://github.com/dscho/git/releases/tag/recreate-merges-v2 Fetch-It-Via: git fetch https://github.com/dscho/git recreate-merges-v2 Interdiff vs v1: diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index ac07a5c3fc9..0e6d020d924 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -371,12 +371,13 @@ have the long commit hash prepended to the format. --recreate-merges[=(rebase-cousins|no-rebase-cousins)]:: Recreate merge commits instead of flattening the history by replaying merges. Merge conflict resolutions or manual amendments to merge - commits are not preserved. + commits are not recreated automatically, but have to be recreated + manually. + -By default, or when `rebase-cousins` was specified, commits which do not have -`` as direct ancestor are rebased onto `` (or ``, -if specified). If the `rebase-cousins` mode is turned off, such commits will -retain their original branch point. +By default, or when `no-rebase-cousins` was specified, commits which do not +have `` as direct ancestor keep their original branch point. +If the `rebase-cousins` mode is turned on, such commits are rebased onto +`` (or ``, if specified). -p:: --preserve-merges:: diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c index ef08fef4d14..cea99cb3235 100644 --- a/builtin/rebase--helper.c +++ b/builtin/rebase--helper.c @@ -13,7 +13,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) { struct replay_opts opts = REPLAY_OPTS_INIT; unsigned flags = 0, keep_empty = 0, recreate_merges = 0; - int abbreviate_commands = 0, no_rebase_cousins = -1; + int abbreviate_commands = 0, rebase_cousins = -1; enum { CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH, @@ -23,7 +23,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")), OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")), OPT_BOOL(0, "recreate-merges", &recreate_merges, N_("recreate merge commits")), - OPT_BOOL(0, "no-rebase-cousins", &no_rebase_cousins, + OPT_BOOL(0, "rebase-cousins", &rebase_cousins, N_("keep original branch points of cousins")), OPT_CMDMODE(0, "continue", &command, N_("continue rebase"), CONTINUE), @@ -59,10 +59,10 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix) flags |= keep_empty ? TODO_LIST_KEEP_EMPTY : 0; flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0; flags |= recreate_merges ? TODO_LIST_RECREATE_MERGES : 0; - flags |= no_rebase_cousins > 0 ? TODO_LIST_NO_REBASE_COUSINS : 0; + flags |= rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0; flags |= command == SHORTEN_OIDS ? TODO_LIST_SHORTEN_IDS : 0; - if (no_rebase_cousins >= 0&& !recreate_merges) + if (rebase_cousins >= 0 && !recreate_merges) warning(_("--[no-]rebase-cousins has no effect without " "--recreate-merges")); diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 23184c77e88..5e21e4cf269 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -155,17 +155,19 @@ reschedule_last_action () { append_todo_help () { gettext " Commands: -p, pick = use commit -r, reword = use commit, but edit the commit message -e, edit = use commit, but stop for amending -s, squash = use commit, but meld into previous commit -f, fixup = like \"squash\", but discard this commit's log message -x, exec = run command (the rest of the line) using shell -d, drop = remove commit -l, label = label current HEAD with a name -t, reset = reset HEAD to a label -b, bud = reset HEAD to the revision labeled 'onto' -m, merge = create a merge commit using a given commit's message +p, pick = use commit +r, reword = use commit, but edit the commit message +e, edit = use commit, but stop for amending +s, squash = use commit, but meld into previous commit +f, fixup = like \"squash\", but discard this commit's log message +x, exec = run command (the rest of the line) using shell +d, drop = remove commit +l, label