| git-history(1) | |
| ============== | |
| NAME | |
| ---- | |
| git-history - EXPERIMENTAL: Rewrite history | |
| SYNOPSIS | |
| -------- | |
| [synopsis] | |
| git history drop <commit> [--dry-run] [--update-refs=(branches|head)] [--empty=(drop|keep|abort)] | |
| git history fixup <commit> [--dry-run] [--update-refs=(branches|head)] [--reedit-message] [--empty=(drop|keep|abort)] | |
| git history reword <commit> [--dry-run] [--update-refs=(branches|head)] | |
| git history split <commit> [--dry-run] [--update-refs=(branches|head)] [--] [<pathspec>...] | |
| DESCRIPTION | |
| ----------- | |
| Rewrite history by rearranging or modifying specific commits in the | |
| history. | |
| THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE. | |
| This command is related to linkgit:git-rebase[1] in that both commands can be | |
| used to rewrite history. There are a couple of major differences though: | |
| * Most subcommands of linkgit:git-history[1] can work in a bare repository as | |
| they do not need to touch either the index or the worktree. The `fixup` | |
| subcommand is an exception to this, as it reads staged changes from the index. | |
| * linkgit:git-history[1] does not execute any linkgit:githooks[5] at the | |
| current point in time. This may change in the future. | |
| * linkgit:git-history[1] by default updates all branches that are descendants | |
| of the original commit to point to the rewritten commit. | |
| Overall, linkgit:git-history[1] aims to provide a more opinionated way to modify | |
| your commit history that is simpler to use compared to linkgit:git-rebase[1] in | |
| general. | |
| Use linkgit:git-rebase[1] if you want to reapply a range of commits onto a | |
| different base, or interactive rebases if you want to edit a range of commits | |
| at once. | |
| LIMITATIONS | |
| ----------- | |
| This command does not (yet) work with histories that contain merges. You | |
| should use linkgit:git-rebase[1] with the `--rebase-merges` flag instead. | |
| Furthermore, the command does not support operations that can result in merge | |
| conflicts. This limitation is by design as history rewrites are not intended to | |
| be stateful operations. The limitation can be lifted once (if) Git learns about | |
| first-class conflicts. | |
| When using `fixup` with `--empty=drop`, dropping the root commit is not yet | |
| supported. Likewise, `drop` cannot remove the root commit or a merge commit. | |
| COMMANDS | |
| -------- | |
| The following commands are available to rewrite history in different ways: | |
| `drop <commit>`:: | |
| Remove the specified commit from the history. All descendants of the | |
| commit are replayed directly onto its parent. | |
| + | |
| The root commit cannot be dropped as that may lead to edge cases where refs | |
| end up with no commits anymore. Merge commits cannot be dropped either; see | |
| LIMITATIONS. | |
| + | |
| If `HEAD` points at a commit that is to be rewritten, the index and working | |
| tree are updated to match the new `HEAD`. The command aborts before any | |
| references are updated in case local modifications would be overwritten. | |
| + | |
| If replaying any descendant would result in a conflict, the command aborts | |
| with an error. | |
| `fixup <commit>`:: | |
| Apply the currently staged changes to the specified commit. This is | |
| similar in nature to `git commit --fixup=<commit>` followed by `git | |
| rebase --autosquash <commit>~`. Changes are applied to the target | |
| commit by performing a three-way merge between the HEAD commit, the | |
| target commit and the tree generated from staged changes. | |
| + | |
| The commit message and authorship of the target commit are preserved by | |
| default, unless you specify `--reedit-message`. | |
| + | |
| If applying the staged changes would result in a conflict, the command | |
| aborts with an error. All branches that are descendants of the original | |
| commit are updated to point to the rewritten history. | |
| `reword <commit>`:: | |
| Rewrite the commit message of the specified commit. All the other | |
| details of this commit remain unchanged. This command will spawn an | |
| editor with the current message of that commit. | |
| `split <commit> [--] [<pathspec>...]`:: | |
| Interactively split up <commit> into two commits by choosing | |
| hunks introduced by it that will be moved into the new split-out | |
| commit. These hunks will then be written into a new commit that | |
| becomes the parent of the previous commit. The original commit | |
| stays intact, except that its parent will be the newly split-out | |
| commit. | |
| + | |
| The commit messages of the split-up commits will be asked for by launching | |
| the configured editor. Authorship of the commit will be the same as for the | |
| original commit. | |
| + | |
| If passed, _<pathspec>_ can be used to limit which changes shall be split out | |
| of the original commit. Files not matching any of the pathspecs will remain | |
| part of the original commit. For more details, see the 'pathspec' entry in | |
| linkgit:gitglossary[7]. | |
| + | |
| It is invalid to select either all or no hunks, as that would lead to | |
| one of the commits becoming empty. | |
| OPTIONS | |
| ------- | |
| `--dry-run`:: | |
| Do not update any references, but instead print any ref updates in a | |
| format that can be consumed by linkgit:git-update-ref[1]. Necessary new | |
| objects will be written into the repository, so applying these printed | |
| ref updates is generally safe. | |
| `--reedit-message`:: | |
| Open an editor to modify the target commit's message. | |
| `--empty=(drop|keep|abort)`:: | |
| Control what happens when a commit becomes empty as a result of the | |
| fixup. This can happen in two situations: | |
| + | |
| -- | |
| * The fixup target itself becomes empty because the staged changes exactly | |
| cancel out all changes introduced by that commit. | |
| * A descendant commit becomes empty during replay because it introduced the | |
| same change that was just fixed up into an ancestor. | |
| -- | |
| + | |
| With `drop` (the default), empty commits are removed from the rewritten | |
| history. Descendants of a dropped target commit are replayed directly onto | |
| the target's parent. Note that dropping the root commit is not supported; | |
| see LIMITATIONS. | |
| + | |
| With `keep`, empty commits are retained in the rewritten history as-is. | |
| + | |
| With `abort`, the command stops with an error if any commit would become | |
| empty. | |
| `--update-refs=(branches|head)`:: | |
| Control which references will be updated by the command, if any. With | |
| `branches`, all local branches that point to commits which are | |
| descendants of the original commit will be rewritten. With `head`, only | |
| the current `HEAD` reference will be rewritten. Defaults to `branches`. | |
| EXAMPLES | |
| -------- | |
| Fixup a commit | |
| ~~~~~~~~~~~~~~ | |
| ---------- | |
| $ git log --oneline --stat | |
| abc1234 (HEAD -> main) third | |
| third.txt | 1 + | |
| def5678 second | |
| second.txt | 1 + | |
| ghi9012 first | |
| first.txt | 1 + | |
| $ echo "change" >>unrelated.txt | |
| $ git add unrelated.txt | |
| $ git history fixup ghi9012 | |
| $ git log --oneline --stat | |
| jkl3456 (HEAD -> main) third | |
| third.txt | 1 + | |
| mno7890 second | |
| second.txt | 1 + | |
| pqr1234 first | |
| first.txt | 1 + | |
| unrelated.txt | 1 + | |
| ---------- | |
| The staged addition of `unrelated.txt` has been incorporated into the `first` | |
| commit. All descendant commits have been replayed on top of the rewritten | |
| history. | |
| Drop a commit | |
| ~~~~~~~~~~~~~ | |
| ---------- | |
| $ git log --oneline | |
| abc1234 (HEAD -> main) third | |
| def5678 second | |
| ghi9012 first | |
| $ git history drop 'main^{/second}' | |
| $ git log --oneline | |
| jkl3456 (HEAD -> main) third | |
| ghi9012 first | |
| ---------- | |
| The `second` commit has been removed from the history, and `third` has been | |
| replayed directly on top of `first`. All branches that pointed at the dropped | |
| commit have been moved to its parent. | |
| Split a commit | |
| ~~~~~~~~~~~~~~ | |
| ---------- | |
| $ git log --stat --oneline | |
| 3f81232 (HEAD -> main) original | |
| bar | 1 + | |
| foo | 1 + | |
| 2 files changed, 2 insertions(+) | |
| $ git history split HEAD | |
| diff --git a/bar b/bar | |
| new file mode 100644 | |
| index 0000000..5716ca5 | |
| --- /dev/null | |
| +++ b/bar | |
| @@ -0,0 +1 @@ | |
| +bar | |
| (1/1) Stage addition [y,n,q,a,d,p,?]? y | |
| diff --git a/foo b/foo | |
| new file mode 100644 | |
| index 0000000..257cc56 | |
| --- /dev/null | |
| +++ b/foo | |
| @@ -0,0 +1 @@ | |
| +foo | |
| (1/1) Stage addition [y,n,q,a,d,p,?]? n | |
| $ git log --stat --oneline | |
| 7cebe64 (HEAD -> main) original | |
| foo | 1 + | |
| 1 file changed, 1 insertion(+) | |
| d1582f3 split-out commit | |
| bar | 1 + | |
| 1 file changed, 1 insertion(+) | |
| ---------- | |
| GIT | |
| --- | |
| Part of the linkgit:git[1] suite |