git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [GSoC] [PATCH 00/18] builtin rebase options
@ 2018-08-08 15:21 Pratik Karki
  2018-08-08 15:21 ` [PATCH 01/18] builtin rebase: allow selecting the rebase "backend" Pratik Karki
                   ` (18 more replies)
  0 siblings, 19 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This patch series completes the support for all rebase options in the
builtin rebase. This converts the remaining command-line options.

The previous patch series taught the builtin rebase to handle different
actions, this patch series will continue adding functionality to
builtin rebase by teaching it to handle options handled by original rebase
i.e. `--signoff`, `rerere-autoupdate`, et al.

It adds the functionality to the previous patch series,
(https://public-inbox.org/git/20180808150622.9614-1-predatoramigo@gmail.com).

This is the fourth patch series that brings us more closer to a builtin
"git rebase".

If you like to view the development branch, you can view
(https://github.com/git/git/pull/505), where I have kept my commits up to date
and leveraged Travis(there is sporadic failures in t5520 for macos gcc and
isn't due to my patches) for extra testing other than my system.

The next in line patch series which I'll be sending out today are:

builtin rebase rest: The builtin rebase will convert all the remaining shell
scripts from the original rebase to C.
default to builtin rebase: This will turn on the feature-complete builtin
rebase to on.

These patch series are built on top of each other, i.e. they depend on this
order.

Pratik Karki (18):
  builtin rebase: allow selecting the rebase "backend"
  builtin rebase: support --signoff
  builtin rebase: support --rerere-autoupdate
  builtin rebase: support --committer-date-is-author-date
  builtin rebase: support `ignore-whitespace` option
  builtin rebase: support `ignore-date` option
  builtin rebase: support `keep-empty` option
  builtin rebase: support `--autosquash`
  builtin rebase: support `--gpg-sign` option
  builtin rebase: support `-C` and `--whitespace=<type>`
  builtin rebase: support `--autostash` option
  builtin rebase: support `--exec`
  builtin rebase: support `--allow-empty-message` option
  builtin rebase: support --rebase-merges[=[no-]rebase-cousins]
  merge-base --fork-point: extract libified function
  builtin rebase: support `fork-point` option
  builtin rebase: add support for custom merge strategies
  builtin rebase: support --root

 builtin/merge-base.c |  81 +-------
 builtin/rebase.c     | 449 ++++++++++++++++++++++++++++++++++++++++++-
 commit.c             |  81 ++++++++
 commit.h             |   2 +
 4 files changed, 528 insertions(+), 85 deletions(-)

-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 01/18] builtin rebase: allow selecting the rebase "backend"
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 02/18] builtin rebase: support --signoff Pratik Karki
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

With this commit the builtin rebase supports selecting the "rebase
backends" (or "type") `interactive`, `preserve-merges`, and `merge`.

The `state_dir` was already handled according to the rebase type in a
previous commit.

Note that there is one quirk in the shell script: `--interactive`
followed by `--merge` won't reset the type to "merge" but keeps the type
as "interactive". And as t3418 tests this explicitly, we have to support
it in the builtin rebase, too.

Likewise, `--interactive` followed by `--preserve-merges` makes it an
"explicitly interactive" rebase, i.e. a rebase that should show the todo
list, while `--preserve-merges` alone is not interactive (and t5520
tests for this via `git pull --rebase=preserve`).

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 75c4ac66e0..fc9b5a8a60 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -452,6 +452,29 @@ static int can_fast_forward(struct commit *onto, struct object_id *head_oid,
 	return res && is_linear_history(onto, head);
 }
 
+/* -i followed by -m is still -i */
+static int parse_opt_merge(const struct option *opt, const char *arg, int unset)
+{
+	struct rebase_options *opts = opt->value;
+
+	if (!is_interactive(opts))
+		opts->type = REBASE_MERGE;
+
+	return 0;
+}
+
+/* -i followed by -p is still explicitly interactive, but -p alone is not */
+static int parse_opt_interactive(const struct option *opt, const char *arg,
+				 int unset)
+{
+	struct rebase_options *opts = opt->value;
+
+	opts->type = REBASE_INTERACTIVE;
+	opts->flags |= REBASE_INTERACTIVE_EXPLICIT;
+
+	return 0;
+}
+
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
 	struct rebase_options options = {
@@ -510,6 +533,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_CMDMODE(0, "show-current-patch", &action,
 			    N_("show the patch file being applied or merged"),
 			    ACTION_SHOW_CURRENT_PATCH),
+		{ OPTION_CALLBACK, 'm', "merge", &options, NULL,
+			N_("use merging strategies to rebase"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			parse_opt_merge },
+		{ OPTION_CALLBACK, 'i', "interactive", &options, NULL,
+			N_("let the user edit the list of commits to rebase"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			parse_opt_interactive },
+		OPT_SET_INT('p', "preserve-merges", &options.type,
+			    N_("try to recreate merges instead of ignoring "
+			       "them"), REBASE_PRESERVE_MERGES),
 		OPT_END(),
 	};
 
@@ -884,6 +918,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		diff_flush(&opts);
 	}
 
+	if (is_interactive(&options))
+		goto run_rebase;
+
 	/* Detach HEAD and reset the tree */
 	if (options.flags & REBASE_NO_QUIET)
 		printf(_("First, rewinding head to replay your work on top of "
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 02/18] builtin rebase: support --signoff
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
  2018-08-08 15:21 ` [PATCH 01/18] builtin rebase: allow selecting the rebase "backend" Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 03/18] builtin rebase: support --rerere-autoupdate Pratik Karki
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit adds support for `--signoff` which is used to add a
`Signed-off-by` trailer to all the rebased commits. The actual
handling is left to the rebase backends.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index fc9b5a8a60..a491481120 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -93,6 +93,7 @@ struct rebase_options {
 	} flags;
 	struct strbuf git_am_opt;
 	const char *action;
+	int signoff;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -168,6 +169,11 @@ static int read_basic_state(struct rebase_options *opts)
 	if (file_exists(state_dir_path("verbose", opts)))
 		opts->flags |= REBASE_VERBOSE;
 
+	if (file_exists(state_dir_path("signoff", opts))) {
+		opts->signoff = 1;
+		opts->flags |= REBASE_FORCE;
+	}
+
 	strbuf_release(&buf);
 
 	return 0;
@@ -249,6 +255,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 	if (opts->switch_to)
 		add_var(&script_snippet, "switch_to", opts->switch_to);
 	add_var(&script_snippet, "action", opts->action ? opts->action : "");
+	add_var(&script_snippet, "signoff", opts->signoff ? "--signoff" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -513,6 +520,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
 			N_("do not show diffstat of what changed upstream"),
 			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
+		OPT_BOOL(0, "signoff", &options.signoff,
+			 N_("add a Signed-off-by: line to each commit")),
 		OPT_BIT('f', "force-rebase", &options.flags,
 			N_("cherry-pick all commits, even if unchanged"),
 			REBASE_FORCE),
@@ -745,6 +754,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		break;
 	}
 
+	if (options.signoff) {
+		if (options.type == REBASE_PRESERVE_MERGES)
+			die("cannot combine '--signoff' with "
+			    "'--preserve-merges'");
+		strbuf_addstr(&options.git_am_opt, " --signoff");
+		options.flags |= REBASE_FORCE;
+	}
+
 	if (!options.root) {
 		if (argc < 1)
 			die("TODO: handle @{upstream}");
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 03/18] builtin rebase: support --rerere-autoupdate
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
  2018-08-08 15:21 ` [PATCH 01/18] builtin rebase: allow selecting the rebase "backend" Pratik Karki
  2018-08-08 15:21 ` [PATCH 02/18] builtin rebase: support --signoff Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 04/18] builtin rebase: support --committer-date-is-author-date Pratik Karki
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

The `--rerere-autoupdate` option allows rerere to update the index with
resolved conflicts. This commit follows closely the equivalent part of
`git-legacy-rebase.sh`.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index a491481120..1729d2d9e2 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -94,6 +94,7 @@ struct rebase_options {
 	struct strbuf git_am_opt;
 	const char *action;
 	int signoff;
+	int allow_rerere_autoupdate;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -174,6 +175,21 @@ static int read_basic_state(struct rebase_options *opts)
 		opts->flags |= REBASE_FORCE;
 	}
 
+	if (file_exists(state_dir_path("allow_rerere_autoupdate", opts))) {
+		strbuf_reset(&buf);
+		if (read_one(state_dir_path("allow_rerere_autoupdate", opts),
+			    &buf))
+			return -1;
+		if (!strcmp(buf.buf, "--rerere-autoupdate"))
+			opts->allow_rerere_autoupdate = 1;
+		else if (!strcmp(buf.buf, "--no-rerere-autoupdate"))
+			opts->allow_rerere_autoupdate = 0;
+		else
+			warning(_("ignoring invalid allow_rerere_autoupdate: "
+				  "'%s'"), buf.buf);
+	} else
+		opts->allow_rerere_autoupdate = -1;
+
 	strbuf_release(&buf);
 
 	return 0;
@@ -256,6 +272,10 @@ static int run_specific_rebase(struct rebase_options *opts)
 		add_var(&script_snippet, "switch_to", opts->switch_to);
 	add_var(&script_snippet, "action", opts->action ? opts->action : "");
 	add_var(&script_snippet, "signoff", opts->signoff ? "--signoff" : "");
+	add_var(&script_snippet, "allow_rerere_autoupdate",
+		opts->allow_rerere_autoupdate < 0 ? "" :
+		opts->allow_rerere_autoupdate ?
+		"--rerere-autoupdate" : "--no-rerere-autoupdate");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -488,6 +508,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		.type = REBASE_UNSPECIFIED,
 		.flags = REBASE_NO_QUIET,
 		.git_am_opt = STRBUF_INIT,
+		.allow_rerere_autoupdate  = -1,
 	};
 	const char *branch_name;
 	int ret, flags, total_argc, in_progress = 0;
@@ -553,6 +574,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_SET_INT('p', "preserve-merges", &options.type,
 			    N_("try to recreate merges instead of ignoring "
 			       "them"), REBASE_PRESERVE_MERGES),
+		OPT_BOOL(0, "rerere-autoupdate",
+			 &options.allow_rerere_autoupdate,
+			 N_("allow rerere to update index  with resolved "
+			    "conflict")),
 		OPT_END(),
 	};
 
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 04/18] builtin rebase: support --committer-date-is-author-date
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (2 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 03/18] builtin rebase: support --rerere-autoupdate Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 05/18] builtin rebase: support `ignore-whitespace` option Pratik Karki
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This option is simply handed down to `git am` by way of setting the
`git_am_opt` variable that is handled by the `git-rebase--am` backend.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 1729d2d9e2..eef16206c2 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -526,6 +526,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		ACTION_EDIT_TODO,
 		ACTION_SHOW_CURRENT_PATCH,
 	} action = NO_ACTION;
+	int committer_date_is_author_date = 0;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -543,6 +544,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
 		OPT_BOOL(0, "signoff", &options.signoff,
 			 N_("add a Signed-off-by: line to each commit")),
+		OPT_BOOL(0, "committer-date-is-author-date",
+			 &committer_date_is_author_date,
+			 N_("passed to 'git am'")),
 		OPT_BIT('f', "force-rebase", &options.flags,
 			N_("cherry-pick all commits, even if unchanged"),
 			REBASE_FORCE),
@@ -763,6 +767,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (!(options.flags & REBASE_NO_QUIET))
 		strbuf_addstr(&options.git_am_opt, " -q");
 
+	if (committer_date_is_author_date) {
+		strbuf_addstr(&options.git_am_opt,
+			      " --committer-date-is-author-date");
+		options.flags |= REBASE_FORCE;
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 05/18] builtin rebase: support `ignore-whitespace` option
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (3 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 04/18] builtin rebase: support --committer-date-is-author-date Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 06/18] builtin rebase: support `ignore-date` option Pratik Karki
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit adds support for the `--ignore-whitespace` option
of the rebase command. This option is simply passed to the
`--am` backend.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index eef16206c2..7490d215ef 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -527,6 +527,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		ACTION_SHOW_CURRENT_PATCH,
 	} action = NO_ACTION;
 	int committer_date_is_author_date = 0;
+	int ignore_whitespace = 0;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -542,6 +543,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
 			N_("do not show diffstat of what changed upstream"),
 			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
+		OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
+			 N_("passed to 'git apply'")),
 		OPT_BOOL(0, "signoff", &options.signoff,
 			 N_("add a Signed-off-by: line to each commit")),
 		OPT_BOOL(0, "committer-date-is-author-date",
@@ -773,6 +776,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.flags |= REBASE_FORCE;
 	}
 
+	if (ignore_whitespace)
+		strbuf_addstr(&options.git_am_opt, " --ignore-whitespace");
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 06/18] builtin rebase: support `ignore-date` option
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (4 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 05/18] builtin rebase: support `ignore-whitespace` option Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 07/18] builtin rebase: support `keep-empty` option Pratik Karki
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit adds support for `--ignore-date` which is passed to `git am`
to easily change the dates of the rebased commits.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 7490d215ef..42ee040da3 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -527,6 +527,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		ACTION_SHOW_CURRENT_PATCH,
 	} action = NO_ACTION;
 	int committer_date_is_author_date = 0;
+	int ignore_date = 0;
 	int ignore_whitespace = 0;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
@@ -550,6 +551,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "committer-date-is-author-date",
 			 &committer_date_is_author_date,
 			 N_("passed to 'git am'")),
+		OPT_BOOL(0, "ignore-date", &ignore_date,
+			 N_("passed to 'git am'")),
 		OPT_BIT('f', "force-rebase", &options.flags,
 			N_("cherry-pick all commits, even if unchanged"),
 			REBASE_FORCE),
@@ -779,6 +782,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (ignore_whitespace)
 		strbuf_addstr(&options.git_am_opt, " --ignore-whitespace");
 
+	if (ignore_date) {
+		strbuf_addstr(&options.git_am_opt, " --ignore-date");
+		options.flags |= REBASE_FORCE;
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 07/18] builtin rebase: support `keep-empty` option
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (5 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 06/18] builtin rebase: support `ignore-date` option Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-24 16:04   ` Johannes Schindelin
  2018-08-08 15:21 ` [PATCH 08/18] builtin rebase: support `--autosquash` Pratik Karki
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

The `--keep-empty` option can be used to keep the commits that do not
change anything from its parents in the result.

While the scripted version uses `interactive_rebase=implied` to indicate
that the rebase needs to use the `git-rebase--interactive` backend in
non-interactive mode as fallback when figuring out which backend to use,
the C version needs to use a different route because the backend will
already be chosen during the `parse_options()` call.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 42ee040da3..fd9ad8efae 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -95,6 +95,7 @@ struct rebase_options {
 	const char *action;
 	int signoff;
 	int allow_rerere_autoupdate;
+	int keep_empty;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -103,6 +104,23 @@ static int is_interactive(struct rebase_options *opts)
 		opts->type == REBASE_PRESERVE_MERGES;
 }
 
+static void imply_interactive(struct rebase_options *opts, const char *option)
+{
+	switch (opts->type) {
+	case REBASE_AM:
+		die(_("%s requires an interactive rebase"), option);
+		break;
+	case REBASE_INTERACTIVE:
+	case REBASE_PRESERVE_MERGES:
+		break;
+	case REBASE_MERGE:
+		/* we silently *upgrade* --merge to --interactive if needed */
+	default:
+		opts->type = REBASE_INTERACTIVE; /* implied */
+		break;
+	}
+}
+
 /* Returns the filename prefixed by the state_dir */
 static const char *state_dir_path(const char *filename, struct rebase_options *opts)
 {
@@ -276,6 +294,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->allow_rerere_autoupdate < 0 ? "" :
 		opts->allow_rerere_autoupdate ?
 		"--rerere-autoupdate" : "--no-rerere-autoupdate");
+	add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -588,6 +607,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			 &options.allow_rerere_autoupdate,
 			 N_("allow rerere to update index  with resolved "
 			    "conflict")),
+		OPT_BOOL(0, "keep-empty", &options.keep_empty,
+			 N_("preserve empty commits during rebase")),
 		OPT_END(),
 	};
 
@@ -787,6 +808,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.flags |= REBASE_FORCE;
 	}
 
+	if (options.keep_empty)
+		imply_interactive(&options, "--keep-empty");
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 08/18] builtin rebase: support `--autosquash`
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (6 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 07/18] builtin rebase: support `keep-empty` option Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 09/18] builtin rebase: support `--gpg-sign` option Pratik Karki
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit adds support for the `--autosquash` option which is used to
automatically squash the commits marked as `squash` or `fixup` in their
messages. This is converted following `git-legacy-rebase.sh` closely.

This option can also be configured via the Git config setting
rebase.autosquash. To support this, we also add a custom
rebase_config() function in this commit that will be used instead (and
falls back to) git_default_config().

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index fd9ad8efae..79ba65fd75 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -96,6 +96,7 @@ struct rebase_options {
 	int signoff;
 	int allow_rerere_autoupdate;
 	int keep_empty;
+	int autosquash;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -295,6 +296,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->allow_rerere_autoupdate ?
 		"--rerere-autoupdate" : "--no-rerere-autoupdate");
 	add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : "");
+	add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -455,6 +457,11 @@ static int rebase_config(const char *var, const char *value, void *data)
 		return 0;
 	}
 
+	if (!strcmp(var, "rebase.autosquash")) {
+		opts->autosquash = git_config_bool(var, value);
+		return 0;
+	}
+
 	return git_default_config(var, value, data);
 }
 
@@ -609,6 +616,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			    "conflict")),
 		OPT_BOOL(0, "keep-empty", &options.keep_empty,
 			 N_("preserve empty commits during rebase")),
+		OPT_BOOL(0, "autosquash", &options.autosquash,
+			 N_("move commits that begin with "
+			    "squash!/fixup! under -i")),
 		OPT_END(),
 	};
 
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 09/18] builtin rebase: support `--gpg-sign` option
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (7 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 08/18] builtin rebase: support `--autosquash` Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 10/18] builtin rebase: support `-C` and `--whitespace=<type>` Pratik Karki
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit introduces support for `--gpg-sign` option which is used
to GPG-sign commits.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 79ba65fd75..cd9caf4841 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -97,6 +97,7 @@ struct rebase_options {
 	int allow_rerere_autoupdate;
 	int keep_empty;
 	int autosquash;
+	char *gpg_sign_opt;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -209,6 +210,15 @@ static int read_basic_state(struct rebase_options *opts)
 	} else
 		opts->allow_rerere_autoupdate = -1;
 
+	if (file_exists(state_dir_path("gpg_sign_opt", opts))) {
+		strbuf_reset(&buf);
+		if (read_one(state_dir_path("gpg_sign_opt", opts),
+			    &buf))
+			return -1;
+		free(opts->gpg_sign_opt);
+		opts->gpg_sign_opt = xstrdup(buf.buf);
+	}
+
 	strbuf_release(&buf);
 
 	return 0;
@@ -297,6 +307,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 		"--rerere-autoupdate" : "--no-rerere-autoupdate");
 	add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : "");
 	add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : "");
+	add_var(&script_snippet, "gpg_sign_opt", opts->gpg_sign_opt);
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -462,6 +473,13 @@ static int rebase_config(const char *var, const char *value, void *data)
 		return 0;
 	}
 
+	if (!strcmp(var, "commit.gpgsign")) {
+		free(opts->gpg_sign_opt);
+		opts->gpg_sign_opt = git_config_bool(var, value) ?
+			xstrdup("-S") : NULL;
+		return 0;
+	}
+
 	return git_default_config(var, value, data);
 }
 
@@ -555,6 +573,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	int committer_date_is_author_date = 0;
 	int ignore_date = 0;
 	int ignore_whitespace = 0;
+	const char *gpg_sign = NULL;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -619,6 +638,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "autosquash", &options.autosquash,
 			 N_("move commits that begin with "
 			    "squash!/fixup! under -i")),
+		OPT_STRING('S', "gpg-sign", &gpg_sign,
+			   N_("gpg-sign?"), N_("GPG-sign commits")),
 		OPT_END(),
 	};
 
@@ -821,6 +842,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (options.keep_empty)
 		imply_interactive(&options, "--keep-empty");
 
+	if (gpg_sign) {
+		free(options.gpg_sign_opt);
+		options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
@@ -1046,5 +1072,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 cleanup:
 	strbuf_release(&revisions);
 	free(options.head_name);
+	free(options.gpg_sign_opt);
 	return ret;
 }
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 10/18] builtin rebase: support `-C` and `--whitespace=<type>`
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (8 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 09/18] builtin rebase: support `--gpg-sign` option Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 11/18] builtin rebase: support `--autostash` option Pratik Karki
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit converts more code from the shell script version to the
builtin rebase. In this instance, we just have to be careful to
keep support for passing multiple `--whitespace` options, as the
shell script version does so, too.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index cd9caf4841..4437c86513 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -574,6 +574,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	int ignore_date = 0;
 	int ignore_whitespace = 0;
 	const char *gpg_sign = NULL;
+	int opt_c = -1;
+	struct string_list whitespace = STRING_LIST_INIT_NODUP;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -640,6 +642,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			    "squash!/fixup! under -i")),
 		OPT_STRING('S', "gpg-sign", &gpg_sign,
 			   N_("gpg-sign?"), N_("GPG-sign commits")),
+		OPT_STRING_LIST(0, "whitespace", &whitespace,
+				N_("whitespace"), N_("passed to 'git apply'")),
+		OPT_SET_INT('C', 0, &opt_c, N_("passed to 'git apply'"),
+			    REBASE_AM),
 		OPT_END(),
 	};
 
@@ -847,6 +853,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
 	}
 
+	if (opt_c >= 0)
+		strbuf_addf(&options.git_am_opt, " -C%d", opt_c);
+
+	if (whitespace.nr) {
+		int i;
+
+		for (i = 0; i < whitespace.nr; i++) {
+			const char *item = whitespace.items[i].string;
+
+			strbuf_addf(&options.git_am_opt, " --whitespace=%s",
+				    item);
+
+			if ((!strcmp(item, "fix")) || (!strcmp(item, "strip")))
+				options.flags |= REBASE_FORCE;
+		}
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 11/18] builtin rebase: support `--autostash` option
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (9 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 10/18] builtin rebase: support `-C` and `--whitespace=<type>` Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-18 15:59   ` Duy Nguyen
  2018-08-08 15:21 ` [PATCH 12/18] builtin rebase: support `--exec` Pratik Karki
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

To support `--autostash` we introduce a function `apply_autostash()`
just like in `git-legacy-rebase.sh`.

Rather than refactoring and using the same function that exists in
`sequencer.c`, we go a different route here, to avoid clashes with
the sister GSoC project that turns the interactive rebase into a
builtin.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 117 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 109 insertions(+), 8 deletions(-)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 4437c86513..a6bfa73915 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -63,12 +63,6 @@ static int use_builtin_rebase(void)
 	return ret;
 }
 
-static int apply_autostash(void)
-{
-	warning("TODO");
-	return 0;
-}
-
 struct rebase_options {
 	enum rebase_type type;
 	const char *state_dir;
@@ -98,6 +92,7 @@ struct rebase_options {
 	int keep_empty;
 	int autosquash;
 	char *gpg_sign_opt;
+	int autostash;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -224,13 +219,56 @@ static int read_basic_state(struct rebase_options *opts)
 	return 0;
 }
 
+static int apply_autostash(struct rebase_options *opts)
+{
+	const char *path = state_dir_path("autostash", opts);
+	struct strbuf autostash = STRBUF_INIT;
+	struct child_process stash_apply = CHILD_PROCESS_INIT;
+
+	if (!file_exists(path))
+		return 0;
+
+	if (read_one(state_dir_path("autostash", opts), &autostash))
+		return error(_("Could not read '%s'"), path);
+	argv_array_pushl(&stash_apply.args,
+			 "stash", "apply", autostash.buf, NULL);
+	stash_apply.git_cmd = 1;
+	stash_apply.no_stderr = stash_apply.no_stdout =
+		stash_apply.no_stdin = 1;
+	if (!run_command(&stash_apply))
+		printf("Applied autostash.\n");
+	else {
+		struct argv_array args = ARGV_ARRAY_INIT;
+		int res = 0;
+
+		argv_array_pushl(&args,
+				 "stash", "store", "-m", "autostash", "-q",
+				 autostash.buf, NULL);
+		if (run_command_v_opt(args.argv, RUN_GIT_CMD))
+			res = error(_("Cannot store %s"), autostash.buf);
+		argv_array_clear(&args);
+		strbuf_release(&autostash);
+		if (res)
+			return res;
+
+		fprintf(stderr,
+			_("Applying autostash resulted in conflicts.\n"
+			  "Your changes are safe in the stash.\n"
+			  "You can run \"git stash pop\" or \"git stash drop\" "
+			  "at any time.\n"));
+	}
+
+	strbuf_release(&autostash);
+	return 0;
+}
+
 static int finish_rebase(struct rebase_options *opts)
 {
 	struct strbuf dir = STRBUF_INIT;
 	const char *argv_gc_auto[] = { "gc", "--auto", NULL };
 
 	delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
-	apply_autostash();
+	apply_autostash(opts);
 	close_all_packs(the_repository->objects);
 	/*
 	 * We ignore errors in 'gc --auto', since the
@@ -345,7 +383,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 	} else if (status == 2) {
 		struct strbuf dir = STRBUF_INIT;
 
-		apply_autostash();
+		apply_autostash(opts);
 		strbuf_addstr(&dir, opts->state_dir);
 		remove_dir_recursively(&dir, 0);
 		strbuf_release(&dir);
@@ -480,6 +518,11 @@ static int rebase_config(const char *var, const char *value, void *data)
 		return 0;
 	}
 
+	if (!strcmp(var, "rebase.autostash")) {
+		opts->autostash = git_config_bool(var, value);
+		return 0;
+	}
+
 	return git_default_config(var, value, data);
 }
 
@@ -646,6 +689,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 				N_("whitespace"), N_("passed to 'git apply'")),
 		OPT_SET_INT('C', 0, &opt_c, N_("passed to 'git apply'"),
 			    REBASE_AM),
+		OPT_BOOL(0, "autostash", &options.autostash,
+			 N_("automatically stash/stash pop before and after")),
 		OPT_END(),
 	};
 
@@ -975,6 +1020,62 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (read_index(the_repository->index) < 0)
 		die(_("could not read index"));
 
+	if (options.autostash) {
+		struct lock_file lock_file = LOCK_INIT;
+		int fd;
+
+		fd = hold_locked_index(&lock_file, 0);
+		refresh_cache(REFRESH_QUIET);
+		if (0 <= fd)
+			update_index_if_able(&the_index, &lock_file);
+		rollback_lock_file(&lock_file);
+
+		if (has_unstaged_changes(0) || has_uncommitted_changes(0)) {
+			const char *autostash =
+				state_dir_path("autostash", &options);
+			struct child_process stash = CHILD_PROCESS_INIT;
+			struct object_id oid;
+			struct commit *head =
+				lookup_commit_reference(the_repository,
+							&options.orig_head);
+
+			argv_array_pushl(&stash.args,
+					 "stash", "create", "autostash", NULL);
+			stash.git_cmd = 1;
+			stash.no_stdin = 1;
+			strbuf_reset(&buf);
+			if (capture_command(&stash, &buf, GIT_MAX_HEXSZ))
+				die(_("Cannot autostash"));
+			strbuf_trim_trailing_newline(&buf);
+			if (get_oid(buf.buf, &oid))
+				die(_("Unexpected stash response: '%s'"),
+				    buf.buf);
+			strbuf_reset(&buf);
+			strbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);
+
+			if (safe_create_leading_directories_const(autostash))
+				die(_("Could not create directory for '%s'"),
+				    options.state_dir);
+			write_file(autostash, "%s", buf.buf);
+			printf(_("Created autostash: %s\n"), buf.buf);
+			if (reset_head(&head->object.oid, "reset --hard",
+				       NULL, 0) < 0)
+				die(_("could not reset --hard"));
+			printf(_("HEAD is now at %s"),
+			       find_unique_abbrev(&head->object.oid,
+						  DEFAULT_ABBREV));
+			strbuf_reset(&buf);
+			pp_commit_easy(CMIT_FMT_ONELINE, head, &buf);
+			if (buf.len > 0)
+				printf(" %s", buf.buf);
+			putchar('\n');
+
+			if (discard_index(the_repository->index) < 0 ||
+				read_index(the_repository->index) < 0)
+				die(_("could not read index"));
+		}
+	}
+
 	if (require_clean_work_tree("rebase",
 				    _("Please commit or stash them."), 1, 1)) {
 		ret = 1;
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 12/18] builtin rebase: support `--exec`
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (10 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 11/18] builtin rebase: support `--autostash` option Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 13/18] builtin rebase: support `--allow-empty-message` option Pratik Karki
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit adds support for the `--exec` option which takes a shell
command-line as argument. This argument will be appended as an `exec
<cmd>` command after each line in the todo list that creates a commit in
the final history.  commands.

Note: while the shell script version of `git rebase` assigned the empty
string to `cmd` by default, we *unset* it here because the code looks
nicer and it does not change the behavior.

The `--exec` option requires `--interactive` machinery.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index a6bfa73915..c9e992b526 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -93,6 +93,7 @@ struct rebase_options {
 	int autosquash;
 	char *gpg_sign_opt;
 	int autostash;
+	char *cmd;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -346,6 +347,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : "");
 	add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : "");
 	add_var(&script_snippet, "gpg_sign_opt", opts->gpg_sign_opt);
+	add_var(&script_snippet, "cmd", opts->cmd);
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -619,6 +621,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	const char *gpg_sign = NULL;
 	int opt_c = -1;
 	struct string_list whitespace = STRING_LIST_INIT_NODUP;
+	struct string_list exec = STRING_LIST_INIT_NODUP;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -691,6 +694,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			    REBASE_AM),
 		OPT_BOOL(0, "autostash", &options.autostash,
 			 N_("automatically stash/stash pop before and after")),
+		OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
+				N_("add exec lines after each commit of the "
+				   "editable list")),
 		OPT_END(),
 	};
 
@@ -915,6 +921,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		}
 	}
 
+	if (exec.nr) {
+		int i;
+
+		imply_interactive(&options, "--exec");
+
+		strbuf_reset(&buf);
+		for (i = 0; i < exec.nr; i++)
+			strbuf_addf(&buf, "exec %s\n", exec.items[i].string);
+		options.cmd = xstrdup(buf.buf);
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
@@ -1197,5 +1214,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	strbuf_release(&revisions);
 	free(options.head_name);
 	free(options.gpg_sign_opt);
+	free(options.cmd);
 	return ret;
 }
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 13/18] builtin rebase: support `--allow-empty-message` option
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (11 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 12/18] builtin rebase: support `--exec` Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 14/18] builtin rebase: support --rebase-merges[=[no-]rebase-cousins] Pratik Karki
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit introduces the `--allow-empty-message` option to
`builtin/rebase.c`. The motivation behind this option is: if there are
empty messages (which is not allowed in Git by default, but can be
imported from different version control systems), the rebase will fail.

Using `--allow-empty-message` overrides that behaviour which will allow
the commits having empty messages to continue in rebase operation.

Note: a very recent change made this the default in the shell scripted
`git rebase`, therefore the builtin rebase does the same.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index c9e992b526..dfb1e6c25b 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -94,6 +94,7 @@ struct rebase_options {
 	char *gpg_sign_opt;
 	int autostash;
 	char *cmd;
+	int allow_empty_message;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -348,6 +349,8 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : "");
 	add_var(&script_snippet, "gpg_sign_opt", opts->gpg_sign_opt);
 	add_var(&script_snippet, "cmd", opts->cmd);
+	add_var(&script_snippet, "allow_empty_message",
+		opts->allow_empty_message ?  "--allow-empty-message" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -598,6 +601,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		.flags = REBASE_NO_QUIET,
 		.git_am_opt = STRBUF_INIT,
 		.allow_rerere_autoupdate  = -1,
+		.allow_empty_message = 1,
 	};
 	const char *branch_name;
 	int ret, flags, total_argc, in_progress = 0;
@@ -697,6 +701,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
 				N_("add exec lines after each commit of the "
 				   "editable list")),
+		OPT_BOOL(0, "allow-empty-message",
+			 &options.allow_empty_message,
+			 N_("allow rebasing commits with empty messages")),
 		OPT_END(),
 	};
 
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 14/18] builtin rebase: support --rebase-merges[=[no-]rebase-cousins]
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (12 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 13/18] builtin rebase: support `--allow-empty-message` option Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 15/18] merge-base --fork-point: extract libified function Pratik Karki
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

The mode to rebase non-linear branches is now supported by the builtin
rebase, too.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index dfb1e6c25b..0b94d2daaa 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -95,6 +95,7 @@ struct rebase_options {
 	int autostash;
 	char *cmd;
 	int allow_empty_message;
+	int rebase_merges, rebase_cousins;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -351,6 +352,10 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "cmd", opts->cmd);
 	add_var(&script_snippet, "allow_empty_message",
 		opts->allow_empty_message ?  "--allow-empty-message" : "");
+	add_var(&script_snippet, "rebase_merges",
+		opts->rebase_merges ? "t" : "");
+	add_var(&script_snippet, "rebase_cousins",
+		opts->rebase_cousins ? "t" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -626,6 +631,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	int opt_c = -1;
 	struct string_list whitespace = STRING_LIST_INIT_NODUP;
 	struct string_list exec = STRING_LIST_INIT_NODUP;
+	const char *rebase_merges = NULL;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -704,6 +710,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "allow-empty-message",
 			 &options.allow_empty_message,
 			 N_("allow rebasing commits with empty messages")),
+		{OPTION_STRING, 'r', "rebase-merges", &rebase_merges,
+			N_("mode"),
+			N_("try to rebase merges instead of skipping them"),
+			PARSE_OPT_OPTARG, NULL, (intptr_t)""},
 		OPT_END(),
 	};
 
@@ -939,6 +949,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.cmd = xstrdup(buf.buf);
 	}
 
+	if (rebase_merges) {
+		if (!*rebase_merges)
+			; /* default mode; do nothing */
+		else if (!strcmp("rebase-cousins", rebase_merges))
+			options.rebase_cousins = 1;
+		else if (strcmp("no-rebase-cousins", rebase_merges))
+			die(_("Unknown mode: %s"), rebase_merges);
+		options.rebase_merges = 1;
+		imply_interactive(&options, "--rebase-merges");
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 15/18] merge-base --fork-point: extract libified function
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (13 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 14/18] builtin rebase: support --rebase-merges[=[no-]rebase-cousins] Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 16/18] builtin rebase: support `fork-point` option Pratik Karki
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

We need this functionality in the builtin rebase.

Note: to make this function truly reusable, we have to switch the call
get_merges_many_dirty() to get_merges_many() because we want the commit
flags to be reset (otherwise, subsequent get_merge_bases() calls would
obtain incorrect results). This did not matter when the function was
called in `git rev-parse --fork-point` because in that command, the
process definitely did not traverse any commits before exiting.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/merge-base.c | 81 ++++----------------------------------------
 commit.c             | 81 ++++++++++++++++++++++++++++++++++++++++++++
 commit.h             |  2 ++
 3 files changed, 89 insertions(+), 75 deletions(-)

diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 08d91b1f0c..790ceaeed6 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -110,54 +110,12 @@ static int handle_is_ancestor(int argc, const char **argv)
 		return 1;
 }
 
-struct rev_collect {
-	struct commit **commit;
-	int nr;
-	int alloc;
-	unsigned int initial : 1;
-};
-
-static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
-{
-	struct commit *commit;
-
-	if (is_null_oid(oid))
-		return;
-
-	commit = lookup_commit(the_repository, oid);
-	if (!commit ||
-	    (commit->object.flags & TMP_MARK) ||
-	    parse_commit(commit))
-		return;
-
-	ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
-	revs->commit[revs->nr++] = commit;
-	commit->object.flags |= TMP_MARK;
-}
-
-static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
-				  const char *ident, timestamp_t timestamp,
-				  int tz, const char *message, void *cbdata)
-{
-	struct rev_collect *revs = cbdata;
-
-	if (revs->initial) {
-		revs->initial = 0;
-		add_one_commit(ooid, revs);
-	}
-	add_one_commit(noid, revs);
-	return 0;
-}
-
 static int handle_fork_point(int argc, const char **argv)
 {
 	struct object_id oid;
 	char *refname;
+	struct commit *derived, *fork_point;
 	const char *commitname;
-	struct rev_collect revs;
-	struct commit *derived;
-	struct commit_list *bases;
-	int i, ret = 0;
 
 	switch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {
 	case 0:
@@ -173,41 +131,14 @@ static int handle_fork_point(int argc, const char **argv)
 		die("Not a valid object name: '%s'", commitname);
 
 	derived = lookup_commit_reference(the_repository, &oid);
-	memset(&revs, 0, sizeof(revs));
-	revs.initial = 1;
-	for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
 
-	if (!revs.nr && !get_oid(refname, &oid))
-		add_one_commit(&oid, &revs);
+	fork_point = get_fork_point(refname, derived);
 
-	for (i = 0; i < revs.nr; i++)
-		revs.commit[i]->object.flags &= ~TMP_MARK;
-
-	bases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit);
-
-	/*
-	 * There should be one and only one merge base, when we found
-	 * a common ancestor among reflog entries.
-	 */
-	if (!bases || bases->next) {
-		ret = 1;
-		goto cleanup_return;
-	}
-
-	/* And the found one must be one of the reflog entries */
-	for (i = 0; i < revs.nr; i++)
-		if (&bases->item->object == &revs.commit[i]->object)
-			break; /* found */
-	if (revs.nr <= i) {
-		ret = 1; /* not found */
-		goto cleanup_return;
-	}
-
-	printf("%s\n", oid_to_hex(&bases->item->object.oid));
+	if (!fork_point)
+		return 1;
 
-cleanup_return:
-	free_commit_list(bases);
-	return ret;
+	printf("%s\n", oid_to_hex(&fork_point->object.oid));
+	return 0;
 }
 
 int cmd_merge_base(int argc, const char **argv, const char *prefix)
diff --git a/commit.c b/commit.c
index 30d1af2b20..a3fc77a4eb 100644
--- a/commit.c
+++ b/commit.c
@@ -17,6 +17,7 @@
 #include "sha1-lookup.h"
 #include "wt-status.h"
 #include "advice.h"
+#include "refs.h"
 
 static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
 
@@ -958,6 +959,86 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
 	return result;
 }
 
+struct rev_collect {
+	struct commit **commit;
+	int nr;
+	int alloc;
+	unsigned int initial : 1;
+};
+
+static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
+{
+	struct commit *commit;
+
+	if (is_null_oid(oid))
+		return;
+
+	commit = lookup_commit(the_repository, oid);
+	if (!commit ||
+	    (commit->object.flags & TMP_MARK) ||
+	    parse_commit(commit))
+		return;
+
+	ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
+	revs->commit[revs->nr++] = commit;
+	commit->object.flags |= TMP_MARK;
+}
+
+static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
+				  const char *ident, timestamp_t timestamp,
+				  int tz, const char *message, void *cbdata)
+{
+	struct rev_collect *revs = cbdata;
+
+	if (revs->initial) {
+		revs->initial = 0;
+		add_one_commit(ooid, revs);
+	}
+	add_one_commit(noid, revs);
+	return 0;
+}
+
+struct commit *get_fork_point(const char *refname, struct commit *commit)
+{
+	struct object_id oid;
+	struct rev_collect revs;
+	struct commit_list *bases;
+	int i;
+	struct commit *ret = NULL;
+
+	memset(&revs, 0, sizeof(revs));
+	revs.initial = 1;
+	for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
+
+	if (!revs.nr && !get_oid(refname, &oid))
+		add_one_commit(&oid, &revs);
+
+	for (i = 0; i < revs.nr; i++)
+		revs.commit[i]->object.flags &= ~TMP_MARK;
+
+	bases = get_merge_bases_many(commit, revs.nr, revs.commit);
+
+	/*
+	 * There should be one and only one merge base, when we found
+	 * a common ancestor among reflog entries.
+	 */
+	if (!bases || bases->next)
+		goto cleanup_return;
+
+	/* And the found one must be one of the reflog entries */
+	for (i = 0; i < revs.nr; i++)
+		if (&bases->item->object == &revs.commit[i]->object)
+			break; /* found */
+	if (revs.nr <= i)
+		goto cleanup_return;
+
+	ret = bases->item;
+
+cleanup_return:
+	free_commit_list(bases);
+	return ret;
+}
+
 struct commit_list *get_octopus_merge_bases(struct commit_list *in)
 {
 	struct commit_list *i, *j, *k, *ret = NULL;
diff --git a/commit.h b/commit.h
index da0db36eba..b34240017f 100644
--- a/commit.h
+++ b/commit.h
@@ -211,6 +211,8 @@ extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
 /* To be used only when object flags after this call no longer matter */
 extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);
 
+struct commit *get_fork_point(const char *refname, struct commit *commit);
+
 /* largest positive number a signed 32-bit integer can contain */
 #define INFINITE_DEPTH 0x7fffffff
 
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 16/18] builtin rebase: support `fork-point` option
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (14 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 15/18] merge-base --fork-point: extract libified function Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 17/18] builtin rebase: add support for custom merge strategies Pratik Karki
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit adds support for `--fork-point` and `--no-fork-point`.
This is converted as-is from `git-legacy-rebase.sh`.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 0b94d2daaa..72e64868b2 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -632,6 +632,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	struct string_list whitespace = STRING_LIST_INIT_NODUP;
 	struct string_list exec = STRING_LIST_INIT_NODUP;
 	const char *rebase_merges = NULL;
+	int fork_point = -1;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -714,6 +715,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			N_("mode"),
 			N_("try to rebase merges instead of skipping them"),
 			PARSE_OPT_OPTARG, NULL, (intptr_t)""},
+		OPT_BOOL(0, "fork-point", &fork_point,
+			 N_("use 'merge-base --fork-point' to refine upstream")),
 		OPT_END(),
 	};
 
@@ -1062,6 +1065,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	} else
 		BUG("unexpected number of arguments left to parse");
 
+	if (fork_point > 0) {
+		struct commit *head =
+			lookup_commit_reference(the_repository,
+						&options.orig_head);
+		options.restrict_revision =
+			get_fork_point(options.upstream_name, head);
+	}
+
 	if (read_index(the_repository->index) < 0)
 		die(_("could not read index"));
 
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 17/18] builtin rebase: add support for custom merge strategies
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (15 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 16/18] builtin rebase: support `fork-point` option Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-08-08 15:21 ` [PATCH 18/18] builtin rebase: support --root Pratik Karki
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

When running a rebase in non-am mode, it uses the recursive merge to
cherry-pick the commits, and the rebase command allows to configure
the merge strategy to be used in this operation.

This commit adds that support to the builtin rebase.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 72e64868b2..65e7be1c48 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -96,6 +96,7 @@ struct rebase_options {
 	char *cmd;
 	int allow_empty_message;
 	int rebase_merges, rebase_cousins;
+	char *strategy, *strategy_opts;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -217,6 +218,22 @@ static int read_basic_state(struct rebase_options *opts)
 		opts->gpg_sign_opt = xstrdup(buf.buf);
 	}
 
+	if (file_exists(state_dir_path("strategy", opts))) {
+		strbuf_reset(&buf);
+		if (read_one(state_dir_path("strategy", opts), &buf))
+			return -1;
+		free(opts->strategy);
+		opts->strategy = xstrdup(buf.buf);
+	}
+
+	if (file_exists(state_dir_path("strategy_opts", opts))) {
+		strbuf_reset(&buf);
+		if (read_one(state_dir_path("strategy_opts", opts), &buf))
+			return -1;
+		free(opts->strategy_opts);
+		opts->strategy_opts = xstrdup(buf.buf);
+	}
+
 	strbuf_release(&buf);
 
 	return 0;
@@ -356,6 +373,8 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->rebase_merges ? "t" : "");
 	add_var(&script_snippet, "rebase_cousins",
 		opts->rebase_cousins ? "t" : "");
+	add_var(&script_snippet, "strategy", opts->strategy);
+	add_var(&script_snippet, "strategy_opts", opts->strategy_opts);
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -633,6 +652,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	struct string_list exec = STRING_LIST_INIT_NODUP;
 	const char *rebase_merges = NULL;
 	int fork_point = -1;
+	struct string_list strategy_options = STRING_LIST_INIT_NODUP;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -717,6 +737,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			PARSE_OPT_OPTARG, NULL, (intptr_t)""},
 		OPT_BOOL(0, "fork-point", &fork_point,
 			 N_("use 'merge-base --fork-point' to refine upstream")),
+		OPT_STRING('s', "strategy", &options.strategy,
+			   N_("strategy"), N_("use the given merge strategy")),
+		OPT_STRING_LIST('X', "strategy-option", &strategy_options,
+				N_("option"),
+				N_("pass the argument through to the merge "
+				   "strategy")),
 		OPT_END(),
 	};
 
