git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Liam Beguin <liambeguin@gmail.com>
To: johannes.schindelin@gmx.de
Cc: git@vger.kernel.org, gitster@pobox.com, peff@peff.net,
	philipoakley@iee.org, phillip.wood@dunelm.org.uk
Subject: [PATCH v4 10/10] rebase -i: rearrange fixup/squash lines using the rebase--helper
Date: Thu, 25 May 2017 23:16:39 -0400	[thread overview]
Message-ID: <20170526031639.10790-1-liambeguin@gmail.com> (raw)
In-Reply-To: <6825a2bb46f43687af0565e4d38224d472932203.1493414945.git.johannes.schindelin@gmx.de>

Hi Johannes,

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> This operation has quadratic complexity, which is especially painful
> on Windows, where shell scripts are *already* slow (mainly due to the
> overhead of the POSIX emulation layer).
>
> Let's reimplement this with linear complexity (using a hash map to
> match the commits' subject lines) for the common case; Sadly, the
> fixup/squash feature's design neglected performance considerations,
> allowing arbitrary prefixes (read: `fixup! hell` will match the
> commit subject `hello world`), which means that we are stuck with
> quadratic performance in the worst case.
>
> The reimplemented logic also happens to fix a bug where commented-out
> lines (representing empty patches) were dropped by the previous code.
>
> While at it, clarify how the fixup/squash feature works in `git rebase
> -i`'s man page.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  Documentation/git-rebase.txt |  16 ++--
>  builtin/rebase--helper.c     |   6 +-
>  git-rebase--interactive.sh   |  90 +-------------------
>  sequencer.c                  | 195 +++++++++++++++++++++++++++++++++++++++++++
>  sequencer.h                  |   1 +
>  t/t3415-rebase-autosquash.sh |   2 +-
>  6 files changed, 212 insertions(+), 98 deletions(-)
>
> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
> index 53f4e144444..c5464aa5365 100644
> --- a/Documentation/git-rebase.txt
> +++ b/Documentation/git-rebase.txt
> @@ -430,13 +430,15 @@ without an explicit `--interactive`.
>  --autosquash::
>  --no-autosquash::
>  	When the commit log message begins with "squash! ..." (or
> -	"fixup! ..."), and there is a commit whose title begins with
> -	the same ..., automatically modify the todo list of rebase -i
> -	so that the commit marked for squashing comes right after the
> -	commit to be modified, and change the action of the moved
> -	commit from `pick` to `squash` (or `fixup`).  Ignores subsequent
> -	"fixup! " or "squash! " after the first, in case you referred to an
> -	earlier fixup/squash with `git commit --fixup/--squash`.
> +	"fixup! ..."), and there is already a commit in the todo list that
> +	matches the same `...`, automatically modify the todo list of rebase
> +	-i so that the commit marked for squashing comes right after the
> +	commit to be modified, and change the action of the moved commit
> +	from `pick` to `squash` (or `fixup`).  A commit matches the `...` if
> +	the commit subject matches, or if the `...` refers to the commit's
> +	hash. As a fall-back, partial matches of the commit subject work,
> +	too.  The recommended way to create fixup/squash commits is by using
> +	the `--fixup`/`--squash` options of linkgit:git-commit[1].
>  +
>  This option is only valid when the `--interactive` option is used.
>  +
> diff --git a/builtin/rebase--helper.c b/builtin/rebase--helper.c
> index de3ccd9bfbc..e6591f01112 100644
> --- a/builtin/rebase--helper.c
> +++ b/builtin/rebase--helper.c
> @@ -14,7 +14,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
>  	int keep_empty = 0;
>  	enum {
>  		CONTINUE = 1, ABORT, MAKE_SCRIPT, SHORTEN_SHA1S, EXPAND_SHA1S,
> -		CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS
> +		CHECK_TODO_LIST, SKIP_UNNECESSARY_PICKS, REARRANGE_SQUASH
>  	} command = 0;
>  	struct option options[] = {
>  		OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
> @@ -33,6 +33,8 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
>  			N_("check the todo list"), CHECK_TODO_LIST),
>  		OPT_CMDMODE(0, "skip-unnecessary-picks", &command,
>  			N_("skip unnecessary picks"), SKIP_UNNECESSARY_PICKS),
> +		OPT_CMDMODE(0, "rearrange-squash", &command,
> +			N_("rearrange fixup/squash lines"), REARRANGE_SQUASH),
>  		OPT_END()
>  	};
>  
> @@ -59,5 +61,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
>  		return !!check_todo_list();
>  	if (command == SKIP_UNNECESSARY_PICKS && argc == 1)
>  		return !!skip_unnecessary_picks();
> +	if (command == REARRANGE_SQUASH && argc == 1)
> +		return !!rearrange_squash();
>  	usage_with_options(builtin_rebase_helper_usage, options);
>  }
> diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
> index 92e3ca1de3b..84c6e62518f 100644
> --- a/git-rebase--interactive.sh
> +++ b/git-rebase--interactive.sh
> @@ -721,94 +721,6 @@ collapse_todo_ids() {
>  	git rebase--helper --shorten-sha1s
>  }
>  
> -# Rearrange the todo list that has both "pick sha1 msg" and
> -# "pick sha1 fixup!/squash! msg" appears in it so that the latter
> -# comes immediately after the former, and change "pick" to
> -# "fixup"/"squash".
> -#
> -# Note that if the config has specified a custom instruction format
> -# each log message will be re-retrieved in order to normalize the
> -# autosquash arrangement
> -rearrange_squash () {
> -	format=$(git config --get rebase.instructionFormat)
> -	# extract fixup!/squash! lines and resolve any referenced sha1's
> -	while read -r pick sha1 message
> -	do
> -		test -z "${format}" || message=$(git log -n 1 --format="%s" ${sha1})
> -		case "$message" in
> -		"squash! "*|"fixup! "*)
> -			action="${message%%!*}"
> -			rest=$message
> -			prefix=
> -			# skip all squash! or fixup! (but save for later)
> -			while :
> -			do
> -				case "$rest" in
> -				"squash! "*|"fixup! "*)
> -					prefix="$prefix${rest%%!*},"
> -					rest="${rest#*! }"
> -					;;
> -				*)
> -					break
> -					;;
> -				esac
> -			done
> -			printf '%s %s %s %s\n' "$sha1" "$action" "$prefix" "$rest"
> -			# if it's a single word, try to resolve to a full sha1 and
> -			# emit a second copy. This allows us to match on both message
> -			# and on sha1 prefix
> -			if test "${rest#* }" = "$rest"; then
> -				fullsha="$(git rev-parse -q --verify "$rest" 2>/dev/null)"
> -				if test -n "$fullsha"; then
> -					# prefix the action to uniquely identify this line as
> -					# intended for full sha1 match
> -					echo "$sha1 +$action $prefix $fullsha"
> -				fi
> -			fi
> -		esac
> -	done >"$1.sq" <"$1"
> -	test -s "$1.sq" || return
> -
> -	used=
> -	while read -r pick sha1 message
> -	do
> -		case " $used" in
> -		*" $sha1 "*) continue ;;
> -		esac
> -		printf '%s\n' "$pick $sha1 $message"
> -		test -z "${format}" || message=$(git log -n 1 --format="%s" ${sha1})
> -		used="$used$sha1 "
> -		while read -r squash action msg_prefix msg_content
> -		do
> -			case " $used" in
> -			*" $squash "*) continue ;;
> -			esac
> -			emit=0
> -			case "$action" in
> -			+*)
> -				action="${action#+}"
> -				# full sha1 prefix test
> -				case "$msg_content" in "$sha1"*) emit=1;; esac ;;
> -			*)
> -				# message prefix test
> -				case "$message" in "$msg_content"*) emit=1;; esac ;;
> -			esac
> -			if test $emit = 1; then
> -				if test -n "${format}"
> -				then
> -					msg_content=$(git log -n 1 --format="${format}" ${squash})
> -				else
> -					msg_content="$(echo "$msg_prefix" | sed "s/,/! /g")$msg_content"
> -				fi
> -				printf '%s\n' "$action $squash $msg_content"
> -				used="$used$squash "
> -			fi
> -		done <"$1.sq"
> -	done >"$1.rearranged" <"$1"
> -	cat "$1.rearranged" >"$1"
> -	rm -f "$1.sq" "$1.rearranged"
> -}
> -
>  # Add commands after a pick or after a squash/fixup serie
>  # in the todo list.
>  add_exec_commands () {
> @@ -1068,7 +980,7 @@ then
>  fi
>  
>  test -s "$todo" || echo noop >> "$todo"
> -test -n "$autosquash" && rearrange_squash "$todo"
> +test -z "$autosquash" || git rebase--helper --rearrange-squash || exit
>  test -n "$cmd" && add_exec_commands "$todo"
>  
>  todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
> diff --git a/sequencer.c b/sequencer.c
> index 72e3ad8d145..63a588f0916 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -19,6 +19,7 @@
>  #include "trailer.h"
>  #include "log-tree.h"
>  #include "wt-status.h"
> +#include "hashmap.h"
>  
>  #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
>  
> @@ -2723,3 +2724,197 @@ int skip_unnecessary_picks(void)
>  
>  	return 0;
>  }
> +
> +struct subject2item_entry {
> +	struct hashmap_entry entry;
> +	int i;
> +	char subject[FLEX_ARRAY];
> +};
> +
> +static int subject2item_cmp(const struct subject2item_entry *a,
> +	const struct subject2item_entry *b, const void *key)
> +{
> +	return key ? strcmp(a->subject, key) : strcmp(a->subject, b->subject);
> +}
> +
> +/*
> + * Rearrange the todo list that has both "pick sha1 msg" and "pick sha1
> + * fixup!/squash! msg" in it so that the latter is put immediately after the
> + * former, and change "pick" to "fixup"/"squash".
> + *
> + * Note that if the config has specified a custom instruction format, each log
> + * message will have to be retrieved from the commit (as the oneline in the
> + * script cannot be trusted) in order to normalize the autosquash arrangement.
> + */
> +int rearrange_squash(void)
> +{
> +	const char *todo_file = rebase_path_todo();
> +	struct todo_list todo_list = TODO_LIST_INIT;
> +	struct hashmap subject2item;
> +	int res = 0, rearranged = 0, *next, *tail, fd, i;
> +	char **subjects;
> +
> +	fd = open(todo_file, O_RDONLY);
> +	if (fd < 0)
> +		return error_errno(_("could not open '%s'"), todo_file);
> +	if (strbuf_read(&todo_list.buf, fd, 0) < 0) {
> +		close(fd);
> +		return error(_("could not read '%s'."), todo_file);
> +	}
> +	close(fd);
> +	if (parse_insn_buffer(todo_list.buf.buf, &todo_list) < 0) {
> +		todo_list_release(&todo_list);
> +		return -1;
> +	}
> +
> +	/*
> +	 * The hashmap maps onelines to the respective todo list index.
> +	 *
> +	 * If any items need to be rearranged, the next[i] value will indicate
> +	 * which item was moved directly after the i'th.
> +	 *
> +	 * In that case, last[i] will indicate the index of the latest item to
> +	 * be moved to appear after the i'th.
> +	 */
> +	hashmap_init(&subject2item, (hashmap_cmp_fn) subject2item_cmp,
> +		     todo_list.nr);
> +	ALLOC_ARRAY(next, todo_list.nr);
> +	ALLOC_ARRAY(tail, todo_list.nr);
> +	ALLOC_ARRAY(subjects, todo_list.nr);
> +	for (i = 0; i < todo_list.nr; i++) {
> +		struct strbuf buf = STRBUF_INIT;
> +		struct todo_item *item = todo_list.items + i;
> +		const char *commit_buffer, *subject, *p;
> +		size_t subject_len;
> +		int i2 = -1;
> +		struct subject2item_entry *entry;
> +
> +		next[i] = tail[i] = -1;
> +		if (item->command >= TODO_EXEC) {
> +			subjects[i] = NULL;
> +			continue;
> +		}
> +
> +		if (is_fixup(item->command)) {
> +			todo_list_release(&todo_list);
> +			return error(_("the script was already rearranged."));
> +		}
> +
> +		item->commit->util = item;
> +
> +		parse_commit(item->commit);
> +		commit_buffer = get_commit_buffer(item->commit, NULL);
> +		find_commit_subject(commit_buffer, &subject);
> +		format_subject(&buf, subject, " ");
> +		subject = subjects[i] = strbuf_detach(&buf, &subject_len);
> +		unuse_commit_buffer(item->commit, commit_buffer);
> +		if ((skip_prefix(subject, "fixup! ", &p) ||
> +		     skip_prefix(subject, "squash! ", &p))) {
> +			struct commit *commit2;
> +
> +			for (;;) {
> +				while (isspace(*p))
> +					p++;
> +				if (!skip_prefix(p, "fixup! ", &p) &&
> +				    !skip_prefix(p, "squash! ", &p))
> +					break;
> +			}
> +
> +			if ((entry = hashmap_get_from_hash(&subject2item,
> +							   strhash(p), p)))
> +				/* found by title */
> +				i2 = entry->i;
> +			else if (!strchr(p, ' ') &&
> +				 (commit2 =
> +				  lookup_commit_reference_by_name(p)) &&
> +				 commit2->util)
> +				/* found by commit name */
> +				i2 = (struct todo_item *)commit2->util
> +					- todo_list.items;
> +			else {
> +				/* copy can be a prefix of the commit subject */
> +				for (i2 = 0; i2 < i; i2++)
> +					if (subjects[i2] &&
> +					    starts_with(subjects[i2], p))
> +						break;
> +				if (i2 == i)
> +					i2 = -1;
> +			}
> +		}
> +		if (i2 >= 0) {
> +			rearranged = 1;
> +			todo_list.items[i].command =
> +				starts_with(subject, "fixup!") ?
> +				TODO_FIXUP : TODO_SQUASH;
> +			if (next[i2] < 0)
> +				next[i2] = i;
> +			else
> +				next[tail[i2]] = i;
> +			tail[i2] = i;
> +		} else if (!hashmap_get_from_hash(&subject2item,
> +						strhash(subject), subject)) {
> +			FLEX_ALLOC_MEM(entry, subject, subject, subject_len);
> +			entry->i = i;
> +			hashmap_entry_init(entry, strhash(entry->subject));
> +			hashmap_put(&subject2item, entry);
> +		}
> +	}
> +
> +	if (rearranged) {
> +		struct strbuf buf = STRBUF_INIT;
> +
> +		for (i = 0; i < todo_list.nr; i++) {
> +			enum todo_command command = todo_list.items[i].command;
> +			int cur = i;
> +
> +			/*
> +			 * Initially, all commands are 'pick's. If it is a
> +			 * fixup or a squash now, we have rearranged it.
> +			 */
> +			if (is_fixup(command))
> +				continue;
> +
> +			while (cur >= 0) {
> +				int offset = todo_list.items[cur].offset_in_buf;
> +				int end_offset = cur + 1 < todo_list.nr ?
> +					todo_list.items[cur + 1].offset_in_buf :
> +					todo_list.buf.len;
> +				char *bol = todo_list.buf.buf + offset;
> +				char *eol = todo_list.buf.buf + end_offset;

I got a little confused with these offsets. I know it was part of a
previous series, but maybe we could add a description to the fields
of `struct todo_list` and `struct todo_item`.
Other than that, I don't have any particular comments.

> +
> +				/* replace 'pick', by 'fixup' or 'squash' */
> +				command = todo_list.items[cur].command;
> +				if (is_fixup(command)) {
> +					strbuf_addstr(&buf,
> +						todo_command_info[command].str);
> +					bol += strcspn(bol, " \t");
> +				}
> +
> +				strbuf_add(&buf, bol, eol - bol);
> +
> +				cur = next[cur];
> +			}
> +		}
> +
> +		fd = open(todo_file, O_WRONLY);
> +		if (fd < 0)
> +			res = error_errno(_("could not open '%s'"), todo_file);
> +		else if (write(fd, buf.buf, buf.len) < 0)
> +			res = error_errno(_("could not read '%s'."), todo_file);
> +		else if (ftruncate(fd, buf.len) < 0)
> +			res = error_errno(_("could not finish '%s'"),
> +					   todo_file);
> +		close(fd);
> +		strbuf_release(&buf);
> +	}
> +
> +	free(next);
> +	free(tail);
> +	for (i = 0; i < todo_list.nr; i++)
> +		free(subjects[i]);
> +	free(subjects);
> +	hashmap_free(&subject2item, 1);
> +	todo_list_release(&todo_list);
> +
> +	return res;
> +}
> diff --git a/sequencer.h b/sequencer.h
> index 28e1fc1e9bb..1c94bec7622 100644
> --- a/sequencer.h
> +++ b/sequencer.h
> @@ -51,6 +51,7 @@ int sequencer_make_script(int keep_empty, FILE *out,
>  int transform_todo_ids(int shorten_sha1s);
>  int check_todo_list(void);
>  int skip_unnecessary_picks(void);
> +int rearrange_squash(void);
>  
>  extern const char sign_off_header[];
>  
> diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
> index 926bb3da788..2f88f50c057 100755
> --- a/t/t3415-rebase-autosquash.sh
> +++ b/t/t3415-rebase-autosquash.sh
> @@ -290,7 +290,7 @@ set_backup_editor () {
>  	test_set_editor "$PWD/backup-editor.sh"
>  }
>  
> -test_expect_failure 'autosquash with multiple empty patches' '
> +test_expect_success 'autosquash with multiple empty patches' '
>  	test_tick &&
>  	git commit --allow-empty -m "empty" &&
>  	test_tick &&
> -- 
> 2.12.2.windows.2.800.gede8f145e06

Liam

  reply	other threads:[~2017-05-26  3:16 UTC|newest]

Thread overview: 100+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-02 16:22 [PATCH 0/9] The final building block for a faster rebase -i Johannes Schindelin
2016-09-02 16:23 ` [PATCH 1/9] rebase -i: generate the script via rebase--helper Johannes Schindelin
2016-09-02 16:23 ` [PATCH 2/9] rebase -i: remove useless indentation Johannes Schindelin
2016-09-02 16:23 ` [PATCH 3/9] rebase -i: do not invent onelines when expanding/collapsing SHA-1s Johannes Schindelin
2016-09-02 16:23 ` [PATCH 4/9] rebase -i: also expand/collapse the SHA-1s via the rebase--helper Johannes Schindelin
2016-09-02 20:56   ` Dennis Kaarsemaker
2016-09-03  7:01     ` Johannes Schindelin
2016-09-02 16:23 ` [PATCH 5/9] t3404: relax rebase.missingCommitsCheck tests Johannes Schindelin
2016-09-02 16:23 ` [PATCH 6/9] rebase -i: check for missing commits in the rebase--helper Johannes Schindelin
2016-09-02 20:59   ` Dennis Kaarsemaker
2016-09-02 16:23 ` [PATCH 7/9] rebase -i: skip unnecessary picks using " Johannes Schindelin
2016-09-02 16:23 ` [PATCH 8/9] t3415: test fixup with wrapped oneline Johannes Schindelin
2016-09-02 16:23 ` [PATCH 9/9] rebase -i: rearrange fixup/squash lines using the rebase--helper Johannes Schindelin
2016-09-03 18:03   ` Josh Triplett
2016-09-04  6:47     ` Johannes Schindelin
2017-04-25 13:51 ` [PATCH v2 0/9] The final building block for a faster rebase -i Johannes Schindelin
2017-04-25 13:51   ` [PATCH v2 1/9] rebase -i: generate the script via rebase--helper Johannes Schindelin
2017-04-26 10:45     ` Jeff King
2017-04-26 11:34       ` Johannes Schindelin
2017-04-25 13:51   ` [PATCH v2 2/9] rebase -i: remove useless indentation Johannes Schindelin
2017-04-25 13:51   ` [PATCH v2 3/9] rebase -i: do not invent onelines when expanding/collapsing SHA-1s Johannes Schindelin
2017-04-25 13:51   ` [PATCH v2 4/9] rebase -i: also expand/collapse the SHA-1s via the rebase--helper Johannes Schindelin
2017-04-25 13:52   ` [PATCH v2 5/9] t3404: relax rebase.missingCommitsCheck tests Johannes Schindelin
2017-04-25 13:52   ` [PATCH v2 6/9] rebase -i: check for missing commits in the rebase--helper Johannes Schindelin
2017-04-25 13:52   ` [PATCH v2 7/9] rebase -i: skip unnecessary picks using " Johannes Schindelin
2017-04-26 10:55     ` Jeff King
2017-04-26 11:31       ` Johannes Schindelin
2017-04-25 13:52   ` [PATCH v2 8/9] t3415: test fixup with wrapped oneline Johannes Schindelin
2017-04-25 13:52   ` [PATCH v2 9/9] rebase -i: rearrange fixup/squash lines using the rebase--helper Johannes Schindelin
2017-04-26  3:32   ` [PATCH v2 0/9] The final building block for a faster rebase -i Junio C Hamano
2017-04-26 11:59   ` [PATCH v3 " Johannes Schindelin
2017-04-26 11:59     ` [PATCH v3 1/9] rebase -i: generate the script via rebase--helper Johannes Schindelin
2017-04-27  4:31       ` Junio C Hamano
2017-04-27 14:18         ` Johannes Schindelin
2017-04-28  0:13           ` Junio C Hamano
2017-04-28  2:36             ` Junio C Hamano
2017-04-28 15:13             ` Johannes Schindelin
2017-05-01  3:11               ` Junio C Hamano
2017-05-01 11:47                 ` Johannes Schindelin
2017-04-28 10:08       ` Phillip Wood
2017-04-28 19:22         ` Johannes Schindelin
2017-05-01 10:06           ` Phillip Wood
2017-05-01 11:58             ` Johannes Schindelin
2017-05-01  0:49         ` Junio C Hamano
2017-05-01 11:06           ` Johannes Schindelin
2017-04-26 11:59     ` [PATCH v3 2/9] rebase -i: remove useless indentation Johannes Schindelin
2017-04-26 11:59     ` [PATCH v3 3/9] rebase -i: do not invent onelines when expanding/collapsing SHA-1s Johannes Schindelin
2017-04-26 11:59     ` [PATCH v3 4/9] rebase -i: also expand/collapse the SHA-1s via the rebase--helper Johannes Schindelin
2017-04-27  5:00       ` Junio C Hamano
2017-04-27  6:47         ` Junio C Hamano
2017-04-27 21:44         ` Johannes Schindelin
2017-04-28  0:15           ` Junio C Hamano
2017-04-28 15:15             ` Johannes Schindelin
2017-04-26 11:59     ` [PATCH v3 5/9] t3404: relax rebase.missingCommitsCheck tests Johannes Schindelin
2017-04-27  5:05       ` Junio C Hamano
2017-04-27 22:01         ` Johannes Schindelin
2017-04-26 11:59     ` [PATCH v3 6/9] rebase -i: check for missing commits in the rebase--helper Johannes Schindelin
2017-04-27  5:32       ` Junio C Hamano
2017-04-28 15:10         ` Johannes Schindelin
2017-04-26 12:00     ` [PATCH v3 7/9] rebase -i: skip unnecessary picks using " Johannes Schindelin
2017-04-26 12:00     ` [PATCH v3 8/9] t3415: test fixup with wrapped oneline Johannes Schindelin
2017-04-26 12:00     ` [PATCH v3 9/9] rebase -i: rearrange fixup/squash lines using the rebase--helper Johannes Schindelin
2017-04-28 21:30     ` [PATCH v4 00/10] The final building block for a faster rebase -i Johannes Schindelin
2017-04-28 21:31       ` [PATCH v4 01/10] t3415: verify that an empty instructionFormat is handled as before Johannes Schindelin
2017-04-28 21:31       ` [PATCH v4 02/10] rebase -i: generate the script via rebase--helper Johannes Schindelin
2017-05-26  3:15         ` Liam Beguin
2017-05-29 10:59           ` Johannes Schindelin
2017-05-30 15:57             ` liam Beguin
2017-05-30 18:19           ` liam Beguin
2017-05-29  6:07         ` Junio C Hamano
2017-05-29 10:54           ` Johannes Schindelin
2017-05-30  4:57             ` Junio C Hamano
2017-05-30 14:59               ` Johannes Schindelin
2017-05-30 15:08               ` revision API design, was " Johannes Schindelin
2017-05-30 22:53                 ` Junio C Hamano
2017-06-01  6:48                   ` Junio C Hamano
2017-04-28 21:31       ` [PATCH v4 03/10] rebase -i: remove useless indentation Johannes Schindelin
2017-05-26  3:15         ` Liam Beguin
2017-05-26 17:50           ` Stefan Beller
2017-05-27  3:15             ` liam Beguin
2017-04-28 21:32       ` [PATCH v4 04/10] rebase -i: do not invent onelines when expanding/collapsing SHA-1s Johannes Schindelin
2017-04-28 21:32       ` [PATCH v4 05/10] rebase -i: also expand/collapse the SHA-1s via the rebase--helper Johannes Schindelin
2017-05-26  3:15         ` Liam Beguin
2017-05-29 11:20           ` Johannes Schindelin
2017-04-28 21:32       ` [PATCH v4 06/10] t3404: relax rebase.missingCommitsCheck tests Johannes Schindelin
2017-04-28 21:32       ` [PATCH v4 07/10] rebase -i: check for missing commits in the rebase--helper Johannes Schindelin
2017-04-28 21:32       ` [PATCH v4 08/10] rebase -i: skip unnecessary picks using " Johannes Schindelin
2017-04-28 21:32       ` [PATCH v4 09/10] t3415: test fixup with wrapped oneline Johannes Schindelin
2017-04-28 21:33       ` [PATCH v4 10/10] rebase -i: rearrange fixup/squash lines using the rebase--helper Johannes Schindelin
2017-05-26  3:16         ` Liam Beguin [this message]
2017-05-29 11:26           ` Johannes Schindelin
2017-05-26  3:15       ` [PATCH v4 00/10] The final building block for a faster rebase -i Liam Beguin
2017-05-27 16:23         ` René Scharfe
2017-05-29 10:51           ` Johannes Schindelin
2017-05-29 12:50             ` Ævar Arnfjörð Bjarmason
2017-05-30 15:44               ` Johannes Schindelin
2017-05-30 20:22                 ` Ævar Arnfjörð Bjarmason
2017-05-31 18:46                   ` Ævar Arnfjörð Bjarmason
2017-05-29 10:56         ` Johannes Schindelin
2017-05-29  8:30       ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170526031639.10790-1-liambeguin@gmail.com \
    --to=liambeguin@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=johannes.schindelin@gmx.de \
    --cc=peff@peff.net \
    --cc=philipoakley@iee.org \
    --cc=phillip.wood@dunelm.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).