git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / code / Atom feed
* [PATCH v8 00/10] Reject non-ff pulls by default
@ 2020-11-25  3:29 Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 01/10] pull: refactor fast-forward check Felipe Contreras
                   ` (9 more replies)
  0 siblings, 10 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

This is an attempt to revive the old patch series [1].

Since v7 of the series the pull.mode configuration is added, and the warning has been updated to
make use of that.

What is missing from the old series is:
  * Add git pull --merge
  * Actually change the default to ff-only

Cheers.

[1] https://lore.kernel.org/git/1398988808-29678-1-git-send-email-felipe.contreras@gmail.com/


Felipe Contreras (10):
  pull: refactor fast-forward check
  pull: cleanup autostash check
  pull: trivial cleanup
  pull: move default warning
  pull: display default warning only when non-ff
  test: pull-options: revert unnecessary changes
  rebase: add REBASE_DEFAULT
  pull: add pull.mode
  pull: add pull.mode=ff-only
  pull: improve default warning

 Documentation/config/branch.txt |   6 ++
 Documentation/config/pull.txt   |   6 ++
 Documentation/git-pull.txt      |  17 ++++
 builtin/pull.c                  | 146 ++++++++++++++++++++++----------
 builtin/remote.c                |  22 ++++-
 rebase.c                        |  12 +++
 rebase.h                        |  13 ++-
 t/t5520-pull.sh                 |  92 ++++++++++++++++++++
 t/t5521-pull-options.sh         |  22 ++---
 t/t7601-merge-pull-config.sh    |  49 ++++-------
 10 files changed, 297 insertions(+), 88 deletions(-)

-- 
2.29.2


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

* [PATCH v8 01/10] pull: refactor fast-forward check
  2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
@ 2020-11-25  3:29 ` Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 02/10] pull: cleanup autostash check Felipe Contreras
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

This way we will be able to do the check unconditionally (merge or
rebase).

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 builtin/pull.c | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index 17aa63cd35..e2de0d4c91 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -906,6 +906,20 @@ static int run_rebase(const struct object_id *curr_head,
 	return ret;
 }
 
+static int get_can_ff(struct object_id *orig_head, struct object_id *orig_merge_head)
+{
+	int ret;
+	struct commit_list *list = NULL;
+	struct commit *merge_head, *head;
+
+	head = lookup_commit_reference(the_repository, orig_head);
+	commit_list_insert(head, &list);
+	merge_head = lookup_commit_reference(the_repository, orig_merge_head);
+	ret = repo_is_descendant_of(the_repository, merge_head, list);
+	free_commit_list(list);
+	return ret;
+}
+
 int cmd_pull(int argc, const char **argv, const char *prefix)
 {
 	const char *repo, **refspecs;
@@ -1016,22 +1030,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 		    submodule_touches_in_range(the_repository, &rebase_fork_point, &curr_head))
 			die(_("cannot rebase with locally recorded submodule modifications"));
 		if (!autostash) {
-			struct commit_list *list = NULL;
-			struct commit *merge_head, *head;
-
-			head = lookup_commit_reference(the_repository,
-						       &orig_head);
-			commit_list_insert(head, &list);
-			merge_head = lookup_commit_reference(the_repository,
-							     &merge_heads.oid[0]);
-			if (repo_is_descendant_of(the_repository,
-						  merge_head, list)) {
+			if (get_can_ff(&orig_head, &merge_heads.oid[0])) {
 				/* we can fast-forward this without invoking rebase */
 				opt_ff = "--ff-only";
 				ran_ff = 1;
 				ret = run_merge();
 			}
-			free_commit_list(list);
 		}
 		if (!ran_ff)
 			ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
-- 
2.29.2


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

* [PATCH v8 02/10] pull: cleanup autostash check
  2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 01/10] pull: refactor fast-forward check Felipe Contreras
@ 2020-11-25  3:29 ` Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 03/10] pull: trivial cleanup Felipe Contreras
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

This essentially reverts commit f15e7cf5cc.

Once commit d9f15d37f1 introduced the autostash option for the merge
mode, it's not necessary to skip the fast-forward run_merge() when
autostash is set.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 builtin/pull.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index e2de0d4c91..eaa268c559 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -926,7 +926,6 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	struct oid_array merge_heads = OID_ARRAY_INIT;
 	struct object_id orig_head, curr_head;
 	struct object_id rebase_fork_point;
-	int autostash;
 
 	if (!getenv("GIT_REFLOG_ACTION"))
 		set_reflog_message(argc, argv);
@@ -959,8 +958,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (get_oid("HEAD", &orig_head))
 		oidclr(&orig_head);
 
-	autostash = config_autostash;
 	if (opt_rebase) {
+		int autostash = config_autostash;
 		if (opt_autostash != -1)
 			autostash = opt_autostash;
 
@@ -1029,13 +1028,11 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 		     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) &&
 		    submodule_touches_in_range(the_repository, &rebase_fork_point, &curr_head))
 			die(_("cannot rebase with locally recorded submodule modifications"));
-		if (!autostash) {
-			if (get_can_ff(&orig_head, &merge_heads.oid[0])) {
-				/* we can fast-forward this without invoking rebase */
-				opt_ff = "--ff-only";
-				ran_ff = 1;
-				ret = run_merge();
-			}
+		if (get_can_ff(&orig_head, &merge_heads.oid[0])) {
+			/* we can fast-forward this without invoking rebase */
+			opt_ff = "--ff-only";
+			ran_ff = 1;
+			ret = run_merge();
 		}
 		if (!ran_ff)
 			ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
-- 
2.29.2


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

* [PATCH v8 03/10] pull: trivial cleanup
  2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 01/10] pull: refactor fast-forward check Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 02/10] pull: cleanup autostash check Felipe Contreras
@ 2020-11-25  3:29 ` Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 04/10] pull: move default warning Felipe Contreras
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

There's no need to store ran_ff. Now it's obvious from the conditionals.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 builtin/pull.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index eaa268c559..121b9fb0e1 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -1023,19 +1023,18 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 	if (opt_rebase) {
 		int ret = 0;
-		int ran_ff = 0;
 		if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
 		     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) &&
 		    submodule_touches_in_range(the_repository, &rebase_fork_point, &curr_head))
 			die(_("cannot rebase with locally recorded submodule modifications"));
+
 		if (get_can_ff(&orig_head, &merge_heads.oid[0])) {
 			/* we can fast-forward this without invoking rebase */
 			opt_ff = "--ff-only";
-			ran_ff = 1;
 			ret = run_merge();
-		}
-		if (!ran_ff)
+		} else {
 			ret = run_rebase(&curr_head, merge_heads.oid, &rebase_fork_point);
+		}
 
 		if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||
 			     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))
-- 
2.29.2


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