@@ -963,6 +989,37 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		imply_interactive(&options, "--rebase-merges");
 	}
 
+	if (strategy_options.nr) {
+		int i;
+
+		if (!options.strategy)
+			options.strategy = "recursive";
+
+		strbuf_reset(&buf);
+		for (i = 0; i < strategy_options.nr; i++)
+			strbuf_addf(&buf, " --%s",
+				    strategy_options.items[i].string);
+		options.strategy_opts = xstrdup(buf.buf);
+	}
+
+	if (options.strategy) {
+		options.strategy = xstrdup(options.strategy);
+		switch (options.type) {
+		case REBASE_AM:
+			die(_("--strategy requires --merge or --interactive"));
+		case REBASE_MERGE:
+		case REBASE_INTERACTIVE:
+		case REBASE_PRESERVE_MERGES:
+			/* compatible */
+			break;
+		case REBASE_UNSPECIFIED:
+			options.type = REBASE_MERGE;
+			break;
+		default:
+			BUG("unhandled rebase type (%d)", options.type);
+		}
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH 18/18] builtin rebase: support --root
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (16 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 17/18] builtin rebase: add support for custom merge strategies Pratik Karki
@ 2018-08-08 15:21 ` Pratik Karki
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki @ 2018-08-08 15:21 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This option allows to rebase entire histories up to, and including, the
root commit.

The conversion from the shell script is straight-forward, apart from
the fact that we do not have to write an empty tree in C.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
---
 builtin/rebase.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 65e7be1c48..94abaaa890 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -76,6 +76,7 @@ struct rebase_options {
 	const char *revisions;
 	const char *switch_to;
 	int root;
+	struct object_id *squash_onto;
 	struct commit *restrict_revision;
 	int dont_finish_rebase;
 	enum {
@@ -375,6 +376,9 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->rebase_cousins ? "t" : "");
 	add_var(&script_snippet, "strategy", opts->strategy);
 	add_var(&script_snippet, "strategy_opts", opts->strategy_opts);
+	add_var(&script_snippet, "rebase_root", opts->root ? "t" : "");
+	add_var(&script_snippet, "squash_onto",
+		opts->squash_onto ? oid_to_hex(opts->squash_onto) : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -653,6 +657,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	const char *rebase_merges = NULL;
 	int fork_point = -1;
 	struct string_list strategy_options = STRING_LIST_INIT_NODUP;
+	struct object_id squash_onto;
+	char *squash_onto_name = NULL;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -743,6 +749,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 				N_("option"),
 				N_("pass the argument through to the merge "
 				   "strategy")),
+		OPT_BOOL(0, "root", &options.root,
+			 N_("rebase all reachable commits up to the root(s)")),
 		OPT_END(),
 	};
 
@@ -1020,6 +1028,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		}
 	}
 
+	if (options.root && !options.onto_name)
+		imply_interactive(&options, "--root without --onto");
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
@@ -1058,8 +1069,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		if (!options.upstream)
 			die(_("invalid upstream '%s'"), options.upstream_name);
 		options.upstream_arg = options.upstream_name;
-	} else
-		die("TODO: upstream for --root");
+	} else {
+		if (!options.onto_name) {
+			if (commit_tree("", 0, the_hash_algo->empty_tree, NULL,
+					&squash_onto, NULL, NULL) < 0)
+				die(_("Could not create new root commit"));
+			options.squash_onto = &squash_onto;
+			options.onto_name = squash_onto_name =
+				xstrdup(oid_to_hex(&squash_onto));
+		}
+		options.upstream_name = NULL;
+		options.upstream = NULL;
+		if (argc > 1)
+			usage_with_options(builtin_rebase_usage,
+					   builtin_rebase_options);
+		options.upstream_arg = "--root";
+	}
 
 	/* Make sure the branch to rebase onto is valid. */
 	if (!options.onto_name)
@@ -1207,6 +1232,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	 */
 	if (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&
 	    !is_interactive(&options) && !options.restrict_revision &&
+	    options.upstream &&
 	    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
 		int flag;
 
@@ -1311,5 +1337,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	free(options.head_name);
 	free(options.gpg_sign_opt);
 	free(options.cmd);
+	free(squash_onto_name);
 	return ret;
 }
-- 
2.18.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 11/18] builtin rebase: support `--autostash` option
  2018-08-08 15:21 ` [PATCH 11/18] builtin rebase: support `--autostash` option Pratik Karki
