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

[PATCH 5/7] fast-forward: add new builtin

From
Felipe Contreras <felipe.contreras@gmail.com>
Date
Jul 22, 2021, 00:08 UTC
Message-ID
<20210722000854.1899129-6-felipe.contreras@gmail.com>
In-Reply-To
<20210722000854.1899129-1-felipe.contreras@gmail.com>

This is one of the most common git operations, it makes sense it has its own built-in.

Additionally it's more user friendly than `git merge` because by default does --ff-only and thus shows the diverging advice.

Moreover, the documentation about fast-forwards is scattered, by having a standalone command users can be referred to it very simply:

  git help fast-forward
This is basically the same as `git merge --ff-only` (for now).
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 .gitignore                             |  1 +
 Documentation/git-fast-forward.txt     | 26 ++++++++++++++++++++++++++
 Makefile                               |  1 +
 builtin.h                              |  1 +
 builtin/merge.c                        | 15 +++++++++++++++
 contrib/completion/git-completion.bash | 10 ++++++++++
 git.c                                  |  1 +
 t/t7600-merge.sh                       | 21 +++++++++++++++++++++
 8 files changed, 76 insertions(+)
 create mode 100644 Documentation/git-fast-forward.txt
diff --git a/.gitignore b/.gitignore
index 311841f9be..45703399b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,6 +62,7 @@
 /git-describe
 /git-env--helper
 /git-fast-export
+/git-fast-forward
 /git-fast-import
 /git-fetch
 /git-fetch-pack
diff --git a/Documentation/git-fast-forward.txt b/Documentation/git-fast-forward.txt
new file mode 100644
index 0000000000..d457022629
--- /dev/null
+++ b/Documentation/git-fast-forward.txt
@@ -0,0 +1,26 @@
+git-fast-forward(1)
+===================
+
+NAME
+----
+git-fast-forward - Advance the branch pointer
+
+SYNOPSIS
+--------
+[verse]
+'git fast-forward' [<commit>]
+
+DESCRIPTION
+-----------
+Incorporates changes into the current branch. By default the upstream branch is
+used, but a different commit can be specified in the arguments.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOUR MAY CHANGE.
+
+SEE ALSO
+--------
+linkgit:git-merge[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index c7c46c017d..a05c309188 100644
--- a/Makefile
+++ b/Makefile
@@ -777,6 +777,7 @@ BUILT_INS += $(patsubst builtin/%.o,git-%$X,$(BUILTIN_OBJS))
 
 BUILT_INS += git-cherry$X
 BUILT_INS += git-cherry-pick$X
+BUILT_INS += git-fast-forward$X
 BUILT_INS += git-format-patch$X
 BUILT_INS += git-fsck-objects$X
 BUILT_INS += git-init$X
diff --git a/builtin.h b/builtin.h
index 16ecd5586f..601e438c9b 100644
--- a/builtin.h
+++ b/builtin.h
@@ -151,6 +151,7 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix);
 int cmd_difftool(int argc, const char **argv, const char *prefix);
 int cmd_env__helper(int argc, const char **argv, const char *prefix);
 int cmd_fast_export(int argc, const char **argv, const char *prefix);
+int cmd_fast_forward(int argc, const char **argv, const char *prefix);
 int cmd_fast_import(int argc, const char **argv, const char *prefix);
 int cmd_fetch(int argc, const char **argv, const char *prefix);
 int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
diff --git a/builtin/merge.c b/builtin/merge.c
index 2770dabf22..1836f98f82 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -61,6 +61,11 @@ static const char * const builtin_merge_usage[] = {
 	NULL
 };
 
+static const char * const builtin_ff_usage[] = {
+	N_("git fast-forward [<commit>]"),
+	NULL
+};
+
 static int show_diffstat = 1, shortlog_len = -1, squash;
 static int option_commit = -1;
 static int option_edit = -1;
@@ -304,6 +309,10 @@ static struct option builtin_merge_options[] = {
 	OPT_END()
 };
 