* [PATCH v8 04/10] pull: move default warning
  2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
                   ` (2 preceding siblings ...)
  2020-11-25  3:29 ` [PATCH v8 03/10] pull: trivial cleanup Felipe Contreras
@ 2020-11-25  3:29 ` Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 05/10] pull: display default warning only when non-ff Felipe Contreras
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

Up to the point where can check if we can fast-forward or not.

No functional changes.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 builtin/pull.c | 37 ++++++++++++++++++++++---------------
 1 file changed, 22 insertions(+), 15 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index 121b9fb0e1..9a0f7937c2 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -27,6 +27,8 @@
 #include "commit-reach.h"
 #include "sequencer.h"
 
+static int default_mode;
+
 /**
  * Parses the value of --rebase. If value is a false value, returns
  * REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is
@@ -344,20 +346,7 @@ static enum rebase_type config_get_rebase(void)
 	if (!git_config_get_value("pull.rebase", &value))
 		return parse_config_rebase("pull.rebase", value, 1);
 
-	if (opt_verbosity >= 0 && !opt_ff) {
-		warning(_("Pulling without specifying how to reconcile divergent branches is\n"
-			"discouraged. You can squelch this message by running one of the following\n"
-			"commands sometime before your next pull:\n"
-			"\n"
-			"  git config pull.rebase false  # merge (the default strategy)\n"
-			"  git config pull.rebase true   # rebase\n"
-			"  git config pull.ff only       # fast-forward only\n"
-			"\n"
-			"You can replace \"git config\" with \"git config --global\" to set a default\n"
-			"preference for all repositories. You can also pass --rebase, --no-rebase,\n"
-			"or --ff-only on the command line to override the configured default per\n"
-			"invocation.\n"));
-	}
+	default_mode = 1;
 
 	return REBASE_FALSE;
 }
@@ -926,6 +915,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	struct oid_array merge_heads = OID_ARRAY_INIT;
 	struct object_id orig_head, curr_head;
 	struct object_id rebase_fork_point;
+	int can_ff;
 
 	if (!getenv("GIT_REFLOG_ACTION"))
 		set_reflog_message(argc, argv);
@@ -1021,6 +1011,23 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (opt_rebase && merge_heads.nr > 1)
 		die(_("Cannot rebase onto multiple branches."));
 
+	can_ff = get_can_ff(&orig_head, &merge_heads.oid[0]);
+
+	if (default_mode && opt_verbosity >= 0 && !opt_ff) {
+		warning(_("Pulling without specifying how to reconcile divergent branches is\n"
+			"discouraged. You can squelch this message by running one of the following\n"
+			"commands sometime before your next pull:\n"
+			"\n"
+			"  git config pull.rebase false  # merge (the default strategy)\n"
+			"  git config pull.rebase true   # rebase\n"
+			"  git config pull.ff only       # fast-forward only\n"
+			"\n"
+			"You can replace \"git config\" with \"git config --global\" to set a default\n"
+			"preference for all repositories. You can also pass --rebase, --no-rebase,\n"
+			"or --ff-only on the command line to override the configured default per\n"
+			"invocation.\n"));
+	}
+
 	if (opt_rebase) {
 		int ret = 0;
 		if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
@@ -1028,7 +1035,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 		    submodule_touches_in_range(the_repository, &rebase_fork_point, &curr_head))
 			die(_("cannot rebase with locally recorded submodule modifications"));
 
-		if (get_can_ff(&orig_head, &merge_heads.oid[0])) {
+		if (can_ff) {
 			/* we can fast-forward this without invoking rebase */
 			opt_ff = "--ff-only";
 			ret = run_merge();
-- 
2.29.2


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

* [PATCH v8 05/10] pull: display default warning only when non-ff
  2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
                   ` (3 preceding siblings ...)
  2020-11-25  3:29 ` [PATCH v8 04/10] pull: move default warning Felipe Contreras
@ 2020-11-25  3:29 ` Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 06/10] test: pull-options: revert unnecessary changes Felipe Contreras
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

There's no need to display the annoying warning on every pull... only
the ones that are not fast-forward.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 builtin/pull.c               |  2 +-
 t/t7601-merge-pull-config.sh | 28 +++++++++++++++++-----------
 2 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index 9a0f7937c2..479bdaf0ee 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -1013,7 +1013,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 	can_ff = get_can_ff(&orig_head, &merge_heads.oid[0]);
 
