git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v8 00/16] rebase -i: offer to recreate commit topology by rebasing merges

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Apr 21, 2018, 10:29 UTC
Message-ID
<cover.1524306546.git.johannes.schindelin@gmx.de>
In-Reply-To
<cover.1524139900.git.johannes.schindelin@gmx.de>

Junio, I think this is now ready for `next`. Thank you for your patience and help with this.

Once upon a time, I dreamed of an interactive rebase that would not linearize all patches and drop all merge commits, 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 --rebase-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 --rebase-merges. And then one to allow for rebasing merge commits in a smarter way (this one will need a bit more work, though, as it can result in very complicated, nested merge conflicts *very* easily).

Changes since v7:
- Touched up all the documentation (it was a mistake to copy-edit the
  --preserve-merges description, for example).
- Disentangled the rescheduling of label/reset/merge from the one of the
  pick/fixup/squash code path (thanks Phillip!).
- When the merge failed, we now write out .git/rebase-merge/patch.
- An `exec git cherry-pick` or `exec git revert` will no longer mess
  with refs/rewritten/ in sequencer_remove_state() (d'oh....).
Johannes Schindelin (14):
  sequencer: avoid using errno clobbered by rollback_lock_file()
  sequencer: make rearrange_squash() a bit more obvious
  sequencer: refactor how original todo list lines are accessed
  sequencer: offer helpful advice when a command was rescheduled
  sequencer: introduce the `merge` command
  sequencer: fast-forward `merge` commands, if possible
  rebase-helper --make-script: introduce a flag to rebase merges
  rebase: introduce the --rebase-merges option
  sequencer: make refs generated by the `label` command worktree-local
  sequencer: handle post-rewrite for merge commands
  rebase --rebase-merges: avoid "empty merges"
  pull: accept --rebase=merges to recreate the branch topology
  rebase -i: introduce --rebase-merges=[no-]rebase-cousins
  rebase -i --rebase-merges: add a section to the man page
Phillip Wood (1):
  rebase --rebase-merges: add test for --keep-empty
Stefan Beller (1):
  git-rebase--interactive: clarify arguments
 Documentation/config.txt               |   8 +
 Documentation/git-pull.txt             |   6 +-
 Documentation/git-rebase.txt           | 160 ++++-
 builtin/pull.c                         |  14 +-
 builtin/rebase--helper.c               |  13 +-
 builtin/remote.c                       |  18 +-
 contrib/completion/git-completion.bash |   4 +-
 git-rebase--interactive.sh             |  22 +-
 git-rebase.sh                          |  16 +
 refs.c                                 |   3 +-
 sequencer.c                            | 891 +++++++++++++++++++++++--
 sequencer.h                            |   7 +
 t/t3421-rebase-topology-linear.sh      |   1 +
 t/t3430-rebase-merges.sh               | 244 +++++++
 14 files changed, 1347 insertions(+), 60 deletions(-)
 create mode 100755 t/t3430-rebase-merges.sh
base-commit: fe0a9eaf31dd0c349ae4308498c33a5c3794b293
Published-As: https://github.com/dscho/git/releases/tag/recreate-merges-v8
Fetch-It-Via: git fetch https://github.com/dscho/git recreate-merges-v8
Interdiff vs v7:
 diff --git a/Documentation/config.txt b/Documentation/config.txt
 index da46f154bb3..d6bcb5dcb67 100644
 --- a/Documentation/config.txt
 +++ b/Documentation/config.txt
 @@ -1059,8 +1059,8 @@ branch.<name>.rebase::
  	branch-specific manner.
  +
  When `merges`, pass the `--rebase-merges` option to 'git rebase'
 -so that locally committed merge commits will not be flattened
 -by running 'git pull'.
 +so that the local merge commits are included in the rebase (see
 +linkgit:git-rebase[1] for details).
  +
  When preserve, also pass `--preserve-merges` along to 'git rebase'
  so that locally committed merge commits will not be flattened
 @@ -2622,8 +2622,8 @@ pull.rebase::
  	per-branch basis.
  +
  When `merges`, pass the `--rebase-merges` option to 'git rebase'
 -so that locally committed merge commits will not be flattened
 -by running 'git pull'.
 +so that the local merge commits are included in the rebase (see
 +linkgit:git-rebase[1] for details).
  +
  When preserve, also pass `--preserve-merges` along to 'git rebase'
  so that locally committed merge commits will not be flattened
 diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
 index 6f76d815dd3..4e0ad6fd8e0 100644
 --- a/Documentation/git-pull.txt
 +++ b/Documentation/git-pull.txt
 @@ -109,7 +109,8 @@ include::merge-options.txt[]
  	to avoid rebasing non-local changes.
  +
  When set to `merges`, rebase using `git rebase --rebase-merges` so that
 -locally created merge commits will not be flattened.
 +the local merge commits are included in the rebase (see
 +linkgit:git-rebase[1] for details).
  +
  When set to preserve, rebase with the `--preserve-merges` option passed
  to `git rebase` so that locally created merge commits will not be flattened.
 diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
 index 0ff83b62821..3b996e46d6a 100644
 --- a/Documentation/git-rebase.txt
 +++ b/Documentation/git-rebase.txt
 @@ -380,15 +380,25 @@ have the long commit hash prepended to the format.
  
  -r::
  --rebase-merges[=(rebase-cousins|no-rebase-cousins)]::
 -	Rebase merge commits instead of flattening the history by replaying
 -	merges. Merge conflict resolutions or manual amendments to merge
 -	commits are not rebased automatically, but have to be applied
 +	By default, a rebase will simply drop merge commits and only rebase
 +	the non-merge commits. With this option, it will try to preserve
 +	the branching structure within the commits that are to be rebased,
 +	by recreating the merge commits. If a merge commit resolved any merge
 +	or contained manual amendments, then they will have to be re-applied
  	manually.
  +
  By default, or when `no-rebase-cousins` was specified, commits which do not
  have `<upstream>` as direct ancestor will keep their original branch point.
 -If the `rebase-cousins` mode is turned on, such commits are rebased onto
 -`<upstream>` (or `<onto>`, if specified).
 +If the `rebase-cousins` mode is turned on, such commits are instead rebased
 +onto `<upstream>` (or `<onto>`, if specified).
 ++
 +This mode is similar in spirit to `--preserve-merges`, but in contrast to
 +that option works well in interactive rebases: commits can be reordered,
 +inserted and dropped at will.
 ++
 +It is currently only possible to recreate the merge commits using the
 +`recursive` merge strategy; Different merge strategies can be used only via
 +explicit `exec git merge -s <strategy> [...]` commands.
  +
  See also REBASING MERGES below.
  
 @@ -795,8 +805,9 @@ REBASING MERGES
  The interactive rebase command was originally designed to handle
  individual patch series. As such, it makes sense to exclude merge
  commits from the todo list, as the developer may have merged the
 -current `master` while working on the branch, only to eventually
 -rebase all the commits onto `master` (skipping the merge commits).
 +then-current `master` while working on the branch, only to rebase
 +all the commits onto `master` eventually (skipping the merge
 +commits).
  
  However, there are legitimate reasons why a developer may want to
  recreate merge commits: to keep the branch structure (or "commit
 @@ -846,21 +857,23 @@ merge -C a1b2c3 refactor-button # Merge 'refactor-button'
  merge -C 6f5e4d report-a-bug # Merge 'report-a-bug'
  ------------
  
 -In contrast to a regular interactive rebase, there are `label`, `reset` and
 -`merge` commands in addition to `pick` ones.
 +In contrast to a regular interactive rebase, there are `label`, `reset`
 +and `merge` commands in addition to `pick` ones.
  
  The `label` command associates a label with the current HEAD when that
  command is executed. These labels are created as worktree-local refs
  (`refs/rewritten/<label>`) that will be deleted when the rebase
  finishes. That way, rebase operations in multiple worktrees linked to
 -the same repository do not interfere with one another. If the `label` command
 -fails, it is rescheduled immediately, with a helpful message how to proceed.
 +the same repository do not interfere with one another. If the `label`
 +command fails, it is rescheduled immediately, with a helpful message how
 +to proceed.
  
 -The `reset` command is essentially a `git read-tree -m -u` (think: `git
 -reset --hard`, but refusing to overwrite untracked files) to the
 -specified revision (typically a previously-labeled one). If the `reset`
 -command fails, it is rescheduled immediately, with a helpful message how to
 -proceed.
 +The `reset` command resets the HEAD, index and worktree to the specified
 +revision. It is isimilar to an `exec git reset --hard <label>`, but
 +refuses to overwrite untracked files. If the `reset` command fails, it is
 +rescheduled immediately, with a helpful message how to edit the todo list
 +(this typically happens when a `reset` command was inserted into the todo
 +list manually and contains a typo).
  
  The `merge` command will merge the specified revision into whatever is
  HEAD at that time. With `-C <original-commit>`, the commit message of
 @@ -875,7 +888,7 @@ At this time, the `merge` command will *always* use the `recursive`
  merge strategy, with no way to choose a different one. To work around
  this, an `exec` command can be used to call `git merge` explicitly,
  using the fact that the labels are worktree-local refs (the ref
 -`refs/rewritten/onto` would correspond to the label `onto`).
 +`refs/rewritten/onto` would correspond to the label `onto`, for example).
  
  Note: the first command (`label onto`) labels the revision onto which
  the commits are rebased; The name `onto` is just a convention, as a nod
 @@ -925,7 +938,7 @@ The todo list presented by `--preserve-merges --interactive` does not
  represent the topology of the revision graph.  Editing commits and
  rewording their commit messages should work fine, but attempts to
  reorder commits tend to produce counterintuitive results. Use
 ---rebase-merges for a more faithful representation.
 +`--rebase-merges` in such scenarios instead.
  
  For example, an attempt to rearrange
  ------------
 diff --git a/sequencer.c b/sequencer.c
 index 3c7bb5d3fd8..9ffadbb3d3c 100644
 --- a/sequencer.c
 +++ b/sequencer.c
 @@ -258,7 +258,8 @@ int sequencer_remove_state(struct replay_opts *opts)
  	struct strbuf buf = STRBUF_INIT;
  	int i;
  
 -	if (strbuf_read_file(&buf, rebase_path_refs_to_delete(), 0) > 0) {
 +	if (is_rebase_i(opts) &&
 +	    strbuf_read_file(&buf, rebase_path_refs_to_delete(), 0) > 0) {
  		char *p = buf.buf;
  		while (*p) {
  			char *eol = strchr(p, '\n');
 @@ -2960,7 +2961,7 @@ N_("Could not execute the todo command\n"
  
  static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
  {
 -	int res = 0;
 +	int res = 0, reschedule = 0;
  
  	setenv(GIT_REFLOG_ACTION, action_name(opts), 0);
  	if (opts->allow_ff)
 @@ -3002,7 +3003,7 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
  			res = do_pick_commit(item->command, item->commit,
  					opts, is_final_fixup(todo_list));
  			if (is_rebase_i(opts) && res < 0) {
 -reschedule:
 +				/* Reschedule */
  				advise(_(rescheduled_advice),
  				       get_item_line_length(todo_list,
  							    todo_list->current),
 @@ -3059,21 +3060,42 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
  			}
  		} else if (item->command == TODO_LABEL) {
  			if ((res = do_label(item->arg, item->arg_len)))
 -				goto reschedule;
 +				reschedule = 1;
  		} else if (item->command == TODO_RESET) {
  			if ((res = do_reset(item->arg, item->arg_len, opts)))
 -				goto reschedule;
 +				reschedule = 1;
  		} else if (item->command == TODO_MERGE) {
 -			res = do_merge(item->commit, item->arg, item->arg_len,
 -				       item->flags, opts);
 -			if (res < 0)
 -				goto reschedule;
 -			if (item->commit)
 +			if ((res = do_merge(item->commit,
 +					    item->arg, item->arg_len,
 +					    item->flags, opts)) < 0)
 +				reschedule = 1;
 +			else if (item->commit)
  				record_in_rewritten(&item->commit->object.oid,
  						    peek_command(todo_list, 1));
 +			if (res > 0)
 +				/* failed with merge conflicts */
 +				return error_with_patch(item->commit,
 +							item->arg,
 +							item->arg_len, opts,
 +							res, 0);
  		} else if (!is_noop(item->command))
  			return error(_("unknown command %d"), item->command);
  
 +		if (reschedule) {
 +			advise(_(rescheduled_advice),
 +			       get_item_line_length(todo_list,
 +						    todo_list->current),
 +			       get_item_line(todo_list, todo_list->current));
 +			todo_list->current--;
 +			if (save_todo(todo_list, opts))
 +				return -1;
 +			if (item->commit)
 +				return error_with_patch(item->commit,
 +							item->arg,
 +							item->arg_len, opts,
 +							res, 0);
 +		}
 +
  		todo_list->current++;
  		if (res)
  			return res;
 diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh
 index f2de7059830..3d4dfdf7bec 100755
 --- a/t/t3430-rebase-merges.sh
 +++ b/t/t3430-rebase-merges.sh
 @@ -125,6 +125,29 @@ test_expect_success '`reset` refuses to overwrite untracked files' '
  	git rebase --abort
  '
  
 +test_expect_success 'failed `merge` writes patch (may be rescheduled, too)' '
 +	test_when_finished "test_might_fail git rebase --abort" &&
 +	git checkout -b conflicting-merge A &&
 +
 +	: fail because of conflicting untracked file &&
 +	>G.t &&
 +	echo "merge -C H G" >script-from-scratch &&
 +	test_config sequence.editor \""$PWD"/replace-editor.sh\" &&
 +	test_tick &&
 +	test_must_fail git rebase -ir HEAD &&
 +	grep "^merge -C .* G$" .git/rebase-merge/done &&
 +	grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
 +	test_path_is_file .git/rebase-merge/patch &&
 +
 +	: fail because of merge conflict &&
 +	rm G.t .git/rebase-merge/patch &&
 +	git reset --hard &&
 +	test_commit conflicting-G G.t not-G conflicting-G &&
 +	test_must_fail git rebase --continue &&
 +	! grep "^merge -C .* G$" .git/rebase-merge/git-rebase-todo &&
 +	test_path_is_file .git/rebase-merge/patch
 +'
 +
  test_expect_success 'with a branch tip that was cherry-picked already' '
  	git checkout -b already-upstream master &&
  	base="$(git rev-parse --verify HEAD)" &&
-- 
2.17.0.windows.1.15.gaa56ade3205
Previous: Johannes SchindelinNext: Johannes Schindelin
Message 301 of 412 in “rebase -i: offer to recreate merge commits”
  1. 0/8 rebase -i: offer to recreate merge commitsJohannes Schindelin, Jan 18, 2018
  2. 1/8 sequencer: introduce new commands to reset the revisionJohannes Schindelin, Jan 18, 2018
  3. Jacob KellerJan 18, 2018
  4. Johannes SchindelinJan 18, 2018
  5. Jacob KellerJan 18, 2018
  6. Philip OakleyJan 18, 2018
  7. Jacob KellerJan 18, 2018
  8. Johannes SchindelinJan 29, 2018
  9. Junio C HamanoJan 22, 2018
  10. Johannes SchindelinJan 29, 2018
  11. Eric SunshineJan 19, 2018
  12. Junio C HamanoJan 24, 2018
  13. Johannes SchindelinJan 29, 2018
  14. Johannes SchindelinJan 29, 2018
  15. Eric SunshineJan 30, 2018
  16. Phillip WoodJan 19, 2018
  17. Phillip WoodJan 19, 2018
  18. Jacob KellerJan 19, 2018
  19. Johannes SchindelinJan 29, 2018
  20. Johannes SchindelinJan 29, 2018
  21. Johannes SchindelinJan 29, 2018
  22. 2/8 sequencer: introduce the `merge` commandJohannes Schindelin, Jan 18, 2018
  23. Jacob KellerJan 18, 2018
  24. Johannes SchindelinJan 18, 2018
  25. Jacob KellerJan 18, 2018
  26. Eric SunshineJan 19, 2018
  27. Phillip WoodJan 19, 2018
  28. Jacob KellerJan 20, 2018
  29. Johannes SchindelinJan 29, 2018
  30. Johannes SchindelinJan 31, 2018
  31. Phillip WoodJan 31, 2018
  32. Jacob KellerFeb 1, 2018
  33. Junio C HamanoJan 22, 2018
  34. Johannes SchindelinJan 29, 2018
  35. 3/8 sequencer: fast-forward merge commits, if possibleJohannes Schindelin, Jan 18, 2018
  36. Phillip WoodJan 19, 2018
  37. Junio C HamanoJan 23, 2018
  38. Phillip WoodJan 24, 2018
  39. Junio C HamanoJan 24, 2018
  40. Johannes SchindelinJan 29, 2018
  41. Junio C HamanoJan 23, 2018
  42. Johannes SchindelinJan 29, 2018
  43. 4/8 rebase-helper --make-script: introduce a flag to recreate mergesJohannes Schindelin, Jan 18, 2018
  44. Philip OakleyJan 18, 2018
  45. Eric SunshineJan 19, 2018
  46. Junio C HamanoJan 23, 2018
  47. Johannes SchindelinJan 29, 2018
  48. Johannes SchindelinJan 29, 2018
  49. Junio C HamanoJan 23, 2018
  50. Johannes SchindelinJan 29, 2018
  51. 5/8 rebase: introduce the --recreate-merges optionJohannes Schindelin, Jan 18, 2018
  52. Eric SunshineJan 19, 2018
  53. Johannes SchindelinJan 29, 2018
  54. Junio C HamanoJan 23, 2018
  55. Johannes SchindelinFeb 10, 2018
  56. Sergey OrganovFeb 7, 2018
  57. Jacob KellerFeb 7, 2018
  58. Sergey OrganovFeb 7, 2018
  59. Johannes SixtFeb 7, 2018
  60. Johannes SchindelinFeb 7, 2018
  61. Øyvind RønningstadFeb 7, 2018
  62. Junio C HamanoFeb 7, 2018
  63. Johannes SchindelinFeb 8, 2018
  64. Sergey OrganovFeb 14, 2018
  65. Sergey OrganovFeb 9, 2018
  66. Johannes SixtFeb 9, 2018
  67. Jacob KellerFeb 11, 2018
  68. Sergey OrganovFeb 12, 2018
  69. Sergey OrganovFeb 9, 2018
  70. Johannes SchindelinFeb 10, 2018
  71. Sergey OrganovFeb 12, 2018
  72. Johannes SchindelinFeb 12, 2018
  73. Sergey OrganovFeb 13, 2018
  74. Johannes SchindelinFeb 15, 2018
  75. Sergey OrganovFeb 15, 2018
  76. Johannes SchindelinFeb 15, 2018
  77. Sergey OrganovFeb 12, 2018
  78. Johannes SchindelinFeb 12, 2018
  79. Jacob KellerFeb 13, 2018
  80. Sergey OrganovFeb 13, 2018
  81. Jacob KellerFeb 14, 2018
  82. Johannes SchindelinFeb 15, 2018
  83. Sergey OrganovFeb 15, 2018
  84. Johannes SchindelinFeb 15, 2018
  85. Sergey OrganovFeb 13, 2018
  86. Johannes SchindelinFeb 15, 2018
  87. 6/8 sequencer: handle autosquash and post-rewrite for merge commandsJohannes Schindelin, Jan 18, 2018
  88. Jacob KellerJan 18, 2018
  89. Johannes SchindelinJan 18, 2018
  90. Jacob KellerJan 18, 2018
  91. Junio C HamanoJan 23, 2018
  92. 7/8 pull: accept --rebase=recreate to recreate the branch topologyJohannes Schindelin, Jan 18, 2018
  93. 8/8 rebase -i: introduce --recreate-merges=no-rebase-cousinsJohannes Schindelin, Jan 18, 2018
  94. Philip OakleyJan 18, 2018
  95. Johannes SchindelinJan 29, 2018
  96. Eric SunshineJan 20, 2018
  97. Jacob KellerJan 18, 2018
  98. 10/8 interactive rebase feedbackStefan Beller, Jan 18, 2018
  99. 9/8 [DO NOT APPLY, but squash?] git-rebase--interactive: clarify argumentsStefan Beller, Jan 18, 2018
  100. Jacob KellerJan 18, 2018
  101. Johannes SchindelinJan 18, 2018
  102. Stefan BellerJan 18, 2018
  103. Junio C HamanoJan 19, 2018
  104. Jacob KellerJan 20, 2018
  105. Johannes SchindelinJan 29, 2018
  106. 10/8 [DO NOT APPLY, but improve?] rebase--interactive: introduce "stop" commandStefan Beller, Jan 18, 2018
  107. Jacob KellerJan 18, 2018
  108. Philip OakleyJan 18, 2018
  109. Jacob KellerJan 18, 2018
  110. Johannes SchindelinJan 18, 2018
  111. Stefan BellerJan 18, 2018
  112. Junio C HamanoJan 19, 2018
  113. Johannes SchindelinJan 29, 2018
  114. Junio C HamanoJan 23, 2018
  115. Johannes SchindelinJan 29, 2018
  116. 00/10 rebase -i: offer to recreate merge commitsJohannes Schindelin, Jan 29, 2018
  117. 01/10 git-rebase--interactive: clarify argumentsJohannes Schindelin, Jan 29, 2018
  118. 03/10 sequencer: introduce the `merge` commandJohannes Schindelin, Jan 29, 2018
  119. 02/10 sequencer: introduce new commands to reset the revisionJohannes Schindelin, Jan 29, 2018
  120. Eric SunshineJan 30, 2018
  121. Johannes SchindelinFeb 10, 2018
  122. Stefan BellerJan 30, 2018
  123. Johannes SchindelinJan 31, 2018
  124. Phillip WoodJan 31, 2018
  125. Johannes SchindelinFeb 10, 2018
  126. 04/10 sequencer: fast-forward merge commits, if possibleJohannes Schindelin, Jan 29, 2018
  127. 05/10 rebase-helper --make-script: introduce a flag to recreate mergesJohannes Schindelin, Jan 29, 2018
  128. 07/10 sequencer: make refs generated by the `label` command worktree-localJohannes Schindelin, Jan 29, 2018
  129. 06/10 rebase: introduce the --recreate-merges optionJohannes Schindelin, Jan 29, 2018
  130. 08/10 sequencer: handle autosquash and post-rewrite for merge commandsJohannes Schindelin, Jan 29, 2018
  131. 09/10 pull: accept --rebase=recreate to recreate the branch topologyJohannes Schindelin, Jan 29, 2018
  132. 10/10 rebase -i: introduce --recreate-merges=[no-]rebase-cousinsJohannes Schindelin, Jan 29, 2018
  133. Stefan BellerJan 30, 2018
  134. Johannes SchindelinJan 31, 2018
  135. Junio C HamanoJan 30, 2018
  136. Johannes SchindelinJan 31, 2018
  137. Jacob KellerFeb 1, 2018
  138. 00/12 rebase -i: offer to recreate merge commitsJohannes Schindelin, Feb 11, 2018
  139. 01/12 sequencer: avoid using errno clobbered by rollback_lock_file()Johannes Schindelin, Feb 11, 2018
  140. 02/12 sequencer: make rearrange_squash() a bit more obviousJohannes Schindelin, Feb 11, 2018
  141. 03/12 git-rebase--interactive: clarify argumentsJohannes Schindelin, Feb 11, 2018
  142. 04/12 sequencer: introduce new commands to reset the revisionJohannes Schindelin, Feb 11, 2018
  143. Eric SunshineFeb 12, 2018
  144. Johannes SchindelinFeb 12, 2018
  145. 05/12 sequencer: introduce the `merge` commandJohannes Schindelin, Feb 11, 2018
  146. Eric SunshineFeb 12, 2018
  147. Johannes SchindelinFeb 12, 2018
  148. 06/12 sequencer: fast-forward merge commits, if possibleJohannes Schindelin, Feb 11, 2018
  149. 07/12 rebase-helper --make-script: introduce a flag to recreate mergesJohannes Schindelin, Feb 11, 2018
  150. 08/12 rebase: introduce the --recreate-merges optionJohannes Schindelin, Feb 11, 2018
  151. 09/12 sequencer: make refs generated by the `label` command worktree-localJohannes Schindelin, Feb 11, 2018
  152. 10/12 sequencer: handle post-rewrite for merge commandsJohannes Schindelin, Feb 11, 2018
  153. 11/12 pull: accept --rebase=recreate to recreate the branch topologyJohannes Schindelin, Feb 11, 2018
  154. 12/12 rebase -i: introduce --recreate-merges=[no-]rebase-cousinsJohannes Schindelin, Feb 11, 2018
  155. 00/12 rebase -i: offer to recreate merge commitsJohannes Schindelin, Feb 23, 2018
  156. 01/12 sequencer: avoid using errno clobbered by rollback_lock_file()Johannes Schindelin, Feb 23, 2018
  157. 02/12 sequencer: make rearrange_squash() a bit more obviousJohannes Schindelin, Feb 23, 2018
  158. 04/12 sequencer: introduce new commands to reset the revisionJohannes Schindelin, Feb 23, 2018
  159. 03/12 git-rebase--interactive: clarify argumentsJohannes Schindelin, Feb 23, 2018
  160. 05/12 sequencer: introduce the `merge` commandJohannes Schindelin, Feb 23, 2018
  161. 06/12 sequencer: fast-forward merge commits, if possibleJohannes Schindelin, Feb 23, 2018
  162. 07/12 rebase-helper --make-script: introduce a flag to recreate mergesJohannes Schindelin, Feb 23, 2018
  163. 08/12 rebase: introduce the --recreate-merges optionJohannes Schindelin, Feb 23, 2018
  164. 09/12 sequencer: make refs generated by the `label` command worktree-localJohannes Schindelin, Feb 23, 2018
  165. 10/12 sequencer: handle post-rewrite for merge commandsJohannes Schindelin, Feb 23, 2018
  166. 11/12 pull: accept --rebase=recreate to recreate the branch topologyJohannes Schindelin, Feb 23, 2018
  167. 12/12 rebase -i: introduce --recreate-merges=[no-]rebase-cousinsJohannes Schindelin, Feb 23, 2018
  168. Jacob KellerFeb 25, 2018
  169. Johannes SchindelinFeb 26, 2018
  170. 00/12 rebase -i: offer to recreate merge commitsJohannes Schindelin, Feb 26, 2018
  171. 01/12 sequencer: avoid using errno clobbered by rollback_lock_file()Johannes Schindelin, Feb 26, 2018
  172. Martin ÅgrenFeb 27, 2018
  173. Johannes SchindelinMar 2, 2018
  174. 03/12 git-rebase--interactive: clarify argumentsJohannes Schindelin, Feb 26, 2018
  175. 04/12 sequencer: introduce new commands to reset the revisionJohannes Schindelin, Feb 26, 2018
  176. 05/12 sequencer: introduce the `merge` commandJohannes Schindelin, Feb 26, 2018
  177. 07/12 rebase-helper --make-script: introduce a flag to recreate mergesJohannes Schindelin, Feb 26, 2018
  178. 06/12 sequencer: fast-forward merge commits, if possibleJohannes Schindelin, Feb 26, 2018
  179. 08/12 rebase: introduce the --recreate-merges optionJohannes Schindelin, Feb 26, 2018
  180. 09/12 sequencer: make refs generated by the `label` command worktree-localJohannes Schindelin, Feb 26, 2018
  181. 10/12 sequencer: handle post-rewrite for merge commandsJohannes Schindelin, Feb 26, 2018
  182. 11/12 pull: accept --rebase=recreate to recreate the branch topologyJohannes Schindelin, Feb 26, 2018
  183. 12/12 rebase -i: introduce --recreate-merges=[no-]rebase-cousinsJohannes Schindelin, Feb 26, 2018
  184. 02/12 sequencer: make rearrange_squash() a bit more obviousJohannes Schindelin, Feb 26, 2018
  185. Igor DjordjevicMar 6, 2018
  186. Johannes SchindelinMar 7, 2018
  187. 00/15 rebase -i: offer to recreate commit topologyJohannes Schindelin, Apr 10, 2018
  188. 02/15 sequencer: make rearrange_squash() a bit more obviousJohannes Schindelin, Apr 10, 2018
  189. 01/15 sequencer: avoid using errno clobbered by rollback_lock_file()Johannes Schindelin, Apr 10, 2018
  190. 03/15 git-rebase--interactive: clarify argumentsJohannes Schindelin, Apr 10, 2018
  191. 04/15 sequencer: introduce new commands to reset the revisionJohannes Schindelin, Apr 10, 2018
  192. Sergey OrganovApr 11, 2018
  193. Johannes SchindelinApr 11, 2018
  194. Sergey OrganovApr 11, 2018
  195. Phillip WoodApr 13, 2018
  196. Philip OakleyApr 15, 2018
  197. Phillip WoodApr 18, 2018
  198. 05/15 sequencer: introduce the `merge` commandJohannes Schindelin, Apr 10, 2018
  199. Phillip WoodApr 13, 2018
  200. Phillip WoodApr 13, 2018
  201. Johannes SchindelinApr 14, 2018
  202. Phillip WoodApr 18, 2018
  203. Johannes SchindelinApr 19, 2018
  204. 06/15 sequencer: fast-forward `merge` commands, if possibleJohannes Schindelin, Apr 10, 2018
  205. 07/15 rebase-helper --make-script: introduce a flag to rebase mergesJohannes Schindelin, Apr 10, 2018
  206. 08/15 rebase: introduce the --rebase-merges optionJohannes Schindelin, Apr 10, 2018
  207. 09/15 rebase --rebase-merges: add test for --keep-emptyJohannes Schindelin, Apr 10, 2018
  208. 10/15 sequencer: make refs generated by the `label` command worktree-localJohannes Schindelin, Apr 10, 2018
  209. 12/15 rebase --rebase-merges: avoid "empty merges"Johannes Schindelin, Apr 10, 2018
  210. 13/15 pull: accept --rebase=merges to recreate the branch topologyJohannes Schindelin, Apr 10, 2018
  211. 14/15 rebase -i: introduce --rebase-merges=[no-]rebase-cousinsJohannes Schindelin, Apr 10, 2018
  212. Sergey OrganovApr 12, 2018
  213. 15/15 rebase -i --rebase-merges: add a section to the man pageJohannes Schindelin, Apr 10, 2018
  214. Martin ÅgrenApr 10, 2018
  215. Johannes SchindelinApr 10, 2018
  216. Phillip WoodApr 11, 2018
  217. Eric SunshineApr 11, 2018
  218. Johannes SchindelinApr 12, 2018
  219. Phillip WoodApr 13, 2018
  220. Johannes SchindelinApr 12, 2018
  221. Jacob KellerApr 12, 2018
  222. Phillip WoodApr 13, 2018
  223. Sergey OrganovApr 12, 2018
  224. 11/15 sequencer: handle post-rewrite for merge commandsJohannes Schindelin, Apr 10, 2018
  225. Sergey OrganovApr 10, 2018
  226. Johannes SchindelinApr 10, 2018
  227. Sergey OrganovApr 11, 2018
  228. Johannes SchindelinApr 11, 2018
  229. Sergey OrganovApr 11, 2018
  230. Johannes SchindelinApr 11, 2018
  231. Sergey OrganovApr 12, 2018
  232. Johannes SchindelinApr 12, 2018
  233. Jacob KellerApr 11, 2018
  234. Sergey OrganovApr 12, 2018
  235. Jacob KellerApr 12, 2018
  236. Johannes SchindelinApr 12, 2018
  237. Jacob KellerApr 12, 2018
  238. Johannes SchindelinApr 13, 2018
  239. Phillip WoodApr 13, 2018
  240. Johannes SchindelinApr 13, 2018
  241. Sergey OrganovApr 19, 2018
  242. Jacob KellerApr 19, 2018
  243. Sergey OrganovApr 19, 2018
  244. Johannes SchindelinApr 20, 2018
  245. Jacob KellerApr 20, 2018
  246. Sergey OrganovApr 18, 2018
  247. 00/17 rebase -i: offer to recreate commit topologyJohannes Schindelin, Apr 19, 2018
  248. 01/17 sequencer: avoid using errno clobbered by rollback_lock_file()Johannes Schindelin, Apr 19, 2018
  249. 02/17 sequencer: make rearrange_squash() a bit more obviousJohannes Schindelin, Apr 19, 2018
  250. 03/17 sequencer: refactor how original todo list lines are accessedJohannes Schindelin, Apr 19, 2018
  251. 04/17 sequencer: offer helpful advice when a command was rescheduledJohannes Schindelin, Apr 19, 2018
  252. 05/17 git-rebase--interactive: clarify argumentsJohannes Schindelin, Apr 19, 2018
  253. 06/17 sequencer: introduce new commands to reset the revisionJohannes Schindelin, Apr 19, 2018
  254. Phillip WoodApr 20, 2018
  255. Johannes SchindelinApr 20, 2018
  256. 07/17 # This is a combination of 2 commits. # This is the 1st commit message:Johannes Schindelin, Apr 19, 2018
  257. Eric SunshineApr 20, 2018
  258. Johannes SchindelinApr 20, 2018
  259. 0/4 rebase -i: avoid stale "# This is a combination of" in commit messagesJohannes Schindelin, Apr 20, 2018
  260. 1/4 rebase -i: demonstrate bugs with fixup!/squash! commit messagesJohannes Schindelin, Apr 20, 2018
  261. 2/4 rebase -i: Handle "combination of <n> commits" with GETTEXT_POISONJohannes Schindelin, Apr 20, 2018
  262. Stefan BellerApr 20, 2018
  263. Johannes SchindelinApr 21, 2018
  264. 3/4 sequencer: leave a tell-tale when a fixup/squash failedJohannes Schindelin, Apr 20, 2018
  265. Stefan BellerApr 20, 2018
  266. Johannes SchindelinApr 21, 2018
  267. 4/4 rebase --skip: clean up commit message after a failed fixup/squashJohannes Schindelin, Apr 20, 2018
  268. 0/4 rebase -i: avoid stale "# This is a combination of" in commit messagesJohannes Schindelin, Apr 21, 2018
  269. 1/4 rebase -i: demonstrate bugs with fixup!/squash! commit messagesJohannes Schindelin, Apr 21, 2018
  270. 2/4 rebase -i: Handle "combination of <n> commits" with GETTEXT_POISONJohannes Schindelin, Apr 21, 2018
  271. 3/4 sequencer: leave a tell-tale when a fixup/squash failedJohannes Schindelin, Apr 21, 2018
  272. 4/4 rebase --skip: clean up commit message after a failed fixup/squashJohannes Schindelin, Apr 21, 2018
  273. Stefan BellerApr 23, 2018
  274. Phillip WoodApr 23, 2018
  275. Johannes SchindelinApr 25, 2018
  276. Phillip WoodApr 25, 2018
  277. Johannes SchindelinApr 26, 2018
  278. Phillip WoodApr 26, 2018
  279. Junio C HamanoApr 24, 2018
  280. 0/4 rebase -i: avoid stale "# This is a combination of" in commit messagesJohannes Schindelin, Apr 27, 2018
  281. 1/4 rebase -i: demonstrate bugs with fixup!/squash! commit messagesJohannes Schindelin, Apr 27, 2018
  282. 3/4 sequencer: always commit without editing when asked forJohannes Schindelin, Apr 27, 2018
  283. 2/4 rebase -i: Handle "combination of <n> commits" with GETTEXT_POISONJohannes Schindelin, Apr 27, 2018
  284. 4/4 rebase --skip: clean up commit message after a failed fixup/squashJohannes Schindelin, Apr 27, 2018
  285. Stefan BellerApr 27, 2018
  286. Johannes SchindelinApr 28, 2018
  287. Phillip WoodMay 6, 2018
  288. Phillip WoodMay 9, 2018
  289. Johannes SchindelinOct 2, 2018
  290. Phillip WoodOct 8, 2018
  291. 08/17 sequencer: fast-forward `merge` commands, if possibleJohannes Schindelin, Apr 19, 2018
  292. 09/17 rebase-helper --make-script: introduce a flag to rebase mergesJohannes Schindelin, Apr 19, 2018
  293. 10/17 rebase: introduce the --rebase-merges optionJohannes Schindelin, Apr 19, 2018
  294. 11/17 rebase --rebase-merges: add test for --keep-emptyJohannes Schindelin, Apr 19, 2018
  295. 12/17 sequencer: make refs generated by the `label` command worktree-localJohannes Schindelin, Apr 19, 2018
  296. 13/17 sequencer: handle post-rewrite for merge commandsJohannes Schindelin, Apr 19, 2018
  297. 14/17 rebase --rebase-merges: avoid "empty merges"Johannes Schindelin, Apr 19, 2018
  298. 15/17 pull: accept --rebase=merges to recreate the branch topologyJohannes Schindelin, Apr 19, 2018
  299. 16/17 rebase -i: introduce --rebase-merges=[no-]rebase-cousinsJohannes Schindelin, Apr 19, 2018
  300. 17/17 rebase -i --rebase-merges: add a section to the man pageJohannes Schindelin, Apr 19, 2018
  301. 00/16 rebase -i: offer to recreate commit topology by rebasing mergesJohannes Schindelin, Apr 21, 2018
  302. 01/16 sequencer: avoid using errno clobbered by rollback_lock_file()Johannes Schindelin, Apr 21, 2018
  303. 02/16 sequencer: make rearrange_squash() a bit more obviousJohannes Schindelin, Apr 21, 2018
  304. 03/16 sequencer: refactor how original todo list lines are accessedJohannes Schindelin, Apr 21, 2018
  305. 04/16 sequencer: offer helpful advice when a command was rescheduledJohannes Schindelin, Apr 21, 2018
  306. 05/16 git-rebase--interactive: clarify argumentsJohannes Schindelin, Apr 21, 2018
  307. 06/16 sequencer: introduce the `merge` commandJohannes Schindelin, Apr 21, 2018
  308. Phillip WoodApr 21, 2018
  309. Phillip WoodApr 22, 2018
  310. Johannes SchindelinApr 23, 2018
  311. Johannes SchindelinApr 23, 2018
  312. Phillip WoodApr 23, 2018
  313. Martin ÅgrenApr 24, 2018
  314. 1/2 merge: setup `opts` later in `checkout_fast_forward()`Martin Ågren, Apr 24, 2018
  315. Jacob KellerApr 24, 2018
  316. Martin ÅgrenApr 24, 2018
  317. Johannes SchindelinApr 24, 2018
  318. 2/2 unpack_trees_options: free messages when doneMartin Ågren, Apr 24, 2018
  319. Elijah NewrenApr 24, 2018
  320. Martin ÅgrenApr 28, 2018
  321. Johannes SchindelinApr 28, 2018
  322. Elijah NewrenApr 28, 2018
  323. Elijah NewrenMay 16, 2018
  324. 0/3 unpack_trees_options: free messages when doneMartin Ågren, May 16, 2018
  325. 1/3 merge: setup `opts` later in `checkout_fast_forward()`Martin Ågren, May 16, 2018
  326. Stefan BellerMay 16, 2018
  327. Martin ÅgrenMay 16, 2018
  328. Jacob KellerMay 16, 2018
  329. Jacob KellerMay 16, 2018
  330. Junio C HamanoMay 17, 2018
  331. Jacob KellerMay 18, 2018
  332. 2/3 merge-recursive: provide pair of `unpack_trees_{start,finish}()`Martin Ågren, May 16, 2018
  333. 3/3 unpack_trees_options: free messages when doneMartin Ågren, May 16, 2018
  334. Junio C HamanoMay 17, 2018
  335. Martin ÅgrenMay 18, 2018
  336. 0/3 unpack_trees_options: free messages when doneMartin Ågren, May 18, 2018
  337. 1/3 merge: setup `opts` later in `checkout_fast_forward()`Martin Ågren, May 18, 2018
  338. 2/3 merge-recursive: provide pair of `unpack_trees_{start,finish}()`Martin Ågren, May 18, 2018
  339. 3/3 unpack_trees_options: free messages when doneMartin Ågren, May 18, 2018
  340. Jeff KingMay 18, 2018
  341. Elijah NewrenMay 18, 2018
  342. Jeff KingMay 19, 2018
  343. Martin ÅgrenMay 19, 2018
  344. 0/4 unpack_trees_options: free messages when doneMartin Ågren, May 20, 2018
  345. 1/4 merge: setup `opts` later in `checkout_fast_forward()`Martin Ågren, May 20, 2018
  346. 2/4 merge-recursive: provide pair of `unpack_trees_{start,finish}()`Martin Ågren, May 20, 2018
  347. 3/4 string-list: provide `string_list_appendf()`Martin Ågren, May 20, 2018
  348. Jacob KellerMay 20, 2018
  349. Re*: [PATCH v4 3/4] string-list: provide `string_list_appendf()`Junio C Hamano, May 21, 2018
  350. Junio C HamanoMay 21, 2018
  351. Jeff KingMay 21, 2018
  352. 0/4 unpack_trees_options: free messages when doneMartin Ågren, May 21, 2018
  353. 1/4 merge: setup `opts` later in `checkout_fast_forward()`Martin Ågren, May 21, 2018
  354. 2/4 merge-recursive: provide pair of `unpack_trees_{start,finish}()`Martin Ågren, May 21, 2018
  355. 3/4 argv-array: return the pushed string from argv_push*()Martin Ågren, May 21, 2018
  356. 4/4 unpack_trees_options: free messages when doneMartin Ågren, May 21, 2018
  357. Jeff KingMay 21, 2018
  358. Junio C HamanoMay 22, 2018
  359. Junio C HamanoMay 22, 2018
  360. Martin ÅgrenMay 22, 2018
  361. Junio C HamanoMay 23, 2018
  362. Jeff KingMay 21, 2018
  363. 4/4 unpack_trees_options: free messages when doneMartin Ågren, May 20, 2018
  364. Elijah NewrenMay 16, 2018
  365. Ben PeartMay 17, 2018
  366. Johannes SchindelinApr 24, 2018
  367. Philip OakleyApr 22, 2018
  368. Johannes SchindelinApr 23, 2018
  369. Philip OakleyApr 23, 2018
  370. Johannes SchindelinApr 24, 2018
  371. Philip OakleyApr 24, 2018
  372. Philip OakleyApr 22, 2018
  373. 07/16 sequencer: fast-forward `merge` commands, if possibleJohannes Schindelin, Apr 21, 2018
  374. 08/16 rebase-helper --make-script: introduce a flag to rebase mergesJohannes Schindelin, Apr 21, 2018
  375. Philip OakleyApr 22, 2018
  376. Johannes SchindelinApr 24, 2018
  377. 09/16 rebase: introduce the --rebase-merges optionJohannes Schindelin, Apr 21, 2018
  378. Philip OakleyApr 22, 2018
  379. Johannes SchindelinApr 24, 2018
  380. Philip OakleyApr 22, 2018
  381. Junio C HamanoApr 24, 2018
  382. Johannes SchindelinApr 24, 2018
  383. Johannes SchindelinApr 24, 2018
  384. 10/16 rebase --rebase-merges: add test for --keep-emptyJohannes Schindelin, Apr 21, 2018
  385. 11/16 sequencer: make refs generated by the `label` command worktree-localJohannes Schindelin, Apr 21, 2018
  386. 12/16 sequencer: handle post-rewrite for merge commandsJohannes Schindelin, Apr 21, 2018
  387. 13/16 rebase --rebase-merges: avoid "empty merges"Johannes Schindelin, Apr 21, 2018
  388. 14/16 pull: accept --rebase=merges to recreate the branch topologyJohannes Schindelin, Apr 21, 2018
  389. 15/16 rebase -i: introduce --rebase-merges=[no-]rebase-cousinsJohannes Schindelin, Apr 21, 2018
  390. 16/16 rebase -i --rebase-merges: add a section to the man pageJohannes Schindelin, Apr 21, 2018
  391. 00/17 rebase -i: offer to recreate commit topology by rebasing mergesJohannes Schindelin, Apr 25, 2018
  392. 01/17 sequencer: avoid using errno clobbered by rollback_lock_file()Johannes Schindelin, Apr 25, 2018
  393. 02/17 sequencer: make rearrange_squash() a bit more obviousJohannes Schindelin, Apr 25, 2018
  394. 03/17 sequencer: refactor how original todo list lines are accessedJohannes Schindelin, Apr 25, 2018
  395. 04/17 sequencer: offer helpful advice when a command was rescheduledJohannes Schindelin, Apr 25, 2018
  396. 05/17 git-rebase--interactive: clarify argumentsJohannes Schindelin, Apr 25, 2018
  397. 06/17 sequencer: introduce new commands to reset the revisionJohannes Schindelin, Apr 25, 2018
  398. 07/17 sequencer: introduce the `merge` commandJohannes Schindelin, Apr 25, 2018
  399. 08/17 sequencer: fast-forward `merge` commands, if possibleJohannes Schindelin, Apr 25, 2018
  400. 09/17 rebase-helper --make-script: introduce a flag to rebase mergesJohannes Schindelin, Apr 25, 2018
  401. 10/17 rebase: introduce the --rebase-merges optionJohannes Schindelin, Apr 25, 2018
  402. 11/17 rebase --rebase-merges: add test for --keep-emptyJohannes Schindelin, Apr 25, 2018
  403. 12/17 sequencer: make refs generated by the `label` command worktree-localJohannes Schindelin, Apr 25, 2018
  404. 13/17 sequencer: handle post-rewrite for merge commandsJohannes Schindelin, Apr 25, 2018
  405. 15/17 pull: accept --rebase=merges to recreate the branch topologyJohannes Schindelin, Apr 25, 2018
  406. 16/17 rebase -i: introduce --rebase-merges=[no-]rebase-cousinsJohannes Schindelin, Apr 25, 2018
  407. 14/17 rebase --rebase-merges: avoid "empty merges"Johannes Schindelin, Apr 25, 2018
  408. 17/17 rebase -i --rebase-merges: add a section to the man pageJohannes Schindelin, Apr 25, 2018
  409. Junio C HamanoApr 26, 2018
  410. Junio C HamanoApr 26, 2018
  411. Sergey OrganovMay 25, 2018
  412. Sergey OrganovMay 25, 2018

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.