git rebase -i on steroids: turn your Git history into patch file series and back
Perl Shell
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


cj-git-patchtool is a tool to edit the history of a Git repository.

In that regard it is similar to `git rebase -i`; but unlike it, with
cj-git-patchtool you edit the history in a file that persists across
modification runs, so you can modify your changes incrementally
without risk of loosing your editing work. But not only the history is
kept in a file, but the patches as well: this allows to edit
individual patches persistently, too. There's also a tool included
called `wig` which uses `wiggle` to try to resolve conflicts that can
arise from history changes; and it saves the resolutions back into the
patch files, too. So, it always gives you access to the state in the
form of disk files, and you can change it and re-"run" the
modifications until you're done. It even checks the files into a new
Git repository on its own, so that you can commit your changes to the
state if you want, to keep a history of your history editing work :).


* install chj-bin and chj-perllib:

   # cd /opt; mkdir chj; cd chj
   # git clone perllib
   # git clone bin
   # mkdir -p /usr/local/lib/site_perl/Class
   # ln -s /opt/chj/perllib/Chj /usr/local/lib/site_perl/
   # ln -s /opt/chj/perllib/Class/ /usr/local/lib/site_perl/Class

  and add /opt/chj/bin to your PATH (through your .bash_profile or

*  # cd /opt/chj
   # git clone

  and add /opt/chj/cj-git-patchtool to your PATH

* install wiggle (Debian has it in the "wiggle" package)


In a terminal window, go to the root of the working directory of the
Git repository whose history you want to change, and check out the
branch that you want to change, with HEAD being the last commit of the
history that you want to edit.

If you run this tool the first time, from within the working directory
of the repository that you want to change:

 $ mkdir PATCHES
 $ git config --global core.excludesfile ~/.gitignore_global
 $ echo /PATCHES/ >> ~/.gitignore_global

Find the commit before the oldest commit you want to edit, then run
(-s and --start are equivalent):

$ cj-git-patchtool -s $commitbeforeoldest

This will open two windows, (a) an editor window with a file named
"_list" containing a list of all patches (the history), and (b) a
terminal window with the shell prompt in the directory that contains
the file that has been opened in the editor, as well as all the
individual patch files (as well as a file "_baseid" that contains
$commitbeforeoldest), as well as a .git dir with these files already
checked in (in case you want to commit your editing work).

Now edit the _list, adhering to these rules:

* Patches on subsequent lines are squashed. Put an empty line between
  each pair of patches or groups of patches that should become a new

* Within each group, put a star "*" at the start of a line to
  indicate the patch that determines the message and author time of
  the new commit.

* Alternatively, within each group, put a double quote '"' at
  the start of a line to indicate the patch that determines the
  message of the new commit. The author time is instead taken to be
  the latest author time of all patches in the series.

  And/or put a 't' at the start of a line to indicate the patch that
  determines the author time (but not the message).

* Alternatively, insert a group of lines somewhere in the group,
  starting and ending in square brackets that contains the commit
  message, like:

multiple lines are possible

* Existing commit messages can also be modified by adding a line
  starting with "prefix: " and then a string; the string will be
  prepended to the commit message.

* A line that starts with "%" is taken to be a shell script to run at
  that point during application of the patch series.

  For example '% bash' will run a subshell, which gives you the
  possibility to access the working directory of the partially applied
  history interactively. Or, '% make test' might run your test suite,

  If the script fails (does not exit 0), patch application is

* Any line that starts with "#" is ignored.

(I suggest you run `gitk &` and step through the history to see the
full commit messages and diffs easily while editing _list.)

If you want to apply the changed history, go to the terminal where you
ran cj-git-patchtool. It should now display
PATCHES/$name_of_the_patch_subdirectory as part of the prompt; this is
a reminder that you're in a subshell there. The subshell sees some new
commands, and those know where to find the directory with the history
state without further ado. To apply the history, run:

$ app

If the history applies cleanly, it will say "Ok" at the
end. Otherwise, fix your _list, or if it's a conflict, try:

$ wig patchfilename  # only the filename, not the full path

This will run `wiggle` and if it worked, will save the resolved diff
back to the patch file so that you don't have to run `wig` in
subsequent `app` runs.

If you're done, just close the editor buffer, exit the terminal with
the state files, and exit the subshell (hit ctl-d).

If you later decide that you didn't actually finish, run:

$ cj-git-patchtool --resume PATCHES/$name_of_the_patch_subdirectory

to get back into the subshell. (Currently, you'll have to reopen the
_list file and terminal with the state directory manually.)


use the `dupa` tool from chj-bin.git for duplicating patches (for
splitting them)

use the `cj-git-filter-branch--add-emptytail` tool from the same place
if you want to modify the initial commit in a repository (it grafts a
temporary empty commit to the tail.)

You could use the `cj-git-graftwrite` tool from the same place to
change the grafts file (somewhat) more easily. If you need to work up
to the very first commit in the history, it may be useful to prefix
the history with a commit with an empty tree, which can be created
with `cj-git-null`.

When in the cj-git-patchtool shell context, `help-cj-git-patchtool`
will show a synopsis of the usage.