-	if (default_mode && opt_verbosity >= 0 && !opt_ff) {
+	if (default_mode && !can_ff && opt_verbosity >= 0 && !opt_ff) {
 		warning(_("Pulling without specifying how to reconcile divergent branches is\n"
 			"discouraged. You can squelch this message by running one of the following\n"
 			"commands sometime before your next pull:\n"
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index c5c4ea5fc0..02e2a9b2c6 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -28,59 +28,65 @@ test_expect_success 'setup' '
 '
 
 test_expect_success 'pull.rebase not set' '
-	git reset --hard c0 &&
+	git reset --hard c2 &&
 	git pull . c1 2>err &&
 	test_i18ngrep "Pulling without specifying how to reconcile" err
 '
 
-test_expect_success 'pull.rebase not set and pull.ff=true' '
+test_expect_success 'pull.rebase not set (fast-forward)' '
 	git reset --hard c0 &&
+	git pull . c1 2>err &&
+	test_i18ngrep ! "Pulling without specifying how to reconcile" err
+'
+
+test_expect_success 'pull.rebase not set and pull.ff=true' '
+	git reset --hard c2 &&
 	test_config pull.ff true &&
 	git pull . c1 2>err &&
 	test_i18ngrep ! "Pulling without specifying how to reconcile" err
 '
 
 test_expect_success 'pull.rebase not set and pull.ff=false' '
-	git reset --hard c0 &&
+	git reset --hard c2 &&
 	test_config pull.ff false &&
 	git pull . c1 2>err &&
 	test_i18ngrep ! "Pulling without specifying how to reconcile" err
 '
 
 test_expect_success 'pull.rebase not set and pull.ff=only' '
-	git reset --hard c0 &&
+	git reset --hard c2 &&
 	test_config pull.ff only &&
-	git pull . c1 2>err &&
+	test_must_fail git pull . c1 2>err &&
 	test_i18ngrep ! "Pulling without specifying how to reconcile" err
 '
 
 test_expect_success 'pull.rebase not set and --rebase given' '
-	git reset --hard c0 &&
+	git reset --hard c2 &&
 	git pull --rebase . c1 2>err &&
 	test_i18ngrep ! "Pulling without specifying how to reconcile" err
 '
 
 test_expect_success 'pull.rebase not set and --no-rebase given' '
-	git reset --hard c0 &&
+	git reset --hard c2 &&
 	git pull --no-rebase . c1 2>err &&
 	test_i18ngrep ! "Pulling without specifying how to reconcile" err
 '
 
 test_expect_success 'pull.rebase not set and --ff given' '
-	git reset --hard c0 &&
+	git reset --hard c2 &&
 	git pull --ff . c1 2>err &&
 	test_i18ngrep ! "Pulling without specifying how to reconcile" err
 '
 
 test_expect_success 'pull.rebase not set and --no-ff given' '
-	git reset --hard c0 &&
+	git reset --hard c2 &&
 	git pull --no-ff . c1 2>err &&
 	test_i18ngrep ! "Pulling without specifying how to reconcile" err
 '
 
 test_expect_success 'pull.rebase not set and --ff-only given' '
-	git reset --hard c0 &&
-	git pull --ff-only . c1 2>err &&
+	git reset --hard c2 &&
+	test_must_fail git pull --ff-only . c1 2>err &&
 	test_i18ngrep ! "Pulling without specifying how to reconcile" err
 '
 
-- 
2.29.2


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

* [PATCH v8 06/10] test: pull-options: revert unnecessary changes
  2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
                   ` (4 preceding siblings ...)
  2020-11-25  3:29 ` [PATCH v8 05/10] pull: display default warning only when non-ff Felipe Contreras
@ 2020-11-25  3:29 ` Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 07/10] rebase: add REBASE_DEFAULT Felipe Contreras
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

Commit d18c950a69 changed these tests, but it's unclear why. Probably
because earlier versions of the patch series died instead of printing a
warning.

Cc: Alex Henrie <alexhenrie24@gmail.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 t/t5521-pull-options.sh | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh
index db1a381cd9..1a4fe2583a 100755
--- a/t/t5521-pull-options.sh
+++ b/t/t5521-pull-options.sh
@@ -11,10 +11,10 @@ test_expect_success 'setup' '
 	 git commit -m one)
 '
 
-test_expect_success 'git pull -q --no-rebase' '
+test_expect_success 'git pull -q' '
 	mkdir clonedq &&
 	(cd clonedq && git init &&
-	git pull -q --no-rebase "../parent" >out 2>err &&
+	git pull -q "../parent" >out 2>err &&
 	test_must_be_empty err &&
 	test_must_be_empty out)
 '
@@ -30,10 +30,10 @@ test_expect_success 'git pull -q --rebase' '
 	test_must_be_empty out)
 '
 
-test_expect_success 'git pull --no-rebase' '
+test_expect_success 'git pull' '
 	mkdir cloned &&
 	(cd cloned && git init &&
-	git pull --no-rebase "../parent" >out 2>err &&
+	git pull "../parent" >out 2>err &&
 	test -s err &&
 	test_must_be_empty out)
 '
@@ -46,10 +46,10 @@ test_expect_success 'git pull --rebase' '
 	test_must_be_empty out)
 '
 
-test_expect_success 'git pull -v --no-rebase' '
+test_expect_success 'git pull -v' '
 	mkdir clonedv &&
 	(cd clonedv && git init &&
-	git pull -v --no-rebase "../parent" >out 2>err &&
+	git pull -v "../parent" >out 2>err &&
 	test -s err &&
 	test_must_be_empty out)
 '
@@ -62,25 +62,25 @@ test_expect_success 'git pull -v --rebase' '
 	test_must_be_empty out)
 '
 
-test_expect_success 'git pull -v -q --no-rebase' '
+test_expect_success 'git pull -v -q' '
 	mkdir clonedvq &&
 	(cd clonedvq && git init &&
-	git pull -v -q --no-rebase "../parent" >out 2>err &&
+	git pull -v -q "../parent" >out 2>err &&
 	test_must_be_empty out &&
 	test_must_be_empty err)
 '
 
-test_expect_success 'git pull -q -v --no-rebase' '
+test_expect_success 'git pull -q -v' '
 	mkdir clonedqv &&
 	(cd clonedqv && git init &&
-	git pull -q -v --no-rebase "../parent" >out 2>err &&
+	git pull -q -v "../parent" >out 2>err &&
 	test_must_be_empty out &&
 	test -s err)
 '
 test_expect_success 'git pull --cleanup errors early on invalid argument' '
 	mkdir clonedcleanup &&
 	(cd clonedcleanup && git init &&
-	test_must_fail git pull --no-rebase --cleanup invalid "../parent" >out 2>err &&
+	test_must_fail git pull --cleanup invalid "../parent" >out 2>err &&
 	test_must_be_empty out &&
 	test -s err)
 '
-- 
2.29.2


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

* [PATCH v8 07/10] rebase: add REBASE_DEFAULT
  2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
                   ` (5 preceding siblings ...)
  2020-11-25  3:29 ` [PATCH v8 06/10] test: pull-options: revert unnecessary changes Felipe Contreras
@ 2020-11-25  3:29 ` Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 08/10] pull: add pull.mode Felipe Contreras
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

So that we can distinguish when the user has forced an option.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 builtin/pull.c | 20 ++++++++------------
 rebase.h       |  3 ++-
 2 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index 479bdaf0ee..0df7d27343 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -27,8 +27,6 @@
 #include "commit-reach.h"
 #include "sequencer.h"
 
-static int default_mode;
-
 /**
  * Parses the value of --rebase. If value is a false value, returns
  * REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is
@@ -346,9 +344,7 @@ static enum rebase_type config_get_rebase(void)
 	if (!git_config_get_value("pull.rebase", &value))
 		return parse_config_rebase("pull.rebase", value, 1);
 
-	default_mode = 1;
-
-	return REBASE_FALSE;
+	return REBASE_DEFAULT;
 }
 
 /**
@@ -443,7 +439,7 @@ static void NORETURN die_no_merge_candidates(const char *repo, const char **refs
 	const char *remote = curr_branch ? curr_branch->remote_name : NULL;
 
 	if (*refspecs) {
-		if (opt_rebase)
+		if (opt_rebase >= REBASE_TRUE)
 			fprintf_ln(stderr, _("There is no candidate for rebasing against among the refs that you just fetched."));
 		else
 			fprintf_ln(stderr, _("There are no candidates for merging among the refs that you just fetched."));
@@ -456,7 +452,7 @@ static void NORETURN die_no_merge_candidates(const char *repo, const char **refs
 			repo);
 	} else if (!curr_branch) {
 		fprintf_ln(stderr, _("You are not currently on a branch."));
-		if (opt_rebase)
+		if (opt_rebase >= REBASE_TRUE)
 			fprintf_ln(stderr, _("Please specify which branch you want to rebase against."));
 		else
 			fprintf_ln(stderr, _("Please specify which branch you want to merge with."));
@@ -471,7 +467,7 @@ static void NORETURN die_no_merge_candidates(const char *repo, const char **refs
 			remote_name = _("<remote>");
 
 		fprintf_ln(stderr, _("There is no tracking information for the current branch."));
-		if (opt_rebase)
+		if (opt_rebase >= REBASE_TRUE)
 			fprintf_ln(stderr, _("Please specify which branch you want to rebase against."));
 		else
 			fprintf_ln(stderr, _("Please specify which branch you want to merge with."));
@@ -948,7 +944,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (get_oid("HEAD", &orig_head))
 		oidclr(&orig_head);
 
-	if (opt_rebase) {
+	if (opt_rebase >= REBASE_TRUE) {
 		int autostash = config_autostash;
 		if (opt_autostash != -1)
 			autostash = opt_autostash;
@@ -1008,12 +1004,12 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			die(_("Cannot merge multiple branches into empty head."));
 		return pull_into_void(merge_heads.oid, &curr_head);
 	}
-	if (opt_rebase && merge_heads.nr > 1)
+	if (opt_rebase >= REBASE_TRUE && merge_heads.nr > 1)
 		die(_("Cannot rebase onto multiple branches."));
 
 	can_ff = get_can_ff(&orig_head, &merge_heads.oid[0]);
 
-	if (default_mode && !can_ff && opt_verbosity >= 0 && !opt_ff) {
+	if (!opt_rebase && !can_ff && opt_verbosity >= 0 && !opt_ff) {
 		warning(_("Pulling without specifying how to reconcile divergent branches is\n"
 			"discouraged. You can squelch this message by running one of the following\n"
 			"commands sometime before your next pull:\n"
@@ -1028,7 +1024,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"invocation.\n"));
 	}
 
-	if (opt_rebase) {
+	if (opt_rebase >= REBASE_TRUE) {
 		int ret = 0;
 		if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
 		     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) &&
diff --git a/rebase.h b/rebase.h
index cc723d4748..34d4acfd74 100644
--- a/rebase.h
+++ b/rebase.h
@@ -3,7 +3,8 @@
 
 enum rebase_type {
 	REBASE_INVALID = -1,
-	REBASE_FALSE = 0,
+	REBASE_DEFAULT = 0,
+	REBASE_FALSE,
 	REBASE_TRUE,
 	REBASE_PRESERVE,
 	REBASE_MERGES,
-- 
2.29.2


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

* [PATCH v8 08/10] pull: add pull.mode
  2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
                   ` (6 preceding siblings ...)
  2020-11-25  3:29 ` [PATCH v8 07/10] rebase: add REBASE_DEFAULT Felipe Contreras
@ 2020-11-25  3:29 ` Felipe Contreras
  2020-11-25 12:31   ` Philip Oakley
  2020-11-25  3:29 ` [PATCH v8 09/10] pull: add pull.mode=ff-only Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 10/10] pull: improve default warning Felipe Contreras
  9 siblings, 1 reply; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

This way we can add more modes and the default can be something else,
namely it can be set to "ff-only", so eventually we can reject
non-fast-forward merges by default.

Also 'branch.<name>.pullmode'.

For now we simply override the rebase mode.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 Documentation/config/branch.txt |  6 ++++
 Documentation/config/pull.txt   |  6 ++++
 builtin/pull.c                  | 57 ++++++++++++++++++++++++++++++---
 builtin/remote.c                | 19 ++++++++++-
 rebase.c                        | 10 ++++++
 rebase.h                        |  9 ++++++
 t/t5520-pull.sh                 | 42 ++++++++++++++++++++++++
 t/t7601-merge-pull-config.sh    |  7 ++++
 8 files changed, 151 insertions(+), 5 deletions(-)

diff --git a/Documentation/config/branch.txt b/Documentation/config/branch.txt
index cc5f3249fc..94510a5184 100644
--- a/Documentation/config/branch.txt
+++ b/Documentation/config/branch.txt
@@ -96,6 +96,12 @@ mode.
 it unless you understand the implications (see linkgit:git-rebase[1]
 for details).
 
+branch.<name>.pullmode::
+	When "git pull" is run, this determines if it would either merge or
+	rebase the fetched branch. The possible values are 'merge',
+	'rebase'. See "pull.mode" for doing this in a non
+	branch-specific manner.
+
 branch.<name>.description::
 	Branch description, can be edited with
 	`git branch --edit-description`. Branch description is
diff --git a/Documentation/config/pull.txt b/Documentation/config/pull.txt
index 5404830609..2606515fe4 100644
--- a/Documentation/config/pull.txt
+++ b/Documentation/config/pull.txt
@@ -29,6 +29,12 @@ mode.
 it unless you understand the implications (see linkgit:git-rebase[1]
 for details).
 
+pull.mode::
+	When "git pull" is run, this determines if it would either merge or
+	rebase the fetched branch. The possible values are 'merge',
+	and 'rebase'. See "branch.<name>.pullmode" for doing
+	this in a non branch-specific manner.
+
 pull.octopus::
 	The default merge strategy to use when pulling multiple branches
 	at once.
diff --git a/builtin/pull.c b/builtin/pull.c
index 0df7d27343..feb9a7f6ee 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -49,6 +49,14 @@ static enum rebase_type parse_config_rebase(const char *key, const char *value,
 	return REBASE_INVALID;
 }
 
+static enum pull_mode_type parse_config_pull_mode(const char *key, const char *value)
+{
+	enum pull_mode_type v = pull_mode_parse_value(value);
+	if (v == PULL_MODE_INVALID)
+		die(_("Invalid value for %s: %s"), key, value);
+	return v;
+}
+
 /**
  * Callback for --rebase, which parses arg with parse_config_rebase().
  */
@@ -75,6 +83,7 @@ static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 
 /* Options passed to git-merge or git-rebase */
 static enum rebase_type opt_rebase = -1;
+static enum pull_mode_type mode;
 static char *opt_diffstat;
 static char *opt_log;
 static char *opt_signoff;
@@ -347,6 +356,29 @@ static enum rebase_type config_get_rebase(void)
 	return REBASE_DEFAULT;
 }
 
+static enum pull_mode_type config_get_pull_mode(void)
+{
+	struct branch *curr_branch = branch_get("HEAD");
+	const char *value;
+
+	if (curr_branch) {
+		char *key = xstrfmt("branch.%s.pullmode", curr_branch->name);
+
+		if (!git_config_get_value(key, &value)) {
+			enum pull_mode_type ret = parse_config_pull_mode(key, value);
+			free(key);
+			return ret;
+		}
+
+		free(key);
+	}
+
+	if (!git_config_get_value("pull.mode", &value))
+		return parse_config_pull_mode("pull.mode", value);
+
+	return PULL_MODE_DEFAULT;
+}
+
 /**
  * Read config variables.
  */
@@ -932,8 +964,25 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	if (!opt_ff)
 		opt_ff = xstrdup_or_null(config_get_ff());
 
-	if (opt_rebase < 0)
-		opt_rebase = config_get_rebase();
+	if (opt_rebase < 0) {
+		mode = config_get_pull_mode();
+		switch (mode) {
+		case PULL_MODE_MERGE:
+			opt_rebase = REBASE_FALSE;
+			break;
+		case PULL_MODE_REBASE:
+			opt_rebase = config_get_rebase();
+			if (!opt_rebase) opt_rebase = REBASE_TRUE;
+			break;
+		default:
+			opt_rebase = config_get_rebase();
+		}
+	}
+
+	if (!mode) {
+		if (opt_rebase)
+			mode = opt_rebase >= REBASE_TRUE ? PULL_MODE_REBASE : PULL_MODE_MERGE;
+	}
 
 	if (read_cache_unmerged())
 		die_resolve_conflict("pull");
@@ -1014,8 +1063,8 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"discouraged. You can squelch this message by running one of the following\n"
 			"commands sometime before your next pull:\n"
 			"\n"
-			"  git config pull.rebase false  # merge (the default strategy)\n"
-			"  git config pull.rebase true   # rebase\n"
+			"  git config pull.mode merge    # (the default strategy)\n"
+			"  git config pull.mode rebase\n"
 			"  git config pull.ff only       # fast-forward only\n"
 			"\n"
 			"You can replace \"git config\" with \"git config --global\" to set a default\n"
diff --git a/builtin/remote.c b/builtin/remote.c
index c1b211b272..51b1e675e3 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -269,7 +269,7 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 	char *name;
 	struct string_list_item *item;
 	struct branch_info *info;
-	enum { REMOTE, MERGE, REBASE, PUSH_REMOTE } type;
+	enum { REMOTE, MERGE, REBASE, PUSH_REMOTE, PULL_MODE } type;
 	size_t key_len;
 
 	if (!starts_with(key, "branch."))
@@ -284,6 +284,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 		type = REBASE;
 	else if (strip_suffix(key, ".pushremote", &key_len))
 		type = PUSH_REMOTE;
+	else if (strip_suffix(key, ".pullmode", &key_len))
+		type = PULL_MODE;
 	else
 		return 0;
 	name = xmemdupz(key, key_len);
@@ -324,6 +326,21 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 			warning(_("more than one %s"), orig_key);
 		info->push_remote_name = xstrdup(value);
 		break;
+	case PULL_MODE: {
+		int mode = pull_mode_parse_value(value);
+		switch (mode) {
+		case PULL_MODE_MERGE:
+			info->rebase = REBASE_FALSE;
+			break;
+		case PULL_MODE_REBASE:
+			info->rebase = REBASE_TRUE;
+			break;
+		default:
+			info->rebase = REBASE_INVALID;
+			break;
+		}
+		break;
+	}
 	default:
 		BUG("unexpected type=%d", type);
 	}
diff --git a/rebase.c b/rebase.c
index f8137d859b..bdfca49886 100644
--- a/rebase.c
+++ b/rebase.c
@@ -33,3 +33,13 @@ enum rebase_type rebase_parse_value(const char *value)
 
 	return REBASE_INVALID;
 }
