git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [GSoC] [PATCH 00/11] A minimal builtin rebase
@ 2018-08-08 13:48 Pratik Karki
  2018-08-08 13:48 ` [PATCH 01/11] builtin rebase: support --onto Pratik Karki
                   ` (11 more replies)
  0 siblings, 12 replies; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This patch series provides the bare minimum to run more than the trivial
rebase (i.e. `git rebase <upstream>`).

Here, I have implemented essential options needed to make this a
builtin rebase. Ofcourse, to accomplish the task of builtin rebase, I had to
do essential optimizations and add certain shield which weren't present in
original rebase.

It is based the latest iteration of pk/rebase-in-c, i.e. ac7f467fef8b
(builtin/rebase: support running "git rebase <upstream>", 2018-08-07).

This is the second 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.

I plan on submitting the next patch series today, in this order:

bultin rebase actions: The builtin rebase will add all the rebase actions.
builtin rebase options: The builtin rebase will add all the options supported
by original rebase.
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.

The motivation to organize these patch series is to make review easier and
for pleasant read with the help of my GSoC mentors since, this is the final
week of GSoC and other GSoC students most likely have submitted their
respective works which will need lots of review.

Pratik Karki (11):
  builtin rebase: support --onto
  builtin rebase: support `git rebase --onto A...B`
  builtin rebase: handle the pre-rebase hook (and add --no-verify)
  builtin rebase: support --quiet
  builtin rebase: support the `verbose` and `diffstat` options
  builtin rebase: require a clean worktree
  builtin rebase: try to fast forward when possible
  builtin rebase: support --force-rebase
  builtin rebase: start a new rebase only if none is in progress
  builtin rebase: only store fully-qualified refs in `options.head_name`
  builtin rebase: support `git rebase <upstream> <switch-to>`

 builtin/rebase.c | 333 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 320 insertions(+), 13 deletions(-)

-- 
2.18.0


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

* [PATCH 01/11] builtin rebase: support --onto
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 19:02   ` Junio C Hamano
  2018-08-08 13:48 ` [PATCH 02/11] builtin rebase: support `git rebase --onto A...B` Pratik Karki
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

The `--onto` option is important, as it allows to rebase a range of
commits onto a different base commit (which gave the command its odd
name: "rebase").

This commit introduces options parsing so that different options can
be added in future commits.

Note: As this commit introduces to the parse_options() call (which
"eats" argv[0]), the argc is now expected to be lower by one after this
patch, compared to before this patch: argv[0] no longer refers to the
command name, but to the first (non-option) command-line parameter.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index e695d8a430..742ed31498 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -16,6 +16,16 @@
 #include "cache-tree.h"
 #include "unpack-trees.h"
 #include "lockfile.h"
+#include "parse-options.h"
+
+static char const * const builtin_rebase_usage[] = {
+	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
+		"[<upstream>] [<branch>]"),
+	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
+		"--root [<branch>]"),
+	N_("git rebase --continue | --abort | --skip | --edit-todo"),
+	NULL
+};
 
 static GIT_PATH_FUNC(apply_dir, "rebase-apply")
 static GIT_PATH_FUNC(merge_dir, "rebase-merge")
@@ -301,6 +311,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	int ret, flags;
 	struct strbuf msg = STRBUF_INIT;
 	struct strbuf revisions = STRBUF_INIT;
+	struct option builtin_rebase_options[] = {
+		OPT_STRING(0, "onto", &options.onto_name,
+			   N_("revision"),
+			   N_("rebase onto given branch instead of upstream")),
+		OPT_END(),
+	};
 
 	/*
 	 * NEEDSWORK: Once the builtin rebase has been tested enough
@@ -318,13 +334,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			BUG("sane_execvp() returned???");
 	}
 
-	if (argc != 2)
-		die(_("Usage: %s <base>"), argv[0]);
+	if (argc == 2 && !strcmp(argv[1], "-h"))
+		usage_with_options(builtin_rebase_usage,
+				   builtin_rebase_options);
+
 	prefix = setup_git_directory();
 	trace_repo_setup(prefix);
 	setup_work_tree();
 
 	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix,
+			     builtin_rebase_options,
+			     builtin_rebase_usage, 0);
+
+	if (argc > 2)
+		usage_with_options(builtin_rebase_usage,
+				   builtin_rebase_options);
 
 	switch (options.type) {
 	case REBASE_MERGE:
@@ -343,10 +368,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	}
 
 	if (!options.root) {
-		if (argc < 2)
+		if (argc < 1)
 			die("TODO: handle @{upstream}");
 		else {
-			options.upstream_name = argv[1];
+			options.upstream_name = argv[0];
 			argc--;
 			argv++;
 			if (!strcmp(options.upstream_name, "-"))
@@ -377,7 +402,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	 * orig_head -- commit object name of tip of the branch before rebasing
 	 * head_name -- refs/heads/<that-branch> or "detached HEAD"
 	 */
-	if (argc > 1)
+	if (argc > 0)
 		 die("TODO: handle switch_to");
 	else {
 		/* Do not need to switch branches, we are already on it. */
-- 
2.18.0


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

* [PATCH 02/11] builtin rebase: support `git rebase --onto A...B`
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
  2018-08-08 13:48 ` [PATCH 01/11] builtin rebase: support --onto Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 19:12   ` Junio C Hamano
  2018-08-08 13:48 ` [PATCH 03/11] builtin rebase: handle the pre-rebase hook (and add --no-verify) Pratik Karki
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit implements support for an --onto argument that is actually a
"symmetric range" i.e. `<rev1>...<rev2>`.

The equivalent shell script version of the code offers two different
error messages for the cases where there is no merge base vs more than
one merge base. Though following the similar approach would be nice,
this would create more complexity than it is of current. Currently, for
simple convenience, the `get_oid_mb()` function is used whose return
value does not discern between those two error conditions.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 742ed31498..38c496dd10 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -17,6 +17,7 @@
 #include "unpack-trees.h"
 #include "lockfile.h"
 #include "parse-options.h"
+#include "commit.h"
 
 static char const * const builtin_rebase_usage[] = {
 	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -311,6 +312,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	int ret, flags;
 	struct strbuf msg = STRBUF_INIT;
 	struct strbuf revisions = STRBUF_INIT;
+	struct object_id merge_base;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -387,7 +389,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (!options.onto_name)
 		options.onto_name = options.upstream_name;
 	if (strstr(options.onto_name, "...")) {
-		die("TODO");
+		if (get_oid_mb(options.onto_name, &merge_base) < 0)
+			die(_("'%s': need exactly one merge base"),
+			    options.onto_name);
+		options.onto = lookup_commit_or_die(&merge_base,
+						    options.onto_name);
 	} else {
 		options.onto = peel_committish(options.onto_name);
 		if (!options.onto)
-- 
2.18.0


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

* [PATCH 03/11] builtin rebase: handle the pre-rebase hook (and add --no-verify)
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
  2018-08-08 13:48 ` [PATCH 01/11] builtin rebase: support --onto Pratik Karki
  2018-08-08 13:48 ` [PATCH 02/11] builtin rebase: support `git rebase --onto A...B` Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 19:32   ` Junio C Hamano
  2018-08-08 13:48 ` [PATCH 04/11] builtin rebase: support --quiet Pratik Karki
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit converts the equivalent part of the shell script
`git-legacy-rebase.sh` to run the pre-rebase hook (unless disabled), and
to interrupt the rebase with error if the hook fails.

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 38c496dd10..b79f9b0a9f 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -70,6 +70,7 @@ struct rebase_options {
 	const char *state_dir;
 	struct commit *upstream;
 	const char *upstream_name;
+	const char *upstream_arg;
 	char *head_name;
 	struct object_id orig_head;
 	struct commit *onto;
@@ -310,6 +311,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	};
 	const char *branch_name;
 	int ret, flags;
+	int ok_to_skip_pre_rebase = 0;
 	struct strbuf msg = STRBUF_INIT;
 	struct strbuf revisions = STRBUF_INIT;
 	struct object_id merge_base;
@@ -317,6 +319,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
 			   N_("rebase onto given branch instead of upstream")),
+		OPT_BOOL(0, "no-verify", &ok_to_skip_pre_rebase,
+			 N_("allow pre-rebase hook to run")),
 		OPT_END(),
 	};
 
@@ -382,6 +386,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.upstream = peel_committish(options.upstream_name);
 		if (!options.upstream)
 			die(_("invalid upstream '%s'"), options.upstream_name);
+		options.upstream_arg = options.upstream_name;
 	} else
 		die("TODO: upstream for --root");
 
@@ -430,6 +435,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			die(_("Could not resolve HEAD to a revision"));
 	}
 
+	/* If a hook exists, give it a chance to interrupt*/
+	if (!ok_to_skip_pre_rebase &&
+	    run_hook_le(NULL, "pre-rebase", options.upstream_arg,
+			argc ? argv[0] : NULL, NULL))
+		die(_("The pre-rebase hook refused to rebase."));
+
 	strbuf_addf(&msg, "rebase: checkout %s", options.onto_name);
 	if (reset_head(&options.onto->object.oid, "checkout", NULL, 1))
 		die(_("Could not detach HEAD"));
-- 
2.18.0


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

* [PATCH 04/11] builtin rebase: support --quiet
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
                   ` (2 preceding siblings ...)
  2018-08-08 13:48 ` [PATCH 03/11] builtin rebase: handle the pre-rebase hook (and add --no-verify) Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 18:31   ` Stefan Beller
  2018-08-08 13:48 ` [PATCH 05/11] builtin rebase: support the `verbose` and `diffstat` options Pratik Karki
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit introduces a rebase option `--quiet`. While `--quiet` is
commonly perceived as opposite to `--verbose`, this is not the case for
the rebase command: both `--quiet` and `--verbose` default to `false` if
neither `--quiet` nor `--verbose` is present.

This commit goes further and introduces `--no-quiet` which is the
contrary of `--quiet` and it's introduction doesn't modify any
behaviour.

Note: The `flags` field in `rebase_options` will accumulate more bits in
subsequent commits, in particular a verbose and a diffstat flag. And as
--quoet inthe shell scripted version of the rebase command switches off
--verbose and --stat, and as --verbose switches off --quiet, we use the
(negated) REBASE_NO_QUIET instead of REBASE_QUIET: this allows us to
turn off the quiet mode and turn on the verbose and diffstat mode in a
single OPT_BIT(), and the opposite in a single OPT_NEGBIT().

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index b79f9b0a9f..19fa4d3fc4 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -79,6 +79,10 @@ struct rebase_options {
 	int root;
 	struct commit *restrict_revision;
 	int dont_finish_rebase;
+	enum {
+		REBASE_NO_QUIET = 1<<0,
+	} flags;
+	struct strbuf git_am_opt;
 };
 
 /* Returns the filename prefixed by the state_dir */
@@ -159,6 +163,9 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "revisions", opts->revisions);
 	add_var(&script_snippet, "restrict_revision", opts->restrict_revision ?
 		oid_to_hex(&opts->restrict_revision->object.oid) : NULL);
+	add_var(&script_snippet, "GIT_QUIET",
+		opts->flags & REBASE_NO_QUIET ? "" : "t");
+	add_var(&script_snippet, "git_am_opt", opts->git_am_opt.buf);
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -308,6 +315,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
 	struct rebase_options options = {
 		.type = REBASE_UNSPECIFIED,
+		.flags = REBASE_NO_QUIET,
+		.git_am_opt = STRBUF_INIT,
 	};
 	const char *branch_name;
 	int ret, flags;
@@ -321,6 +330,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			   N_("rebase onto given branch instead of upstream")),
 		OPT_BOOL(0, "no-verify", &ok_to_skip_pre_rebase,
 			 N_("allow pre-rebase hook to run")),
+		OPT_NEGBIT('q', "quiet", &options.flags,
+			   N_("be quiet. implies --no-stat"),
+			   REBASE_NO_QUIET),
 		OPT_END(),
 	};
 
@@ -357,6 +369,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		usage_with_options(builtin_rebase_usage,
 				   builtin_rebase_options);
 
+	if (!(options.flags & REBASE_NO_QUIET))
+		strbuf_addstr(&options.git_am_opt, " -q");
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
2.18.0


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

* [PATCH 05/11] builtin rebase: support the `verbose` and `diffstat` options
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
                   ` (3 preceding siblings ...)
  2018-08-08 13:48 ` [PATCH 04/11] builtin rebase: support --quiet Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 13:48 ` [PATCH 06/11] builtin rebase: require a clean worktree Pratik Karki
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit introduces support for the `-v` and `--stat` options of
rebase.

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

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 19fa4d3fc4..2d3f1d65fb 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -18,6 +18,7 @@
 #include "lockfile.h"
 #include "parse-options.h"
 #include "commit.h"
+#include "diff.h"
 
 static char const * const builtin_rebase_usage[] = {
 	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -81,6 +82,8 @@ struct rebase_options {
 	int dont_finish_rebase;
 	enum {
 		REBASE_NO_QUIET = 1<<0,
+		REBASE_VERBOSE = 1<<1,
+		REBASE_DIFFSTAT = 1<<2,
 	} flags;
 	struct strbuf git_am_opt;
 };
@@ -166,6 +169,10 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "GIT_QUIET",
 		opts->flags & REBASE_NO_QUIET ? "" : "t");
 	add_var(&script_snippet, "git_am_opt", opts->git_am_opt.buf);
+	add_var(&script_snippet, "verbose",
+		opts->flags & REBASE_VERBOSE ? "t" : "");
+	add_var(&script_snippet, "diffstat",
+		opts->flags & REBASE_DIFFSTAT ? "t" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -311,6 +318,21 @@ static int reset_head(struct object_id *oid, const char *action,
 	return ret;
 }
 
+static int rebase_config(const char *var, const char *value, void *data)
+{
+	struct rebase_options *opts = data;
+
+	if (!strcmp(var, "rebase.stat")) {
+		if (git_config_bool(var, value))
+			opts->flags |= REBASE_DIFFSTAT;
+		else
+			opts->flags &= !REBASE_DIFFSTAT;
+		return 0;
+	}
+
+	return git_default_config(var, value, data);
+}
+
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
 	struct rebase_options options = {
@@ -332,7 +354,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			 N_("allow pre-rebase hook to run")),
 		OPT_NEGBIT('q', "quiet", &options.flags,
 			   N_("be quiet. implies --no-stat"),
-			   REBASE_NO_QUIET),
+			   REBASE_NO_QUIET| REBASE_VERBOSE | REBASE_DIFFSTAT),
+		OPT_BIT('v', "verbose", &options.flags,
+			N_("display a diffstat of what changed upstream"),
+			REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),
+		{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
+			N_("do not show diffstat of what changed upstream"),
+			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
 		OPT_END(),
 	};
 
@@ -360,7 +388,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	trace_repo_setup(prefix);
 	setup_work_tree();
 
-	git_config(git_default_config, NULL);
+	git_config(rebase_config, &options);
+
 	argc = parse_options(argc, argv, prefix,
 			     builtin_rebase_options,
 			     builtin_rebase_usage, 0);
@@ -456,6 +485,33 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			argc ? argv[0] : NULL, NULL))
 		die(_("The pre-rebase hook refused to rebase."));
 
