TopGit manages one or more "patch queue"s (aka "patch set"s) using Git.
Whereas a utility such as quilt
maintains each individual patch
as a "diff" file on disk, TopGit (the tg
command) maintains each
individual patch as two branches in Git -- the patch's "branch"
and the patch's "base branch". The patch itself is simply the
"diff" from the patch's "base branch" to the patch's "branch".
Whereas a utilty such as quilt
maintains the list of active patch
"diff" files and the correct order to apply them in a file (the
series
file), TopGit maintains this information in a .topdeps
file that is part of each patch's "branch".
TopGit maintains any desired "documentation" (aka the patch header)
in a .topmsg
file that is also part of each patch's "branch" and
prepends it when generating a patch "diff".
Consider the following files:
frabjous.tar.gz # tarball of "frabjous" sources
0001-brillig.diff # first patch to apply
0002-gimble.diff # second patch to apply
With Quilt they might be used like so:
$ tar -xzf frabjous.tar.gz
$ cd frabjous
$ quilt import ../0001-brillig.diff && quilt push
$ quilt import ../0002-gimble.diff && quilt push
$ quilt applied
patches/0001-brillig.diff
patches/0002-gimble.diff
With TopGit they might be used like so:
$ tar -xzf frabjous.tar.gz
$ cd frabjous
$ git -c init.defaultBranch=master init && git add -A
$ git -c user.name=- -c user.email=- commit -qm frabjous
$ git checkout -b patches
$ git -c user.name=- -c user.email=- am ../0001-brillig.diff
$ git -c user.name=- -c user.email=- am ../0002-gimble.diff
$ git checkout master
$ git config topgit.top-bases heads # not the default...yet!
$ tg -c user.name=- -c user.email=- import ..patches
$ git branch
master
patches
t/brillig
* t/gimble
{top-bases}/t/brillig
{top-bases}/t/gimble
$ tg summary
t/brillig [PATCH] brillig
> t/gimble [PATCH] gimble
$ tg summary --rdeps --heads
t/gimble
t/brillig
master
Whereas with Quilt, the "0001-brillig.diff" patch is maintained as
the original patch file (in patches/0001-brillig.diff
), with
TopGit, the "0001-brillig.diff" patch becomes two Git branches,
{top-bases}/t/brillig
which represents the sources before the
"0001-brillig.diff" patch has been applied and t/brillig
which
represents the sources after the "0001-brillig.diff" patch has been
applied.
The original "0001-brillig.diff" patch can be re-generated with this TopGit command:
$ tg patch t/brillig
And is roughly equivalent to the diff from the {top-bases}/t/brillig
branch to the t/brillig
branch. (It's the diff excluding the two
TopGit metadata files with the patch header prepended to the result.)
To work on the "brillig" patch, one simply does a checkout of the
t/brillig
branch and makes and commits changes as normal using
regular Git commands. After the changes have been made, the "gimble"
patch may need updating if any of the changes made to the "brillig"
patch modified the same files affected by the "gimble" patch. That
can be accomplished with this command:
$ tg update --all
Finally, when a new set of ".diff" patch files needs to be generated, these commands can be used:
$ git checkout t/gimble
$ tg export --quilt --strip --numbered patchdir
$ ls -1 patchdir
0001-brillig.diff
0002-gimble.diff
series
Whereas the series
file in Quilt is (obviously) limited to a
"linear" topology, TopGit's .topdeps
file is not.
For example, consider that you have three patches:
- add "feature A"
- add "feature B"
- add "feature C" that requires both feature A and feature B
If "feature A" and "feature B" are completely independent features, then the order that the "feature A" and "feature B" patches are applied does not matter as long as they are both applied before the "feature C" patch.
TopGit can represent this by listing both the "feature A" and
"feature B" patches in the .topdeps
file for the "feature C"
patch.
Whereas with Quilt there is no history of changes (aka edits) to a patch (unless explicit backups are made along the way), all changes to a patch in TopGit are made via regular Git commands.
This means all the standard Git introspection commands (e.g. "log", "diff", "bisect", "blame", etc.) are available to view the history of an individual patch.
With Quilt when the "upstream" sources are updated (or even an early patch in the series is updated) in such a way as to cause a patch to no longer apply cleanly, the patch must be fixed by hand.
With TopGit, the full Git merge machinery is used to merge the "upstream" changes (or changes to an earlier patch) into the patches in dependency topological order. This can often avoid patch conflicts.
In the case where a patch must be fixed by hand (yes, this still
can happen in TopGit), the Git rerere
(reuse recorded resolution)
mechanism can be used to record the hand-crafted fix and later
automatically reuse that fix when needed.
When there are a very large number of patches in a patch set, it may be difficult to remember (especially if you're not the original author) which individual patch of a "patch set" contains a particular change.
After using the various Git introspection commands (e.g. "log",
"diff", "bisect", "blame", etc.) to locate a commit containing a
particular change, the TopGit tg contains
command can be used to
identify the individual patch of a "patch set" that logically
contains that commit.
In other words, tg contains
identifies which TopGit branch would
produce a patch "diff" file that makes the change introduced by the
given commit.
Because TopGit stores all information directly in Git, all of Git's
normal push/pull/remote functionality can be used to collaborate
on and/or share TopGit "patch set"s with others. The tg push
command facilitates pushing all branches in one or more TopGit
"patch set"s at once.
With Quilt it is possible to use different series
files to combine
patch "diff" files into different arrangements (e.g. for different
machine architectures or development branches).
TopGit also allows multiple "patch set"s to exist at the same time where a single "patch" may be used by more than one "patch set".
As an alternative to maintaining two or more different versions of
the same patch (e.g. for different development branches) under
different names such as, for example, "patch1-oldstable", "patch1-stable"
and "patch1-unstable", it's possible to use a TopGit tag to record
the state of a "patch set" (via the tg tag
command) and then later
go back to that state (via the tg shell
command) to, for example,
produce an updated patch set for an older software version and
record that new state of the older software version "patch set"
without disturbing the current version of the "patch set".
The advantage of using this mechanism is that the branch names for the individual patches always remain the same no matter how many different versions are being kept.
TopGit can import and export "patch set"s to other formats. This includes the one "diff" file per patch and one "commit" per patch formats.
This makes it easy to produce a set of "diff" patch files on demand for external (e.g. non-Git) use for a "patch set".
Forget about using git rebase
on a TopGit branch (either a patch's
"branch" or its "base branch"). With the exception being commits
that have not yet been merged into any other patch's "branch" or
"base branch". (TopGit does, however, have its own tgstash
that
provides a kind of "undo" after unfortunate update accidents.)
The merge history for a "patch set" can become rather complex as a
"patch set" is maintained over time (via the tg update
command)
since nothing is ever thrown away.
TopGit has a learning curve and those unfamiliar with Git will need to become comfortable with Git too.
Full documentation is available including a fully formatted
version of the manual (created from README_DOCS.rst
which
incorporates a few examples) and the TopGit changelog.