+
+enum pull_mode_type pull_mode_parse_value(const char *value)
+{
+	if (!strcmp(value, "merge") || !strcmp(value, "m"))
+		return PULL_MODE_MERGE;
+	else if (!strcmp(value, "rebase") || !strcmp(value, "r"))
+		return PULL_MODE_REBASE;
+
+	return PULL_MODE_INVALID;
+}
diff --git a/rebase.h b/rebase.h
index 34d4acfd74..5ab8f4ddd5 100644
--- a/rebase.h
+++ b/rebase.h
@@ -13,4 +13,13 @@ enum rebase_type {
 
 enum rebase_type rebase_parse_value(const char *value);
 
+enum pull_mode_type {
+	PULL_MODE_INVALID = -1,
+	PULL_MODE_DEFAULT = 0,
+	PULL_MODE_MERGE,
+	PULL_MODE_REBASE
+};
+
+enum pull_mode_type pull_mode_parse_value(const char *value);
+
 #endif /* REBASE */
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index 9fae07cdfa..eb0086bd1c 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -449,6 +449,16 @@ test_expect_success 'pull.rebase' '
 	test_cmp expect actual
 '
 
+test_expect_success 'pull.mode rebase' '
+	git reset --hard before-rebase &&
+	test_config pull.mode rebase &&
+	git pull . copy &&
+	test_cmp_rev HEAD^ copy &&
+	echo new >expect &&
+	git show HEAD:file2 >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'pull --autostash & pull.rebase=true' '
 	test_config pull.rebase true &&
 	test_pull_autostash 1 --autostash
@@ -523,6 +533,17 @@ test_expect_success 'pull.rebase=false create a new merge commit' '
 	test_cmp expect actual
 '
 
+test_expect_success 'pull.mode=merge create a new merge commit' '
+	git reset --hard before-preserve-rebase &&
+	test_config pull.mode merge &&
+	git pull . copy &&
+	test_cmp_rev HEAD^1 before-preserve-rebase &&
+	test_cmp_rev HEAD^2 copy &&
+	echo file3 >expect &&
+	git show HEAD:file3.t >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'pull.rebase=true flattens keep-merge' '
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase true &&
@@ -552,6 +573,16 @@ test_expect_success REBASE_P \
 	test_cmp_rev HEAD^2 keep-merge
 '
 
+test_expect_success REBASE_P \
+	'pull.rebase=preserve rebases and merges keep-merge with pull.mode' '
+	git reset --hard before-preserve-rebase &&
+	test_config pull.mode rebase &&
+	test_config pull.rebase preserve &&
+	git pull . copy &&
+	test_cmp_rev HEAD^^ copy &&
+	test_cmp_rev HEAD^2 keep-merge
+'
+
 test_expect_success 'pull.rebase=interactive' '
 	write_script "$TRASH_DIRECTORY/fake-editor" <<-\EOF &&
 	echo I was here >fake.out &&
@@ -593,6 +624,17 @@ test_expect_success '--rebase=false create a new merge commit' '
 	test_cmp expect actual
 '
 
+test_expect_success '--rebase=false create a new merge commit with pull.mode' '
+	git reset --hard before-preserve-rebase &&
+	test_config pull.mode rebase &&
+	git pull --rebase=false . copy &&
+	test_cmp_rev HEAD^1 before-preserve-rebase &&
+	test_cmp_rev HEAD^2 copy &&
+	echo file3 >expect &&
+	git show HEAD:file3.t >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success '--rebase=true rebases and flattens keep-merge' '
 	git reset --hard before-preserve-rebase &&
 	test_config pull.rebase preserve &&
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index 02e2a9b2c6..4a36ad30e2 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -39,6 +39,13 @@ test_expect_success 'pull.rebase not set (fast-forward)' '
 	test_i18ngrep ! "Pulling without specifying how to reconcile" err
 '
 
+test_expect_success 'pull.mode set' '
+	git reset --hard c2 &&
+	test_config pull.mode merge &&
+	git pull . c1 2>err &&
+	test_i18ngrep ! "Pulling without specifying how to reconcile" err
+'
+
 test_expect_success 'pull.rebase not set and pull.ff=true' '
 	git reset --hard c2 &&
 	test_config pull.ff true &&
-- 
2.29.2


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

* [PATCH v8 09/10] pull: add pull.mode=ff-only
  2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
                   ` (7 preceding siblings ...)
  2020-11-25  3:29 ` [PATCH v8 08/10] pull: add pull.mode Felipe Contreras
@ 2020-11-25  3:29 ` Felipe Contreras
  2020-11-25  3:29 ` [PATCH v8 10/10] pull: improve default warning Felipe Contreras
  9 siblings, 0 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

It is very typical for Git newcomers to inadvertently create merges and
worse; inadvertently pushing them. This is one of the reasons many
experienced users prefer to avoid 'git pull', and recommend newcomers to
avoid it as well.

To avoid these problems, and keep 'git pull' useful, it has been
suggested that 'git pull' barfs by default if the merge is
non-fast-forward, which unfortunately would break backwards
compatibility.

This patch leaves everything in place to enable this new mode, but it
only gets enabled if the user specifically configures it;

  pull.mode = ff-only.

Later on this mode can be enabled by default.

For the full discussion you can read:

https://lore.kernel.org/git/5363BB9F.40102@xiplink.com/

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 Documentation/config/branch.txt |  2 +-
 Documentation/config/pull.txt   |  2 +-
 builtin/pull.c                  | 10 +++++++--
 builtin/remote.c                |  3 +++
 rebase.c                        |  2 ++
 rebase.h                        |  3 ++-
 t/t5520-pull.sh                 | 36 +++++++++++++++++++++++++++++++++
 7 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/Documentation/config/branch.txt b/Documentation/config/branch.txt
index 94510a5184..39f60cd8f7 100644
--- a/Documentation/config/branch.txt
+++ b/Documentation/config/branch.txt
@@ -99,7 +99,7 @@ for details).
 branch.<name>.pullmode::
 	When "git pull" is run, this determines if it would either merge or
 	rebase the fetched branch. The possible values are 'merge',