+	if (options.flags & REBASE_DIFFSTAT) {
+		struct diff_options opts;
+
+		if (options.flags & REBASE_VERBOSE)
+			printf(_("Changes from %s to %s:\n"),
+				oid_to_hex(&merge_base),
+				oid_to_hex(&options.onto->object.oid));
+
+		/* We want color (if set), but no pager */
+		diff_setup(&opts);
+		opts.stat_width = -1; /* use full terminal width */
+		opts.stat_graph_width = -1; /* respect statGraphWidth config */
+		opts.output_format |=
+			DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+		opts.detect_rename = DIFF_DETECT_RENAME;
+		diff_setup_done(&opts);
+		diff_tree_oid(&merge_base, &options.onto->object.oid,
+			      "", &opts);
+		diffcore_std(&opts);
+		diff_flush(&opts);
+	}
+
+	/* Detach HEAD and reset the tree */
+	if (options.flags & REBASE_NO_QUIET)
+		printf(_("First, rewinding head to replay your work on top of "
+			 "it...\n"));
+
 	strbuf_addf(&msg, "rebase: checkout %s", options.onto_name);
 	if (reset_head(&options.onto->object.oid, "checkout", NULL, 1))
 		die(_("Could not detach HEAD"));
-- 
2.18.0


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

* [PATCH 06/11] builtin rebase: require a clean worktree
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
                   ` (4 preceding siblings ...)
  2018-08-08 13:48 ` [PATCH 05/11] builtin rebase: support the `verbose` and `diffstat` options Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 13:48 ` [PATCH 07/11] builtin rebase: try to fast forward when possible Pratik Karki
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit reads the index of the repository for rebase and checks
whether the repository is ready for rebase.

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 2d3f1d65fb..afef0b0046 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -19,6 +19,7 @@
 #include "parse-options.h"
 #include "commit.h"
 #include "diff.h"
+#include "wt-status.h"
 
 static char const * const builtin_rebase_usage[] = {
 	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -479,6 +480,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			die(_("Could not resolve HEAD to a revision"));
 	}
 
+	if (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;
+		goto cleanup;
+	}
+
 	/* If a hook exists, give it a chance to interrupt*/
 	if (!ok_to_skip_pre_rebase &&
 	    run_hook_le(NULL, "pre-rebase", options.upstream_arg,
@@ -528,6 +538,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 	ret = !!run_specific_rebase(&options);
 
+cleanup:
 	strbuf_release(&revisions);
 	free(options.head_name);
 	return ret;
-- 
2.18.0


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

* [PATCH 07/11] builtin rebase: try to fast forward when possible
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
                   ` (5 preceding siblings ...)
  2018-08-08 13:48 ` [PATCH 06/11] builtin rebase: require a clean worktree Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 13:48 ` [PATCH 08/11] builtin rebase: support --force-rebase Pratik Karki
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

In this commit, we add support to fast forward.

Note: we will need the merge base later, therefore the call to
can_fast_forward() really needs to be the first one when testing whether
we can skip the rebase entirely (otherwise, it would make more sense to
skip the possibly expensive operation if, say, running an interactive
rebase).

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index afef0b0046..52a218cd18 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -20,6 +20,7 @@
 #include "commit.h"
 #include "diff.h"
 #include "wt-status.h"
+#include "revision.h"
 
 static char const * const builtin_rebase_usage[] = {
 	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -89,6 +90,12 @@ struct rebase_options {
 	struct strbuf git_am_opt;
 };
 
+static int is_interactive(struct rebase_options *opts)
+{
+	return opts->type == REBASE_INTERACTIVE ||
+		opts->type == REBASE_PRESERVE_MERGES;
+}
+
 /* Returns the filename prefixed by the state_dir */
 static const char *state_dir_path(const char *filename, struct rebase_options *opts)
 {
@@ -334,6 +341,46 @@ static int rebase_config(const char *var, const char *value, void *data)
 	return git_default_config(var, value, data);
 }
 
+/*
+ * Determines whether the commits in from..to are linear, i.e. contain
+ * no merge commits. This function *expects* `from` to be an ancestor of
+ * `to`.
+ */
+static int is_linear_history(struct commit *from, struct commit *to)
+{
+	while (to && to != from) {
+		parse_commit(to);
+		if (!to->parents)
+			return 1;
+		if (to->parents->next)
+			return 0;
+		to = to->parents->item;
+	}
+	return 1;
+}
+
+static int can_fast_forward(struct commit *onto, struct object_id *head_oid,
+			    struct object_id *merge_base)
+{
+	struct commit *head = lookup_commit(the_repository, head_oid);
+	struct commit_list *merge_bases;
+	int res;
+
+	if (!head)
+		return 0;
+
+	merge_bases = get_merge_bases(onto, head);
+	if (merge_bases && !merge_bases->next) {
+		oidcpy(merge_base, &merge_bases->item->object.oid);
+		res = !oidcmp(merge_base, &onto->object.oid);
+	} else {
+		oidcpy(merge_base, &null_oid);
+		res = 0;
+	}
+	free_commit_list(merge_bases);
+	return res && is_linear_history(onto, head);
+}
+
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
 	struct rebase_options options = {
@@ -489,6 +536,31 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 	}
 
+	/*
+	 * Now we are rebasing commits upstream..orig_head (or with --root,
+	 * everything leading up to orig_head) on top of onto.
+	 */
+
+	/*
+	 * Check if we are already based on onto with linear history,
+	 * but this should be done only when upstream and onto are the same
+	 * and if this is not an interactive rebase.
+	 */
+	if (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&
+	    !is_interactive(&options) && !options.restrict_revision &&
+	    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
+		int flag;
+
+		if (!(options.flags & REBASE_NO_QUIET))
+			; /* be quiet */
+		else if (!strcmp(branch_name, "HEAD") &&
+			resolve_ref_unsafe("HEAD", 0, NULL, &flag))
+			puts(_("HEAD is up to date, rebase forced."));
+		else
+			printf(_("Current branch %s is up to date, rebase "
+				 "forced.\n"), branch_name);
+	}
+
 	/* If a hook exists, give it a chance to interrupt*/
 	if (!ok_to_skip_pre_rebase &&
 	    run_hook_le(NULL, "pre-rebase", options.upstream_arg,
-- 
2.18.0


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

* [PATCH 08/11] builtin rebase: support --force-rebase
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
                   ` (6 preceding siblings ...)
  2018-08-08 13:48 ` [PATCH 07/11] builtin rebase: try to fast forward when possible Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 18:51   ` Stefan Beller
  2018-08-08 13:48 ` [PATCH 09/11] builtin rebase: start a new rebase only if none is in progress Pratik Karki
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

In this commit, we add support to `--force-rebase` option. The
equivalent part of the shell script found in `git-legacy-rebase.sh` is
converted as faithfully as possible to C.

The --force-rebase option ensures that the rebase does not simply
fast-forward even if it could.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 52a218cd18..8a7bf3d468 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -86,6 +86,7 @@ struct rebase_options {
 		REBASE_NO_QUIET = 1<<0,
 		REBASE_VERBOSE = 1<<1,
 		REBASE_DIFFSTAT = 1<<2,
+		REBASE_FORCE = 1<<3,
 	} flags;
 	struct strbuf git_am_opt;
 };
@@ -181,6 +182,8 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->flags & REBASE_VERBOSE ? "t" : "");
 	add_var(&script_snippet, "diffstat",
 		opts->flags & REBASE_DIFFSTAT ? "t" : "");
+	add_var(&script_snippet, "force_rebase",
+		opts->flags & REBASE_FORCE ? "t" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -409,6 +412,12 @@ 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_BIT('f', "force-rebase", &options.flags,
+			N_("cherry-pick all commits, even if unchanged"),
+			REBASE_FORCE),
+		OPT_BIT(0, "no-ff", &options.flags,
+			N_("cherry-pick all commits, even if unchanged"),
+			REBASE_FORCE),
 		OPT_END(),
 	};
 
@@ -551,10 +560,21 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
 		int flag;
 
-		if (!(options.flags & REBASE_NO_QUIET))
+		if (!(options.flags & REBASE_FORCE)) {
+			if (!(options.flags & REBASE_NO_QUIET))
+				; /* be quiet */
+			else if (!strcmp(branch_name, "HEAD") &&
+				 resolve_ref_unsafe("HEAD", 0, NULL, &flag))
+				puts(_("HEAD is up to date."));
+			else
+				printf(_("Current branch %s is up to date.\n"),
+				       branch_name);
+			ret = !!finish_rebase(&options);
+			goto cleanup;
+		} else if (!(options.flags & REBASE_NO_QUIET))
 			; /* be quiet */
 		else if (!strcmp(branch_name, "HEAD") &&
-			resolve_ref_unsafe("HEAD", 0, NULL, &flag))
+			 resolve_ref_unsafe("HEAD", 0, NULL, &flag))
 			puts(_("HEAD is up to date, rebase forced."));
 		else
 			printf(_("Current branch %s is up to date, rebase "
-- 
2.18.0


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

* [PATCH 09/11] builtin rebase: start a new rebase only if none is in progress
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
                   ` (7 preceding siblings ...)
  2018-08-08 13:48 ` [PATCH 08/11] builtin rebase: support --force-rebase Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 18:59   ` Stefan Beller
  2018-08-08 13:48 ` [PATCH 10/11] builtin rebase: only store fully-qualified refs in `options.head_name` Pratik Karki
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

To run a new rebase, there needs to be a check to assure that no other
rebase is in progress. New rebase operation cannot start until an
ongoing rebase operation completes or is terminated.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 8a7bf3d468..a261f552f1 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -87,6 +87,7 @@ struct rebase_options {
 		REBASE_VERBOSE = 1<<1,
 		REBASE_DIFFSTAT = 1<<2,
 		REBASE_FORCE = 1<<3,
+		REBASE_INTERACTIVE_EXPLICIT = 1<<4,
 	} flags;
 	struct strbuf git_am_opt;
 };
@@ -392,10 +393,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		.git_am_opt = STRBUF_INIT,
 	};
 	const char *branch_name;
-	int ret, flags;
+	int ret, flags, in_progress = 0;
 	int ok_to_skip_pre_rebase = 0;
 	struct strbuf msg = STRBUF_INIT;
 	struct strbuf revisions = STRBUF_INIT;
+	struct strbuf buf = STRBUF_INIT;
 	struct object_id merge_base;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
@@ -447,6 +449,30 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 	git_config(rebase_config, &options);
 
+	if (is_directory(apply_dir())) {
+		options.type = REBASE_AM;
+		options.state_dir = apply_dir();
+	} else if (is_directory(merge_dir())) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "%s/rewritten", merge_dir());
+		if (is_directory(buf.buf)) {
+			options.type = REBASE_PRESERVE_MERGES;
+			options.flags |= REBASE_INTERACTIVE_EXPLICIT;
+		} else {
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "%s/interactive", merge_dir());
+			if(file_exists(buf.buf)) {
+				options.type = REBASE_INTERACTIVE;
+				options.flags |= REBASE_INTERACTIVE_EXPLICIT;
+			} else
+				options.type = REBASE_MERGE;
+		}
+		options.state_dir = merge_dir();
+	}
+
+	if (options.type != REBASE_UNSPECIFIED)
+		in_progress = 1;
+
 	argc = parse_options(argc, argv, prefix,
 			     builtin_rebase_options,
 			     builtin_rebase_usage, 0);
@@ -455,6 +481,26 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		usage_with_options(builtin_rebase_usage,
 				   builtin_rebase_options);
 
+	/* Make sure no rebase is in progress */
+	if (in_progress) {
+		const char *last_slash = strrchr(options.state_dir, '/');
+		const char *state_dir_base =
+			last_slash ? last_slash + 1 : options.state_dir;
+		const char *cmd_live_rebase =
+			"git rebase (--continue | --abort | --skip)";
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "rm -fr \"%s\"", options.state_dir);
+		die(_("It seems that there is already a %s directory, and\n"
+		      "I wonder if you are in the middle of another rebase.  "
+		      "If that is the\n"
+		      "case, please try\n\t%s\n"
+		      "If that is not the case, please\n\t%s\n"
+		      "and run me again.  I am stopping in case you still "
+		      "have something\n"
+		      "valuable there.\n"),
+		    state_dir_base, cmd_live_rebase,buf.buf);
+	}
+
 	if (!(options.flags & REBASE_NO_QUIET))
 		strbuf_addstr(&options.git_am_opt, " -q");
 
-- 
2.18.0


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