@ 2018-08-18 15:59   ` Duy Nguyen
  2018-08-24 16:06     ` Johannes Schindelin
  0 siblings, 1 reply; 44+ messages in thread
From: Duy Nguyen @ 2018-08-18 15:59 UTC (permalink / raw)
  To: Pratik Karki
  Cc: Git Mailing List, Christian Couder, Johannes Schindelin,
	Stefan Beller, alban.gruin, Junio C Hamano

On Wed, Aug 8, 2018 at 5:26 PM Pratik Karki <predatoramigo@gmail.com> wrote:
> @@ -224,13 +219,56 @@ static int read_basic_state(struct rebase_options *opts)
>         return 0;
>  }
>
> +static int apply_autostash(struct rebase_options *opts)
> +{
> +       const char *path = state_dir_path("autostash", opts);
> +       struct strbuf autostash = STRBUF_INIT;
> +       struct child_process stash_apply = CHILD_PROCESS_INIT;
> +
> +       if (!file_exists(path))
> +               return 0;
> +
> +       if (read_one(state_dir_path("autostash", opts), &autostash))
> +               return error(_("Could not read '%s'"), path);
> +       argv_array_pushl(&stash_apply.args,
> +                        "stash", "apply", autostash.buf, NULL);
> +       stash_apply.git_cmd = 1;
> +       stash_apply.no_stderr = stash_apply.no_stdout =
> +               stash_apply.no_stdin = 1;
> +       if (!run_command(&stash_apply))
> +               printf("Applied autostash.\n");

I think you need _() here.

> +       else {
> +               struct argv_array args = ARGV_ARRAY_INIT;
> +               int res = 0;
> +
> +               argv_array_pushl(&args,
> +                                "stash", "store", "-m", "autostash", "-q",
> +                                autostash.buf, NULL);
> +               if (run_command_v_opt(args.argv, RUN_GIT_CMD))
> +                       res = error(_("Cannot store %s"), autostash.buf);
> +               argv_array_clear(&args);
> +               strbuf_release(&autostash);
> +               if (res)
> +                       return res;
> +
> +               fprintf(stderr,
> +                       _("Applying autostash resulted in conflicts.\n"
> +                         "Your changes are safe in the stash.\n"
> +                         "You can run \"git stash pop\" or \"git stash drop\" "
> +                         "at any time.\n"));
> +       }
> +
> +       strbuf_release(&autostash);
> +       return 0;
> +}
> +
>  static int finish_rebase(struct rebase_options *opts)
>  {
>         struct strbuf dir = STRBUF_INIT;
>         const char *argv_gc_auto[] = { "gc", "--auto", NULL };
>
>         delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
> -       apply_autostash();
> +       apply_autostash(opts);
>         close_all_packs(the_repository->objects);
>         /*
>          * We ignore errors in 'gc --auto', since the
-- 
Duy

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 07/18] builtin rebase: support `keep-empty` option
  2018-08-08 15:21 ` [PATCH 07/18] builtin rebase: support `keep-empty` option Pratik Karki
@ 2018-08-24 16:04   ` Johannes Schindelin
  0 siblings, 0 replies; 44+ messages in thread
From: Johannes Schindelin @ 2018-08-24 16:04 UTC (permalink / raw)
  To: Pratik Karki; +Cc: git, christian.couder, sbeller, alban.gruin, gitster

Hi,

On Wed, 8 Aug 2018, Pratik Karki wrote:

> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 42ee040da3..fd9ad8efae 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -588,6 +607,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  			 &options.allow_rerere_autoupdate,
>  			 N_("allow rerere to update index  with resolved "
>  			    "conflict")),
> +		OPT_BOOL(0, "keep-empty", &options.keep_empty,
> +			 N_("preserve empty commits during rebase")),
>  		OPT_END(),

This forgets the short option `-k`, I just noticed. I then looked at the
rest of the options, and they seem not to forget the short option
anywhere.

I will fix this before sending v2.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH 11/18] builtin rebase: support `--autostash` option
  2018-08-18 15:59   ` Duy Nguyen
@ 2018-08-24 16:06     ` Johannes Schindelin
  0 siblings, 0 replies; 44+ messages in thread
From: Johannes Schindelin @ 2018-08-24 16:06 UTC (permalink / raw)
  To: Duy Nguyen
  Cc: Pratik Karki, Git Mailing List, Christian Couder, Stefan Beller,
	alban.gruin, Junio C Hamano

Hi Duy,

On Sat, 18 Aug 2018, Duy Nguyen wrote:

> On Wed, Aug 8, 2018 at 5:26 PM Pratik Karki <predatoramigo@gmail.com> wrote:
> > @@ -224,13 +219,56 @@ static int read_basic_state(struct rebase_options *opts)
> >         return 0;
> >  }
> >
> > +static int apply_autostash(struct rebase_options *opts)
> > +{
> > +       const char *path = state_dir_path("autostash", opts);
> > +       struct strbuf autostash = STRBUF_INIT;
> > +       struct child_process stash_apply = CHILD_PROCESS_INIT;
> > +
> > +       if (!file_exists(path))
> > +               return 0;
> > +
> > +       if (read_one(state_dir_path("autostash", opts), &autostash))
> > +               return error(_("Could not read '%s'"), path);
> > +       argv_array_pushl(&stash_apply.args,
> > +                        "stash", "apply", autostash.buf, NULL);
> > +       stash_apply.git_cmd = 1;
> > +       stash_apply.no_stderr = stash_apply.no_stdout =
> > +               stash_apply.no_stdin = 1;
> > +       if (!run_command(&stash_apply))
> > +               printf("Applied autostash.\n");
> 
> I think you need _() here.

Good catch.

Will fix before sending v2,
Dscho

> 
> > +       else {
> > +               struct argv_array args = ARGV_ARRAY_INIT;
> > +               int res = 0;
> > +
> > +               argv_array_pushl(&args,
> > +                                "stash", "store", "-m", "autostash", "-q",
> > +                                autostash.buf, NULL);
> > +               if (run_command_v_opt(args.argv, RUN_GIT_CMD))
> > +                       res = error(_("Cannot store %s"), autostash.buf);
> > +               argv_array_clear(&args);
> > +               strbuf_release(&autostash);
> > +               if (res)
> > +                       return res;
> > +
> > +               fprintf(stderr,
> > +                       _("Applying autostash resulted in conflicts.\n"
> > +                         "Your changes are safe in the stash.\n"
> > +                         "You can run \"git stash pop\" or \"git stash drop\" "
> > +                         "at any time.\n"));
> > +       }
> > +
> > +       strbuf_release(&autostash);
> > +       return 0;
> > +}
> > +
> >  static int finish_rebase(struct rebase_options *opts)
> >  {
> >         struct strbuf dir = STRBUF_INIT;
> >         const char *argv_gc_auto[] = { "gc", "--auto", NULL };
> >
> >         delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
> > -       apply_autostash();
> > +       apply_autostash(opts);
> >         close_all_packs(the_repository->objects);
> >         /*
> >          * We ignore errors in 'gc --auto', since the
> -- 
> Duy
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 00/18] builtin rebase options
  2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
                   ` (17 preceding siblings ...)
  2018-08-08 15:21 ` [PATCH 18/18] builtin rebase: support --root Pratik Karki
@ 2018-09-04 21:59 ` Johannes Schindelin via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 01/18] builtin rebase: allow selecting the rebase "backend" Pratik Karki via GitGitGadget
                     ` (18 more replies)
  18 siblings, 19 replies; 44+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2018-09-04 21:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

This patch series completes the support for all rebase options in the
builtin rebase, e.g. --signoff, rerere-autoupdate, etc.

It is based on pk/rebase -in-c-3-acts.

Changes since v1:

 * Added the forgotten -k short option for --keep-empty (and verified that
   no other short options were forgotten).
 * The "Applied autostash" message is now translated (as was the original in
   the shell script version).

Pratik Karki (18):
  builtin rebase: allow selecting the rebase "backend"
  builtin rebase: support --signoff
  builtin rebase: support --rerere-autoupdate
  builtin rebase: support --committer-date-is-author-date
  builtin rebase: support `ignore-whitespace` option
  builtin rebase: support `ignore-date` option
  builtin rebase: support `keep-empty` option
  builtin rebase: support `--autosquash`
  builtin rebase: support `--gpg-sign` option
  builtin rebase: support `-C` and `--whitespace=<type>`
  builtin rebase: support `--autostash` option
  builtin rebase: support `--exec`
  builtin rebase: support `--allow-empty-message` option
  builtin rebase: support --rebase-merges[=[no-]rebase-cousins]
  merge-base --fork-point: extract libified function
  builtin rebase: support `fork-point` option
  builtin rebase: add support for custom merge strategies
  builtin rebase: support --root

 builtin/merge-base.c |  81 +-------
 builtin/rebase.c     | 449 ++++++++++++++++++++++++++++++++++++++++++-
 commit.c             |  81 ++++++++
 commit.h             |   2 +
 4 files changed, 528 insertions(+), 85 deletions(-)


base-commit: e01f72be63e6cb58243124abb2491f9d5dbcdbef
Published-As: https://github.com/gitgitgadget/git/releases/tags/pr-33%2Fdscho%2Frebase-in-c-4-opts-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-33/dscho/rebase-in-c-4-opts-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/33

Range-diff vs v1:

  1:  22a65191f8 !  1:  7f751c6ce1 builtin rebase: allow selecting the rebase "backend"
     @@ -19,6 +19,7 @@
          tests for this via `git pull --rebase=preserve`).
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
  2:  cb9129890b !  2:  1e2ce4b34e builtin rebase: support --signoff
     @@ -7,6 +7,7 @@
          handling is left to the rebase backends.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
  3:  99ff1fc128 !  3:  a301ef6bbd builtin rebase: support --rerere-autoupdate
     @@ -7,6 +7,7 @@
          `git-legacy-rebase.sh`.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
  4:  cb6596ea93 !  4:  8f67a3969d builtin rebase: support --committer-date-is-author-date
     @@ -6,6 +6,7 @@
          `git_am_opt` variable that is handled by the `git-rebase--am` backend.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
  5:  bf3279c2d5 !  5:  f04394a500 builtin rebase: support `ignore-whitespace` option
     @@ -7,6 +7,7 @@
          `--am` backend.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
  6:  804e1969c2 !  6:  83bb277509 builtin rebase: support `ignore-date` option
     @@ -6,6 +6,7 @@
          to easily change the dates of the rebased commits.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
  7:  fcf2243476 !  7:  a8f12bf01f builtin rebase: support `keep-empty` option
     @@ -12,6 +12,7 @@
          already be chosen during the `parse_options()` call.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
     @@ -60,7 +61,7 @@
       			 &options.allow_rerere_autoupdate,
       			 N_("allow rerere to update index  with resolved "
       			    "conflict")),
     -+		OPT_BOOL(0, "keep-empty", &options.keep_empty,
     ++		OPT_BOOL('k', "keep-empty", &options.keep_empty,
      +			 N_("preserve empty commits during rebase")),
       		OPT_END(),
       	};
  8:  b4ecffc8f1 !  8:  1b6851e5e1 builtin rebase: support `--autosquash`
     @@ -12,6 +12,7 @@
          falls back to) git_default_config().
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
     @@ -46,7 +47,7 @@
       
      @@
       			    "conflict")),
     - 		OPT_BOOL(0, "keep-empty", &options.keep_empty,
     + 		OPT_BOOL('k', "keep-empty", &options.keep_empty,
       			 N_("preserve empty commits during rebase")),
      +		OPT_BOOL(0, "autosquash", &options.autosquash,
      +			 N_("move commits that begin with "
  9:  e2a26f10e5 !  9:  b8055fb258 builtin rebase: support `--gpg-sign` option
     @@ -6,6 +6,7 @@
          to GPG-sign commits.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
 10:  a1f3245250 ! 10:  98908573ce builtin rebase: support `-C` and `--whitespace=<type>`
     @@ -8,6 +8,7 @@
          shell script version does so, too.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
 11:  7b3c0dbbd9 ! 11:  5e5e5cb758 builtin rebase: support `--autostash` option
     @@ -11,6 +11,7 @@
          builtin.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
     @@ -57,7 +58,7 @@
      +	stash_apply.no_stderr = stash_apply.no_stdout =
      +		stash_apply.no_stdin = 1;
      +	if (!run_command(&stash_apply))
     -+		printf("Applied autostash.\n");
     ++		printf(_("Applied autostash.\n"));
      +	else {
      +		struct argv_array args = ARGV_ARRAY_INIT;
      +		int res = 0;
 12:  6f6b3d9339 ! 12:  01e5cb3e91 builtin rebase: support `--exec`
     @@ -14,6 +14,7 @@
          The `--exec` option requires `--interactive` machinery.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
 13:  fa643c4b3f ! 13:  1c723ad592 builtin rebase: support `--allow-empty-message` option
     @@ -14,6 +14,7 @@
          `git rebase`, therefore the builtin rebase does the same.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
 14:  00d7ccd356 ! 14:  1bebcde41c builtin rebase: support --rebase-merges[=[no-]rebase-cousins]
     @@ -6,6 +6,7 @@
          rebase, too.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
 15:  1cf16f416e ! 15:  05652bccfe merge-base --fork-point: extract libified function
     @@ -12,6 +12,7 @@
          process definitely did not traverse any commits before exiting.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/merge-base.c b/builtin/merge-base.c
      --- a/builtin/merge-base.c
 16:  78ffb7aaff ! 16:  25f6771947 builtin rebase: support `fork-point` option
     @@ -6,6 +6,7 @@
          This is converted as-is from `git-legacy-rebase.sh`.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
 17:  693b662542 ! 17:  10dc87d4ff builtin rebase: add support for custom merge strategies
     @@ -9,6 +9,7 @@
          This commit adds that support to the builtin rebase.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c
 18:  95679ccf0b ! 18:  f155141023 builtin rebase: support --root
     @@ -9,6 +9,7 @@
          the fact that we do not have to write an empty tree in C.
      
          Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
     +    Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
      
      diff --git a/builtin/rebase.c b/builtin/rebase.c
      --- a/builtin/rebase.c

-- 
gitgitgadget

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 01/18] builtin rebase: allow selecting the rebase "backend"
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
@ 2018-09-04 21:59   ` Pratik Karki via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 02/18] builtin rebase: support --signoff Pratik Karki via GitGitGadget
                     ` (17 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

With this commit the builtin rebase supports selecting the "rebase
backends" (or "type") `interactive`, `preserve-merges`, and `merge`.

The `state_dir` was already handled according to the rebase type in a
previous commit.

Note that there is one quirk in the shell script: `--interactive`
followed by `--merge` won't reset the type to "merge" but keeps the type
as "interactive". And as t3418 tests this explicitly, we have to support
it in the builtin rebase, too.

Likewise, `--interactive` followed by `--preserve-merges` makes it an
"explicitly interactive" rebase, i.e. a rebase that should show the todo
list, while `--preserve-merges` alone is not interactive (and t5520
tests for this via `git pull --rebase=preserve`).

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 75c4ac66e0..fc9b5a8a60 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -452,6 +452,29 @@ static int can_fast_forward(struct commit *onto, struct object_id *head_oid,
 	return res && is_linear_history(onto, head);
 }
 
+/* -i followed by -m is still -i */
+static int parse_opt_merge(const struct option *opt, const char *arg, int unset)
+{
+	struct rebase_options *opts = opt->value;
+
+	if (!is_interactive(opts))
+		opts->type = REBASE_MERGE;
+
+	return 0;
+}
+
+/* -i followed by -p is still explicitly interactive, but -p alone is not */
+static int parse_opt_interactive(const struct option *opt, const char *arg,
+				 int unset)
+{
+	struct rebase_options *opts = opt->value;
+
+	opts->type = REBASE_INTERACTIVE;
+	opts->flags |= REBASE_INTERACTIVE_EXPLICIT;
+
+	return 0;
+}
+
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
 	struct rebase_options options = {
@@ -510,6 +533,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_CMDMODE(0, "show-current-patch", &action,
 			    N_("show the patch file being applied or merged"),
 			    ACTION_SHOW_CURRENT_PATCH),
+		{ OPTION_CALLBACK, 'm', "merge", &options, NULL,
+			N_("use merging strategies to rebase"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			parse_opt_merge },
+		{ OPTION_CALLBACK, 'i', "interactive", &options, NULL,
+			N_("let the user edit the list of commits to rebase"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			parse_opt_interactive },
+		OPT_SET_INT('p', "preserve-merges", &options.type,
+			    N_("try to recreate merges instead of ignoring "
+			       "them"), REBASE_PRESERVE_MERGES),
 		OPT_END(),
 	};
 
@@ -884,6 +918,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		diff_flush(&opts);
 	}
 
+	if (is_interactive(&options))
+		goto run_rebase;
+
 	/* Detach HEAD and reset the tree */
 	if (options.flags & REBASE_NO_QUIET)
 		printf(_("First, rewinding head to replay your work on top of "
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 02/18] builtin rebase: support --signoff
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 01/18] builtin rebase: allow selecting the rebase "backend" Pratik Karki via GitGitGadget
@ 2018-09-04 21:59   ` Pratik Karki via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 03/18] builtin rebase: support --rerere-autoupdate Pratik Karki via GitGitGadget
                     ` (16 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit adds support for `--signoff` which is used to add a
`Signed-off-by` trailer to all the rebased commits. The actual
handling is left to the rebase backends.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index fc9b5a8a60..a491481120 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -93,6 +93,7 @@ struct rebase_options {
 	} flags;
 	struct strbuf git_am_opt;
 	const char *action;
+	int signoff;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -168,6 +169,11 @@ static int read_basic_state(struct rebase_options *opts)
 	if (file_exists(state_dir_path("verbose", opts)))
 		opts->flags |= REBASE_VERBOSE;
 
+	if (file_exists(state_dir_path("signoff", opts))) {
+		opts->signoff = 1;
+		opts->flags |= REBASE_FORCE;
+	}
+
 	strbuf_release(&buf);
 
 	return 0;
@@ -249,6 +255,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 	if (opts->switch_to)
 		add_var(&script_snippet, "switch_to", opts->switch_to);
 	add_var(&script_snippet, "action", opts->action ? opts->action : "");
+	add_var(&script_snippet, "signoff", opts->signoff ? "--signoff" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -513,6 +520,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
 			N_("do not show diffstat of what changed upstream"),
 			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
+		OPT_BOOL(0, "signoff", &options.signoff,
+			 N_("add a Signed-off-by: line to each commit")),
 		OPT_BIT('f', "force-rebase", &options.flags,
 			N_("cherry-pick all commits, even if unchanged"),
 			REBASE_FORCE),
@@ -745,6 +754,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		break;
 	}
 
+	if (options.signoff) {
+		if (options.type == REBASE_PRESERVE_MERGES)
+			die("cannot combine '--signoff' with "
+			    "'--preserve-merges'");
+		strbuf_addstr(&options.git_am_opt, " --signoff");
+		options.flags |= REBASE_FORCE;
+	}
+
 	if (!options.root) {
 		if (argc < 1)
 			die("TODO: handle @{upstream}");
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 03/18] builtin rebase: support --rerere-autoupdate
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 01/18] builtin rebase: allow selecting the rebase "backend" Pratik Karki via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 02/18] builtin rebase: support --signoff Pratik Karki via GitGitGadget
@ 2018-09-04 21:59   ` Pratik Karki via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 04/18] builtin rebase: support --committer-date-is-author-date Pratik Karki via GitGitGadget
                     ` (15 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

The `--rerere-autoupdate` option allows rerere to update the index with
resolved conflicts. This commit follows closely the equivalent part of
`git-legacy-rebase.sh`.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index a491481120..1729d2d9e2 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -94,6 +94,7 @@ struct rebase_options {
 	struct strbuf git_am_opt;
 	const char *action;
 	int signoff;
+	int allow_rerere_autoupdate;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -174,6 +175,21 @@ static int read_basic_state(struct rebase_options *opts)
 		opts->flags |= REBASE_FORCE;
 	}
 
+	if (file_exists(state_dir_path("allow_rerere_autoupdate", opts))) {
+		strbuf_reset(&buf);
+		if (read_one(state_dir_path("allow_rerere_autoupdate", opts),
+			    &buf))
+			return -1;
+		if (!strcmp(buf.buf, "--rerere-autoupdate"))
+			opts->allow_rerere_autoupdate = 1;
+		else if (!strcmp(buf.buf, "--no-rerere-autoupdate"))
+			opts->allow_rerere_autoupdate = 0;
+		else
+			warning(_("ignoring invalid allow_rerere_autoupdate: "
+				  "'%s'"), buf.buf);
+	} else
+		opts->allow_rerere_autoupdate = -1;
+
 	strbuf_release(&buf);
 
 	return 0;
@@ -256,6 +272,10 @@ static int run_specific_rebase(struct rebase_options *opts)
 		add_var(&script_snippet, "switch_to", opts->switch_to);
 	add_var(&script_snippet, "action", opts->action ? opts->action : "");
 	add_var(&script_snippet, "signoff", opts->signoff ? "--signoff" : "");
+	add_var(&script_snippet, "allow_rerere_autoupdate",
+		opts->allow_rerere_autoupdate < 0 ? "" :
+		opts->allow_rerere_autoupdate ?
+		"--rerere-autoupdate" : "--no-rerere-autoupdate");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -488,6 +508,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		.type = REBASE_UNSPECIFIED,
 		.flags = REBASE_NO_QUIET,
 		.git_am_opt = STRBUF_INIT,
+		.allow_rerere_autoupdate  = -1,
 	};
 	const char *branch_name;
 	int ret, flags, total_argc, in_progress = 0;
@@ -553,6 +574,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_SET_INT('p', "preserve-merges", &options.type,
 			    N_("try to recreate merges instead of ignoring "
 			       "them"), REBASE_PRESERVE_MERGES),
+		OPT_BOOL(0, "rerere-autoupdate",
+			 &options.allow_rerere_autoupdate,
+			 N_("allow rerere to update index  with resolved "
+			    "conflict")),
 		OPT_END(),
 	};
 
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 04/18] builtin rebase: support --committer-date-is-author-date
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (2 preceding siblings ...)
  2018-09-04 21:59   ` [PATCH v2 03/18] builtin rebase: support --rerere-autoupdate Pratik Karki via GitGitGadget
@ 2018-09-04 21:59   ` Pratik Karki via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 05/18] builtin rebase: support `ignore-whitespace` option Pratik Karki via GitGitGadget
                     ` (14 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This option is simply handed down to `git am` by way of setting the
`git_am_opt` variable that is handled by the `git-rebase--am` backend.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 1729d2d9e2..eef16206c2 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -526,6 +526,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		ACTION_EDIT_TODO,
 		ACTION_SHOW_CURRENT_PATCH,
 	} action = NO_ACTION;
+	int committer_date_is_author_date = 0;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -543,6 +544,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
 		OPT_BOOL(0, "signoff", &options.signoff,
 			 N_("add a Signed-off-by: line to each commit")),
+		OPT_BOOL(0, "committer-date-is-author-date",
+			 &committer_date_is_author_date,
+			 N_("passed to 'git am'")),
 		OPT_BIT('f', "force-rebase", &options.flags,
 			N_("cherry-pick all commits, even if unchanged"),
 			REBASE_FORCE),
@@ -763,6 +767,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (!(options.flags & REBASE_NO_QUIET))
 		strbuf_addstr(&options.git_am_opt, " -q");
 
+	if (committer_date_is_author_date) {
+		strbuf_addstr(&options.git_am_opt,
+			      " --committer-date-is-author-date");
+		options.flags |= REBASE_FORCE;
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 05/18] builtin rebase: support `ignore-whitespace` option
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (3 preceding siblings ...)
  2018-09-04 21:59   ` [PATCH v2 04/18] builtin rebase: support --committer-date-is-author-date Pratik Karki via GitGitGadget