-	'rebase'. See "pull.mode" for doing this in a non
+	'rebase', and 'ff-only'. See "pull.mode" for doing this in a non
 	branch-specific manner.
 
 branch.<name>.description::
diff --git a/Documentation/config/pull.txt b/Documentation/config/pull.txt
index 2606515fe4..daa14f1170 100644
--- a/Documentation/config/pull.txt
+++ b/Documentation/config/pull.txt
@@ -32,7 +32,7 @@ for details).
 pull.mode::
 	When "git pull" is run, this determines if it would either merge or
 	rebase the fetched branch. The possible values are 'merge',
-	and 'rebase'. See "branch.<name>.pullmode" for doing
+	'rebase', and 'ff-only'. See "branch.<name>.pullmode" for doing
 	this in a non branch-specific manner.
 
 pull.octopus::
diff --git a/builtin/pull.c b/builtin/pull.c
index feb9a7f6ee..3aa7f56142 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -980,7 +980,9 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 	}
 
 	if (!mode) {
-		if (opt_rebase)
+		if (opt_ff && !strcmp(opt_ff, "--ff-only"))
+			mode = PULL_MODE_FF_ONLY;
+		else if (opt_rebase)
 			mode = opt_rebase >= REBASE_TRUE ? PULL_MODE_REBASE : PULL_MODE_MERGE;
 	}
 