* [PATCH 10/11] builtin rebase: only store fully-qualified refs in `options.head_name`
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
                   ` (8 preceding siblings ...)
  2018-08-08 13:48 ` [PATCH 09/11] builtin rebase: start a new rebase only if none is in progress Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 13:48 ` [PATCH 11/11] builtin rebase: support `git rebase <upstream> <switch-to>` Pratik Karki
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
  11 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

When running a rebase on a detached HEAD, we currently store the string
"detached HEAD" in options.head_name. That is a faithful translation of
the shell script version, and we still kind of need it for the purposes of
the scripted backends.

It is poor style for C, though, where we would really only want a valid,
fully-qualified ref name as value, and NULL for detached HEADs, using
"detached HEAD" for display only. Make it so.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index a261f552f1..63634210c0 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -169,7 +169,8 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "upstream_name", opts->upstream_name);
 	add_var(&script_snippet, "upstream",
 				 oid_to_hex(&opts->upstream->object.oid));
-	add_var(&script_snippet, "head_name", opts->head_name);
+	add_var(&script_snippet, "head_name",
+		opts->head_name ? opts->head_name : "detached HEAD");
 	add_var(&script_snippet, "orig_head", oid_to_hex(&opts->orig_head));
 	add_var(&script_snippet, "onto", oid_to_hex(&opts->onto->object.oid));
 	add_var(&script_snippet, "onto_name", opts->onto_name);
@@ -251,6 +252,9 @@ static int reset_head(struct object_id *oid, const char *action,
 		*old_orig = NULL, oid_old_orig;
 	int ret = 0;
 
+	if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
+		BUG("Not a fully qualified branch: '%s'", switch_to_branch);
+
 	if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
 		return -1;
 
@@ -558,7 +562,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	 * branch_name -- branch/commit being rebased, or
 	 * 		  HEAD (already detached)
 	 * orig_head -- commit object name of tip of the branch before rebasing
-	 * head_name -- refs/heads/<that-branch> or "detached HEAD"
+	 * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)
 	 */
 	if (argc > 0)
 		 die("TODO: handle switch_to");
@@ -575,7 +579,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 				branch_name = options.head_name;
 
 		} else {
-			options.head_name = xstrdup("detached HEAD");
+			free(options.head_name);
+			options.head_name = NULL;
 			branch_name = "HEAD";
 		}
 		if (get_oid("HEAD", &options.orig_head))
-- 
2.18.0


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

* [PATCH 11/11] builtin rebase: support `git rebase <upstream> <switch-to>`
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
                   ` (9 preceding siblings ...)
  2018-08-08 13:48 ` [PATCH 10/11] builtin rebase: only store fully-qualified refs in `options.head_name` Pratik Karki
@ 2018-08-08 13:48 ` Pratik Karki
  2018-08-08 16:03   ` Duy Nguyen
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
  11 siblings, 1 reply; 42+ messages in thread
From: Pratik Karki @ 2018-08-08 13:48 UTC (permalink / raw)
  To: git
  Cc: christian.couder, Johannes.Schindelin, sbeller, alban.gruin,
	gitster, Pratik Karki

This commit adds support for `switch-to` which is used to switch to the
target branch if needed. The equivalent codes found in shell script
`git-legacy-rebase.sh` is converted to builtin `rebase.c`.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 63634210c0..b2ddfa8dbf 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -79,6 +79,7 @@ struct rebase_options {
 	struct commit *onto;
 	const char *onto_name;
 	const char *revisions;
+	const char *switch_to;
 	int root;
 	struct commit *restrict_revision;
 	int dont_finish_rebase;
@@ -186,6 +187,8 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->flags & REBASE_DIFFSTAT ? "t" : "");
 	add_var(&script_snippet, "force_rebase",
 		opts->flags & REBASE_FORCE ? "t" : "");
+	if (opts->switch_to)
+		add_var(&script_snippet, "switch_to", opts->switch_to);
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -564,9 +567,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	 * orig_head -- commit object name of tip of the branch before rebasing
 	 * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)
 	 */
-	if (argc > 0)
-		 die("TODO: handle switch_to");
-	else {
+	if (argc == 1) {
+		/* Is it "rebase other branchname" or "rebase other commit"? */
+		branch_name = argv[0];
+		options.switch_to = argv[0];
+
+		/* Is it a local branch? */
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "refs/heads/%s", branch_name);
+		if (!read_ref(buf.buf, &options.orig_head))
+			options.head_name = xstrdup(buf.buf);
+		/* If not is it a valid ref (branch or commit)? */
+		else if (!get_oid(branch_name, &options.orig_head))
+			options.head_name = NULL;
+		else
+			die(_("fatal: no such branch/commit '%s'"),
+			    branch_name);
+	} else if (argc == 0) {
 		/* Do not need to switch branches, we are already on it. */
 		options.head_name =
 			xstrdup_or_null(resolve_ref_unsafe("HEAD", 0, NULL,
@@ -585,7 +602,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		}
 		if (get_oid("HEAD", &options.orig_head))
 			die(_("Could not resolve HEAD to a revision"));
-	}
+	} else
+		BUG("unexpected number of arguments left to parse");
 
 	if (read_index(the_repository->index) < 0)
 		die(_("could not read index"));
@@ -612,6 +630,28 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		int flag;
 
 		if (!(options.flags & REBASE_FORCE)) {
+			/* Lazily switch to the target branch if needed... */
+			if (options.switch_to) {
+				struct object_id oid;
+
+				if (get_oid(options.switch_to, &oid) < 0) {
+					ret = !!error(_("could not parse '%s'"),
+						      options.switch_to);
+					goto cleanup;
+				}
+
+				strbuf_reset(&buf);
+				strbuf_addf(&buf, "rebase: checkout %s",
+					    options.switch_to);
+				if (reset_head(&oid, "checkout",
+					       options.head_name, 0) < 0) {
+					ret = !!error(_("could not switch to "
+							"%s"),
+						      options.switch_to);
+					goto cleanup;
+				}
+			}
+
 			if (!(options.flags & REBASE_NO_QUIET))
 				; /* be quiet */
 			else if (!strcmp(branch_name, "HEAD") &&
-- 
2.18.0


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

* Re: [PATCH 11/11] builtin rebase: support `git rebase <upstream> <switch-to>`
  2018-08-08 13:48 ` [PATCH 11/11] builtin rebase: support `git rebase <upstream> <switch-to>` Pratik Karki
@ 2018-08-08 16:03   ` Duy Nguyen
  2018-08-08 18:52     ` Johannes Schindelin
  0 siblings, 1 reply; 42+ messages in thread
From: Duy Nguyen @ 2018-08-08 16:03 UTC (permalink / raw)
  To: Pratik Karki
  Cc: Git Mailing List, Christian Couder, Johannes Schindelin,
	Stefan Beller, alban.gruin, Junio C Hamano

(not really a review, this patch just happens to catch my eyes)

On Wed, Aug 8, 2018 at 3:55 PM Pratik Karki <predatoramigo@gmail.com> wrote:
>
> This commit adds support for `switch-to` which is used to switch to the
> target branch if needed. The equivalent codes found in shell script
> `git-legacy-rebase.sh` is converted to builtin `rebase.c`.
>
> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
> ---
>  builtin/rebase.c | 48 ++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 44 insertions(+), 4 deletions(-)
>
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 63634210c0..b2ddfa8dbf 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -79,6 +79,7 @@ struct rebase_options {
>         struct commit *onto;
>         const char *onto_name;
>         const char *revisions;
> +       const char *switch_to;
>         int root;
>         struct commit *restrict_revision;
>         int dont_finish_rebase;
> @@ -186,6 +187,8 @@ static int run_specific_rebase(struct rebase_options *opts)
>                 opts->flags & REBASE_DIFFSTAT ? "t" : "");
>         add_var(&script_snippet, "force_rebase",
>                 opts->flags & REBASE_FORCE ? "t" : "");
> +       if (opts->switch_to)
> +               add_var(&script_snippet, "switch_to", opts->switch_to);
>
>         switch (opts->type) {
>         case REBASE_AM:
> @@ -564,9 +567,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>          * orig_head -- commit object name of tip of the branch before rebasing
>          * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)
>          */
> -       if (argc > 0)
> -                die("TODO: handle switch_to");
> -       else {
> +       if (argc == 1) {
> +               /* Is it "rebase other branchname" or "rebase other commit"? */
> +               branch_name = argv[0];
> +               options.switch_to = argv[0];
> +
> +               /* Is it a local branch? */
> +               strbuf_reset(&buf);
> +               strbuf_addf(&buf, "refs/heads/%s", branch_name);
> +               if (!read_ref(buf.buf, &options.orig_head))
> +                       options.head_name = xstrdup(buf.buf);
> +               /* If not is it a valid ref (branch or commit)? */
> +               else if (!get_oid(branch_name, &options.orig_head))
> +                       options.head_name = NULL;
> +               else
> +                       die(_("fatal: no such branch/commit '%s'"),

die() automatically adds "fatal:" so you should not add it yourself here

> +                           branch_name);
> +       } else if (argc == 0) {
>                 /* Do not need to switch branches, we are already on it. */
>                 options.head_name =
>                         xstrdup_or_null(resolve_ref_unsafe("HEAD", 0, NULL,
> @@ -585,7 +602,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>                 }
>                 if (get_oid("HEAD", &options.orig_head))
>                         die(_("Could not resolve HEAD to a revision"));
> -       }
> +       } else
> +               BUG("unexpected number of arguments left to parse");

Does this mean "git base one two three" triggers this BUG? If so, this
should be a die() instead. I did not real the full source code, so
maybe this case is already caught higher up.
-- 
Duy

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

* Re: [PATCH 04/11] builtin rebase: support --quiet
  2018-08-08 13:48 ` [PATCH 04/11] builtin rebase: support --quiet Pratik Karki
@ 2018-08-08 18:31   ` Stefan Beller
  2018-08-08 19:37     ` Junio C Hamano
  0 siblings, 1 reply; 42+ messages in thread
From: Stefan Beller @ 2018-08-08 18:31 UTC (permalink / raw)
  To: Pratik Karki
  Cc: git, Christian Couder, Johannes Schindelin, Alban Gruin, Junio C Hamano

On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:
>
> This commit introduces a rebase option `--quiet`. While `--quiet` is
> commonly perceived as opposite to `--verbose`, this is not the case for
> the rebase command: both `--quiet` and `--verbose` default to `false` if
> neither `--quiet` nor `--verbose` is present.
>
> This commit goes further and introduces `--no-quiet` which is the
> contrary of `--quiet` and it's introduction doesn't modify any
> behaviour.
>
> Note: The `flags` field in `rebase_options` will accumulate more bits in
> subsequent commits, in particular a verbose and a diffstat flag. And as
> --quoet inthe shell scripted version of the rebase command switches off

  --quote in the

(in case a resend is needed)

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

* Re: [PATCH 08/11] builtin rebase: support --force-rebase
  2018-08-08 13:48 ` [PATCH 08/11] builtin rebase: support --force-rebase Pratik Karki
@ 2018-08-08 18:51   ` Stefan Beller
  2018-08-24 16:10     ` Johannes Schindelin
  0 siblings, 1 reply; 42+ messages in thread
From: Stefan Beller @ 2018-08-08 18:51 UTC (permalink / raw)
  To: Pratik Karki
  Cc: git, Christian Couder, Johannes Schindelin, Alban Gruin, Junio C Hamano

On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:

> @@ -551,10 +560,21 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
[...]
>                         ; /* be quiet */
>                 else if (!strcmp(branch_name, "HEAD") &&
> -                       resolve_ref_unsafe("HEAD", 0, NULL, &flag))
> +                        resolve_ref_unsafe("HEAD", 0, NULL, &flag))

This line is changing only the indentation whitespace?
Would it make sense to have it in the previous patch?

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

* Re: [PATCH 11/11] builtin rebase: support `git rebase <upstream> <switch-to>`
  2018-08-08 16:03   ` Duy Nguyen
@ 2018-08-08 18:52     ` Johannes Schindelin
  0 siblings, 0 replies; 42+ messages in thread
From: Johannes Schindelin @ 2018-08-08 18:52 UTC (permalink / raw)
  To: Duy Nguyen
  Cc: Pratik Karki, Git Mailing List, Christian Couder, Stefan Beller,
	alban.gruin, Junio C Hamano

Hi Duy,

On Wed, 8 Aug 2018, Duy Nguyen wrote:

> On Wed, Aug 8, 2018 at 3:55 PM Pratik Karki <predatoramigo@gmail.com> wrote:
> >
> > diff --git a/builtin/rebase.c b/builtin/rebase.c
> > index 63634210c0..b2ddfa8dbf 100644
> > --- a/builtin/rebase.c
> > +++ b/builtin/rebase.c
> > @@ -585,7 +602,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
> >                 }
> >                 if (get_oid("HEAD", &options.orig_head))
> >                         die(_("Could not resolve HEAD to a revision"));
> > -       }
> > +       } else
> > +               BUG("unexpected number of arguments left to parse");
> 
> Does this mean "git base one two three" triggers this BUG? If so, this
> should be a die() instead. I did not real the full source code, so
> maybe this case is already caught higher up.

As you can see from

	https://github.com/git/git/blob/v2.18.0/git-rebase.sh#L615

the original, Unix shell script version of `git rebase` also says "BUG"
here. And if you care to look at

	https://github.com/git/git/blob/3358abdcb/builtin/rebase.c#L870-L872

you will see that there is a proper check for the correct amount of
command-line parameters.

So at this point, it would indeed indicate a bug if the `argc` had an
unexpected value.

Ciao,
Dscho

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

* Re: [PATCH 09/11] builtin rebase: start a new rebase only if none is in progress
  2018-08-08 13:48 ` [PATCH 09/11] builtin rebase: start a new rebase only if none is in progress Pratik Karki
@ 2018-08-08 18:59   ` Stefan Beller
  2018-08-24 16:13     ` Johannes Schindelin
  0 siblings, 1 reply; 42+ messages in thread
From: Stefan Beller @ 2018-08-08 18:59 UTC (permalink / raw)
  To: Pratik Karki
  Cc: git, Christian Couder, Johannes Schindelin, Alban Gruin, Junio C Hamano

On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:
>
> To run a new rebase, there needs to be a check to assure that no other
> rebase is in progress. New rebase operation cannot start until an
> ongoing rebase operation completes or is terminated.
>
> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
> ---
>  builtin/rebase.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 47 insertions(+), 1 deletion(-)
>
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 8a7bf3d468..a261f552f1 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -87,6 +87,7 @@ struct rebase_options {
>                 REBASE_VERBOSE = 1<<1,
>                 REBASE_DIFFSTAT = 1<<2,
>                 REBASE_FORCE = 1<<3,
> +               REBASE_INTERACTIVE_EXPLICIT = 1<<4,
>         } flags;
>         struct strbuf git_am_opt;
>  };
> @@ -392,10 +393,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>                 .git_am_opt = STRBUF_INIT,
>         };
>         const char *branch_name;
> -       int ret, flags;
> +       int ret, flags, in_progress = 0;
>         int ok_to_skip_pre_rebase = 0;
>         struct strbuf msg = STRBUF_INIT;
>         struct strbuf revisions = STRBUF_INIT;
> +       struct strbuf buf = STRBUF_INIT;
>         struct object_id merge_base;
>         struct option builtin_rebase_options[] = {
>                 OPT_STRING(0, "onto", &options.onto_name,
> @@ -447,6 +449,30 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>
>         git_config(rebase_config, &options);
>
> +       if (is_directory(apply_dir())) {
> +               options.type = REBASE_AM;
> +               options.state_dir = apply_dir();
> +       } else if (is_directory(merge_dir())) {
> +               strbuf_reset(&buf);
> +               strbuf_addf(&buf, "%s/rewritten", merge_dir());
> +               if (is_directory(buf.buf)) {
> +                       options.type = REBASE_PRESERVE_MERGES;
> +                       options.flags |= REBASE_INTERACTIVE_EXPLICIT;
> +               } else {
> +                       strbuf_reset(&buf);
> +                       strbuf_addf(&buf, "%s/interactive", merge_dir());
> +                       if(file_exists(buf.buf)) {
> +                               options.type = REBASE_INTERACTIVE;
> +                               options.flags |= REBASE_INTERACTIVE_EXPLICIT;
> +                       } else
> +                               options.type = REBASE_MERGE;
> +               }
> +               options.state_dir = merge_dir();
> +       }
> +
> +       if (options.type != REBASE_UNSPECIFIED)
> +               in_progress = 1;
> +
>         argc = parse_options(argc, argv, prefix,
>                              builtin_rebase_options,
>                              builtin_rebase_usage, 0);
> @@ -455,6 +481,26 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>                 usage_with_options(builtin_rebase_usage,
>                                    builtin_rebase_options);
>
> +       /* Make sure no rebase is in progress */

The faithful conversion doesn't even stop at the comments. ;-)
I shortly wondered if this is the best place for this comment,
but let's just keep it here to have the 1:1 rewrite.


> +       if (in_progress) {
[...]
> +                   state_dir_base, cmd_live_rebase,buf.buf);

In case a resend is needed, add a whitespace after the
comma and buf.buf, please.

So far I have not seen anything major that would warrant a resend.

Thanks,
Stefan

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

* Re: [PATCH 01/11] builtin rebase: support --onto
  2018-08-08 13:48 ` [PATCH 01/11] builtin rebase: support --onto Pratik Karki