@ 2018-09-04 21:59   ` Pratik Karki via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 06/18] builtin rebase: support `ignore-date` option Pratik Karki via GitGitGadget
                     ` (13 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit adds support for the `--ignore-whitespace` option
of the rebase command. This option is simply passed to the
`--am` backend.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index eef16206c2..7490d215ef 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -527,6 +527,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		ACTION_SHOW_CURRENT_PATCH,
 	} action = NO_ACTION;
 	int committer_date_is_author_date = 0;
+	int ignore_whitespace = 0;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -542,6 +543,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
 			N_("do not show diffstat of what changed upstream"),
 			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
+		OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
+			 N_("passed to 'git apply'")),
 		OPT_BOOL(0, "signoff", &options.signoff,
 			 N_("add a Signed-off-by: line to each commit")),
 		OPT_BOOL(0, "committer-date-is-author-date",
@@ -773,6 +776,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.flags |= REBASE_FORCE;
 	}
 
+	if (ignore_whitespace)
+		strbuf_addstr(&options.git_am_opt, " --ignore-whitespace");
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 06/18] builtin rebase: support `ignore-date` option
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (4 preceding siblings ...)
  2018-09-04 21:59   ` [PATCH v2 05/18] builtin rebase: support `ignore-whitespace` option Pratik Karki via GitGitGadget
@ 2018-09-04 21:59   ` Pratik Karki via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 07/18] builtin rebase: support `keep-empty` option Pratik Karki via GitGitGadget
                     ` (12 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit adds support for `--ignore-date` which is passed to `git am`
to easily change the dates of the rebased commits.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 7490d215ef..42ee040da3 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -527,6 +527,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		ACTION_SHOW_CURRENT_PATCH,
 	} action = NO_ACTION;
 	int committer_date_is_author_date = 0;
+	int ignore_date = 0;
 	int ignore_whitespace = 0;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
@@ -550,6 +551,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "committer-date-is-author-date",
 			 &committer_date_is_author_date,
 			 N_("passed to 'git am'")),
+		OPT_BOOL(0, "ignore-date", &ignore_date,
+			 N_("passed to 'git am'")),
 		OPT_BIT('f', "force-rebase", &options.flags,
 			N_("cherry-pick all commits, even if unchanged"),
 			REBASE_FORCE),
@@ -779,6 +782,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (ignore_whitespace)
 		strbuf_addstr(&options.git_am_opt, " --ignore-whitespace");
 
+	if (ignore_date) {
+		strbuf_addstr(&options.git_am_opt, " --ignore-date");
+		options.flags |= REBASE_FORCE;
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 07/18] builtin rebase: support `keep-empty` option
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (5 preceding siblings ...)
  2018-09-04 21:59   ` [PATCH v2 06/18] builtin rebase: support `ignore-date` option Pratik Karki via GitGitGadget
