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

Re: [PATCH v2 2/2] rebase --exec: make it work with --rebase-merges

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Aug 9, 2018, 09:22 UTC
Message-ID
<nycvar.QRO.7.76.6.1808091039080.71@tvgsbejvaqbjf.bet>
In-Reply-To
<f7da64c2-0477-07dd-35ef-7cfd16447bd5@talktalk.net>
Hi Phillip,
On Mon, 6 Aug 2018, Phillip Wood wrote:
Show 75 quoted lines
> On 06/08/18 10:52, Johannes Schindelin via GitGitGadget wrote:
> > 
> > From: Johannes Schindelin <johannes.schindelin@gmx.de>
> > 
> > The idea of `--exec` is to append an `exec` call after each `pick`.
> > 
> > Since the introduction of fixup!/squash! commits, this idea was extended
> > to apply to "pick, possibly followed by a fixup/squash chain", i.e. an
> > exec would not be inserted between a `pick` and any of its corresponding
> > `fixup` or `squash` lines.
> > 
> > The current implementation uses a dirty trick to achieve that: it
> > assumes that there are only pick/fixup/squash commands, and then
> > *inserts* the `exec` lines before any `pick` but the first, and appends
> > a final one.
> > 
> > With the todo lists generated by `git rebase --rebase-merges`, this
> > simple implementation shows its problems: it produces the exact wrong
> > thing when there are `label`, `reset` and `merge` commands.
> > 
> > Let's change the implementation to do exactly what we want: look for
> > `pick` lines, skip any fixup/squash chains, and then insert the `exec`
> > line. Lather, rinse, repeat.
> > 
> > While at it, also add `exec` lines after `merge` commands, because they
> > are similar in spirit to `pick` commands: they add new commits.
> > 
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >   sequencer.c              | 37 +++++++++++++++++++++++++++----------
> >   t/t3430-rebase-merges.sh |  2 +-
> >   2 files changed, 28 insertions(+), 11 deletions(-)
> > 
> > diff --git a/sequencer.c b/sequencer.c
> > index 31038472f..ed2e694ff 100644
> > --- a/sequencer.c
> > +++ b/sequencer.c
> > @@ -4244,10 +4244,9 @@ int sequencer_add_exec_commands(const char *commands)
> >   {
> >    const char *todo_file = rebase_path_todo();
> >    struct todo_list todo_list = TODO_LIST_INIT;
> > -	struct todo_item *item;
> >    struct strbuf *buf = &todo_list.buf;
> >    size_t offset = 0, commands_len = strlen(commands);
> > -	int i, first;
> > +	int i, insert;
> >   
> >    if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
> >   		return error(_("could not read '%s'."), todo_file);
> > @@ -4257,19 +4256,37 @@ int sequencer_add_exec_commands(const char
> > *commands)
> >    	return error(_("unusable todo list: '%s'"), todo_file);
> >    }
> >   -	first = 1;
> > -	/* insert <commands> before every pick except the first one */
> > -	for (item = todo_list.items, i = 0; i < todo_list.nr; i++, item++) {
> > -		if (item->command == TODO_PICK && !first) {
> > -			strbuf_insert(buf, item->offset_in_buf + offset,
> > -				      commands, commands_len);
> > +	/*
> > +	 * Insert <commands> after every pick. Here, fixup/squash chains
> > +	 * are considered part of the pick, so we insert the commands *after*
> > +	 * those chains if there are any.
> > +	 */
> > +	insert = -1;
> > +	for (i = 0; i < todo_list.nr; i++) {
> > +		enum todo_command command = todo_list.items[i].command;
> > +
> > +		if (insert >= 0) {
> > +			/* skip fixup/squash chains */
> > +			if (command == TODO_COMMENT)
> > +				continue;
> 
> insert is not updated so if the next command is not a fixup the exec
> line will be inserted before the comment.
Yes, this is very much on purpose. Take this todo list, for example:
	pick 123456 this patch
	# pick 987654 this was an empty commit

You definitely do not want the `exec` to appear after that commented-out empty commit.

Show 31 quoted lines
> > +			else if (is_fixup(command)) {
> > +				insert = i + 1;
> > +				continue;
> > +			}
> > +			strbuf_insert(buf,
> > +				      todo_list.items[insert].offset_in_buf +
> > +				      offset, commands, commands_len);
> >   			offset += commands_len;
> > +			insert = -1;
> >   		}
> > -		first = 0;
> > +
> > +		if (command == TODO_PICK || command == TODO_MERGE)
> > +			insert = i + 1;
> >    }
> >   
> >   	/* append final <commands> */
> > -	strbuf_add(buf, commands, commands_len);
> > +	if (insert >= 0 || !offset)
> > +		strbuf_add(buf, commands, commands_len);
> 
> Having read your other message about this patch I think if you wanted to fix
> the position of the final exec in the case where the todo list ends with a
> comment you could do something like
> 
> 	if (insert >= 0)
> 		strbuf_insert(buf,
> 			      todo_list.items[insert].offset_in_buf +
> 			      offset, commands, commands_len);
> 	else
> 		strbuf_add(buf, commands, commands_len);

That does not really work, as `insert` can point *after* the last line, in which case `todo_list.items[insert]` is undefined (and in the worst case, causes a segmentation fault).

> I'm not sure it matters that much though

Well, it does matter to me. After having this in the back of my head, and after your comment, I think it *is* worth the additional complexity after all.

Will come up with a new iteration.

Ciao, Dscho

Previous: Phillip WoodNext: Phillip Wood
Message 15 of 21 in “Make git rebase work with --rebase-merges and --exec”
  1. 0/2 Make git rebase work with --rebase-merges and --execJohannes Schindelin via GitGitGadget, Aug 3, 2018
  2. 1/2 t3430: demonstrate what -r, --autosquash & --exec should doJohannes Schindelin via GitGitGadget, Aug 3, 2018
  3. 2/2 rebase --exec: make it work with --rebase-mergesJohannes Schindelin via GitGitGadget, Aug 3, 2018
  4. Junio C HamanoAug 3, 2018
  5. Johannes SchindelinAug 6, 2018
  6. Johannes SchindelinAug 6, 2018
  7. Junio C HamanoAug 6, 2018
  8. Junio C HamanoAug 3, 2018
  9. Johannes SchindelinAug 6, 2018
  10. 0/2 Make git rebase work with --rebase-merges and --execJohannes Schindelin via GitGitGadget, Aug 6, 2018
  11. 1/2 t3430: demonstrate what -r, --autosquash & --exec should doJohannes Schindelin via GitGitGadget, Aug 6, 2018
  12. 2/2 rebase --exec: make it work with --rebase-mergesJohannes Schindelin via GitGitGadget, Aug 6, 2018
  13. Phillip WoodAug 6, 2018
  14. Phillip WoodAug 6, 2018
  15. Johannes SchindelinAug 9, 2018
  16. Phillip WoodAug 9, 2018
  17. Johannes SchindelinAug 9, 2018
  18. Johannes SchindelinAug 6, 2018
  19. 0/2 Make git rebase work with --rebase-merges and --execJohannes Schindelin via GitGitGadget, Aug 9, 2018
  20. 1/2 t3430: demonstrate what -r, --autosquash & --exec should doJohannes Schindelin via GitGitGadget, Aug 9, 2018
  21. 2/2 rebase --exec: make it work with --rebase-mergesJohannes Schindelin via GitGitGadget, Aug 9, 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.