@ 2018-08-08 19:02   ` Junio C Hamano
  2018-08-24 16:21     ` Johannes Schindelin
  0 siblings, 1 reply; 42+ messages in thread
From: Junio C Hamano @ 2018-08-08 19:02 UTC (permalink / raw)
  To: Pratik Karki
  Cc: git, christian.couder, Johannes.Schindelin, sbeller, alban.gruin

Pratik Karki <predatoramigo@gmail.com> writes:

> The `--onto` option is important, as it allows to rebase a range of
> commits onto a different base commit (which gave the command its odd
> name: "rebase").

Is there anything unimportant?  A rhetorical question, of course.

The quite casual and natural use of "to rebase" as a verb in the
first sentence contradicts with what the parenthetical "its odd
name" comment says.  Perhaps drop everything after "(which..."?

i.e.

	The `--onto` option allows to rebase a range of commits onto
	a different base commit.  Port the support for the option to
	the C re-implementation.

> This commit introduces options parsing so that different options can
> be added in future commits.

We usually do not say "This commit does X", or (worse) "I do X in
this commit".  Instead, order the codebase to be like so, e.g.
"Support command line options by adding a call to parse_options();
later commits will add more options by building on top." or
something like that.

> @@ -318,13 +334,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  			BUG("sane_execvp() returned???");
>  	}
>  
> -	if (argc != 2)
> -		die(_("Usage: %s <base>"), argv[0]);
> +	if (argc == 2 && !strcmp(argv[1], "-h"))
> +		usage_with_options(builtin_rebase_usage,
> +				   builtin_rebase_options);
> +
>  	prefix = setup_git_directory();
>  	trace_repo_setup(prefix);
>  	setup_work_tree();
>
>  	git_config(git_default_config, NULL);
> +	argc = parse_options(argc, argv, prefix,
> +			     builtin_rebase_options,
> +			     builtin_rebase_usage, 0);
> +
> +	if (argc > 2)
> +		usage_with_options(builtin_rebase_usage,
> +				   builtin_rebase_options);

OK.  This correctly calls the parser after repository setup.

>  	switch (options.type) {
>  	case REBASE_MERGE:
> @@ -343,10 +368,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  	}
>  
>  	if (!options.root) {
> -		if (argc < 2)
> +		if (argc < 1)
>  			die("TODO: handle @{upstream}");
>  		else {
> -			options.upstream_name = argv[1];
> +			options.upstream_name = argv[0];
>  			argc--;
>  			argv++;
>  			if (!strcmp(options.upstream_name, "-"))
> @@ -377,7 +402,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  	 * orig_head -- commit object name of tip of the branch before rebasing
>  	 * head_name -- refs/heads/<that-branch> or "detached HEAD"
>  	 */
> -	if (argc > 1)
> +	if (argc > 0)
>  		 die("TODO: handle switch_to");
>  	else {
>  		/* Do not need to switch branches, we are already on it. */

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

* Re: [PATCH 02/11] builtin rebase: support `git rebase --onto A...B`
  2018-08-08 13:48 ` [PATCH 02/11] builtin rebase: support `git rebase --onto A...B` Pratik Karki
@ 2018-08-08 19:12   ` Junio C Hamano
  2018-08-26 18:36     ` Johannes Schindelin
  0 siblings, 1 reply; 42+ messages in thread
From: Junio C Hamano @ 2018-08-08 19:12 UTC (permalink / raw)
  To: Pratik Karki
  Cc: git, christian.couder, Johannes.Schindelin, sbeller, alban.gruin

Pratik Karki <predatoramigo@gmail.com> writes:

> This commit implements support for an --onto argument that is actually a
> "symmetric range" i.e. `<rev1>...<rev2>`.
>
> The equivalent shell script version of the code offers two different
> error messages for the cases where there is no merge base vs more than
> one merge base. Though following the similar approach would be nice,
> this would create more complexity than it is of current. Currently, for

Sorry, but it is unclear what you mean by "than it is of current."
Do you mean we leave it broken at this step in the series for now
for expediency, with the intention to later revisit and fix it, or
do you mean something else?

> simple convenience, the `get_oid_mb()` function is used whose return
> value does not discern between those two error conditions.
>
> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
> ...
> @@ -387,7 +389,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  	if (!options.onto_name)
>  		options.onto_name = options.upstream_name;
>  	if (strstr(options.onto_name, "...")) {
> -		die("TODO");
> +		if (get_oid_mb(options.onto_name, &merge_base) < 0)
> +			die(_("'%s': need exactly one merge base"),
> +			    options.onto_name);
> +		options.onto = lookup_commit_or_die(&merge_base,
> +						    options.onto_name);

The original is slightly sloppy in that it will misparse

	rebase --onto 'master^{/log ... message}'

and this shares the same, which I think is probably OK.  When this
actually becomes problematic, the original can easily be salvaged by
making it to fall back to the same peel_committish in its else
clause; I am not sure if this C rewrite is as easily be fixed the
same way, though.

>  	} else {
>  		options.onto = peel_committish(options.onto_name);
>  		if (!options.onto)

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

* Re: [PATCH 03/11] builtin rebase: handle the pre-rebase hook (and add --no-verify)
  2018-08-08 13:48 ` [PATCH 03/11] builtin rebase: handle the pre-rebase hook (and add --no-verify) Pratik Karki
@ 2018-08-08 19:32   ` Junio C Hamano
  2018-08-27 12:15     ` Johannes Schindelin
  0 siblings, 1 reply; 42+ messages in thread
From: Junio C Hamano @ 2018-08-08 19:32 UTC (permalink / raw)
  To: Pratik Karki
  Cc: git, christian.couder, Johannes.Schindelin, sbeller, alban.gruin

Pratik Karki <predatoramigo@gmail.com> writes:

> This commit converts the equivalent part of the shell script
> `git-legacy-rebase.sh` to run the pre-rebase hook (unless disabled), and
> to interrupt the rebase with error if the hook fails.
>
> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
> ---

Introduction of upstream_arg in this step looked a bit
surprising, but the hook invocation is the only thing that uses it,
so it is understandable.

"rebase: handle the re-rebase hook and --no-verify" would have been
sufficient, without "add" or parentheses.

>  builtin/rebase.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
>
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 38c496dd10..b79f9b0a9f 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -70,6 +70,7 @@ struct rebase_options {
>  	const char *state_dir;
>  	struct commit *upstream;
>  	const char *upstream_name;
> +	const char *upstream_arg;
>  	char *head_name;
>  	struct object_id orig_head;
>  	struct commit *onto;
> @@ -310,6 +311,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  	};
>  	const char *branch_name;
>  	int ret, flags;
> +	int ok_to_skip_pre_rebase = 0;
>  	struct strbuf msg = STRBUF_INIT;
>  	struct strbuf revisions = STRBUF_INIT;
>  	struct object_id merge_base;
> @@ -317,6 +319,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  		OPT_STRING(0, "onto", &options.onto_name,
>  			   N_("revision"),
>  			   N_("rebase onto given branch instead of upstream")),
> +		OPT_BOOL(0, "no-verify", &ok_to_skip_pre_rebase,
> +			 N_("allow pre-rebase hook to run")),

Do we need to catch "--no-no-verify" ourselves with NONEG bit, or is
this sufficient to tell parse_options() machinery to take care of
it?

>  		OPT_END(),
>  	};
>  
> @@ -382,6 +386,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  		options.upstream = peel_committish(options.upstream_name);
>  		if (!options.upstream)
>  			die(_("invalid upstream '%s'"), options.upstream_name);
> +		options.upstream_arg = options.upstream_name;
>  	} else
>  		die("TODO: upstream for --root");
>  
> @@ -430,6 +435,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  			die(_("Could not resolve HEAD to a revision"));
>  	}
>  
> +	/* If a hook exists, give it a chance to interrupt*/
> +	if (!ok_to_skip_pre_rebase &&
> +	    run_hook_le(NULL, "pre-rebase", options.upstream_arg,
> +			argc ? argv[0] : NULL, NULL))
> +		die(_("The pre-rebase hook refused to rebase."));
> +
>  	strbuf_addf(&msg, "rebase: checkout %s", options.onto_name);
>  	if (reset_head(&options.onto->object.oid, "checkout", NULL, 1))
>  		die(_("Could not detach HEAD"));

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

* Re: [PATCH 04/11] builtin rebase: support --quiet
  2018-08-08 18:31   ` Stefan Beller
@ 2018-08-08 19:37     ` Junio C Hamano
  2018-08-27 12:31       ` Johannes Schindelin
  0 siblings, 1 reply; 42+ messages in thread
From: Junio C Hamano @ 2018-08-08 19:37 UTC (permalink / raw)
  To: Stefan Beller
  Cc: Pratik Karki, git, Christian Couder, Johannes Schindelin, Alban Gruin

Stefan Beller <sbeller@google.com> writes:

> On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:
>>
>> This commit introduces a rebase option `--quiet`. While `--quiet` is
>> commonly perceived as opposite to `--verbose`, this is not the case for
>> the rebase command: both `--quiet` and `--verbose` default to `false` if
>> neither `--quiet` nor `--verbose` is present.
>>
>> This commit goes further and introduces `--no-quiet` which is the
>> contrary of `--quiet` and it's introduction doesn't modify any
>> behaviour.

Why?  Is it for completeness (i.e. does the scripted version take
such an option and addition of --no-quiet makes the C rewrite behave
the same)?

>> Note: The `flags` field in `rebase_options` will accumulate more bits in
>> subsequent commits, in particular a verbose and a diffstat flag. And as
>> --quoet inthe shell scripted version of the rebase command switches off
>
>   --quote in the
>
> (in case a resend is needed)

Meaning --quiet?


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

* Re: [PATCH 08/11] builtin rebase: support --force-rebase
  2018-08-08 18:51   ` Stefan Beller
@ 2018-08-24 16:10     ` Johannes Schindelin
  0 siblings, 0 replies; 42+ messages in thread
From: Johannes Schindelin @ 2018-08-24 16:10 UTC (permalink / raw)
  To: Stefan Beller
  Cc: Pratik Karki, git, Christian Couder, Alban Gruin, Junio C Hamano

Hi Stefan,

On Wed, 8 Aug 2018, Stefan Beller wrote:

> On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:
> 
> > @@ -551,10 +560,21 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
> [...]
> >                         ; /* be quiet */
> >                 else if (!strcmp(branch_name, "HEAD") &&
> > -                       resolve_ref_unsafe("HEAD", 0, NULL, &flag))
> > +                        resolve_ref_unsafe("HEAD", 0, NULL, &flag))
> 
> This line is changing only the indentation whitespace?
> Would it make sense to have it in the previous patch?

Correct. I will fix this before sending the next iteration,
Dscho

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

* Re: [PATCH 09/11] builtin rebase: start a new rebase only if none is in progress
  2018-08-08 18:59   ` Stefan Beller
@ 2018-08-24 16:13     ` Johannes Schindelin
  0 siblings, 0 replies; 42+ messages in thread
From: Johannes Schindelin @ 2018-08-24 16:13 UTC (permalink / raw)
  To: Stefan Beller
  Cc: Pratik Karki, git, Christian Couder, Alban Gruin, Junio C Hamano

Hi Stefan,

On Wed, 8 Aug 2018, Stefan Beller wrote:

> On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:
> >
> > diff --git a/builtin/rebase.c b/builtin/rebase.c
> > index 8a7bf3d468..a261f552f1 100644
> > --- a/builtin/rebase.c
> > +++ b/builtin/rebase.c
> > @@ -455,6 +481,26 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
> >                 usage_with_options(builtin_rebase_usage,
> >                                    builtin_rebase_options);
> >
> > +       /* Make sure no rebase is in progress */
> 
> The faithful conversion doesn't even stop at the comments. ;-)

Yes, I insisted on it.

TBH it is a bit of a shame that we cannot fix all those error messages
going to stdout, but... you know... One step after the other.

> I shortly wondered if this is the best place for this comment,
> but let's just keep it here to have the 1:1 rewrite.

It should probably be inside the conditional block, but as you say: the
original had it in a funny spot, and so does the converted code.

> > +       if (in_progress) {
> [...]
> > +                   state_dir_base, cmd_live_rebase,buf.buf);
> 
> In case a resend is needed, add a whitespace after the
> comma and buf.buf, please.

I will fix this before sending the next iteration.

Thanks for the review!
Dscho

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

* Re: [PATCH 01/11] builtin rebase: support --onto
  2018-08-08 19:02   ` Junio C Hamano