@ 2018-09-04 21:59   ` Pratik Karki via GitGitGadget
  2018-09-04 21:59   ` [PATCH v2 08/18] builtin rebase: support `--autosquash` Pratik Karki via GitGitGadget
                     ` (11 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

The `--keep-empty` option can be used to keep the commits that do not
change anything from its parents in the result.

While the scripted version uses `interactive_rebase=implied` to indicate
that the rebase needs to use the `git-rebase--interactive` backend in
non-interactive mode as fallback when figuring out which backend to use,
the C version needs to use a different route because the backend will
already be chosen during the `parse_options()` call.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 42ee040da3..9c00f3568f 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -95,6 +95,7 @@ struct rebase_options {
 	const char *action;
 	int signoff;
 	int allow_rerere_autoupdate;
+	int keep_empty;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -103,6 +104,23 @@ static int is_interactive(struct rebase_options *opts)
 		opts->type == REBASE_PRESERVE_MERGES;
 }
 
+static void imply_interactive(struct rebase_options *opts, const char *option)
+{
+	switch (opts->type) {
+	case REBASE_AM:
+		die(_("%s requires an interactive rebase"), option);
+		break;
+	case REBASE_INTERACTIVE:
+	case REBASE_PRESERVE_MERGES:
+		break;
+	case REBASE_MERGE:
+		/* we silently *upgrade* --merge to --interactive if needed */
+	default:
+		opts->type = REBASE_INTERACTIVE; /* implied */
+		break;
+	}
+}
+
 /* Returns the filename prefixed by the state_dir */
 static const char *state_dir_path(const char *filename, struct rebase_options *opts)
 {
@@ -276,6 +294,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->allow_rerere_autoupdate < 0 ? "" :
 		opts->allow_rerere_autoupdate ?
 		"--rerere-autoupdate" : "--no-rerere-autoupdate");
+	add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -588,6 +607,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			 &options.allow_rerere_autoupdate,
 			 N_("allow rerere to update index  with resolved "
 			    "conflict")),
+		OPT_BOOL('k', "keep-empty", &options.keep_empty,
+			 N_("preserve empty commits during rebase")),
 		OPT_END(),
 	};
 
@@ -787,6 +808,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.flags |= REBASE_FORCE;
 	}
 
+	if (options.keep_empty)
+		imply_interactive(&options, "--keep-empty");
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 08/18] builtin rebase: support `--autosquash`
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (6 preceding siblings ...)
  2018-09-04 21:59   ` [PATCH v2 07/18] builtin rebase: support `keep-empty` option Pratik Karki via GitGitGadget
@ 2018-09-04 21:59   ` Pratik Karki via GitGitGadget
  2018-09-04 22:00   ` [PATCH v2 09/18] builtin rebase: support `--gpg-sign` option Pratik Karki via GitGitGadget
                     ` (10 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:59 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit adds support for the `--autosquash` option which is used to
automatically squash the commits marked as `squash` or `fixup` in their
messages. This is converted following `git-legacy-rebase.sh` closely.

This option can also be configured via the Git config setting
rebase.autosquash. To support this, we also add a custom
rebase_config() function in this commit that will be used instead (and
falls back to) git_default_config().

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 9c00f3568f..c80eebfbd2 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -96,6 +96,7 @@ struct rebase_options {
 	int signoff;
 	int allow_rerere_autoupdate;
 	int keep_empty;
+	int autosquash;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -295,6 +296,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->allow_rerere_autoupdate ?
 		"--rerere-autoupdate" : "--no-rerere-autoupdate");
 	add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : "");
+	add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -455,6 +457,11 @@ static int rebase_config(const char *var, const char *value, void *data)
 		return 0;
 	}
 
+	if (!strcmp(var, "rebase.autosquash")) {
+		opts->autosquash = git_config_bool(var, value);
+		return 0;
+	}
+
 	return git_default_config(var, value, data);
 }
 
@@ -609,6 +616,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			    "conflict")),
 		OPT_BOOL('k', "keep-empty", &options.keep_empty,
 			 N_("preserve empty commits during rebase")),
+		OPT_BOOL(0, "autosquash", &options.autosquash,
+			 N_("move commits that begin with "
+			    "squash!/fixup! under -i")),
 		OPT_END(),
 	};
 
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 09/18] builtin rebase: support `--gpg-sign` option
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (7 preceding siblings ...)
  2018-09-04 21:59   ` [PATCH v2 08/18] builtin rebase: support `--autosquash` Pratik Karki via GitGitGadget
@ 2018-09-04 22:00   ` Pratik Karki via GitGitGadget
  2018-09-04 22:00   ` [PATCH v2 10/18] builtin rebase: support `-C` and `--whitespace=<type>` Pratik Karki via GitGitGadget
                     ` (9 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 22:00 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit introduces support for `--gpg-sign` option which is used
to GPG-sign commits.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index c80eebfbd2..0ab86b7c4c 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -97,6 +97,7 @@ struct rebase_options {
 	int allow_rerere_autoupdate;
 	int keep_empty;
 	int autosquash;
+	char *gpg_sign_opt;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -209,6 +210,15 @@ static int read_basic_state(struct rebase_options *opts)
 	} else
 		opts->allow_rerere_autoupdate = -1;
 
+	if (file_exists(state_dir_path("gpg_sign_opt", opts))) {
+		strbuf_reset(&buf);
+		if (read_one(state_dir_path("gpg_sign_opt", opts),
+			    &buf))
+			return -1;
+		free(opts->gpg_sign_opt);
+		opts->gpg_sign_opt = xstrdup(buf.buf);
+	}
+
 	strbuf_release(&buf);
 
 	return 0;
@@ -297,6 +307,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 		"--rerere-autoupdate" : "--no-rerere-autoupdate");
 	add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : "");
 	add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : "");
+	add_var(&script_snippet, "gpg_sign_opt", opts->gpg_sign_opt);
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -462,6 +473,13 @@ static int rebase_config(const char *var, const char *value, void *data)
 		return 0;
 	}
 
+	if (!strcmp(var, "commit.gpgsign")) {
+		free(opts->gpg_sign_opt);
+		opts->gpg_sign_opt = git_config_bool(var, value) ?
+			xstrdup("-S") : NULL;
+		return 0;
+	}
+
 	return git_default_config(var, value, data);
 }
 
@@ -555,6 +573,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	int committer_date_is_author_date = 0;
 	int ignore_date = 0;
 	int ignore_whitespace = 0;
+	const char *gpg_sign = NULL;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -619,6 +638,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "autosquash", &options.autosquash,
 			 N_("move commits that begin with "
 			    "squash!/fixup! under -i")),
+		OPT_STRING('S', "gpg-sign", &gpg_sign,
+			   N_("gpg-sign?"), N_("GPG-sign commits")),
 		OPT_END(),
 	};
 
@@ -821,6 +842,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (options.keep_empty)
 		imply_interactive(&options, "--keep-empty");
 
+	if (gpg_sign) {
+		free(options.gpg_sign_opt);
+		options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
@@ -1046,5 +1072,6 @@ run_rebase:
 cleanup:
 	strbuf_release(&revisions);
 	free(options.head_name);
+	free(options.gpg_sign_opt);
 	return ret;
 }
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 10/18] builtin rebase: support `-C` and `--whitespace=<type>`
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (8 preceding siblings ...)
  2018-09-04 22:00   ` [PATCH v2 09/18] builtin rebase: support `--gpg-sign` option Pratik Karki via GitGitGadget