@@ -1065,7 +1067,7 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"\n"
 			"  git config pull.mode merge    # (the default strategy)\n"
 			"  git config pull.mode rebase\n"
-			"  git config pull.ff only       # fast-forward only\n"
+			"  git config pull.mode ff-only  # fast-forward only\n"
 			"\n"
 			"You can replace \"git config\" with \"git config --global\" to set a default\n"
 			"preference for all repositories. You can also pass --rebase, --no-rebase,\n"
@@ -1073,6 +1075,10 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 			"invocation.\n"));
 	}
 
+	if (mode == PULL_MODE_FF_ONLY && !can_ff)
+		die(_("The pull was not fast-forward, please either merge or rebase.\n"
+			"If unsure, run 'git pull --no-rebase'."));
+
 	if (opt_rebase >= REBASE_TRUE) {
 		int ret = 0;
 		if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
diff --git a/builtin/remote.c b/builtin/remote.c
index 51b1e675e3..34d3ea9d38 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -335,6 +335,9 @@ static int config_read_branches(const char *key, const char *value, void *cb)
 		case PULL_MODE_REBASE:
 			info->rebase = REBASE_TRUE;
 			break;
+		case PULL_MODE_FF_ONLY:
+			info->rebase = REBASE_TRUE;
+			break;
 		default:
 			info->rebase = REBASE_INVALID;
 			break;
diff --git a/rebase.c b/rebase.c
index bdfca49886..c6233e888f 100644
--- a/rebase.c
+++ b/rebase.c
@@ -40,6 +40,8 @@ enum pull_mode_type pull_mode_parse_value(const char *value)
 		return PULL_MODE_MERGE;
 	else if (!strcmp(value, "rebase") || !strcmp(value, "r"))
 		return PULL_MODE_REBASE;
+	else if (!strcmp(value, "ff-only") || !strcmp(value, "f"))
+		return PULL_MODE_FF_ONLY;
 
 	return PULL_MODE_INVALID;
 }
diff --git a/rebase.h b/rebase.h
index 5ab8f4ddd5..432bcb55c4 100644
--- a/rebase.h
+++ b/rebase.h
@@ -17,7 +17,8 @@ enum pull_mode_type {
 	PULL_MODE_INVALID = -1,
 	PULL_MODE_DEFAULT = 0,
 	PULL_MODE_MERGE,
-	PULL_MODE_REBASE
+	PULL_MODE_REBASE,
+	PULL_MODE_FF_ONLY
 };
 
 enum pull_mode_type pull_mode_parse_value(const char *value);
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index eb0086bd1c..ba78c16d73 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -861,4 +861,40 @@ test_expect_success 'git pull --rebase against local branch' '
 	test_cmp expect file2
 '
 