@ 2018-08-24 16:21     ` Johannes Schindelin
  0 siblings, 0 replies; 42+ messages in thread
From: Johannes Schindelin @ 2018-08-24 16:21 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Pratik Karki, git, christian.couder, sbeller, alban.gruin

Hi Junio,

On Wed, 8 Aug 2018, Junio C Hamano wrote:

> Pratik Karki <predatoramigo@gmail.com> writes:
> 
> > The `--onto` option is important, as it allows to rebase a range of
> > commits onto a different base commit (which gave the command its odd
> > name: "rebase").
> 
> Is there anything unimportant?  A rhetorical question, of course.

You might think it is a rhetorical question, but obviously it is not, as
your reaction testifies.

But certainly there are more important options and less important options!
The most important options are those that are frequently used.

> The quite casual and natural use of "to rebase" as a verb in the
> first sentence contradicts with what the parenthetical "its odd
> name" comment says.  Perhaps drop everything after "(which..."?
> 
> i.e.
> 
> 	The `--onto` option allows to rebase a range of commits onto
> 	a different base commit.  Port the support for the option to
> 	the C re-implementation.

I'd rather keep it.

Remember, a story is easier to read than a dull academic treatise. I want
to have a little bit of a personal touch when I stumble over these commit
messages again. And I know I will.

> > This commit introduces options parsing so that different options can
> > be added in future commits.
> 
> We usually do not say "This commit does X", or (worse) "I do X in
> this commit".

Oh, don't we now? ;-)

(This *was* a rhetorical question, as *I* use this tense all the time, and
unless you have quietly rewritten my commit messages without my knowledge
nor consent, the Git commit history is full of these instances.)

> Instead, order the codebase to be like so, e.g.  "Support command line
> options by adding a call to parse_options(); later commits will add more
> options by building on top." or something like that.

To be quite frank with you, I hoped for a review that would focus a teeny
tiny bit on the correctness of the code.

If you want to continue to nit-pick the commit messages, that's fine, of
course, but do understand that I am not really prepared to change a whole
lot there, unless you point out outright errors or false statements. Those
naturally need fixing.

Also, please note that I will now *definitely* focus on bug fixes, as I am
really eager to get those speed improvements into Git for Windows v2.19.0.

And I don't know whether I have said this publicly yet: I will send the
next iterations of Pratik's patch series. He is busy with exams (GSoC
really caters for US schedules, students who are in countries with very
different university schedules are a bit out of luck here), and I really
want these patches.

Ciao,
Dscho

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

* Re: [PATCH 02/11] builtin rebase: support `git rebase --onto A...B`
  2018-08-08 19:12   ` Junio C Hamano
@ 2018-08-26 18:36     ` Johannes Schindelin
  0 siblings, 0 replies; 42+ messages in thread
From: Johannes Schindelin @ 2018-08-26 18:36 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Pratik Karki, git, christian.couder, sbeller, alban.gruin

Hi Junio,

On Wed, 8 Aug 2018, Junio C Hamano wrote:

> Pratik Karki <predatoramigo@gmail.com> writes:
> 
> > This commit implements support for an --onto argument that is actually a
> > "symmetric range" i.e. `<rev1>...<rev2>`.
> >
> > The equivalent shell script version of the code offers two different
> > error messages for the cases where there is no merge base vs more than
> > one merge base. Though following the similar approach would be nice,
> > this would create more complexity than it is of current. Currently, for
> 
> Sorry, but it is unclear what you mean by "than it is of current."
> Do you mean we leave it broken at this step in the series for now
> for expediency, with the intention to later revisit and fix it, or
> do you mean something else?

I suggested to drop the distinction, in favor of simpler code. Not for the
time being, but for good.

I reworded the commit message thusly:

    builtin rebase: support `git rebase --onto A...B`

    This commit implements support for an --onto argument that is actually a
    "symmetric range" i.e. `<rev1>...<rev2>`.

    The equivalent shell script version of the code offers two different
    error messages for the cases where there is no merge base vs more than
    one merge base.

    Though it would be nice to retain this distinction, dropping it makes it
    possible to simply use the `get_oid_mb()` function. Besides, it happens
    rarely in real-world scenarios.

    Therefore, in the interest of keeping the code less complex, let's just
    use that function, and live with an error message that does not
    distinguish between those two error conditions.

> > @@ -387,7 +389,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
> >  	if (!options.onto_name)
> >  		options.onto_name = options.upstream_name;
> >  	if (strstr(options.onto_name, "...")) {
> > -		die("TODO");
> > +		if (get_oid_mb(options.onto_name, &merge_base) < 0)
> > +			die(_("'%s': need exactly one merge base"),
> > +			    options.onto_name);
> > +		options.onto = lookup_commit_or_die(&merge_base,
> > +						    options.onto_name);
> 
> The original is slightly sloppy in that it will misparse
> 
> 	rebase --onto 'master^{/log ... message}'
> 
> and this shares the same, which I think is probably OK.

I did run into this recently, but not with an `--onto` option. I forgot
the details (I meant to write it down, and forgot that, too).

Sorry for musing, back on the topic. Yes, it shares the same, and *that*
makes it okay. Remember: this patch series is not about improving `git
rebase` at all. It is about converting from shell script to builtin.

> When this actually becomes problematic, the original can easily be
> salvaged by making it to fall back to the same peel_committish in its
> else clause; I am not sure if this C rewrite is as easily be fixed the
> same way, though.

I will make a note so that I hopefully won't forget.

Thanks,
Dscho

> 
> >  	} else {
> >  		options.onto = peel_committish(options.onto_name);
> >  		if (!options.onto)
> 

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

* Re: [PATCH 03/11] builtin rebase: handle the pre-rebase hook (and add --no-verify)
  2018-08-08 19:32   ` Junio C Hamano
@ 2018-08-27 12:15     ` Johannes Schindelin
  0 siblings, 0 replies; 42+ messages in thread
From: Johannes Schindelin @ 2018-08-27 12:15 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Pratik Karki, git, christian.couder, sbeller, alban.gruin

Hi Junio,

On Wed, 8 Aug 2018, Junio C Hamano wrote:

> Pratik Karki <predatoramigo@gmail.com> writes:
> 
> > This commit converts the equivalent part of the shell script
> > `git-legacy-rebase.sh` to run the pre-rebase hook (unless disabled), and
> > to interrupt the rebase with error if the hook fails.
> >
> > Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
> > ---
> 
> Introduction of upstream_arg in this step looked a bit
> surprising, but the hook invocation is the only thing that uses it,
> so it is understandable.

Yep, that's literally all that `upstream_arg` is used for:

$ git grep upstream_arg v2.19.0-rc0
v2.19.0-rc0:git-rebase.sh:      upstream_arg="$upstream_name"
v2.19.0-rc0:git-rebase.sh:      upstream_arg=--root
v2.19.0-rc0:git-rebase.sh:run_pre_rebase_hook "$upstream_arg" "$@"

> "rebase: handle the re-rebase hook and --no-verify" would have been
> sufficient, without "add" or parentheses.

Fixed.

> > diff --git a/builtin/rebase.c b/builtin/rebase.c
> > index 38c496dd10..b79f9b0a9f 100644
> > --- a/builtin/rebase.c
> > +++ b/builtin/rebase.c
> > @@ -317,6 +319,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
> >  		OPT_STRING(0, "onto", &options.onto_name,
> >  			   N_("revision"),
> >  			   N_("rebase onto given branch instead of upstream")),
> > +		OPT_BOOL(0, "no-verify", &ok_to_skip_pre_rebase,
> > +			 N_("allow pre-rebase hook to run")),
> 
> Do we need to catch "--no-no-verify" ourselves with NONEG bit, or is
> this sufficient to tell parse_options() machinery to take care of
> it?

I just issued

	$ ./git rebase --verify --no-no-verify --xyz

and it showed

	error: unknown option `xyz'
	[... usage ...]

I vaguely remembered that the parse_options() machinery special-cases
"no-" prefixes, and my test seems to confirm it.

Holler if you want a more in-depth analysis.

Ciao,
Dscho

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

* Re: [PATCH 04/11] builtin rebase: support --quiet
  2018-08-08 19:37     ` Junio C Hamano
@ 2018-08-27 12:31       ` Johannes Schindelin
  0 siblings, 0 replies; 42+ messages in thread
From: Johannes Schindelin @ 2018-08-27 12:31 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Stefan Beller, Pratik Karki, git, Christian Couder, Alban Gruin

Hi Junio,

On Wed, 8 Aug 2018, Junio C Hamano wrote:

> Stefan Beller <sbeller@google.com> writes:
> 
> > On Wed, Aug 8, 2018 at 6:51 AM Pratik Karki <predatoramigo@gmail.com> wrote:
> >>
> >> This commit introduces a rebase option `--quiet`. While `--quiet` is
> >> commonly perceived as opposite to `--verbose`, this is not the case for
> >> the rebase command: both `--quiet` and `--verbose` default to `false` if
> >> neither `--quiet` nor `--verbose` is present.
> >>
> >> This commit goes further and introduces `--no-quiet` which is the
> >> contrary of `--quiet` and it's introduction doesn't modify any
> >> behaviour.
> 
> Why?  Is it for completeness (i.e. does the scripted version take
> such an option and addition of --no-quiet makes the C rewrite behave
> the same)?

Ah. I mentioned that an explanation for this is needed in the commit
message, and I guess that it is a bit too subtle. The part you clipped
from your quoted text says:

	[... `--quiet`] switches off --verbose and --stat, and as
	--verbose switches off --quiet, we use the (negated)
	REBASE_NO_QUIET instead of REBASE_QUIET: this allows us to turn
	off the quiet mode and turn on the verbose and diffstat mode in a
	single OPT_BIT(), and the opposite in a single OPT_NEGBIT().

I agree that this is a pretty convoluted way to express the issue. See
below for an attempt at a clearer commit message.

> >> Note: The `flags` field in `rebase_options` will accumulate more bits in
> >> subsequent commits, in particular a verbose and a diffstat flag. And as
> >> --quoet inthe shell scripted version of the rebase command switches off
> >
> >   --quote in the
> >
> > (in case a resend is needed)
> 
> Meaning --quiet?

Yep. I should have paid more attention in my pre-submission review, sorry.

I changed the commit message to read like this:

	builtin rebase: support --quiet

	This commit introduces a rebase option `--quiet`. While `--quiet` is
	commonly perceived as opposite to `--verbose`, this is not the case for
	the rebase command: both `--quiet` and `--verbose` default to `false` if
	neither `--quiet` nor `--verbose` is present.

	Despite the default being `false` for both verbose and quiet mode,
	passing the `--quiet` option will turn off verbose mode, and `--verbose`
	will turn off quiet mode.

	This patch introduces the `flags` bit field, with `REBASE_NO_QUIET`
	as first user (with many more to come).

	We do *not* use `REBASE_QUIET` here for an important reason: To keep the
	implementation simple, this commit introduces `--no-quiet` instead of
	`--quiet`, so that a single `OPT_NEGBIT()` can turn on quiet mode and
	turn off verbose and diffstat mode at the same time. Likewise, the
	companion commit which will introduce support for `--verbose` will have
	a single `OPT_BIT()` that turns off quiet mode and turns on verbose and
	diffstat mode at the same time.

Ciao,
Dscho

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

* [PATCH v2 00/11] A minimal builtin rebase
  2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
                   ` (10 preceding siblings ...)
  2018-08-08 13:48 ` [PATCH 11/11] builtin rebase: support `git rebase <upstream> <switch-to>` Pratik Karki
@ 2018-09-04 21:27 ` Johannes Schindelin via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 01/11] builtin rebase: support --onto Pratik Karki via GitGitGadget
                     ` (10 more replies)
  11 siblings, 11 replies; 42+ messages in thread
From: Johannes Schindelin via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

This patch series provides the bare minimum to run more than just the
trivial rebase (i.e. git rebase <upstream>): it implements the most common
options such as --onto.

It is based the latest iteration of pk/rebase-in-c.

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

Changes since v1:

 * Many commit messages were reworded.
 * An indentation fix was folded into the commit that introduces the
   incorrect indentation.
 * A missing space after a comma was inserted.

Pratik Karki (11):
  builtin rebase: support --onto
  builtin rebase: support `git rebase --onto A...B`
  builtin rebase: handle the pre-rebase hook and --no-verify
  builtin rebase: support --quiet
  builtin rebase: support the `verbose` and `diffstat` options
  builtin rebase: require a clean worktree
  builtin rebase: try to fast forward when possible
  builtin rebase: support --force-rebase
  builtin rebase: start a new rebase only if none is in progress
  builtin rebase: only store fully-qualified refs in `options.head_name`
  builtin rebase: support `git rebase <upstream> <switch-to>`

 builtin/rebase.c | 333 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 320 insertions(+), 13 deletions(-)


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