@ 2018-09-04 22:00   ` Pratik Karki via GitGitGadget
  2018-09-04 22:00   ` [PATCH v2 11/18] builtin rebase: support `--autostash` option Pratik Karki via GitGitGadget
                     ` (8 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 22:00 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit converts more code from the shell script version to the
builtin rebase. In this instance, we just have to be careful to
keep support for passing multiple `--whitespace` options, as the
shell script version does so, too.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 0ab86b7c4c..63ffe5e1ff 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -574,6 +574,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	int ignore_date = 0;
 	int ignore_whitespace = 0;
 	const char *gpg_sign = NULL;
+	int opt_c = -1;
+	struct string_list whitespace = STRING_LIST_INIT_NODUP;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -640,6 +642,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			    "squash!/fixup! under -i")),
 		OPT_STRING('S', "gpg-sign", &gpg_sign,
 			   N_("gpg-sign?"), N_("GPG-sign commits")),
+		OPT_STRING_LIST(0, "whitespace", &whitespace,
+				N_("whitespace"), N_("passed to 'git apply'")),
+		OPT_SET_INT('C', 0, &opt_c, N_("passed to 'git apply'"),
+			    REBASE_AM),
 		OPT_END(),
 	};
 
@@ -847,6 +853,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
 	}
 
+	if (opt_c >= 0)
+		strbuf_addf(&options.git_am_opt, " -C%d", opt_c);
+
+	if (whitespace.nr) {
+		int i;
+
+		for (i = 0; i < whitespace.nr; i++) {
+			const char *item = whitespace.items[i].string;
+
+			strbuf_addf(&options.git_am_opt, " --whitespace=%s",
+				    item);
+
+			if ((!strcmp(item, "fix")) || (!strcmp(item, "strip")))
+				options.flags |= REBASE_FORCE;
+		}
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 11/18] builtin rebase: support `--autostash` option
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (9 preceding siblings ...)
  2018-09-04 22:00   ` [PATCH v2 10/18] builtin rebase: support `-C` and `--whitespace=<type>` Pratik Karki via GitGitGadget
@ 2018-09-04 22:00   ` Pratik Karki via GitGitGadget
  2018-09-04 22:00   ` [PATCH v2 12/18] builtin rebase: support `--exec` Pratik Karki via GitGitGadget
                     ` (7 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 22:00 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

To support `--autostash` we introduce a function `apply_autostash()`
just like in `git-legacy-rebase.sh`.

Rather than refactoring and using the same function that exists in
`sequencer.c`, we go a different route here, to avoid clashes with
the sister GSoC project that turns the interactive rebase into a
builtin.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 117 +++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 109 insertions(+), 8 deletions(-)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 63ffe5e1ff..1e35b82d9a 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -63,12 +63,6 @@ static int use_builtin_rebase(void)
 	return ret;
 }
 
-static int apply_autostash(void)
-{
-	warning("TODO");
-	return 0;
-}
-
 struct rebase_options {
 	enum rebase_type type;
 	const char *state_dir;
@@ -98,6 +92,7 @@ struct rebase_options {
 	int keep_empty;
 	int autosquash;
 	char *gpg_sign_opt;
+	int autostash;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -224,13 +219,56 @@ static int read_basic_state(struct rebase_options *opts)
 	return 0;
 }
 
+static int apply_autostash(struct rebase_options *opts)
+{
+	const char *path = state_dir_path("autostash", opts);
+	struct strbuf autostash = STRBUF_INIT;
+	struct child_process stash_apply = CHILD_PROCESS_INIT;
+
+	if (!file_exists(path))
+		return 0;
+
+	if (read_one(state_dir_path("autostash", opts), &autostash))
+		return error(_("Could not read '%s'"), path);
+	argv_array_pushl(&stash_apply.args,
+			 "stash", "apply", autostash.buf, NULL);
+	stash_apply.git_cmd = 1;
+	stash_apply.no_stderr = stash_apply.no_stdout =
+		stash_apply.no_stdin = 1;
+	if (!run_command(&stash_apply))
+		printf(_("Applied autostash.\n"));
+	else {
+		struct argv_array args = ARGV_ARRAY_INIT;
+		int res = 0;
+
+		argv_array_pushl(&args,
+				 "stash", "store", "-m", "autostash", "-q",
+				 autostash.buf, NULL);
+		if (run_command_v_opt(args.argv, RUN_GIT_CMD))
+			res = error(_("Cannot store %s"), autostash.buf);
+		argv_array_clear(&args);
+		strbuf_release(&autostash);
+		if (res)
+			return res;
+
+		fprintf(stderr,
+			_("Applying autostash resulted in conflicts.\n"
+			  "Your changes are safe in the stash.\n"
+			  "You can run \"git stash pop\" or \"git stash drop\" "
+			  "at any time.\n"));
+	}
+
+	strbuf_release(&autostash);
+	return 0;
+}
+
 static int finish_rebase(struct rebase_options *opts)
 {
 	struct strbuf dir = STRBUF_INIT;
 	const char *argv_gc_auto[] = { "gc", "--auto", NULL };
 
 	delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
-	apply_autostash();
+	apply_autostash(opts);
 	close_all_packs(the_repository->objects);
 	/*
 	 * We ignore errors in 'gc --auto', since the
@@ -345,7 +383,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 	} else if (status == 2) {
 		struct strbuf dir = STRBUF_INIT;
 
-		apply_autostash();
+		apply_autostash(opts);
 		strbuf_addstr(&dir, opts->state_dir);
 		remove_dir_recursively(&dir, 0);
 		strbuf_release(&dir);
@@ -480,6 +518,11 @@ static int rebase_config(const char *var, const char *value, void *data)
 		return 0;
 	}
 
+	if (!strcmp(var, "rebase.autostash")) {
+		opts->autostash = git_config_bool(var, value);
+		return 0;
+	}
+
 	return git_default_config(var, value, data);
 }
 
@@ -646,6 +689,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 				N_("whitespace"), N_("passed to 'git apply'")),
 		OPT_SET_INT('C', 0, &opt_c, N_("passed to 'git apply'"),
 			    REBASE_AM),
+		OPT_BOOL(0, "autostash", &options.autostash,
+			 N_("automatically stash/stash pop before and after")),
 		OPT_END(),
 	};
 
@@ -975,6 +1020,62 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (read_index(the_repository->index) < 0)
 		die(_("could not read index"));
 
+	if (options.autostash) {
+		struct lock_file lock_file = LOCK_INIT;
+		int fd;
+
+		fd = hold_locked_index(&lock_file, 0);
+		refresh_cache(REFRESH_QUIET);
+		if (0 <= fd)
+			update_index_if_able(&the_index, &lock_file);
+		rollback_lock_file(&lock_file);
+
+		if (has_unstaged_changes(0) || has_uncommitted_changes(0)) {
+			const char *autostash =
+				state_dir_path("autostash", &options);
+			struct child_process stash = CHILD_PROCESS_INIT;
+			struct object_id oid;
+			struct commit *head =
+				lookup_commit_reference(the_repository,
+							&options.orig_head);
+
+			argv_array_pushl(&stash.args,
+					 "stash", "create", "autostash", NULL);
+			stash.git_cmd = 1;
+			stash.no_stdin = 1;
+			strbuf_reset(&buf);
+			if (capture_command(&stash, &buf, GIT_MAX_HEXSZ))
+				die(_("Cannot autostash"));
+			strbuf_trim_trailing_newline(&buf);
+			if (get_oid(buf.buf, &oid))
+				die(_("Unexpected stash response: '%s'"),
+				    buf.buf);
+			strbuf_reset(&buf);
+			strbuf_add_unique_abbrev(&buf, &oid, DEFAULT_ABBREV);
+
+			if (safe_create_leading_directories_const(autostash))
+				die(_("Could not create directory for '%s'"),
+				    options.state_dir);
+			write_file(autostash, "%s", buf.buf);
+			printf(_("Created autostash: %s\n"), buf.buf);
+			if (reset_head(&head->object.oid, "reset --hard",
+				       NULL, 0) < 0)
+				die(_("could not reset --hard"));
+			printf(_("HEAD is now at %s"),
+			       find_unique_abbrev(&head->object.oid,
+						  DEFAULT_ABBREV));
+			strbuf_reset(&buf);
+			pp_commit_easy(CMIT_FMT_ONELINE, head, &buf);
+			if (buf.len > 0)
+				printf(" %s", buf.buf);
+			putchar('\n');
+
+			if (discard_index(the_repository->index) < 0 ||
+				read_index(the_repository->index) < 0)
+				die(_("could not read index"));
+		}
+	}
+
 	if (require_clean_work_tree("rebase",
 				    _("Please commit or stash them."), 1, 1)) {
 		ret = 1;
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 12/18] builtin rebase: support `--exec`
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (10 preceding siblings ...)
  2018-09-04 22:00   ` [PATCH v2 11/18] builtin rebase: support `--autostash` option Pratik Karki via GitGitGadget
@ 2018-09-04 22:00   ` Pratik Karki via GitGitGadget
  2018-09-04 22:00   ` [PATCH v2 13/18] builtin rebase: support `--allow-empty-message` option Pratik Karki via GitGitGadget
                     ` (6 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 22:00 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit adds support for the `--exec` option which takes a shell
command-line as argument. This argument will be appended as an `exec
<cmd>` command after each line in the todo list that creates a commit in
the final history.  commands.

Note: while the shell script version of `git rebase` assigned the empty
string to `cmd` by default, we *unset* it here because the code looks
nicer and it does not change the behavior.

The `--exec` option requires `--interactive` machinery.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 1e35b82d9a..2547be9efe 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -93,6 +93,7 @@ struct rebase_options {
 	int autosquash;
 	char *gpg_sign_opt;
 	int autostash;
+	char *cmd;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -346,6 +347,7 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "keep_empty", opts->keep_empty ? "yes" : "");
 	add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : "");
 	add_var(&script_snippet, "gpg_sign_opt", opts->gpg_sign_opt);
+	add_var(&script_snippet, "cmd", opts->cmd);
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -619,6 +621,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	const char *gpg_sign = NULL;
 	int opt_c = -1;
 	struct string_list whitespace = STRING_LIST_INIT_NODUP;
+	struct string_list exec = STRING_LIST_INIT_NODUP;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -691,6 +694,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			    REBASE_AM),
 		OPT_BOOL(0, "autostash", &options.autostash,
 			 N_("automatically stash/stash pop before and after")),
+		OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
+				N_("add exec lines after each commit of the "
+				   "editable list")),
 		OPT_END(),
 	};
 
@@ -915,6 +921,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		}
 	}
 
+	if (exec.nr) {
+		int i;
+
+		imply_interactive(&options, "--exec");
+
+		strbuf_reset(&buf);
+		for (i = 0; i < exec.nr; i++)
+			strbuf_addf(&buf, "exec %s\n", exec.items[i].string);
+		options.cmd = xstrdup(buf.buf);
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
@@ -1197,5 +1214,6 @@ cleanup:
 	strbuf_release(&revisions);
 	free(options.head_name);
 	free(options.gpg_sign_opt);
+	free(options.cmd);
 	return ret;
 }
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 13/18] builtin rebase: support `--allow-empty-message` option
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (11 preceding siblings ...)
  2018-09-04 22:00   ` [PATCH v2 12/18] builtin rebase: support `--exec` Pratik Karki via GitGitGadget
@ 2018-09-04 22:00   ` Pratik Karki via GitGitGadget
  2018-09-04 22:00   ` [PATCH v2 14/18] builtin rebase: support --rebase-merges[=[no-]rebase-cousins] Pratik Karki via GitGitGadget
                     ` (5 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 22:00 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit introduces the `--allow-empty-message` option to
`builtin/rebase.c`. The motivation behind this option is: if there are
empty messages (which is not allowed in Git by default, but can be
imported from different version control systems), the rebase will fail.

Using `--allow-empty-message` overrides that behaviour which will allow
the commits having empty messages to continue in rebase operation.

Note: a very recent change made this the default in the shell scripted
`git rebase`, therefore the builtin rebase does the same.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 2547be9efe..3e37603da4 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -94,6 +94,7 @@ struct rebase_options {
 	char *gpg_sign_opt;
 	int autostash;
 	char *cmd;
+	int allow_empty_message;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -348,6 +349,8 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "autosquash", opts->autosquash ? "t" : "");
 	add_var(&script_snippet, "gpg_sign_opt", opts->gpg_sign_opt);
 	add_var(&script_snippet, "cmd", opts->cmd);
+	add_var(&script_snippet, "allow_empty_message",
+		opts->allow_empty_message ?  "--allow-empty-message" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -598,6 +601,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		.flags = REBASE_NO_QUIET,
 		.git_am_opt = STRBUF_INIT,
 		.allow_rerere_autoupdate  = -1,
+		.allow_empty_message = 1,
 	};
 	const char *branch_name;
 	int ret, flags, total_argc, in_progress = 0;
@@ -697,6 +701,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
 				N_("add exec lines after each commit of the "
 				   "editable list")),
+		OPT_BOOL(0, "allow-empty-message",
+			 &options.allow_empty_message,
+			 N_("allow rebasing commits with empty messages")),
 		OPT_END(),
 	};
 
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 14/18] builtin rebase: support --rebase-merges[=[no-]rebase-cousins]
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (12 preceding siblings ...)
  2018-09-04 22:00   ` [PATCH v2 13/18] builtin rebase: support `--allow-empty-message` option Pratik Karki via GitGitGadget
@ 2018-09-04 22:00   ` Pratik Karki via GitGitGadget
  2018-09-04 22:00   ` [PATCH v2 15/18] merge-base --fork-point: extract libified function Pratik Karki via GitGitGadget
                     ` (4 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 22:00 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

The mode to rebase non-linear branches is now supported by the builtin
rebase, too.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 3e37603da4..bcacffda33 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -95,6 +95,7 @@ struct rebase_options {
 	int autostash;
 	char *cmd;
 	int allow_empty_message;
+	int rebase_merges, rebase_cousins;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -351,6 +352,10 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "cmd", opts->cmd);
 	add_var(&script_snippet, "allow_empty_message",
 		opts->allow_empty_message ?  "--allow-empty-message" : "");
+	add_var(&script_snippet, "rebase_merges",
+		opts->rebase_merges ? "t" : "");
+	add_var(&script_snippet, "rebase_cousins",
+		opts->rebase_cousins ? "t" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -626,6 +631,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	int opt_c = -1;
 	struct string_list whitespace = STRING_LIST_INIT_NODUP;
 	struct string_list exec = STRING_LIST_INIT_NODUP;
+	const char *rebase_merges = NULL;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -704,6 +710,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_BOOL(0, "allow-empty-message",
 			 &options.allow_empty_message,
 			 N_("allow rebasing commits with empty messages")),
+		{OPTION_STRING, 'r', "rebase-merges", &rebase_merges,
+			N_("mode"),
+			N_("try to rebase merges instead of skipping them"),
+			PARSE_OPT_OPTARG, NULL, (intptr_t)""},
 		OPT_END(),
 	};
 
@@ -939,6 +949,17 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.cmd = xstrdup(buf.buf);
 	}
 
+	if (rebase_merges) {
+		if (!*rebase_merges)
+			; /* default mode; do nothing */
+		else if (!strcmp("rebase-cousins", rebase_merges))
+			options.rebase_cousins = 1;
+		else if (strcmp("no-rebase-cousins", rebase_merges))
+			die(_("Unknown mode: %s"), rebase_merges);
+		options.rebase_merges = 1;
+		imply_interactive(&options, "--rebase-merges");
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 15/18] merge-base --fork-point: extract libified function
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (13 preceding siblings ...)
  2018-09-04 22:00   ` [PATCH v2 14/18] builtin rebase: support --rebase-merges[=[no-]rebase-cousins] Pratik Karki via GitGitGadget
