blob: 2b8e4e782aa827de3be31f43af312ab2a03401d8 [file] [log] [blame]
StGIT Tutorial
##############
StGIT is a Python application that provides functionality similar to
quilt (i.e. pushing/popping patches to/from a stack) using GIT instead
of 'diff' and 'patch'. StGIT stores its patches in a GIT repository as
normal GIT commit objects.
StGIT is not an SCM interface on top of GIT. For standard SCM
operations, either use GIT's porcelain commands or the Cogito tool.
StGIT is available for download at http://www.procode.org/stgit/ .
This tutorial assumes you are already familiar with GIT. For more
information on GIT, see the GIT_tutorial or git(7) .
Basic Operation
===============
Help
----
For a full list of StGIT commands:
stg help
For help on individual subcommands:
stg <cmd> (-h | --help)
Repository initialisation
-------------------------
In stand-alone mode, StGIT is used in conjunction with a GIT repository
that is already initialised (using 'git-init-db'). StGIT cannot be used
outside of a GIT repository.
Any branch in a GIT repository may be managed by StGIT. Each branch
managed by StGIT contains an independent series of StGIT patches.
To initialise an existing GIT branch to be managed by StGIT, cd into the
top of your GIT repository, check out the branch you'd like to manage
with StGIT, and type:
stg init
Run the 'stg init' command for any pre-existing GIT branches intended to
be used with StGIT.
You can switch between GIT branches with:
stg branch [<branch name>]
This checks out the named branch and places you at the topmost applied
StGIT patch in that branch.
Alternately, you can create branches using only StGIT commands, which
will automatically prepare them for use with StGIT:
stg branch --create <new branch>
Working with remote repositories
--------------------------------
With a single command, StGIT can create and initialize a GIT repository
which mirrors a remote GIT repository. This is known as cloning. All GIT
transports are supported.
To clone a repository, use:
stg clone <repository> <local-dir>
This creates a fresh local repository, initialises a GIT database in it,
pulls the latest version of the remote, and creates and initialises a
'master' branch for use with StGIT.
At any time you can pull the latest changes from the remote repository.
By default, StGIT pulls from the location stored in .git/branches/
origin, and updates the base of the current branch.
To pull the latest changes from a remote repository, use:
stg pull [<branch> or 'origin']
This command removes all applied StGIT patches from the current branch,
updates the branch's base commit, then attempts to re-apply the patches.
Any merge conflicts will halt this process, allowing you to clean up the
conflicts and continue (see below).
If the maintainer of the remote repository includes one of your patches
in the published repository that you pull from, StGIT can usually
recognize that an incoming patch from the remote matches one of yours,
and it turns your local version into an empty patch.
To automatically delete empty patches after a pull, use:
stg clean
As a convention, you should avoid working in the 'master' branch and use
it only as a reference, since it reflects someone else's work. If you
decide to publish your GIT repository, you'll want your own work
separated into its own branch to make it convenient for others to pull
just your patches.
Getting started: creating a patch
---------------------------------
Changes to your working directory are saved in a patch. An StGIT patch
is simply a saved set of modifications to your working directory, plus a
saved description. To create an empty StGIT patch in the current branch:
stg new <name>
To save the changes you've made (that is, to refresh a patch), use:
stg refresh
To discard changes in your working directory, use:
git checkout -f
This restores your working directory to the state it was in the last
time the patch was refreshed.
Modified files that haven't been saved via a refresh operation can be
viewed with:
stg status
You can view modified files that have already been saved into a patch:
stg files
The 'stg refresh' command automatically notes changes to files that
already exist in the working directory, but you have to tell StGIT
explicitly if you add, remove, or rename files.
To record the addition or deletion of files in your new patch:
stg add [<file>*]
stg rm [<file>*]
To record the renaming of a file in your new patch, issue both of these
commands:
stg rm <oldfilename>
stg add <newfilename>
Stack manipulation: managing multiple patches
---------------------------------------------
StGIT can manage more than one patch at a time. A series of StGIT
patches in a GIT branch are known collectively as a stack. The new patch
you created above is now the topmost patch in your stack. You can always
see the name of the topmost (current) patch with:
stg top
The topmost patch is used as the default patch for most StGIT
operations. It is the default target of the 'stg refresh' command, for
example.
Patches that are pushed onto the stack are referred to as applied, and
patches that are popped off the stack are referred to as unapplied.
To push/pop a patch to/from a stack:
stg push [--all | <name>]
stg pop [--all]
The last patch you pushed is the topmost patch. This patch is always in
the applied list; StGIT can't operate on an unapplied patch unless you
apply it first.
You can display the order of patches in a stack with one of these
commands:
stg series
stg applied
stg unapplied
By default the 'stg push' command applies the first patch in the
unapplied list, but you can push any patch in the unapplied list by
giving the name of the patch. This is useful if you want to reorder the
patches in a stack.
During a push operation, merge conflicts can occur (especially if you
are changing the order of the patches in your stack). If the push causes
merge conflicts, they need to be fixed and 'stg resolved' run (see
below). A 'push' operation can also be reverted with 'stg push --undo'.
A few more stack basics; to rename a patch:
stg rename <old-name> <new-name>
To delete a patch:
stg delete <name>
This permanently discards the named patch. In other words, the patch no
longer appears in either the applied or unapplied lists, and cannot be
reapplied to the series.
You may want to make patches in your stack a permanent part of your GIT
repository, for example if you are publishing your repository to others.
To do this, use:
stg commit
This merges all applied patches in your patch series into the GIT
repository and removes them from your stack. Use this command only if
you want to permanently store the applied patches and no longer manage
them with StGIT.
Converting between StGIT patches and text diffs
-----------------------------------------------
As mentioned in the introduction, StGIT stores modifications to your
working tree in the form of GIT commits. This means if you want to apply
your changes to a tree not managed by GIT, or send your changes to
someone else in e-mail, you need to convert your StGIT patches into
normal textual diffs that can be applied with the GNU 'patch' command.
The 'stg diff' command is a powerful way to generate and view textual
diffs of patches managed by StGIT.
To view a diff of the topmost patch:
stg diff -r /
Observe that this does not show any changes in the working directory
that have not been saved by a 'refresh'. To view just the changes you've
made since the last refresh, use:
stg diff -r /top
If you want to see the changes made by the patch combined with any
unsaved changes in the working directory, try:
stg diff -r /bottom
You can also show the changes to any patch in your stack with:
stg diff -r <patch>/
Use this command to view all the changes in your stack up through the
current patch:
stg diff -r base
The 'stg diff' command supports a number of other features that are very
useful. Be sure to take a look at the help information for this command.
To convert your StGIT patches into patch files:
stg export [--range=[<patch1>[:<patch2>]]] [<dir-name>]
The 'export' command supports options to automatically number the
patches (-n) or add the '.diff' extension (-d). If you don't tell "stg
export" where to put the patches, it will create directory named "patch-
branchname" in your current directory, and store the patches there.
To e-mail a patch or range of patches:
stg mail [--to=...] (--all | --range=[<patch1>[:<patch2>]] | <patch>)
"stg mail" has a lot of options, so read the output of "stg mail -h" for
more information.
You can also import an existing GNU diff patch file as a new StGIT patch
with a single command. "stg import" will automatically parse through the
patch file and extract a patch description. Use:
stg import [<file>]
This is the equivalent of "stg new" followed by "patch -i <file>", then
"stg refresh -e".
Sometimes the patch file won't apply cleanly. In that case, "stg import"
will leave you with an empty StGIT patch, to which you then apply the
patch file by hand using "patch -i" and your favorite editor.
To merge a GNU diff file (defaulting to the standard input) into the
topmost patch:
stg fold [<file>]
This command supports a '--threeway' option which applies the patch onto
the bottom of the topmost one and performs a three-way merge.
Advanced Usage
==============
Handling merge conflicts
------------------------
Pushing a patch on the stack can fail if the patch cannot be applied
cleanly. This usually happens if there are overlapping changes in the
tree, the patch depends on another patch which is not applied, or if a
patch was not merged upstream in the exact form it was sent.
The 'push' operation stops after the first patch with conflicts. The
'status' command shows the conflict files by marking them with a 'C'. If
the 'keeporig' options is set to 'yes' (the default), the original files
involved in the merge operations are left in the tree as <file>.older,
<file>.local and <file>.remote for better analysis of the conflict. If
'diff3' is used as the merger (the default), markers are added to the
conflicted files as well.
Run the 'resolved' command to mark the conflicts resolved and remove the
temporary merge files from the working tree. Then run the 'refresh'
command to update the StGIT patch with the modifications you made to
resolve the conflict.
Configuration file
------------------
StGIT tries to read the configuration options from the following files:
/etc/stgitrc, ~/.stgitrc and .git/stgitrc. The latter overrides the
options in the former files. If no file is found, the defaults are used.
An example configuration file with options description can be found in
the examples/ directory. Most users would probably only define the
'smtpserver' option used by the 'mail' command.
The gitmergeonefile.py script does the three-way merging on individual
files using the tool specified by the 'merger' option. The user can
specify a smarter tool to be used.
Templates
---------
The 'export' and 'mail' commands use templates for generating the patch
files or e-mails. The default templates are installed under <prefix>/
share/stgit/templates/ and, combined with the extra options available
for the commands, should be enough for most users. The template format
uses the standard Python string formatting rules. The variables
available are shown in the the help message for the commands.
The 'mail' command can also send an initial e-mail for which there is no
default template. The <prefix>/share/stgit/examples/firstmail.tmpl file
can be used as an example.
A default description for new patches can be defined in the .git/
patchdescr.tmpl file. This is useful for things like signed-off-by
lines.
Merging two patches into one
----------------------------
There is no command to do this directly at the moment but one can export
the patch to be merged and use the 'stg fold' command on the generated
diff file. Assuming that the merged patch was not already applied, the
operation will succeed. Pushing the merged patch onto the stack will
result in an empty patch (StGIT notifying the user) that can be safely
deleted.
Technical Information
=====================
A bit of StGIT patch theory
---------------------------
We assume that a patch is a diff between two nodes - bottom and top. A
node is a commit SHA1 id or tree SHA1 id in the GIT terminology:
P - patch
N - node
P = diff(Nt, Nb)
Nb - bottom (start) node
Nt - top (end) node
Nf - first node (for log generation)
For an ordered stack of patches:
P1 = diff(N1, N0)
P2 = diff(N2, N1)
...
Ps = P1 + P2 + P3 + ... = diff(Nst, Nsb)
Ps - the big patch of the whole stack
Nsb - bottom stack node (= N0)
Nst - top stack node (= Nn)
Applying (pushing) a patch on the stack (Nst can differ from Nb) is done
by diff3 merging. The new patch becomes:
P' = diff(Nt', Nb')
Nb' = Nst
Nt' = diff3(Nst, Nb, Nt)
(note that the diff3 parameters order is: branch1, ancestor, branch2)
The above operation allows easy patch re-ordering.
Removing (popping) a patch from the stack is done by simply setting the
Nst to Nb.
Layout of the .git directory
----------------------------
HEAD -> refs/heads/<something>
objects/
??/
...
refs/
heads/
master - the master commit id
...
tags/
...
branches/
...
patches/
master/
applied - list of applied patches
unapplied - list of not-yet applied patches
current - name of the topmost patch
patch1/
bottom - the bottom id of the patch
top - the top id of the patch
description - the patch description
authname - author's name
authemail - author's e-mail
commname - committer's name
commemail - committer's e-mail
patch2/
...
...
...