Range-diff vs v1:

  1:  c5f67c35ea !  1:  fba1b3e2a9 builtin rebase: support --onto
     @@ -15,6 +15,7 @@
          command name, but to the first (non-option) command-line parameter.
      
          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:  35d141c32a !  2:  f9826ab58f builtin rebase: support `git rebase --onto A...B`
     @@ -7,12 +7,18 @@
      
          The equivalent shell script version of the code offers two different
          error messages for the cases where there is no merge base vs more than
     -    one merge base. Though following the similar approach would be nice,
     -    this would create more complexity than it is of current. Currently, for
     -    simple convenience, the `get_oid_mb()` function is used whose return
     -    value does not discern between those two error conditions.
     +    one merge base.
     +
     +    Though it would be nice to retain this distinction, dropping it makes it
     +    possible to simply use the `get_oid_mb()` function. Besides, it happens
     +    rarely in real-world scenarios.
     +
     +    Therefore, in the interest of keeping the code less complex, let's just
     +    use that function, and live with an error message that does not
     +    distinguish between those two error conditions.
      
          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:  e223f2209d !  3:  7100820def builtin rebase: handle the pre-rebase hook (and add --no-verify)
     @@ -1,12 +1,13 @@
      Author: Pratik Karki <predatoramigo@gmail.com>
      
     -    builtin rebase: handle the pre-rebase hook (and add --no-verify)
     +    builtin rebase: handle the pre-rebase hook and --no-verify
      
          This commit converts the equivalent part of the shell script
          `git-legacy-rebase.sh` to run the pre-rebase hook (unless disabled), and
          to interrupt the rebase with error if the hook fails.
      
          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:  19919e7e24 !  4:  5034f53024 builtin rebase: support --quiet
     @@ -7,19 +7,23 @@
          the rebase command: both `--quiet` and `--verbose` default to `false` if
          neither `--quiet` nor `--verbose` is present.
      
     -    This commit goes further and introduces `--no-quiet` which is the
     -    contrary of `--quiet` and it's introduction doesn't modify any
     -    behaviour.
     +    Despite the default being `false` for both verbose and quiet mode,
     +    passing the `--quiet` option will turn off verbose mode, and `--verbose`
     +    will turn off quiet mode.
      
     -    Note: The `flags` field in `rebase_options` will accumulate more bits in
     -    subsequent commits, in particular a verbose and a diffstat flag. And as
     -    --quoet inthe shell scripted version of the rebase command switches off
     -    --verbose and --stat, and as --verbose switches off --quiet, we use the
     -    (negated) REBASE_NO_QUIET instead of REBASE_QUIET: this allows us to
     -    turn off the quiet mode and turn on the verbose and diffstat mode in a
     -    single OPT_BIT(), and the opposite in a single OPT_NEGBIT().
     +    This patch introduces the `flags` bit field, with `REBASE_NO_QUIET`
     +    as first user (with many more to come).
     +
     +    We do *not* use `REBASE_QUIET` here for an important reason: To keep the
     +    implementation simple, this commit introduces `--no-quiet` instead of
     +    `--quiet`, so that a single `OPT_NEGBIT()` can turn on quiet mode and
     +    turn off verbose and diffstat mode at the same time. Likewise, the
     +    companion commit which will introduce support for `--verbose` will have
     +    a single `OPT_BIT()` that turns off quiet mode and turns on verbose and
     +    diffstat mode at the same time.
      
          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:  cbf318d0de !  5:  ce1e1f266a builtin rebase: support the `verbose` and `diffstat` options
     @@ -11,6 +11,7 @@
          calling) 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
  6:  b440bf9884 !  6:  f11f21d5c6 builtin rebase: require a clean worktree
     @@ -6,6 +6,7 @@
          whether the repository is ready for 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
  7:  0efe9b41f0 !  7:  2ec0b744bf builtin rebase: try to fast forward when possible
     @@ -11,6 +11,7 @@
          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
     @@ -105,7 +106,7 @@
      +		if (!(options.flags & REBASE_NO_QUIET))
      +			; /* be quiet */
      +		else if (!strcmp(branch_name, "HEAD") &&
     -+			resolve_ref_unsafe("HEAD", 0, NULL, &flag))
     ++			 resolve_ref_unsafe("HEAD", 0, NULL, &flag))
      +			puts(_("HEAD is up to date, rebase forced."));
      +		else
      +			printf(_("Current branch %s is up to date, rebase "
  8:  ae019dec3f !  8:  78d90e67de builtin rebase: support --force-rebase
     @@ -10,6 +10,7 @@
          fast-forward even if it could.
      
          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
     @@ -63,8 +64,4 @@
      +		} else if (!(options.flags & REBASE_NO_QUIET))
       			; /* be quiet */
       		else if (!strcmp(branch_name, "HEAD") &&
     --			resolve_ref_unsafe("HEAD", 0, NULL, &flag))
     -+			 resolve_ref_unsafe("HEAD", 0, NULL, &flag))
     - 			puts(_("HEAD is up to date, rebase forced."));
     - 		else
     - 			printf(_("Current branch %s is up to date, rebase "
     + 			 resolve_ref_unsafe("HEAD", 0, NULL, &flag))
  9:  d58d504c03 !  9:  b639bfa5a8 builtin rebase: start a new rebase only if none is in progress
     @@ -7,6 +7,7 @@
          ongoing rebase operation completes or is terminated.
      
          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
     @@ -84,7 +85,7 @@
      +		      "and run me again.  I am stopping in case you still "
      +		      "have something\n"
      +		      "valuable there.\n"),
     -+		    state_dir_base, cmd_live_rebase,buf.buf);
     ++		    state_dir_base, cmd_live_rebase, buf.buf);
      +	}
      +
       	if (!(options.flags & REBASE_NO_QUIET))
 10:  ef468bf3d7 ! 10:  aab01f0b8e builtin rebase: only store fully-qualified refs in `options.head_name`
     @@ -12,6 +12,7 @@
          "detached HEAD" for display only. Make it so.
      
          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:  9a26fc3fac ! 11:  e64190d8ed builtin rebase: support `git rebase <upstream> <switch-to>`
     @@ -7,6 +7,7 @@
          `git-legacy-rebase.sh` is converted to builtin `rebase.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] 42+ messages in thread

* [PATCH v2 01/11] builtin rebase: support --onto
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 02/11] builtin rebase: support `git rebase --onto A...B` Pratik Karki via GitGitGadget
                     ` (9 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

The `--onto` option is important, as it allows to rebase a range of
commits onto a different base commit (which gave the command its odd
name: "rebase").

This commit introduces options parsing so that different options can
be added in future commits.

Note: As this commit introduces to the parse_options() call (which
"eats" argv[0]), the argc is now expected to be lower by one after this
patch, compared to before this patch: argv[0] no longer refers to the
command name, but to the first (non-option) command-line parameter.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index e695d8a430..742ed31498 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -16,6 +16,16 @@
 #include "cache-tree.h"
 #include "unpack-trees.h"
 #include "lockfile.h"
+#include "parse-options.h"
+
+static char const * const builtin_rebase_usage[] = {
+	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
+		"[<upstream>] [<branch>]"),
+	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
+		"--root [<branch>]"),
+	N_("git rebase --continue | --abort | --skip | --edit-todo"),
+	NULL
+};
 
 static GIT_PATH_FUNC(apply_dir, "rebase-apply")
 static GIT_PATH_FUNC(merge_dir, "rebase-merge")
@@ -301,6 +311,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	int ret, flags;
 	struct strbuf msg = STRBUF_INIT;
 	struct strbuf revisions = STRBUF_INIT;
+	struct option builtin_rebase_options[] = {
+		OPT_STRING(0, "onto", &options.onto_name,
+			   N_("revision"),
+			   N_("rebase onto given branch instead of upstream")),
+		OPT_END(),
+	};
 
 	/*
 	 * NEEDSWORK: Once the builtin rebase has been tested enough
@@ -318,13 +334,22 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			BUG("sane_execvp() returned???");
 	}
 
-	if (argc != 2)
-		die(_("Usage: %s <base>"), argv[0]);
+	if (argc == 2 && !strcmp(argv[1], "-h"))
+		usage_with_options(builtin_rebase_usage,
+				   builtin_rebase_options);
+
 	prefix = setup_git_directory();
 	trace_repo_setup(prefix);
 	setup_work_tree();
 
 	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix,
+			     builtin_rebase_options,
+			     builtin_rebase_usage, 0);
+
+	if (argc > 2)
+		usage_with_options(builtin_rebase_usage,
+				   builtin_rebase_options);
 
 	switch (options.type) {
 	case REBASE_MERGE:
@@ -343,10 +368,10 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	}
 
 	if (!options.root) {
-		if (argc < 2)
+		if (argc < 1)
 			die("TODO: handle @{upstream}");
 		else {
-			options.upstream_name = argv[1];
+			options.upstream_name = argv[0];
 			argc--;
 			argv++;
 			if (!strcmp(options.upstream_name, "-"))
@@ -377,7 +402,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	 * orig_head -- commit object name of tip of the branch before rebasing
 	 * head_name -- refs/heads/<that-branch> or "detached HEAD"
 	 */
-	if (argc > 1)
+	if (argc > 0)
 		 die("TODO: handle switch_to");
 	else {
 		/* Do not need to switch branches, we are already on it. */
-- 
gitgitgadget


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

* [PATCH v2 02/11] builtin rebase: support `git rebase --onto A...B`
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 01/11] builtin rebase: support --onto Pratik Karki via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 03/11] builtin rebase: handle the pre-rebase hook and --no-verify Pratik Karki via GitGitGadget
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit implements support for an --onto argument that is actually a
"symmetric range" i.e. `<rev1>...<rev2>`.

The equivalent shell script version of the code offers two different
error messages for the cases where there is no merge base vs more than
one merge base.

Though it would be nice to retain this distinction, dropping it makes it
possible to simply use the `get_oid_mb()` function. Besides, it happens
rarely in real-world scenarios.

Therefore, in the interest of keeping the code less complex, let's just
use that function, and live with an error message that does not
distinguish between those two error conditions.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 742ed31498..38c496dd10 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -17,6 +17,7 @@
 #include "unpack-trees.h"
 #include "lockfile.h"
 #include "parse-options.h"
+#include "commit.h"
 
 static char const * const builtin_rebase_usage[] = {
 	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -311,6 +312,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	int ret, flags;
 	struct strbuf msg = STRBUF_INIT;
 	struct strbuf revisions = STRBUF_INIT;
+	struct object_id merge_base;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
@@ -387,7 +389,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (!options.onto_name)
 		options.onto_name = options.upstream_name;
 	if (strstr(options.onto_name, "...")) {
-		die("TODO");
+		if (get_oid_mb(options.onto_name, &merge_base) < 0)
+			die(_("'%s': need exactly one merge base"),
+			    options.onto_name);
+		options.onto = lookup_commit_or_die(&merge_base,
+						    options.onto_name);
 	} else {
 		options.onto = peel_committish(options.onto_name);
 		if (!options.onto)
-- 
gitgitgadget


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

* [PATCH v2 03/11] builtin rebase: handle the pre-rebase hook and --no-verify
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 01/11] builtin rebase: support --onto Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 02/11] builtin rebase: support `git rebase --onto A...B` Pratik Karki via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 04/11] builtin rebase: support --quiet Pratik Karki via GitGitGadget
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit converts the equivalent part of the shell script
`git-legacy-rebase.sh` to run the pre-rebase hook (unless disabled), and
to interrupt the rebase with error if the hook fails.

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 38c496dd10..b79f9b0a9f 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -70,6 +70,7 @@ struct rebase_options {
 	const char *state_dir;
 	struct commit *upstream;
 	const char *upstream_name;
+	const char *upstream_arg;
 	char *head_name;
 	struct object_id orig_head;
 	struct commit *onto;
@@ -310,6 +311,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	};
 	const char *branch_name;
 	int ret, flags;
+	int ok_to_skip_pre_rebase = 0;
 	struct strbuf msg = STRBUF_INIT;
 	struct strbuf revisions = STRBUF_INIT;
 	struct object_id merge_base;
@@ -317,6 +319,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		OPT_STRING(0, "onto", &options.onto_name,
 			   N_("revision"),
 			   N_("rebase onto given branch instead of upstream")),
+		OPT_BOOL(0, "no-verify", &ok_to_skip_pre_rebase,
+			 N_("allow pre-rebase hook to run")),
 		OPT_END(),
 	};
 
@@ -382,6 +386,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		options.upstream = peel_committish(options.upstream_name);
 		if (!options.upstream)
 			die(_("invalid upstream '%s'"), options.upstream_name);
+		options.upstream_arg = options.upstream_name;
 	} else
 		die("TODO: upstream for --root");
 
@@ -430,6 +435,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			die(_("Could not resolve HEAD to a revision"));
 	}
 
+	/* If a hook exists, give it a chance to interrupt*/
+	if (!ok_to_skip_pre_rebase &&
+	    run_hook_le(NULL, "pre-rebase", options.upstream_arg,
+			argc ? argv[0] : NULL, NULL))
+		die(_("The pre-rebase hook refused to rebase."));
+
 	strbuf_addf(&msg, "rebase: checkout %s", options.onto_name);
 	if (reset_head(&options.onto->object.oid, "checkout", NULL, 1))
 		die(_("Could not detach HEAD"));
-- 
gitgitgadget


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

* [PATCH v2 04/11] builtin rebase: support --quiet
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
                     ` (2 preceding siblings ...)
  2018-09-04 21:27   ` [PATCH v2 03/11] builtin rebase: handle the pre-rebase hook and --no-verify Pratik Karki via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 05/11] builtin rebase: support the `verbose` and `diffstat` options Pratik Karki via GitGitGadget
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit introduces a rebase option `--quiet`. While `--quiet` is
commonly perceived as opposite to `--verbose`, this is not the case for
the rebase command: both `--quiet` and `--verbose` default to `false` if
neither `--quiet` nor `--verbose` is present.

Despite the default being `false` for both verbose and quiet mode,
passing the `--quiet` option will turn off verbose mode, and `--verbose`
will turn off quiet mode.

This patch introduces the `flags` bit field, with `REBASE_NO_QUIET`
as first user (with many more to come).

We do *not* use `REBASE_QUIET` here for an important reason: To keep the
implementation simple, this commit introduces `--no-quiet` instead of
`--quiet`, so that a single `OPT_NEGBIT()` can turn on quiet mode and
turn off verbose and diffstat mode at the same time. Likewise, the
companion commit which will introduce support for `--verbose` will have
a single `OPT_BIT()` that turns off quiet mode and turns on verbose and
diffstat mode at the same time.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index b79f9b0a9f..19fa4d3fc4 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -79,6 +79,10 @@ struct rebase_options {
 	int root;
 	struct commit *restrict_revision;
 	int dont_finish_rebase;
+	enum {
+		REBASE_NO_QUIET = 1<<0,
+	} flags;
+	struct strbuf git_am_opt;
 };
 
 /* Returns the filename prefixed by the state_dir */
@@ -159,6 +163,9 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "revisions", opts->revisions);
 	add_var(&script_snippet, "restrict_revision", opts->restrict_revision ?
 		oid_to_hex(&opts->restrict_revision->object.oid) : NULL);
+	add_var(&script_snippet, "GIT_QUIET",
+		opts->flags & REBASE_NO_QUIET ? "" : "t");
+	add_var(&script_snippet, "git_am_opt", opts->git_am_opt.buf);
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -308,6 +315,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
 	struct rebase_options options = {
 		.type = REBASE_UNSPECIFIED,
+		.flags = REBASE_NO_QUIET,
+		.git_am_opt = STRBUF_INIT,
 	};
 	const char *branch_name;
 	int ret, flags;
@@ -321,6 +330,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			   N_("rebase onto given branch instead of upstream")),
 		OPT_BOOL(0, "no-verify", &ok_to_skip_pre_rebase,
 			 N_("allow pre-rebase hook to run")),
+		OPT_NEGBIT('q', "quiet", &options.flags,
+			   N_("be quiet. implies --no-stat"),
+			   REBASE_NO_QUIET),
 		OPT_END(),
 	};
 
@@ -357,6 +369,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		usage_with_options(builtin_rebase_usage,
 				   builtin_rebase_options);
 
+	if (!(options.flags & REBASE_NO_QUIET))
+		strbuf_addstr(&options.git_am_opt, " -q");
+
 	switch (options.type) {
 	case REBASE_MERGE:
 	case REBASE_INTERACTIVE:
-- 
gitgitgadget


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

* [PATCH v2 05/11] builtin rebase: support the `verbose` and `diffstat` options
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
                     ` (3 preceding siblings ...)
  2018-09-04 21:27   ` [PATCH v2 04/11] builtin rebase: support --quiet Pratik Karki via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 06/11] builtin rebase: require a clean worktree Pratik Karki via GitGitGadget
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit introduces support for the `-v` and `--stat` options of
rebase.

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

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 19fa4d3fc4..2d3f1d65fb 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -18,6 +18,7 @@
 #include "lockfile.h"
 #include "parse-options.h"
 #include "commit.h"
+#include "diff.h"
 
 static char const * const builtin_rebase_usage[] = {
 	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -81,6 +82,8 @@ struct rebase_options {
 	int dont_finish_rebase;
 	enum {
 		REBASE_NO_QUIET = 1<<0,
+		REBASE_VERBOSE = 1<<1,
+		REBASE_DIFFSTAT = 1<<2,
 	} flags;
 	struct strbuf git_am_opt;
 };
@@ -166,6 +169,10 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "GIT_QUIET",
 		opts->flags & REBASE_NO_QUIET ? "" : "t");
 	add_var(&script_snippet, "git_am_opt", opts->git_am_opt.buf);