@ 2018-09-04 22:00   ` Pratik Karki via GitGitGadget
  2018-09-04 22:00   ` [PATCH v2 16/18] builtin rebase: support `fork-point` option Pratik Karki via GitGitGadget
                     ` (3 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 22:00 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

We need this functionality in the builtin rebase.

Note: to make this function truly reusable, we have to switch the call
get_merges_many_dirty() to get_merges_many() because we want the commit
flags to be reset (otherwise, subsequent get_merge_bases() calls would
obtain incorrect results). This did not matter when the function was
called in `git rev-parse --fork-point` because in that command, the
process definitely did not traverse any commits before exiting.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/merge-base.c | 81 ++++----------------------------------------
 commit.c             | 81 ++++++++++++++++++++++++++++++++++++++++++++
 commit.h             |  2 ++
 3 files changed, 89 insertions(+), 75 deletions(-)

diff --git a/builtin/merge-base.c b/builtin/merge-base.c
index 08d91b1f0c..790ceaeed6 100644
--- a/builtin/merge-base.c
+++ b/builtin/merge-base.c
@@ -110,54 +110,12 @@ static int handle_is_ancestor(int argc, const char **argv)
 		return 1;
 }
 
-struct rev_collect {
-	struct commit **commit;
-	int nr;
-	int alloc;
-	unsigned int initial : 1;
-};
-
-static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
-{
-	struct commit *commit;
-
-	if (is_null_oid(oid))
-		return;
-
-	commit = lookup_commit(the_repository, oid);
-	if (!commit ||
-	    (commit->object.flags & TMP_MARK) ||
-	    parse_commit(commit))
-		return;
-
-	ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
-	revs->commit[revs->nr++] = commit;
-	commit->object.flags |= TMP_MARK;
-}
-
-static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
-				  const char *ident, timestamp_t timestamp,
-				  int tz, const char *message, void *cbdata)
-{
-	struct rev_collect *revs = cbdata;
-
-	if (revs->initial) {
-		revs->initial = 0;
-		add_one_commit(ooid, revs);
-	}
-	add_one_commit(noid, revs);
-	return 0;
-}
-
 static int handle_fork_point(int argc, const char **argv)
 {
 	struct object_id oid;
 	char *refname;
+	struct commit *derived, *fork_point;
 	const char *commitname;
-	struct rev_collect revs;
-	struct commit *derived;
-	struct commit_list *bases;
-	int i, ret = 0;
 
 	switch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {
 	case 0:
@@ -173,41 +131,14 @@ static int handle_fork_point(int argc, const char **argv)
 		die("Not a valid object name: '%s'", commitname);
 
 	derived = lookup_commit_reference(the_repository, &oid);
-	memset(&revs, 0, sizeof(revs));
-	revs.initial = 1;
-	for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
 
-	if (!revs.nr && !get_oid(refname, &oid))
-		add_one_commit(&oid, &revs);
+	fork_point = get_fork_point(refname, derived);
 
-	for (i = 0; i < revs.nr; i++)
-		revs.commit[i]->object.flags &= ~TMP_MARK;
-
-	bases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit);
-
-	/*
-	 * There should be one and only one merge base, when we found
-	 * a common ancestor among reflog entries.
-	 */
-	if (!bases || bases->next) {
-		ret = 1;
-		goto cleanup_return;
-	}
-
-	/* And the found one must be one of the reflog entries */
-	for (i = 0; i < revs.nr; i++)
-		if (&bases->item->object == &revs.commit[i]->object)
-			break; /* found */
-	if (revs.nr <= i) {
-		ret = 1; /* not found */
-		goto cleanup_return;
-	}
-
-	printf("%s\n", oid_to_hex(&bases->item->object.oid));
+	if (!fork_point)
+		return 1;
 
-cleanup_return:
-	free_commit_list(bases);
-	return ret;
+	printf("%s\n", oid_to_hex(&fork_point->object.oid));
+	return 0;
 }
 
 int cmd_merge_base(int argc, const char **argv, const char *prefix)
diff --git a/commit.c b/commit.c
index 30d1af2b20..a3fc77a4eb 100644
--- a/commit.c
+++ b/commit.c
@@ -17,6 +17,7 @@
 #include "sha1-lookup.h"
 #include "wt-status.h"
 #include "advice.h"
+#include "refs.h"
 
 static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
 
@@ -958,6 +959,86 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
 	return result;
 }
 
+struct rev_collect {
+	struct commit **commit;
+	int nr;
+	int alloc;
+	unsigned int initial : 1;
+};
+
+static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
+{
+	struct commit *commit;
+
+	if (is_null_oid(oid))
+		return;
+
+	commit = lookup_commit(the_repository, oid);
+	if (!commit ||
+	    (commit->object.flags & TMP_MARK) ||
+	    parse_commit(commit))
+		return;
+
+	ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
+	revs->commit[revs->nr++] = commit;
+	commit->object.flags |= TMP_MARK;
+}
+
+static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
+				  const char *ident, timestamp_t timestamp,
+				  int tz, const char *message, void *cbdata)
+{
+	struct rev_collect *revs = cbdata;
+
+	if (revs->initial) {
+		revs->initial = 0;
+		add_one_commit(ooid, revs);
+	}
+	add_one_commit(noid, revs);
+	return 0;
+}
+
+struct commit *get_fork_point(const char *refname, struct commit *commit)
+{
+	struct object_id oid;
+	struct rev_collect revs;
+	struct commit_list *bases;
+	int i;
+	struct commit *ret = NULL;
+
+	memset(&revs, 0, sizeof(revs));
+	revs.initial = 1;
+	for_each_reflog_ent(refname, collect_one_reflog_ent, &revs);
+
+	if (!revs.nr && !get_oid(refname, &oid))
+		add_one_commit(&oid, &revs);
+
+	for (i = 0; i < revs.nr; i++)
+		revs.commit[i]->object.flags &= ~TMP_MARK;
+
+	bases = get_merge_bases_many(commit, revs.nr, revs.commit);
+
+	/*
+	 * There should be one and only one merge base, when we found
+	 * a common ancestor among reflog entries.
+	 */
+	if (!bases || bases->next)
+		goto cleanup_return;
+
+	/* And the found one must be one of the reflog entries */
+	for (i = 0; i < revs.nr; i++)
+		if (&bases->item->object == &revs.commit[i]->object)
+			break; /* found */
+	if (revs.nr <= i)
+		goto cleanup_return;
+
+	ret = bases->item;
+
+cleanup_return:
+	free_commit_list(bases);
+	return ret;
+}
+
 struct commit_list *get_octopus_merge_bases(struct commit_list *in)
 {
 	struct commit_list *i, *j, *k, *ret = NULL;
diff --git a/commit.h b/commit.h
index da0db36eba..b34240017f 100644
--- a/commit.h
+++ b/commit.h
@@ -211,6 +211,8 @@ extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
 /* To be used only when object flags after this call no longer matter */
 extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);
 
+struct commit *get_fork_point(const char *refname, struct commit *commit);
+
 /* largest positive number a signed 32-bit integer can contain */
 #define INFINITE_DEPTH 0x7fffffff
 
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 16/18] builtin rebase: support `fork-point` option
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (14 preceding siblings ...)
  2018-09-04 22:00   ` [PATCH v2 15/18] merge-base --fork-point: extract libified function Pratik Karki via GitGitGadget
@ 2018-09-04 22:00   ` Pratik Karki via GitGitGadget
  2018-09-04 22:00   ` [PATCH v2 17/18] builtin rebase: add support for custom merge strategies Pratik Karki via GitGitGadget
                     ` (2 subsequent siblings)
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 22:00 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit adds support for `--fork-point` and `--no-fork-point`.
This is converted as-is from `git-legacy-rebase.sh`.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index bcacffda33..6c101e1260 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -632,6 +632,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	struct string_list whitespace = STRING_LIST_INIT_NODUP;
 	struct string_list exec = STRING_LIST_INIT_NODUP;
 	const char *rebase_merges = NULL;
+	int fork_point = -1;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -714,6 +715,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			N_("mode"),
 			N_("try to rebase merges instead of skipping them"),
 			PARSE_OPT_OPTARG, NULL, (intptr_t)""},
+		OPT_BOOL(0, "fork-point", &fork_point,
+			 N_("use 'merge-base --fork-point' to refine upstream")),
 		OPT_END(),
 	};
 
@@ -1062,6 +1065,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	} else
 		BUG("unexpected number of arguments left to parse");
 
+	if (fork_point > 0) {
+		struct commit *head =
+			lookup_commit_reference(the_repository,
+						&options.orig_head);
+		options.restrict_revision =
+			get_fork_point(options.upstream_name, head);
+	}
+
 	if (read_index(the_repository->index) < 0)
 		die(_("could not read index"));
 
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 17/18] builtin rebase: add support for custom merge strategies
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (15 preceding siblings ...)
  2018-09-04 22:00   ` [PATCH v2 16/18] builtin rebase: support `fork-point` option Pratik Karki via GitGitGadget
@ 2018-09-04 22:00   ` Pratik Karki via GitGitGadget
  2018-09-04 22:00   ` [PATCH v2 18/18] builtin rebase: support --root Pratik Karki via GitGitGadget
  2018-09-06 19:50   ` [PATCH v2 00/18] builtin rebase options Junio C Hamano
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 22:00 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

When running a rebase in non-am mode, it uses the recursive merge to
cherry-pick the commits, and the rebase command allows to configure
the merge strategy to be used in this operation.

This commit adds that support to the builtin rebase.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 6c101e1260..847c7daf1c 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -96,6 +96,7 @@ struct rebase_options {
 	char *cmd;
 	int allow_empty_message;
 	int rebase_merges, rebase_cousins;
+	char *strategy, *strategy_opts;
 };
 
 static int is_interactive(struct rebase_options *opts)
@@ -217,6 +218,22 @@ static int read_basic_state(struct rebase_options *opts)
 		opts->gpg_sign_opt = xstrdup(buf.buf);
 	}
 
+	if (file_exists(state_dir_path("strategy", opts))) {
+		strbuf_reset(&buf);
+		if (read_one(state_dir_path("strategy", opts), &buf))
+			return -1;
+		free(opts->strategy);
+		opts->strategy = xstrdup(buf.buf);
+	}
+
+	if (file_exists(state_dir_path("strategy_opts", opts))) {
+		strbuf_reset(&buf);
+		if (read_one(state_dir_path("strategy_opts", opts), &buf))
+			return -1;
+		free(opts->strategy_opts);
+		opts->strategy_opts = xstrdup(buf.buf);
+	}
+
 	strbuf_release(&buf);
 
 	return 0;
@@ -356,6 +373,8 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->rebase_merges ? "t" : "");
 	add_var(&script_snippet, "rebase_cousins",
 		opts->rebase_cousins ? "t" : "");
+	add_var(&script_snippet, "strategy", opts->strategy);
+	add_var(&script_snippet, "strategy_opts", opts->strategy_opts);
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -633,6 +652,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	struct string_list exec = STRING_LIST_INIT_NODUP;
 	const char *rebase_merges = NULL;
 	int fork_point = -1;
+	struct string_list strategy_options = STRING_LIST_INIT_NODUP;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -717,6 +737,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			PARSE_OPT_OPTARG, NULL, (intptr_t)""},
 		OPT_BOOL(0, "fork-point", &fork_point,
 			 N_("use 'merge-base --fork-point' to refine upstream")),
+		OPT_STRING('s', "strategy", &options.strategy,
+			   N_("strategy"), N_("use the given merge strategy")),
+		OPT_STRING_LIST('X', "strategy-option", &strategy_options,
+				N_("option"),
+				N_("pass the argument through to the merge "
+				   "strategy")),
 		OPT_END(),
 	};
 
@@ -963,6 +989,37 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		imply_interactive(&options, "--rebase-merges");
 	}
 
+	if (strategy_options.nr) {
+		int i;
+
+		if (!options.strategy)
+			options.strategy = "recursive";
+
+		strbuf_reset(&buf);
+		for (i = 0; i < strategy_options.nr; i++)
+			strbuf_addf(&buf, " --%s",
+				    strategy_options.items[i].string);
+		options.strategy_opts = xstrdup(buf.buf);
+	}
+
+	if (options.strategy) {
+		options.strategy = xstrdup(options.strategy);
+		switch (options.type) {
+		case REBASE_AM:
+			die(_("--strategy requires --merge or --interactive"));
+		case REBASE_MERGE:
+		case REBASE_INTERACTIVE:
+		case REBASE_PRESERVE_MERGES:
+			/* compatible */
+			break;
+		case REBASE_UNSPECIFIED:
+			options.type = REBASE_MERGE;
+			break;
+		default:
+			BUG("unhandled rebase type (%d)", options.type);
+		}
+	}
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
gitgitgadget


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 18/18] builtin rebase: support --root
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (16 preceding siblings ...)
  2018-09-04 22:00   ` [PATCH v2 17/18] builtin rebase: add support for custom merge strategies Pratik Karki via GitGitGadget
@ 2018-09-04 22:00   ` Pratik Karki via GitGitGadget
  2018-09-06 19:50   ` [PATCH v2 00/18] builtin rebase options Junio C Hamano
  18 siblings, 0 replies; 44+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 22:00 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This option allows to rebase entire histories up to, and including, the
root commit.

The conversion from the shell script is straight-forward, apart from
the fact that we do not have to write an empty tree in C.

Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/rebase.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 847c7daf1c..71b92658ec 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -76,6 +76,7 @@ struct rebase_options {
 	const char *revisions;
 	const char *switch_to;
 	int root;
+	struct object_id *squash_onto;
 	struct commit *restrict_revision;
 	int dont_finish_rebase;
 	enum {
@@ -375,6 +376,9 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->rebase_cousins ? "t" : "");
 	add_var(&script_snippet, "strategy", opts->strategy);
 	add_var(&script_snippet, "strategy_opts", opts->strategy_opts);
+	add_var(&script_snippet, "rebase_root", opts->root ? "t" : "");
+	add_var(&script_snippet, "squash_onto",
+		opts->squash_onto ? oid_to_hex(opts->squash_onto) : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -653,6 +657,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	const char *rebase_merges = NULL;
 	int fork_point = -1;
 	struct string_list strategy_options = STRING_LIST_INIT_NODUP;
+	struct object_id squash_onto;
+	char *squash_onto_name = NULL;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -743,6 +749,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 				N_("option"),
 				N_("pass the argument through to the merge "
 				   "strategy")),
+		OPT_BOOL(0, "root", &options.root,
+			 N_("rebase all reachable commits up to the root(s)")),
 		OPT_END(),
 	};
 
@@ -1020,6 +1028,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		}
 	}
 
+	if (options.root && !options.onto_name)
+		imply_interactive(&options, "--root without --onto");
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
@@ -1058,8 +1069,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		if (!options.upstream)
 			die(_("invalid upstream '%s'"), options.upstream_name);
 		options.upstream_arg = options.upstream_name;
-	} else
-		die("TODO: upstream for --root");
+	} else {
+		if (!options.onto_name) {
+			if (commit_tree("", 0, the_hash_algo->empty_tree, NULL,
+					&squash_onto, NULL, NULL) < 0)
+				die(_("Could not create new root commit"));
+			options.squash_onto = &squash_onto;
+			options.onto_name = squash_onto_name =
+				xstrdup(oid_to_hex(&squash_onto));
+		}
+		options.upstream_name = NULL;
+		options.upstream = NULL;
+		if (argc > 1)
+			usage_with_options(builtin_rebase_usage,
+					   builtin_rebase_options);
+		options.upstream_arg = "--root";
+	}
 
 	/* Make sure the branch to rebase onto is valid. */
 	if (!options.onto_name)
@@ -1207,6 +1232,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	 */
 	if (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&
 	    !is_interactive(&options) && !options.restrict_revision &&
+	    options.upstream &&
 	    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
 		int flag;
 
@@ -1311,5 +1337,6 @@ cleanup:
 	free(options.head_name);
 	free(options.gpg_sign_opt);
 	free(options.cmd);
+	free(squash_onto_name);
 	return ret;
 }
-- 
gitgitgadget

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/18] builtin rebase options
  2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
                     ` (17 preceding siblings ...)
  2018-09-04 22:00   ` [PATCH v2 18/18] builtin rebase: support --root Pratik Karki via GitGitGadget
