]> git.ipfire.org Git - thirdparty/git.git/commitdiff
builtin: add new "history" command
authorPatrick Steinhardt <ps@pks.im>
Wed, 1 Oct 2025 15:57:31 +0000 (17:57 +0200)
committerJunio C Hamano <gitster@pobox.com>
Wed, 1 Oct 2025 19:33:29 +0000 (12:33 -0700)
When rewriting history via git-rebase(1) there are a couple of very
common use cases:

  - The ordering of two commits should be reversed.

  - A commit should be split up into two commits.

  - A commit should be dropped from the history completely.

  - Multiple commits should be squashed into one.

While these operations are all doable, it often feels needlessly cludgy
to do so by doing an interactive rebase, using the editor to say what
one wants, and then perform the actions. Furthermore, some operations
like splitting up a commit into two are way more involved than that and
require a whole series of commands.

Add a new "history" command to plug this gap. This command will have
several different subcommands to imperatively rewrite history for common
use cases like the above. These commands will be implemented in
subsequent commits.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
.gitignore
Documentation/git-history.adoc [new file with mode: 0644]
Documentation/meson.build
Makefile
builtin.h
builtin/history.c [new file with mode: 0644]
command-list.txt
git.c
meson.build
t/meson.build
t/t3450-history.sh [new file with mode: 0755]

index 802ce70e4830f8017070cc17705aa60066c1358b..3de9f9f16f96fe0daea8007f7b124b9aa86c8ac1 100644 (file)
@@ -77,6 +77,7 @@
 /git-grep
 /git-hash-object
 /git-help
+/git-history
 /git-hook
 /git-http-backend
 /git-http-fetch
diff --git a/Documentation/git-history.adoc b/Documentation/git-history.adoc
new file mode 100644 (file)
index 0000000..1537960
--- /dev/null
@@ -0,0 +1,45 @@
+git-history(1)
+==============
+
+NAME
+----
+git-history - EXPERIMENTAL: Rewrite history of the current branch
+
+SYNOPSIS
+--------
+[synopsis]
+git history [<options>]
+
+DESCRIPTION
+-----------
+
+Rewrite history by rearranging or modifying specific commits in the
+history.
+
+This command is similar to linkgit:git-rebase[1] and uses the same
+underlying machinery. You should use rebases if you either want to
+reapply a range of commits onto a different base, or interactive rebases
+if you want to edit a range of commits.
+
+Note that this command does not (yet) work with histories that contain
+merges. You should use linkgit:git-rebase[1] with the `--rebase-merges`
+flag instead.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+COMMANDS
+--------
+
+This command requires a subcommand. Several subcommands are available to
+rewrite history in different ways:
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.adoc[]
+
+include::config/sequencer.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
index e34965c5b0e236cf143f8409de498f6c26170ec0..36500879e480df5615199114cbbd808b01554958 100644 (file)
@@ -64,6 +64,7 @@ manpages = {
   'git-gui.adoc' : 1,
   'git-hash-object.adoc' : 1,
   'git-help.adoc' : 1,
+  'git-history.adoc' : 1,
   'git-hook.adoc' : 1,
   'git-http-backend.adoc' : 1,
   'git-http-fetch.adoc' : 1,
index 5960c80736719a06fdbe55d28448fa65d15bab30..4e405509e924077c4ff693de38fe4144ab26e81a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1262,6 +1262,7 @@ BUILTIN_OBJS += builtin/get-tar-commit-id.o
 BUILTIN_OBJS += builtin/grep.o
 BUILTIN_OBJS += builtin/hash-object.o
 BUILTIN_OBJS += builtin/help.o
+BUILTIN_OBJS += builtin/history.o
 BUILTIN_OBJS += builtin/hook.o
 BUILTIN_OBJS += builtin/index-pack.o
 BUILTIN_OBJS += builtin/init-db.o
index 1b35565fbd9a3ce184fbe1d2e5c682d662bded9d..93c91d07d4bfdc4f3cd101f2bdb7f88bda92598b 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -172,6 +172,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix, struc
 int cmd_grep(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_hash_object(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_help(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_history(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_hook(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_index_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
 int cmd_init_db(int argc, const char **argv, const char *prefix, struct repository *repo);
diff --git a/builtin/history.c b/builtin/history.c
new file mode 100644 (file)
index 0000000..f6fe326
--- /dev/null
@@ -0,0 +1,22 @@
+#include "builtin.h"
+#include "gettext.h"
+#include "parse-options.h"
+
+int cmd_history(int argc,
+               const char **argv,
+               const char *prefix,
+               struct repository *repo UNUSED)
+{
+       const char * const usage[] = {
+               N_("git history [<options>]"),
+               NULL,
+       };
+       struct option options[] = {
+               OPT_END(),
+       };
+
+       argc = parse_options(argc, argv, prefix, options, usage, 0);
+       if (argc)
+               usagef("unrecognized argument: %s", argv[0]);
+       return 0;
+}
index accd3d0c4b55249ad120452711e9d819fa083d45..f9005cf45979f114142a8a8474c8fcfaa3747bf7 100644 (file)
@@ -115,6 +115,7 @@ git-grep                                mainporcelain           info
 git-gui                                 mainporcelain
 git-hash-object                         plumbingmanipulators
 git-help                                ancillaryinterrogators          complete
+git-history                             mainporcelain           history
 git-hook                                purehelpers
 git-http-backend                        synchingrepositories
 git-http-fetch                          synchelpers
diff --git a/git.c b/git.c
index d020eef021cbea15c6d79e6b8bd8761c82378f63..c7c13cea67610653ebd7ae84a2f8f8eeaa214d9c 100644 (file)
--- a/git.c
+++ b/git.c
@@ -560,6 +560,7 @@ static struct cmd_struct commands[] = {
        { "grep", cmd_grep, RUN_SETUP_GENTLY },
        { "hash-object", cmd_hash_object },
        { "help", cmd_help },
+       { "history", cmd_history, RUN_SETUP },
        { "hook", cmd_hook, RUN_SETUP },
        { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY | NO_PARSEOPT },
        { "init", cmd_init_db },
index c320bdba9fd32f35afdedad6c0be4abc5f5f851b..7630a8fb0a5f3d749e40971ae344b96141f7f1ba 100644 (file)
@@ -604,6 +604,7 @@ builtin_sources = [
   'builtin/grep.c',
   'builtin/hash-object.c',
   'builtin/help.c',
+  'builtin/history.c',
   'builtin/hook.c',
   'builtin/index-pack.c',
   'builtin/init-db.c',
index 7974795fe48c3a3684b5f14addd167648c364727..8b31eb08580ef2cf5391fd93c4bdb2320ae72885 100644 (file)
@@ -382,6 +382,7 @@ integration_tests = [
   't3436-rebase-more-options.sh',
   't3437-rebase-fixup-options.sh',
   't3438-rebase-broken-files.sh',
+  't3450-history.sh',
   't3500-cherry.sh',
   't3501-revert-cherry-pick.sh',
   't3502-cherry-pick-merge.sh',
diff --git a/t/t3450-history.sh b/t/t3450-history.sh
new file mode 100755 (executable)
index 0000000..417c343
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description='tests for git-history command'
+
+. ./test-lib.sh
+
+test_expect_success 'does nothing without any arguments' '
+       git history >out 2>&1 &&
+       test_must_be_empty out
+'
+
+test_expect_success 'raises an error with unknown argument' '
+       test_must_fail git history garbage 2>err &&
+       test_grep "unrecognized argument: garbage" err
+'
+
+test_done