+	add_var(&script_snippet, "verbose",
+		opts->flags & REBASE_VERBOSE ? "t" : "");
+	add_var(&script_snippet, "diffstat",
+		opts->flags & REBASE_DIFFSTAT ? "t" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -311,6 +318,21 @@ static int reset_head(struct object_id *oid, const char *action,
 	return ret;
 }
 
+static int rebase_config(const char *var, const char *value, void *data)
+{
+	struct rebase_options *opts = data;
+
+	if (!strcmp(var, "rebase.stat")) {
+		if (git_config_bool(var, value))
+			opts->flags |= REBASE_DIFFSTAT;
+		else
+			opts->flags &= !REBASE_DIFFSTAT;
+		return 0;
+	}
+
+	return git_default_config(var, value, data);
+}
+
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
 	struct rebase_options options = {
@@ -332,7 +354,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			 N_("allow pre-rebase hook to run")),
 		OPT_NEGBIT('q', "quiet", &options.flags,
 			   N_("be quiet. implies --no-stat"),
-			   REBASE_NO_QUIET),
+			   REBASE_NO_QUIET| REBASE_VERBOSE | REBASE_DIFFSTAT),
+		OPT_BIT('v', "verbose", &options.flags,
+			N_("display a diffstat of what changed upstream"),
+			REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),
+		{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
+			N_("do not show diffstat of what changed upstream"),
+			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
 		OPT_END(),
 	};
 
@@ -360,7 +388,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	trace_repo_setup(prefix);
 	setup_work_tree();
 
-	git_config(git_default_config, NULL);
+	git_config(rebase_config, &options);
+
 	argc = parse_options(argc, argv, prefix,
 			     builtin_rebase_options,
 			     builtin_rebase_usage, 0);
@@ -456,6 +485,33 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			argc ? argv[0] : NULL, NULL))
 		die(_("The pre-rebase hook refused to rebase."));
 
+	if (options.flags & REBASE_DIFFSTAT) {
+		struct diff_options opts;
+
+		if (options.flags & REBASE_VERBOSE)
+			printf(_("Changes from %s to %s:\n"),
+				oid_to_hex(&merge_base),
+				oid_to_hex(&options.onto->object.oid));
+
+		/* We want color (if set), but no pager */
+		diff_setup(&opts);
+		opts.stat_width = -1; /* use full terminal width */
+		opts.stat_graph_width = -1; /* respect statGraphWidth config */
+		opts.output_format |=
+			DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+		opts.detect_rename = DIFF_DETECT_RENAME;
+		diff_setup_done(&opts);
+		diff_tree_oid(&merge_base, &options.onto->object.oid,
+			      "", &opts);
+		diffcore_std(&opts);
+		diff_flush(&opts);
+	}
+
+	/* Detach HEAD and reset the tree */
+	if (options.flags & REBASE_NO_QUIET)
+		printf(_("First, rewinding head to replay your work on top of "
+			 "it...\n"));
+
 	strbuf_addf(&msg, "rebase: checkout %s", options.onto_name);
 	if (reset_head(&options.onto->object.oid, "checkout", NULL, 1))
 		die(_("Could not detach HEAD"));
-- 
gitgitgadget


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

* [PATCH v2 06/11] builtin rebase: require a clean worktree
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
                     ` (4 preceding siblings ...)
  2018-09-04 21:27   ` [PATCH v2 05/11] builtin rebase: support the `verbose` and `diffstat` options Pratik Karki via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 07/11] builtin rebase: try to fast forward when possible Pratik Karki via GitGitGadget
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit reads the index of the repository for rebase and checks
whether the repository is ready for rebase.

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 2d3f1d65fb..afef0b0046 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -19,6 +19,7 @@
 #include "parse-options.h"
 #include "commit.h"
 #include "diff.h"
+#include "wt-status.h"
 
 static char const * const builtin_rebase_usage[] = {
 	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -479,6 +480,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 			die(_("Could not resolve HEAD to a revision"));
 	}
 
+	if (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;
+		goto cleanup;
+	}
+
 	/* If a hook exists, give it a chance to interrupt*/
 	if (!ok_to_skip_pre_rebase &&
 	    run_hook_le(NULL, "pre-rebase", options.upstream_arg,
@@ -528,6 +538,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 	ret = !!run_specific_rebase(&options);
 
+cleanup:
 	strbuf_release(&revisions);
 	free(options.head_name);
 	return ret;
-- 
gitgitgadget


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

* [PATCH v2 07/11] builtin rebase: try to fast forward when possible
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
                     ` (5 preceding siblings ...)
  2018-09-04 21:27   ` [PATCH v2 06/11] builtin rebase: require a clean worktree Pratik Karki via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 08/11] builtin rebase: support --force-rebase Pratik Karki via GitGitGadget
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

In this commit, we add support to fast forward.

Note: we will need the merge base later, therefore the call to
can_fast_forward() really needs to be the first one when testing whether
we can skip the rebase entirely (otherwise, it would make more sense to
skip the possibly expensive operation if, say, running an interactive
rebase).

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index afef0b0046..d67df28efc 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -20,6 +20,7 @@
 #include "commit.h"
 #include "diff.h"
 #include "wt-status.h"
+#include "revision.h"
 
 static char const * const builtin_rebase_usage[] = {
 	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
@@ -89,6 +90,12 @@ struct rebase_options {
 	struct strbuf git_am_opt;
 };
 
+static int is_interactive(struct rebase_options *opts)
+{
+	return opts->type == REBASE_INTERACTIVE ||
+		opts->type == REBASE_PRESERVE_MERGES;
+}
+
 /* Returns the filename prefixed by the state_dir */
 static const char *state_dir_path(const char *filename, struct rebase_options *opts)
 {
@@ -334,6 +341,46 @@ static int rebase_config(const char *var, const char *value, void *data)
 	return git_default_config(var, value, data);
 }
 
+/*
+ * Determines whether the commits in from..to are linear, i.e. contain
+ * no merge commits. This function *expects* `from` to be an ancestor of
+ * `to`.
+ */
+static int is_linear_history(struct commit *from, struct commit *to)
+{
+	while (to && to != from) {
+		parse_commit(to);
+		if (!to->parents)
+			return 1;
+		if (to->parents->next)
+			return 0;
+		to = to->parents->item;
+	}
+	return 1;
+}
+
+static int can_fast_forward(struct commit *onto, struct object_id *head_oid,
+			    struct object_id *merge_base)
+{
+	struct commit *head = lookup_commit(the_repository, head_oid);
+	struct commit_list *merge_bases;
+	int res;
+
+	if (!head)
+		return 0;
+
+	merge_bases = get_merge_bases(onto, head);
+	if (merge_bases && !merge_bases->next) {
+		oidcpy(merge_base, &merge_bases->item->object.oid);
+		res = !oidcmp(merge_base, &onto->object.oid);
+	} else {
+		oidcpy(merge_base, &null_oid);
+		res = 0;
+	}
+	free_commit_list(merge_bases);
+	return res && is_linear_history(onto, head);
+}
+
 int cmd_rebase(int argc, const char **argv, const char *prefix)
 {
 	struct rebase_options options = {
@@ -489,6 +536,31 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		goto cleanup;
 	}
 
+	/*
+	 * Now we are rebasing commits upstream..orig_head (or with --root,
+	 * everything leading up to orig_head) on top of onto.
+	 */
+
+	/*
+	 * Check if we are already based on onto with linear history,
+	 * but this should be done only when upstream and onto are the same
+	 * and if this is not an interactive rebase.
+	 */
+	if (can_fast_forward(options.onto, &options.orig_head, &merge_base) &&
+	    !is_interactive(&options) && !options.restrict_revision &&
+	    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
+		int flag;
+
+		if (!(options.flags & REBASE_NO_QUIET))
+			; /* be quiet */
+		else if (!strcmp(branch_name, "HEAD") &&
+			 resolve_ref_unsafe("HEAD", 0, NULL, &flag))
+			puts(_("HEAD is up to date, rebase forced."));
+		else
+			printf(_("Current branch %s is up to date, rebase "
+				 "forced.\n"), branch_name);
+	}
+
 	/* If a hook exists, give it a chance to interrupt*/
 	if (!ok_to_skip_pre_rebase &&
 	    run_hook_le(NULL, "pre-rebase", options.upstream_arg,
-- 
gitgitgadget


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

* [PATCH v2 08/11] builtin rebase: support --force-rebase
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
                     ` (6 preceding siblings ...)
  2018-09-04 21:27   ` [PATCH v2 07/11] builtin rebase: try to fast forward when possible Pratik Karki via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 09/11] builtin rebase: start a new rebase only if none is in progress Pratik Karki via GitGitGadget
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

In this commit, we add support to `--force-rebase` option. The
equivalent part of the shell script found in `git-legacy-rebase.sh` is
converted as faithfully as possible to C.

The --force-rebase option ensures that the rebase does not simply
fast-forward even if it could.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index d67df28efc..8a7bf3d468 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -86,6 +86,7 @@ struct rebase_options {
 		REBASE_NO_QUIET = 1<<0,
 		REBASE_VERBOSE = 1<<1,
 		REBASE_DIFFSTAT = 1<<2,
+		REBASE_FORCE = 1<<3,
 	} flags;
 	struct strbuf git_am_opt;
 };
@@ -181,6 +182,8 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->flags & REBASE_VERBOSE ? "t" : "");
 	add_var(&script_snippet, "diffstat",
 		opts->flags & REBASE_DIFFSTAT ? "t" : "");
+	add_var(&script_snippet, "force_rebase",
+		opts->flags & REBASE_FORCE ? "t" : "");
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -409,6 +412,12 @@ 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_BIT('f', "force-rebase", &options.flags,
+			N_("cherry-pick all commits, even if unchanged"),
+			REBASE_FORCE),
+		OPT_BIT(0, "no-ff", &options.flags,
+			N_("cherry-pick all commits, even if unchanged"),
+			REBASE_FORCE),
 		OPT_END(),
 	};
 
@@ -551,7 +560,18 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	    !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) {
 		int flag;
 
-		if (!(options.flags & REBASE_NO_QUIET))
+		if (!(options.flags & REBASE_FORCE)) {
+			if (!(options.flags & REBASE_NO_QUIET))
+				; /* be quiet */
+			else if (!strcmp(branch_name, "HEAD") &&
+				 resolve_ref_unsafe("HEAD", 0, NULL, &flag))
+				puts(_("HEAD is up to date."));
+			else
+				printf(_("Current branch %s is up to date.\n"),
+				       branch_name);
+			ret = !!finish_rebase(&options);
+			goto cleanup;
+		} else if (!(options.flags & REBASE_NO_QUIET))
 			; /* be quiet */
 		else if (!strcmp(branch_name, "HEAD") &&
 			 resolve_ref_unsafe("HEAD", 0, NULL, &flag))
-- 
gitgitgadget


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

* [PATCH v2 09/11] builtin rebase: start a new rebase only if none is in progress
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
                     ` (7 preceding siblings ...)
  2018-09-04 21:27   ` [PATCH v2 08/11] builtin rebase: support --force-rebase Pratik Karki via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name` Pratik Karki via GitGitGadget
  2018-09-04 21:27   ` [PATCH v2 11/11] builtin rebase: support `git rebase <upstream> <switch-to>` Pratik Karki via GitGitGadget
  10 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

To run a new rebase, there needs to be a check to assure that no other
rebase is in progress. New rebase operation cannot start until an
ongoing rebase operation completes or is terminated.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 8a7bf3d468..d45f8f9008 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -87,6 +87,7 @@ struct rebase_options {
 		REBASE_VERBOSE = 1<<1,
 		REBASE_DIFFSTAT = 1<<2,
 		REBASE_FORCE = 1<<3,
+		REBASE_INTERACTIVE_EXPLICIT = 1<<4,
 	} flags;
 	struct strbuf git_am_opt;
 };
@@ -392,10 +393,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		.git_am_opt = STRBUF_INIT,
 	};
 	const char *branch_name;
-	int ret, flags;
+	int ret, flags, in_progress = 0;
 	int ok_to_skip_pre_rebase = 0;
 	struct strbuf msg = STRBUF_INIT;
 	struct strbuf revisions = STRBUF_INIT;
+	struct strbuf buf = STRBUF_INIT;
 	struct object_id merge_base;
 	struct option builtin_rebase_options[] = {
 		OPT_STRING(0, "onto", &options.onto_name,
@@ -447,6 +449,30 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 
 	git_config(rebase_config, &options);
 
+	if (is_directory(apply_dir())) {
+		options.type = REBASE_AM;
+		options.state_dir = apply_dir();
+	} else if (is_directory(merge_dir())) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "%s/rewritten", merge_dir());
+		if (is_directory(buf.buf)) {
+			options.type = REBASE_PRESERVE_MERGES;
+			options.flags |= REBASE_INTERACTIVE_EXPLICIT;
+		} else {
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "%s/interactive", merge_dir());
+			if(file_exists(buf.buf)) {
+				options.type = REBASE_INTERACTIVE;
+				options.flags |= REBASE_INTERACTIVE_EXPLICIT;
+			} else
+				options.type = REBASE_MERGE;
+		}
+		options.state_dir = merge_dir();
+	}
+
+	if (options.type != REBASE_UNSPECIFIED)
+		in_progress = 1;
+
 	argc = parse_options(argc, argv, prefix,
 			     builtin_rebase_options,
 			     builtin_rebase_usage, 0);
@@ -455,6 +481,26 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		usage_with_options(builtin_rebase_usage,
 				   builtin_rebase_options);
 
+	/* Make sure no rebase is in progress */
+	if (in_progress) {
+		const char *last_slash = strrchr(options.state_dir, '/');
+		const char *state_dir_base =
+			last_slash ? last_slash + 1 : options.state_dir;
+		const char *cmd_live_rebase =
+			"git rebase (--continue | --abort | --skip)";
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "rm -fr \"%s\"", options.state_dir);
+		die(_("It seems that there is already a %s directory, and\n"
+		      "I wonder if you are in the middle of another rebase.  "
+		      "If that is the\n"
+		      "case, please try\n\t%s\n"
+		      "If that is not the case, please\n\t%s\n"
+		      "and run me again.  I am stopping in case you still "
+		      "have something\n"
+		      "valuable there.\n"),
+		    state_dir_base, cmd_live_rebase, buf.buf);
+	}
+
 	if (!(options.flags & REBASE_NO_QUIET))
 		strbuf_addstr(&options.git_am_opt, " -q");
 