@ 2018-09-06 19:50   ` Junio C Hamano
  2018-09-06 20:38     ` Junio C Hamano
  2018-10-12 12:01     ` Johannes Schindelin
  18 siblings, 2 replies; 44+ messages in thread
From: Junio C Hamano @ 2018-09-06 19:50 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget; +Cc: git, Johannes Schindelin

"Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
writes:

> This patch series completes the support for all rebase options in the
> builtin rebase, e.g. --signoff, rerere-autoupdate, etc.
>
> It is based on pk/rebase -in-c-3-acts.

... which in turn was based on pk/rebase-in-c-2-basic that just got
rerolled, so I would assume that you want pk/rebase-in-c-3-acts I
have rebased on top of the result of applying the updated 2-basic
series.

I've rebuilt the collection of topics up to pk/rebase-in-c-6-final
with these two updated series twice, once doing it manually, like I
did the last time, and another using "rebase -i -r" on top of the
updated pk/rebase-in-c-4-opts.  The resulting trees match, of
course.

I did it twice to try out how it feels to use "rebase -i -r" because
I wanted to make sure what we are shipping in 'master' behaves
sensibly ;-)

Two things I noticed about the recreation of the merge ...

	Reminder to bystanders.  We need to merge ag/rebase-i-in-c
	topic on top of pk/reabse-in-c-5-test topic before applying
	a patch to adjust rebase to call rebase-i using the latter's
	new calling convention.  The topics look like

	- pk/rebase-in-c has three patches on master
	- pk/rebase-in-c-2-basic builds on it, and being replaced
	- pk/rebase-in-c-3-acts builds on 2-basic (no update this time)
	- pk/rebase-in-c-4-opts builds on 3-acts, and being replaced
	- pk/rebase-in-c-5-test builds on 4-opts (no update this time)
	- js/rebase-in-c-5.5 builds on 5-test and merges ag/rebase-in-c
	  topic before applying one patch on it (no update this time)
	- pk/rebase-in-c-6-final builds on 5.5 (no update this time)

	and we are replacing 2-basic with 11 patches and 4-opts with
	18 patches.

... using "rebase -i -r" are that 

 (1) it rebuilt, or at least offered to rebuild, the entire side
     branch, even though there is absolutely no need to.  Leaving
     "pick"s untouched, based on the correct fork point, resulted in
     all picks fast forwarded, but it was somewhat alarming.

 (2) "merge -C <original merge commit> ag/rebase-i-in-c" appeared as
     the insn to merge in the (possibly rebuilt) side branch.  And
     just like "commit -C", it took the merge message from the
     original merge commit, which means that the summary of the
     merged side branch is kept stale.  In this particular case, I
     did not even want to see ag/rebase-i-in-c topic touched, so I
     knew I want to keep the original merge summary, but if the user
     took the offer to rewrite the side branch (e.g. with a "reword"
     to retitle), using the original merge message would probably
     disappoint the user.

I think (1) actually is a feature.  Not everybody is an integrator
who does not want to touch any commit on the topic branch(es) while
rebuilding a single-strand-of-pearls that has many commits and an
occasional merge of the tip of another topic branch.  It's just that
the feature does not suit the workflow I use when I am playing the
top-level integrator role.

I am not sure what should be the ideal behaviour for (2).  I would
imagine that

 - I do want to keep the original title the merge (e.g. "into
   <target branch>", if left to "git merge" to come up with the
   title during "rebase -i" session, would be lost and become "into
   HEAD", which is not what we want);

 - I do want to keep the original commentary in the merge (e.g. what
   you would see in "git log --first-parent master..next" that gives
   summary of each topic getting merged) so that I can update it as
   needed; but 

 - I do want the topic summary fmt-merge-msg produces to be based on
   the updated side branch.

I am not sure if the last item can reliably be filtered out of the
original and replaced with newly generated summary.  If we can do
so, that would be ideal, I guess.

Another observation was that after rebuiding pk/rebase-in-c-6^0 on
top of the updated pk'/rebase-in-c-4 using "rebase -i -r", I of
course still needed to "branch -f" to update pk/rebase-in-c-5,
js/reabse-in-c-5.5, and pk/rebase-in-c-6 branches to point at
appropriate commits.  I do not think it is a good idea to let
"rebase -i" munge these dependent branches by default, but it might
be worth considering it as an option.  Since I want to be more in
control of what happens to the tips of topic branches, I did not
mind at all having to run "branch -f" and having the chance to run
"diff" before doing so, but at the same time, that means doing these
manually in steps building 5 on 4, 5.5 on 5 and then 6 on 5.5,
instead of building 6 on top of 4 using "rebase -i" and then tagging
the intermediate states, gives me more control without forcing me
more work.

I guess that is the answer to a question you asked earlier, which I
haven't answered so far because I didn't have a good grasp of where
my preference was coming from when it was asked.  Now I know, so...


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/18] builtin rebase options
  2018-09-06 19:50   ` [PATCH v2 00/18] builtin rebase options Junio C Hamano
@ 2018-09-06 20:38     ` Junio C Hamano
  2018-10-12 12:01     ` Johannes Schindelin
  1 sibling, 0 replies; 44+ messages in thread
From: Junio C Hamano @ 2018-09-06 20:38 UTC (permalink / raw)
  To: Johannes Schindelin via GitGitGadget; +Cc: git, Johannes Schindelin

Junio C Hamano <gitster@pobox.com> writes:

> I've rebuilt the collection of topics up to pk/rebase-in-c-6-final
> with these two updated series twice, once doing it manually, like I
> did the last time, and another using "rebase -i -r" on top of the
> updated pk/rebase-in-c-4-opts.  The resulting trees match, of
> course.

Just to clarify, "trees match" means "'rebase -i -r' gave us the
correct result" ;-).

> I guess that is the answer to a question you asked earlier, which I
> haven't answered so far because I didn't have a good grasp of where
> my preference was coming from when it was asked.  Now I know, so...

In case the question was unclear it was "is there a reason why you
do not want to use rebase -ir?"

If "cherry-pick" did not lose notes, I would have preferred to do
this kind of rebuilding dependent chains of topics without using
rebase at all, but that is a different story.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 00/18] builtin rebase options
  2018-09-06 19:50   ` [PATCH v2 00/18] builtin rebase options Junio C Hamano
  2018-09-06 20:38     ` Junio C Hamano
@ 2018-10-12 12:01     ` Johannes Schindelin
  1 sibling, 0 replies; 44+ messages in thread
From: Johannes Schindelin @ 2018-10-12 12:01 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johannes Schindelin via GitGitGadget, git

Hi Junio,

On Thu, 6 Sep 2018, Junio C Hamano wrote:

> "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
> writes:
> 
> > This patch series completes the support for all rebase options in the
> > builtin rebase, e.g. --signoff, rerere-autoupdate, etc.
> >
> > It is based on pk/rebase -in-c-3-acts.
> 
> ... which in turn was based on pk/rebase-in-c-2-basic that just got
> rerolled, so I would assume that you want pk/rebase-in-c-3-acts I
> have rebased on top of the result of applying the updated 2-basic
> series.
> 
> I've rebuilt the collection of topics up to pk/rebase-in-c-6-final
> with these two updated series twice, once doing it manually, like I
> did the last time, and another using "rebase -i -r" on top of the
> updated pk/rebase-in-c-4-opts.  The resulting trees match, of
> course.
> 
> I did it twice to try out how it feels to use "rebase -i -r" because
> I wanted to make sure what we are shipping in 'master' behaves
> sensibly ;-)
> 
> Two things I noticed about the recreation of the merge ...
> 
> 	Reminder to bystanders.  We need to merge ag/rebase-i-in-c
> 	topic on top of pk/reabse-in-c-5-test topic before applying
> 	a patch to adjust rebase to call rebase-i using the latter's
> 	new calling convention.  The topics look like
> 
> 	- pk/rebase-in-c has three patches on master
> 	- pk/rebase-in-c-2-basic builds on it, and being replaced
> 	- pk/rebase-in-c-3-acts builds on 2-basic (no update this time)
> 	- pk/rebase-in-c-4-opts builds on 3-acts, and being replaced
> 	- pk/rebase-in-c-5-test builds on 4-opts (no update this time)
> 	- js/rebase-in-c-5.5 builds on 5-test and merges ag/rebase-in-c
> 	  topic before applying one patch on it (no update this time)
> 	- pk/rebase-in-c-6-final builds on 5.5 (no update this time)
> 
> 	and we are replacing 2-basic with 11 patches and 4-opts with
> 	18 patches.
> 
> ... using "rebase -i -r" are that 
> 
>  (1) it rebuilt, or at least offered to rebuild, the entire side
>      branch, even though there is absolutely no need to.  Leaving
>      "pick"s untouched, based on the correct fork point, resulted in
>      all picks fast forwarded, but it was somewhat alarming.

Right. But this is a legacy of our paradigm to script things in Unix shell
script. It not only is slow, error-prone and hard to keep portable, it
also encourages poor design, as you do not have the same expressive power
as C has.

In this case, it harmed us by making it impossible to essentially play out
the rebase in memory and only fall back to writing things into the
worktree upon failure.

However, this is where we want to go. It is still a long way to go,
though, as many code parts are safely in the "we use the worktree to play
out the rebase in its entirety" place.

The "skip_unnecessary_picks" trick is the best we could do so far.

>  (2) "merge -C <original merge commit> ag/rebase-i-in-c" appeared as
>      the insn to merge in the (possibly rebuilt) side branch.  And
>      just like "commit -C", it took the merge message from the
>      original merge commit, which means that the summary of the
>      merged side branch is kept stale.  In this particular case, I
>      did not even want to see ag/rebase-i-in-c topic touched, so I
>      knew I want to keep the original merge summary, but if the user
>      took the offer to rewrite the side branch (e.g. with a "reword"
>      to retitle), using the original merge message would probably
>      disappoint the user.

Right. But the user would then also freely admit that they asked for the
merge commit to be rebased, which is what `--rebase-merges` says.

> I think (1) actually is a feature.  Not everybody is an integrator
> who does not want to touch any commit on the topic branch(es) while
> rebuilding a single-strand-of-pearls that has many commits and an
> occasional merge of the tip of another topic branch.  It's just that
> the feature does not suit the workflow I use when I am playing the
> top-level integrator role.

As I said. The ideal thing would be to invest quite a bit in refactoring
especially the do_pick_commit() function, and then play out the rebase in
memory, where one state variable knows what the "HEAD" is (but the
worktree is left untouched, up until the point when an error occurs, in
which case we want to write out the files). This would also need a major
refactoring of the recursive merge, of course, which conflates the merge
part with the writing of the merge conflicts to disk part.

While I would love to see this happening, I don't think that I can spare
enough time to drive this, at least for a couple of years.

> I am not sure what should be the ideal behaviour for (2).  I would
> imagine that
> 
>  - I do want to keep the original title the merge (e.g. "into
>    <target branch>", if left to "git merge" to come up with the
>    title during "rebase -i" session, would be lost and become "into
>    HEAD", which is not what we want);
> 
>  - I do want to keep the original commentary in the merge (e.g. what
>    you would see in "git log --first-parent master..next" that gives
>    summary of each topic getting merged) so that I can update it as
>    needed; but 
> 
>  - I do want the topic summary fmt-merge-msg produces to be based on
>    the updated side branch.
> 
> I am not sure if the last item can reliably be filtered out of the
> original and replaced with newly generated summary.  If we can do
> so, that would be ideal, I guess.

I think what you want is not the `merge` command, but a custom script that
you can then `exec`.

This could even be automated to some extent, by introducing an option to
`git rebase -i` that lets a script post-process the generated todo list,
something I wanted for a long time.

> Another observation was that after rebuiding pk/rebase-in-c-6^0 on
> top of the updated pk'/rebase-in-c-4 using "rebase -i -r", I of
> course still needed to "branch -f" to update pk/rebase-in-c-5,
> js/reabse-in-c-5.5, and pk/rebase-in-c-6 branches to point at
> appropriate commits.  I do not think it is a good idea to let
> "rebase -i" munge these dependent branches by default, but it might
> be worth considering it as an option.

Yes! Already years ago, I wanted to teach the shears to figure out that a
branch (i.e. a second parent of a merge commit that mentions the branch
name in its oneline) was updated by the rebase, and if the pre-rebase
commit agrees with a local ref of that name, update said ref after the
rebase finished successfully.

There is one big caveat, though: what if one of those branches is checked
out in a worktree?

I think it can be done, and it should be hidden behind an opt-in config
setting.

#leftoverbits?

> Since I want to be more in control of what happens to the tips of topic
> branches, I did not mind at all having to run "branch -f" and having the
> chance to run "diff" before doing so, but at the same time, that means
> doing these manually in steps building 5 on 4, 5.5 on 5 and then 6 on
> 5.5, instead of building 6 on top of 4 using "rebase -i" and then
> tagging the intermediate states, gives me more control without forcing
> me more work.

Sure. This definitely gives you more control.

I am not sure whether you want that control, or whether you *actually*
want more safety guards. If it was me, I would prefer something that can
stop/pause the process when something is obviously going wrong (it could
be a script verifying that, e.g. looking at the length/contents of the
range-diff and ringing an alarm when a commit other than a fixup! was
dropped).

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2018-10-12 12:01 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-08 15:21 [GSoC] [PATCH 00/18] builtin rebase options Pratik Karki
2018-08-08 15:21 ` [PATCH 01/18] builtin rebase: allow selecting the rebase "backend" Pratik Karki
2018-08-08 15:21 ` [PATCH 02/18] builtin rebase: support --signoff Pratik Karki
2018-08-08 15:21 ` [PATCH 03/18] builtin rebase: support --rerere-autoupdate Pratik Karki
2018-08-08 15:21 ` [PATCH 04/18] builtin rebase: support --committer-date-is-author-date Pratik Karki
2018-08-08 15:21 ` [PATCH 05/18] builtin rebase: support `ignore-whitespace` option Pratik Karki
2018-08-08 15:21 ` [PATCH 06/18] builtin rebase: support `ignore-date` option Pratik Karki
2018-08-08 15:21 ` [PATCH 07/18] builtin rebase: support `keep-empty` option Pratik Karki
2018-08-24 16:04   ` Johannes Schindelin
2018-08-08 15:21 ` [PATCH 08/18] builtin rebase: support `--autosquash` Pratik Karki
2018-08-08 15:21 ` [PATCH 09/18] builtin rebase: support `--gpg-sign` option Pratik Karki
2018-08-08 15:21 ` [PATCH 10/18] builtin rebase: support `-C` and `--whitespace=<type>` Pratik Karki
2018-08-08 15:21 ` [PATCH 11/18] builtin rebase: support `--autostash` option Pratik Karki
2018-08-18 15:59   ` Duy Nguyen
2018-08-24 16:06     ` Johannes Schindelin
2018-08-08 15:21 ` [PATCH 12/18] builtin rebase: support `--exec` Pratik Karki
2018-08-08 15:21 ` [PATCH 13/18] builtin rebase: support `--allow-empty-message` option Pratik Karki
2018-08-08 15:21 ` [PATCH 14/18] builtin rebase: support --rebase-merges[=[no-]rebase-cousins] Pratik Karki
2018-08-08 15:21 ` [PATCH 15/18] merge-base --fork-point: extract libified function Pratik Karki
2018-08-08 15:21 ` [PATCH 16/18] builtin rebase: support `fork-point` option Pratik Karki
2018-08-08 15:21 ` [PATCH 17/18] builtin rebase: add support for custom merge strategies Pratik Karki
2018-08-08 15:21 ` [PATCH 18/18] builtin rebase: support --root Pratik Karki
2018-09-04 21:59 ` [PATCH v2 00/18] builtin rebase options Johannes Schindelin via GitGitGadget
2018-09-04 21:59   ` [PATCH v2 01/18] builtin rebase: allow selecting the rebase "backend" Pratik Karki via GitGitGadget
2018-09-04 21:59   ` [PATCH v2 02/18] builtin rebase: support --signoff Pratik Karki via GitGitGadget
2018-09-04 21:59   ` [PATCH v2 03/18] builtin rebase: support --rerere-autoupdate Pratik Karki via GitGitGadget
2018-09-04 21:59   ` [PATCH v2 04/18] builtin rebase: support --committer-date-is-author-date Pratik Karki via GitGitGadget
2018-09-04 21:59   ` [PATCH v2 05/18] builtin rebase: support `ignore-whitespace` option Pratik Karki via GitGitGadget
2018-09-04 21:59   ` [PATCH v2 06/18] builtin rebase: support `ignore-date` option Pratik Karki via GitGitGadget
2018-09-04 21:59   ` [PATCH v2 07/18] builtin rebase: support `keep-empty` option Pratik Karki via GitGitGadget
2018-09-04 21:59   ` [PATCH v2 08/18] builtin rebase: support `--autosquash` Pratik Karki via GitGitGadget
2018-09-04 22:00   ` [PATCH v2 09/18] builtin rebase: support `--gpg-sign` option Pratik Karki via GitGitGadget
2018-09-04 22:00   ` [PATCH v2 10/18] builtin rebase: support `-C` and `--whitespace=<type>` Pratik Karki via GitGitGadget
2018-09-04 22:00   ` [PATCH v2 11/18] builtin rebase: support `--autostash` option Pratik Karki via GitGitGadget
2018-09-04 22:00   ` [PATCH v2 12/18] builtin rebase: support `--exec` Pratik Karki via GitGitGadget
2018-09-04 22:00   ` [PATCH v2 13/18] builtin rebase: support `--allow-empty-message` option Pratik Karki via GitGitGadget
2018-09-04 22:00   ` [PATCH v2 14/18] builtin rebase: support --rebase-merges[=[no-]rebase-cousins] Pratik Karki via GitGitGadget
2018-09-04 22:00   ` [PATCH v2 15/18] merge-base --fork-point: extract libified function Pratik Karki via GitGitGadget
2018-09-04 22:00   ` [PATCH v2 16/18] builtin rebase: support `fork-point` option Pratik Karki via GitGitGadget
2018-09-04 22:00   ` [PATCH v2 17/18] builtin rebase: add support for custom merge strategies Pratik Karki via GitGitGadget
2018-09-04 22:00   ` [PATCH v2 18/18] builtin rebase: support --root Pratik Karki via GitGitGadget
2018-09-06 19:50   ` [PATCH v2 00/18] builtin rebase options Junio C Hamano
2018-09-06 20:38     ` Junio C Hamano
2018-10-12 12:01     ` Johannes Schindelin

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 NNTP newsgroup(s).