+static struct option builtin_ff_options[] = {
+	OPT_END()
+};
+
 static int save_state(struct object_id *stash)
 {
 	int len;
@@ -1742,3 +1751,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 {
 	return merge_common(argc, argv, prefix, builtin_merge_options, builtin_merge_usage);
 }
+
+int cmd_fast_forward(int argc, const char **argv, const char *prefix)
+{
+	fast_forward = FF_ONLY;
+	return merge_common(argc, argv, prefix, builtin_ff_options, builtin_ff_usage);
+}
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 4bdd27ddc8..ec00c20656 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1787,6 +1787,16 @@ _git_difftool ()
 	__git_complete_revlist_file
 }
 
+_git_fast_forward ()
+{
+	case "$cur" in
+	--*)
+		__gitcomp_builtin fast-forward
+		return
+	esac
+	__git_complete_refs
+}
+
 __git_fetch_recurse_submodules="yes on-demand no"
 
 _git_fetch ()
diff --git a/git.c b/git.c
index 18bed9a996..6ab1fb9251 100644
--- a/git.c
+++ b/git.c
@@ -524,6 +524,7 @@ static struct cmd_struct commands[] = {
 	{ "difftool", cmd_difftool, RUN_SETUP_GENTLY },
 	{ "env--helper", cmd_env__helper },
 	{ "fast-export", cmd_fast_export, RUN_SETUP },
+	{ "fast-forward", cmd_fast_forward, RUN_SETUP | NEED_WORK_TREE },
 	{ "fast-import", cmd_fast_import, RUN_SETUP | NO_PARSEOPT },
 	{ "fetch", cmd_fetch, RUN_SETUP },
 	{ "fetch-pack", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 1cbc9715a8..9df1931236 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -205,6 +205,16 @@ test_expect_success 'merge c0 with c1 with --ff-only' '
 
 test_debug 'git log --graph --decorate --oneline --all'
 
+test_expect_success 'fast-forward c0 with c1' '
+	git reset --hard c0 &&
+	git fast-forward c1 &&
+	git fast-forward HEAD c0 c1 &&
+	verify_merge file result.1 &&
+	verify_head "$c1"
+'
+
+test_debug 'git log --graph --decorate --oneline --all'
+
 test_expect_success 'merge from unborn branch' '
 	git checkout -f main &&
 	test_might_fail git branch -D kid &&
@@ -322,6 +332,17 @@ test_expect_success 'merges with --ff-only' '
 	verify_head $c3
 '
 
+test_expect_success 'fast-forward' '
+	git reset --hard c1 &&
+	test_tick &&
+	test_must_fail git fast-forward c2 &&
+	test_must_fail git fast-forward c3 &&
+	test_must_fail git fast-forward c2 c3 &&
+	git reset --hard c0 &&
+	git fast-forward c3 &&
+	verify_head $c3
+'
+
 test_expect_success 'merges with merge.ff=only' '
 	git reset --hard c1 &&
 	test_tick &&
-- 
2.32.0.40.gb9b36f9b52
Previous: Felipe ContrerasNext: Felipe Contreras
Message 6 of 12 in “fast-forward: new command with advice and documentation”
  1. 0/7 fast-forward: new command with advice and documentationFelipe Contreras, Jul 22, 2021
  2. 1/7 merge: improve fatal fast-forward messageFelipe Contreras, Jul 22, 2021
  3. 2/7 merge: add diverging advice for novicesFelipe Contreras, Jul 22, 2021
  4. 3/7 merge: make the diverging advise configurableFelipe Contreras, Jul 22, 2021
  5. 4/7 merge: split cmd_merge()Felipe Contreras, Jul 22, 2021
  6. 5/7 fast-forward: add new builtinFelipe Contreras, Jul 22, 2021
  7. 6/7 doc: fast-forward: explain what it isFelipe Contreras, Jul 22, 2021
  8. 7/7 fast-forward: add help about merge vs. rebaseFelipe Contreras, Jul 22, 2021
  9. Philip OakleyJul 22, 2021
  10. Felipe ContrerasJul 23, 2021
  11. Philip OakleyJul 23, 2021
  12. Felipe ContrerasJul 23, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.