-- 
gitgitgadget


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

* [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name`
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
                     ` (8 preceding siblings ...)
  2018-09-04 21:27   ` [PATCH v2 09/11] builtin rebase: start a new rebase only if none is in progress Pratik Karki via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  2018-09-08  8:52     ` SZEDER Gábor
  2018-09-04 21:27   ` [PATCH v2 11/11] builtin rebase: support `git rebase <upstream> <switch-to>` Pratik Karki via GitGitGadget
  10 siblings, 1 reply; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

When running a rebase on a detached HEAD, we currently store the string
"detached HEAD" in options.head_name. That is a faithful translation of
the shell script version, and we still kind of need it for the purposes of
the scripted backends.

It is poor style for C, though, where we would really only want a valid,
fully-qualified ref name as value, and NULL for detached HEADs, using
"detached HEAD" for display only. Make it so.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index d45f8f9008..afc75fe731 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -169,7 +169,8 @@ static int run_specific_rebase(struct rebase_options *opts)
 	add_var(&script_snippet, "upstream_name", opts->upstream_name);
 	add_var(&script_snippet, "upstream",
 				 oid_to_hex(&opts->upstream->object.oid));
-	add_var(&script_snippet, "head_name", opts->head_name);
+	add_var(&script_snippet, "head_name",
+		opts->head_name ? opts->head_name : "detached HEAD");
 	add_var(&script_snippet, "orig_head", oid_to_hex(&opts->orig_head));
 	add_var(&script_snippet, "onto", oid_to_hex(&opts->onto->object.oid));
 	add_var(&script_snippet, "onto_name", opts->onto_name);
@@ -251,6 +252,9 @@ static int reset_head(struct object_id *oid, const char *action,
 		*old_orig = NULL, oid_old_orig;
 	int ret = 0;
 
+	if (switch_to_branch && !starts_with(switch_to_branch, "refs/"))
+		BUG("Not a fully qualified branch: '%s'", switch_to_branch);
+
 	if (hold_locked_index(&lock, LOCK_REPORT_ON_ERROR) < 0)
 		return -1;
 
@@ -558,7 +562,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	 * branch_name -- branch/commit being rebased, or
 	 * 		  HEAD (already detached)
 	 * orig_head -- commit object name of tip of the branch before rebasing
-	 * head_name -- refs/heads/<that-branch> or "detached HEAD"
+	 * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)
 	 */
 	if (argc > 0)
 		 die("TODO: handle switch_to");
@@ -575,7 +579,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 				branch_name = options.head_name;
 
 		} else {
-			options.head_name = xstrdup("detached HEAD");
+			free(options.head_name);
+			options.head_name = NULL;
 			branch_name = "HEAD";
 		}
 		if (get_oid("HEAD", &options.orig_head))
-- 
gitgitgadget


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

* [PATCH v2 11/11] builtin rebase: support `git rebase <upstream> <switch-to>`
  2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
                     ` (9 preceding siblings ...)
  2018-09-04 21:27   ` [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name` Pratik Karki via GitGitGadget
@ 2018-09-04 21:27   ` Pratik Karki via GitGitGadget
  10 siblings, 0 replies; 42+ messages in thread
From: Pratik Karki via GitGitGadget @ 2018-09-04 21:27 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Pratik Karki

From: Pratik Karki <predatoramigo@gmail.com>

This commit adds support for `switch-to` which is used to switch to the
target branch if needed. The equivalent codes found in shell script
`git-legacy-rebase.sh` is converted to builtin `rebase.c`.

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

diff --git a/builtin/rebase.c b/builtin/rebase.c
index afc75fe731..e817956d96 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -79,6 +79,7 @@ struct rebase_options {
 	struct commit *onto;
 	const char *onto_name;
 	const char *revisions;
+	const char *switch_to;
 	int root;
 	struct commit *restrict_revision;
 	int dont_finish_rebase;
@@ -186,6 +187,8 @@ static int run_specific_rebase(struct rebase_options *opts)
 		opts->flags & REBASE_DIFFSTAT ? "t" : "");
 	add_var(&script_snippet, "force_rebase",
 		opts->flags & REBASE_FORCE ? "t" : "");
+	if (opts->switch_to)
+		add_var(&script_snippet, "switch_to", opts->switch_to);
 
 	switch (opts->type) {
 	case REBASE_AM:
@@ -564,9 +567,23 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	 * orig_head -- commit object name of tip of the branch before rebasing
 	 * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)
 	 */
-	if (argc > 0)
-		 die("TODO: handle switch_to");
-	else {
+	if (argc == 1) {
+		/* Is it "rebase other branchname" or "rebase other commit"? */
+		branch_name = argv[0];
+		options.switch_to = argv[0];
+
+		/* Is it a local branch? */
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "refs/heads/%s", branch_name);
+		if (!read_ref(buf.buf, &options.orig_head))
+			options.head_name = xstrdup(buf.buf);
+		/* If not is it a valid ref (branch or commit)? */
+		else if (!get_oid(branch_name, &options.orig_head))
+			options.head_name = NULL;
+		else
+			die(_("fatal: no such branch/commit '%s'"),
+			    branch_name);
+	} else if (argc == 0) {
 		/* Do not need to switch branches, we are already on it. */
 		options.head_name =
 			xstrdup_or_null(resolve_ref_unsafe("HEAD", 0, NULL,
@@ -585,7 +602,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		}
 		if (get_oid("HEAD", &options.orig_head))
 			die(_("Could not resolve HEAD to a revision"));
-	}
+	} else
+		BUG("unexpected number of arguments left to parse");
 
 	if (read_index(the_repository->index) < 0)
 		die(_("could not read index"));
@@ -612,6 +630,28 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		int flag;
 
 		if (!(options.flags & REBASE_FORCE)) {
+			/* Lazily switch to the target branch if needed... */
+			if (options.switch_to) {
+				struct object_id oid;
+
+				if (get_oid(options.switch_to, &oid) < 0) {
+					ret = !!error(_("could not parse '%s'"),
+						      options.switch_to);
+					goto cleanup;
+				}
+
+				strbuf_reset(&buf);
+				strbuf_addf(&buf, "rebase: checkout %s",
+					    options.switch_to);
+				if (reset_head(&oid, "checkout",
+					       options.head_name, 0) < 0) {
+					ret = !!error(_("could not switch to "
+							"%s"),
+						      options.switch_to);
+					goto cleanup;
+				}
+			}
+
 			if (!(options.flags & REBASE_NO_QUIET))
 				; /* be quiet */
 			else if (!strcmp(branch_name, "HEAD") &&
-- 
gitgitgadget

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

* Re: [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name`
  2018-09-04 21:27   ` [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name` Pratik Karki via GitGitGadget
@ 2018-09-08  8:52     ` SZEDER Gábor
  2018-09-10 16:55       ` Junio C Hamano
  0 siblings, 1 reply; 42+ messages in thread
From: SZEDER Gábor @ 2018-09-08  8:52 UTC (permalink / raw)
  To: Pratik Karki via GitGitGadget
  Cc: git, Junio C Hamano, Pratik Karki, Johannes Schindelin

On Tue, Sep 04, 2018 at 02:27:20PM -0700, Pratik Karki via GitGitGadget wrote:
> From: Pratik Karki <predatoramigo@gmail.com>
> 
> When running a rebase on a detached HEAD, we currently store the string
> "detached HEAD" in options.head_name. That is a faithful translation of
> the shell script version, and we still kind of need it for the purposes of
> the scripted backends.
> 
> It is poor style for C, though, where we would really only want a valid,
> fully-qualified ref name as value, and NULL for detached HEADs, using
> "detached HEAD" for display only. Make it so.
> 
> Signed-off-by: Pratik Karki <predatoramigo@gmail.com>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/rebase.c | 11 ++++++++---
>  1 file changed, 8 insertions(+), 3 deletions(-)
> 
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index d45f8f9008..afc75fe731 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c

> @@ -575,7 +579,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>  				branch_name = options.head_name;
>  
>  		} else {
> -			options.head_name = xstrdup("detached HEAD");
> +			free(options.head_name);
> +			options.head_name = NULL;

Please use FREE_AND_NULL(options.head_name) here.

>  			branch_name = "HEAD";
>  		}
>  		if (get_oid("HEAD", &options.orig_head))
> -- 
> gitgitgadget
> 

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

* Re: [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name`
  2018-09-08  8:52     ` SZEDER Gábor
@ 2018-09-10 16:55       ` Junio C Hamano
  2018-09-10 20:25         ` SZEDER Gábor
  0 siblings, 1 reply; 42+ messages in thread
From: Junio C Hamano @ 2018-09-10 16:55 UTC (permalink / raw)
  To: SZEDER Gábor
  Cc: Pratik Karki via GitGitGadget, git, Pratik Karki, Johannes Schindelin

SZEDER Gábor <szeder.dev@gmail.com> writes:

>>  		} else {
>> -			options.head_name = xstrdup("detached HEAD");
>> +			free(options.head_name);
>> +			options.head_name = NULL;
>
> Please use FREE_AND_NULL(options.head_name) here.

Good; did contrib/coccinelle/free.cocci catch this?

>
>>  			branch_name = "HEAD";
>>  		}
>>  		if (get_oid("HEAD", &options.orig_head))
>> -- 
>> gitgitgadget
>> 

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

* Re: [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name`
  2018-09-10 16:55       ` Junio C Hamano
@ 2018-09-10 20:25         ` SZEDER Gábor
  0 siblings, 0 replies; 42+ messages in thread
From: SZEDER Gábor @ 2018-09-10 20:25 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Pratik Karki via GitGitGadget, git, Pratik Karki, Johannes Schindelin

On Mon, Sep 10, 2018 at 09:55:30AM -0700, Junio C Hamano wrote:
> SZEDER Gábor <szeder.dev@gmail.com> writes:
> 
> >>  		} else {
> >> -			options.head_name = xstrdup("detached HEAD");
> >> +			free(options.head_name);
> >> +			options.head_name = NULL;
> >
> > Please use FREE_AND_NULL(options.head_name) here.
> 
> Good; did contrib/coccinelle/free.cocci catch this?

Yes.

But now that you mention it, I see that it didn't catch it in 'pu' or
in most of the later 'pk/rebase-in-c-X-...' branches, even though they
all have these lines.  It bisects to 0073df2bd3 (builtin rebase:
support --rebase-merges[=[no-]rebase-cousins], 2018-09-04), which
doesn't touch these lines at all.

Strange; I have no idea what's going on.


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

end of thread, other threads:[~2018-09-10 20:25 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-08 13:48 [GSoC] [PATCH 00/11] A minimal builtin rebase Pratik Karki
2018-08-08 13:48 ` [PATCH 01/11] builtin rebase: support --onto Pratik Karki
2018-08-08 19:02   ` Junio C Hamano
2018-08-24 16:21     ` Johannes Schindelin
2018-08-08 13:48 ` [PATCH 02/11] builtin rebase: support `git rebase --onto A...B` Pratik Karki
2018-08-08 19:12   ` Junio C Hamano
2018-08-26 18:36     ` Johannes Schindelin
2018-08-08 13:48 ` [PATCH 03/11] builtin rebase: handle the pre-rebase hook (and add --no-verify) Pratik Karki
2018-08-08 19:32   ` Junio C Hamano
2018-08-27 12:15     ` Johannes Schindelin
2018-08-08 13:48 ` [PATCH 04/11] builtin rebase: support --quiet Pratik Karki
2018-08-08 18:31   ` Stefan Beller
2018-08-08 19:37     ` Junio C Hamano
2018-08-27 12:31       ` Johannes Schindelin
2018-08-08 13:48 ` [PATCH 05/11] builtin rebase: support the `verbose` and `diffstat` options Pratik Karki
2018-08-08 13:48 ` [PATCH 06/11] builtin rebase: require a clean worktree Pratik Karki
2018-08-08 13:48 ` [PATCH 07/11] builtin rebase: try to fast forward when possible Pratik Karki
2018-08-08 13:48 ` [PATCH 08/11] builtin rebase: support --force-rebase Pratik Karki
2018-08-08 18:51   ` Stefan Beller
2018-08-24 16:10     ` Johannes Schindelin
2018-08-08 13:48 ` [PATCH 09/11] builtin rebase: start a new rebase only if none is in progress Pratik Karki
2018-08-08 18:59   ` Stefan Beller
2018-08-24 16:13     ` Johannes Schindelin
2018-08-08 13:48 ` [PATCH 10/11] builtin rebase: only store fully-qualified refs in `options.head_name` Pratik Karki
2018-08-08 13:48 ` [PATCH 11/11] builtin rebase: support `git rebase <upstream> <switch-to>` Pratik Karki
2018-08-08 16:03   ` Duy Nguyen
2018-08-08 18:52     ` Johannes Schindelin
2018-09-04 21:27 ` [PATCH v2 00/11] A minimal builtin rebase Johannes Schindelin via GitGitGadget
2018-09-04 21:27   ` [PATCH v2 01/11] builtin rebase: support --onto Pratik Karki via GitGitGadget
2018-09-04 21:27   ` [PATCH v2 02/11] builtin rebase: support `git rebase --onto A...B` Pratik Karki via GitGitGadget
2018-09-04 21:27   ` [PATCH v2 03/11] builtin rebase: handle the pre-rebase hook and --no-verify Pratik Karki via GitGitGadget
2018-09-04 21:27   ` [PATCH v2 04/11] builtin rebase: support --quiet Pratik Karki via GitGitGadget
2018-09-04 21:27   ` [PATCH v2 05/11] builtin rebase: support the `verbose` and `diffstat` options Pratik Karki via GitGitGadget
2018-09-04 21:27   ` [PATCH v2 06/11] builtin rebase: require a clean worktree Pratik Karki via GitGitGadget
2018-09-04 21:27   ` [PATCH v2 07/11] builtin rebase: try to fast forward when possible Pratik Karki via GitGitGadget
2018-09-04 21:27   ` [PATCH v2 08/11] builtin rebase: support --force-rebase Pratik Karki via GitGitGadget
2018-09-04 21:27   ` [PATCH v2 09/11] builtin rebase: start a new rebase only if none is in progress Pratik Karki via GitGitGadget
2018-09-04 21:27   ` [PATCH v2 10/11] builtin rebase: only store fully-qualified refs in `options.head_name` Pratik Karki via GitGitGadget
2018-09-08  8:52     ` SZEDER Gábor
2018-09-10 16:55       ` Junio C Hamano
2018-09-10 20:25         ` SZEDER Gábor
2018-09-04 21:27   ` [PATCH v2 11/11] builtin rebase: support `git rebase <upstream> <switch-to>` Pratik Karki via GitGitGadget

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).