+test_expect_success 'git pull fast-forward (ff-only)' '
+	test_when_finished "git checkout master && git branch -D other test" &&
+	test_config pull.mode ff-only &&
+	git checkout -b other master &&
+	>new &&
+	git add new &&
+	git commit -m new &&
+	git checkout -b test -t other &&
+	git reset --hard master &&
+	git pull
+'
+
+test_expect_success 'git pull non-fast-forward (ff-only)' '
+	test_when_finished "git checkout master && git branch -D other test" &&
+	test_config pull.mode ff-only &&
+	git checkout -b other master^ &&
+	>new &&
+	git add new &&
+	git commit -m new &&
+	git checkout -b test -t other &&
+	git reset --hard master &&
+	test_must_fail git pull
+'
+
+test_expect_success 'git pull non-fast-forward with merge (ff-only)' '
+	test_when_finished "git checkout master && git branch -D other test" &&
+	test_config pull.mode ff-only &&
+	git checkout -b other master^ &&
+	>new &&
+	git add new &&
+	git commit -m new &&
+	git checkout -b test -t other &&
+	git reset --hard master &&
+	git pull --no-rebase
+'
+
 test_done
-- 
2.29.2


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

* [PATCH v8 10/10] pull: improve default warning
  2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
                   ` (8 preceding siblings ...)
  2020-11-25  3:29 ` [PATCH v8 09/10] pull: add pull.mode=ff-only Felipe Contreras
@ 2020-11-25  3:29 ` Felipe Contreras
  9 siblings, 0 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-11-25  3:29 UTC (permalink / raw)
  To: git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen, Philip Oakley,
	Brian M. Carlson, W. Trevor King, Felipe Contreras

Also, use pull.mode to determine when to show it, and --ff/--no-ff
shouldn't squelch the warning.

Also, improve the documentation so "git pull --help" actually does
explain what's going on.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 Documentation/git-pull.txt   | 17 +++++++++++++++
 builtin/pull.c               | 34 +++++++++++++++---------------
 t/t5520-pull.sh              | 14 +++++++++++++
 t/t7601-merge-pull-config.sh | 40 +++++++-----------------------------
 4 files changed, 55 insertions(+), 50 deletions(-)

diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 5c3fb67c01..ad33d2472c 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -38,6 +38,20 @@ as set by linkgit:git-branch[1] `--track`.
 Assume the following history exists and the current branch is
 "`master`":
 
+------------
+	  A---B---C master on origin
+	 /
+    D---E master
+------------
+
+Then `git pull` will merge in a fast-foward way up to the new master.
+
+------------
+    D---E---A---B---C master, origin/master
+------------
+
+However, a non-fast-foward case looks very different.
+
 ------------
 	  A---B---C master on origin
 	 /
@@ -46,6 +60,9 @@ Assume the following history exists and the current branch is
 	origin/master in your repository
 ------------
 
+By default `git pull` will warn about these situations, however, most likely
+you would want to force a merge, which you can do with `git pull --no-rebase`.
+
 Then "`git pull`" will fetch and replay the changes from the remote
 `master` branch since it diverged from the local `master` (i.e., `E`)
 until its current commit (`C`) on top of `master` and record the
diff --git a/builtin/pull.c b/builtin/pull.c
index 3aa7f56142..8e577b6322 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -1060,25 +1060,25 @@ int cmd_pull(int argc, const char **argv, const char *prefix)
 
 	can_ff = get_can_ff(&orig_head, &merge_heads.oid[0]);
 
-	if (!opt_rebase && !can_ff && opt_verbosity >= 0 && !opt_ff) {
-		warning(_("Pulling without specifying how to reconcile divergent branches is\n"
-			"discouraged. You can squelch this message by running one of the following\n"
-			"commands sometime before your next pull:\n"
-			"\n"
-			"  git config pull.mode merge    # (the default strategy)\n"
-			"  git config pull.mode rebase\n"
-			"  git config pull.mode ff-only  # fast-forward only\n"
-			"\n"
-			"You can replace \"git config\" with \"git config --global\" to set a default\n"
-			"preference for all repositories. You can also pass --rebase, --no-rebase,\n"
-			"or --ff-only on the command line to override the configured default per\n"
-			"invocation.\n"));
+	if (!can_ff) {
+		if (mode == PULL_MODE_FF_ONLY)
+			die(_("The pull was not fast-forward, please either merge or rebase.\n"
+				"If unsure, run 'git pull --no-rebase'."));
+		else if (!mode && opt_verbosity >= 0) {
+			warning(_("The pull was not fast-forward, in the future you will have to choose a merge, or a rebase.\n"
+				"To squelch this message and maintain the current behavior, use:\n"
+				"\n"
+				"  git config --global pull.mode merge\n"
+				"\n"
+				"To squelch this message and adopt the new behavior now, use:\n"
+				"\n"
+				"  git config --global push.mode ff-only\n"
+				"\n"
+				"Falling back to old style for now (merge).\n"
+				"Read 'git pull --help' for more information."));
+		}
 	}
 
-	if (mode == PULL_MODE_FF_ONLY && !can_ff)
-		die(_("The pull was not fast-forward, please either merge or rebase.\n"
-			"If unsure, run 'git pull --no-rebase'."));
-
 	if (opt_rebase >= REBASE_TRUE) {
 		int ret = 0;
 		if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh
index ba78c16d73..29d44d000e 100755
--- a/t/t5520-pull.sh
+++ b/t/t5520-pull.sh
@@ -897,4 +897,18 @@ test_expect_success 'git pull non-fast-forward with merge (ff-only)' '
 	git pull --no-rebase
 '
 
+test_expect_success 'git pull non-fast-forward (default)' '
+	test_when_finished "git checkout master && git branch -D other test" &&
+	git checkout -b other master^ &&
+	>new &&
+	git add new &&
+	git commit -m new &&
+	git checkout -b test -t other &&
+	git reset --hard master &&
+	git pull 2> error &&
+	cat error &&
+	grep -q "The pull was not fast-forward" error &&
+	grep -q "in the future you will have to choose" error
+'
+
 test_done
diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh
index 4a36ad30e2..8a93b37d87 100755
--- a/t/t7601-merge-pull-config.sh
+++ b/t/t7601-merge-pull-config.sh
@@ -30,71 +30,45 @@ test_expect_success 'setup' '
 test_expect_success 'pull.rebase not set' '
 	git reset --hard c2 &&
 	git pull . c1 2>err &&
-	test_i18ngrep "Pulling without specifying how to reconcile" err
+	test_i18ngrep "choose a merge, or a rebase" err
 '
 
 test_expect_success 'pull.rebase not set (fast-forward)' '
 	git reset --hard c0 &&
 	git pull . c1 2>err &&
-	test_i18ngrep ! "Pulling without specifying how to reconcile" err
+	test_i18ngrep ! "choose a merge, or a rebase" err
 '
 
 test_expect_success 'pull.mode set' '
 	git reset --hard c2 &&
 	test_config pull.mode merge &&
 	git pull . c1 2>err &&
-	test_i18ngrep ! "Pulling without specifying how to reconcile" err
-'
-
-test_expect_success 'pull.rebase not set and pull.ff=true' '
-	git reset --hard c2 &&
-	test_config pull.ff true &&
-	git pull . c1 2>err &&
-	test_i18ngrep ! "Pulling without specifying how to reconcile" err
-'
-
-test_expect_success 'pull.rebase not set and pull.ff=false' '
-	git reset --hard c2 &&
-	test_config pull.ff false &&
-	git pull . c1 2>err &&
-	test_i18ngrep ! "Pulling without specifying how to reconcile" err
+	test_i18ngrep ! "choose a merge, or a rebase" err
 '
 
 test_expect_success 'pull.rebase not set and pull.ff=only' '
 	git reset --hard c2 &&
 	test_config pull.ff only &&
 	test_must_fail git pull . c1 2>err &&
-	test_i18ngrep ! "Pulling without specifying how to reconcile" err
+	test_i18ngrep ! "choose a merge, or a rebase" err
 '
 
 test_expect_success 'pull.rebase not set and --rebase given' '
 	git reset --hard c2 &&
 	git pull --rebase . c1 2>err &&
-	test_i18ngrep ! "Pulling without specifying how to reconcile" err
+	test_i18ngrep ! "choose a merge, or a rebase" err
 '
 
 test_expect_success 'pull.rebase not set and --no-rebase given' '
 	git reset --hard c2 &&
 	git pull --no-rebase . c1 2>err &&
-	test_i18ngrep ! "Pulling without specifying how to reconcile" err
-'
-
-test_expect_success 'pull.rebase not set and --ff given' '
-	git reset --hard c2 &&
-	git pull --ff . c1 2>err &&
-	test_i18ngrep ! "Pulling without specifying how to reconcile" err
-'
-
-test_expect_success 'pull.rebase not set and --no-ff given' '
-	git reset --hard c2 &&
-	git pull --no-ff . c1 2>err &&
-	test_i18ngrep ! "Pulling without specifying how to reconcile" err
+	test_i18ngrep ! "choose a merge, or a rebase" err
 '
 
 test_expect_success 'pull.rebase not set and --ff-only given' '
 	git reset --hard c2 &&
 	test_must_fail git pull --ff-only . c1 2>err &&
-	test_i18ngrep ! "Pulling without specifying how to reconcile" err
+	test_i18ngrep ! "choose a merge, or a rebase" err
 '
 
 test_expect_success 'merge c1 with c2' '
-- 
2.29.2


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

* Re: [PATCH v8 08/10] pull: add pull.mode
  2020-11-25  3:29 ` [PATCH v8 08/10] pull: add pull.mode Felipe Contreras
@ 2020-11-25 12:31   ` Philip Oakley
  2020-12-02  5:04     ` Felipe Contreras
  0 siblings, 1 reply; 13+ messages in thread
From: Philip Oakley @ 2020-11-25 12:31 UTC (permalink / raw)
  To: Felipe Contreras, git
  Cc: Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen,
	Brian M. Carlson, W. Trevor King

Accidental repetition of phrasing from branch.<name>.pullmode ?

On 25/11/2020 03:29, Felipe Contreras wrote:
> +pull.mode::
> +	When "git pull" is run, this determines if it would either merge or
> +	rebase the fetched branch. The possible values are 'merge',
> +	and 'rebase'. See "branch.<name>.pullmode" for doing
> +	this in a non branch-specific manner.
> +
s/non//

Same problem in 09/10 I think.
I didn't check the code... Spotted while browsing.
--
Philip

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

* Re: [PATCH v8 08/10] pull: add pull.mode
  2020-11-25 12:31   ` Philip Oakley
@ 2020-12-02  5:04     ` Felipe Contreras
  0 siblings, 0 replies; 13+ messages in thread
From: Felipe Contreras @ 2020-12-02  5:04 UTC (permalink / raw)
  To: Philip Oakley
  Cc: Git, Alex Henrie, Jeff King, Junio C Hamano, Elijah Newren,
	Johannes Schindelin, John Keeping, Richard Hansen,
	Brian M. Carlson, W. Trevor King

On Wed, Nov 25, 2020 at 6:31 AM Philip Oakley <philipoakley@iee.email> wrote:
>
> Accidental repetition of phrasing from branch.<name>.pullmode ?
>
> On 25/11/2020 03:29, Felipe Contreras wrote:
> > +pull.mode::
> > +     When "git pull" is run, this determines if it would either merge or
> > +     rebase the fetched branch. The possible values are 'merge',
> > +     and 'rebase'. See "branch.<name>.pullmode" for doing
> > +     this in a non branch-specific manner.
> > +
> s/non//
>
> Same problem in 09/10 I think.
> I didn't check the code... Spotted while browsing.

Weird. I could swear I copied the text from pull.rebase. Anyway, now I
did: "see branch.<name>.pullmode" for setting this on a per-branch
basis."

-- 
Felipe Contreras

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

end of thread, other threads:[~2020-12-02  5:06 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-25  3:29 [PATCH v8 00/10] Reject non-ff pulls by default Felipe Contreras
2020-11-25  3:29 ` [PATCH v8 01/10] pull: refactor fast-forward check Felipe Contreras
2020-11-25  3:29 ` [PATCH v8 02/10] pull: cleanup autostash check Felipe Contreras
2020-11-25  3:29 ` [PATCH v8 03/10] pull: trivial cleanup Felipe Contreras
2020-11-25  3:29 ` [PATCH v8 04/10] pull: move default warning Felipe Contreras
2020-11-25  3:29 ` [PATCH v8 05/10] pull: display default warning only when non-ff Felipe Contreras
2020-11-25  3:29 ` [PATCH v8 06/10] test: pull-options: revert unnecessary changes Felipe Contreras
2020-11-25  3:29 ` [PATCH v8 07/10] rebase: add REBASE_DEFAULT Felipe Contreras
2020-11-25  3:29 ` [PATCH v8 08/10] pull: add pull.mode Felipe Contreras
2020-11-25 12:31   ` Philip Oakley
2020-12-02  5:04     ` Felipe Contreras
2020-11-25  3:29 ` [PATCH v8 09/10] pull: add pull.mode=ff-only Felipe Contreras
2020-11-25  3:29 ` [PATCH v8 10/10] pull: improve default warning Felipe Contreras

Code repositories for project(s) associated with this inbox:

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

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