Githelper is both a module and a command line utility for working with git working copies.
It is maintained at https://github.com/liyanage/git-tools/tree/master/githelper
The HTML version of this documentation is available at http://liyanage.github.com/git-tools/
You can install githelper directly from github like this:
sudo curl -o /usr/local/bin/githelper.py -L https://github.com/liyanage/git-tools/raw/master/githelper/githelper.py sudo chmod 755 /usr/local/bin/githelper.py
This documentation does not cover the command line utility usage in detail because you can get that with the help option:
The utility is subcommand-based, and each subcommand has its own options. You can get a list of subcommands with the -h option shown above, and each subcommand in turn supports the -h flag:
githelper.py some_subcommand -h
You can extend the set of subcommands by writing plug-in classes. See Extending with Plug-In Classes for details.
You can abbreviate the subcommand name. The abbreviation does not have to be a contiguous prefix or substring of the full name, any sequence of characters that unanbiguously identifies one of the subcommands will work (it must be anchored at the beginning, however).
Below are some command line usage examples. The examples assume a gh shell alias for githelper defined as follows:
$ alias gh githelper.py
To get an overview of the nested working copies, use the tree subcommand:
$ gh tree |<Working copy /path/to/my-great-project> |--<Working copy /path/to/my-great-project/Foo *> |----<Working copy /path/to/my-great-project/Foo/subexternal l*> |--<Working copy /path/to/my-great-project/Bar> |--<Working copy /path/to/my-great-project/Baz> |--<Working copy /path/to/my-great-project/Subproject *> |----<Working copy /path/to/my-great-project/Subproject/ABC/Demo> |--<Working copy /path/to/my-great-project/Xyz>
The * indicates a working copy with uncommited changes. The l indicates a local-only branch, i.e. one that’s not tracking a remote branch
To get a combined git status view, use status:
$ gh status <Working copy /path/to/my-great-project/Foo *> M data.txt <Working copy /path/to/my-great-project/Subproject *> A xyz.dat
Only working copies that have any interesting status are listed.
As a reminder, you could shorten the subcommand name and type just gh sta here.
To check out a certain point in time in the past in all nested working copies, you could use the each subcommand, which runs a shell command in each one:
$ gh each "git checkout \$(git rev-list -n 1 --before='2012-01-01 00:00' master)"
Another useful subcommand is branch, it gives a complete overview of the branch status of each working copy:
$ gh b branch </Users/liyanage/Projects/foo> 0↑ 0↓ master 4c3b6721 1h </Users/liyanage/Projects/foo/repositories/LibraryManager> 0↑ 0↓ master 301105f7 1h </Users/liyanage/Projects/foo/repositories/Reports *> 0↑ 0↓ master 7ffa7408 2h </Users/liyanage/Projects/foo/repositories/analyzer> 0↑ 0↓ feature/xyz c2881596 5h </Users/liyanage/Projects/foo/repositories/common l> 0↑ 0↓ master f0a1ec75 34m
See the subcommand’s detailed help for an explanation of the columns.
Many subcommands, fetch included, run the branch subcommand automatically after they finish.
These are just a few examples, see the command line help for the remaining subcommands.
If the utility does not provide what you need, you can write your own script based on githelper as a module. The rest of this document explains the module’s API.
The main entry point is the GitWorkingCopy class. You instantiate it with the path to a git working copy (which possibly has nested sub-working copies).
You can then traverse the tree of nested working copies by iterating over the GitWorkingCopy instance:
#!/usr/bin/env python import githelper import os import sys root_wc = githelper.GitWorkingCopy(sys.argv) for wc in root_wc: # Gets called once for root_wc and all sub-working copies. # Do something interesting with wc using its API here...
The traverse() method provides another way to do this, it takes a callable, in the following example a function:
def process_working_copy(wc): print wc.current_branch() root_wc = githelper.GitWorkingCopy(sys.argv) root_wc.traverse(process_working_copy)
Any callable object works, in the following example an instance of a class that implements __call__():
class Foo: def __init__(self, some_state): self.some_state = some_state def __call__(self, wc): # possibly use self.some_state print wc.current_branch() root_wc = githelper.GitWorkingCopy(sys.argv) iterator = Foo('bar') root_wc.traverse(iterator)
You can take a look at the various Subcommand... classes in the module’s source code to see examples of the API usage. These classes implement the various subcommands provided by the command line utility front end and they exercise most of the GitWorkingCopy API.
To extend the command line utility with additional custom subcommands, create a file called githelper_local.py and store it somewhere in your PATH. The file must contain one class per subcommand. Each class name must start with Subcommand, anything after that part is used as the actual subcommand name that you pass on the command line to invoke it.
Here is an example githelper_local.py with one subcommand named foo:
from githelper import AbstractSubcommand, GitWorkingCopy class SubcommandFoo(AbstractSubcommand): # The class-level doc comment is reused for the command-line usage help string. """Provide a useful description of this subcommand here""" def __call__(self, wc): print wc return GitWorkingCopy.STOP_TRAVERSAL @classmethod def configure_argument_parser(cls, parser): # Add any command line options here. If you don't need any, just add a "pass" statement instead. parser.add_argument('-b', '--bar', help='Provide a useful description of this option here')
A class to represent a git working copy.
Returns an iterator over self and all of its nested git working copies.
See the example above.
Returns a list of parent working copies.
If the receiver is the root working copy, this returns an empty list.
Returns a list of git branch names.
with wc.chdir_to_path(): # do something useful here inside the working copy directory.
Returns a list of git commits that have not yet been pushed to upstream.
Returns a list of git commits that are only in upstream but not in the local tracking branch.
Stashes the uncommitted changes in the working copy using “stash create”, i.e. without updating the “stash” reference, and runs “git reset –hard”. Prints and returns the commit id if anything was stashed, None otherwise.
Returns the name of the current git branch.
Returns the name of the current git repository.
Returns the output of git status for the files marked as modified, renamed etc.
Hard-resets the current branch to the given ref
Returns True if the working copy has a git branch with the given name
Returns True if the receiver’s working copy has uncommitted modifications.
Many operations depend on a clean state.
Returns True if the receiver does not have a parent working copy.
Returns a list of git branch names not starting with remote/.
Runs the given shell command (array or string) in the receiver’s working directory and returns the output.
|Parameters:||shell (bool) – If True, runs the command through the shell. See the subprocess library module documentation for details.|
Returns a remote branch name matching a list of candidate strings.
Tries to find a remote branch names using all possible combinations of the names in the list. For example, given:
as name_list, it would find any of these:
remotes/foo remotes/Foo remotes/bar remotes/Bar remotes/Foo-Bar remotes/foo-bar remotes/Bar-Foo remotes/bar-foo
etc. and return the part after remotes/ of the first match.
Returns a list of git branch names starting with remote/.
The leading remote/ part will be removed.
Returns the root working copy, which could be self.
Runs the given shell command (array or string) in the receiver’s working directory using FilteringPopen.
Returns True if the receiver’s or one of its nested working copies are dirty.
|Parameters:||list_dirty (bool) – If True, prints the working copy path and the list of dirty files.|
Checks out the given git branch
with wc.switched_to_branch('master'): # do something useful here on the 'master' branch.
Returns a list of tags that point to the given commit
Returns a list of tags that point to the head commit
A wrapper around subprocess.Popen that filters the subprocess’s output.
The constructor’s parameters are forwarded mostly unchanged to Popen's constructor. Exceptions are bufsize, which is set to 1 for line-buffered output, and stdout, and stderr, which are both set to subprocess.PIPE.
This method sets up the Popen instance but does not run it. See run() for that.
Returns the command’s exit code.
Run the command and capture its (potentially filtered) output, similar to subprocess.Popen.communicate().
Returns an array of the stderr lines that were not filtered, with trailing newlines removed.
Returns an array of the stdout lines that were not filtered, with trailing newlines removed.
Represents a set of inclusion/exclusion rules to filter the output of FilteringPopen. You create instance of this class to pass to FilteringPopen.run() (but see run()‘s filter_rules parameter for a convenience shortcut).
There are two independent rule sets to filter stdout and stderr individually. If you don’t supply the (optional) rule set for stderr, the (mandatory) one for stdout is reused.
Rule sets are lists of lists of this form:
rules = [ ('-', r'^foo'), ('-', r'bar$'), ... ]
Each rule is a two-element list where the first element is either the string “-” or “+” representing the actions for exclusion and inclusion, and the second element is a regular expression.
Each line of stdout or stderr output is matched against each regular expression. If one of them matches, the line is filtered out if the action element is “-” or included if the action is “+”. After the first rule matches, no further rules are evaluated.
If no rule matches a given line, the line is included (not filtered out), i.e. there is an implicit last rule like this:
In the example given above, all lines beginning with foo or ending with bar are filtered out.
In the following example, only lines containing foo or bar are included, everything else is filtered out:
rules = [ ('+', r'foo'), ('+', r'bar'), ('-', '.*') ]
A base class for custom subcommand plug-in classes.
You can, but don’t have to, derive from this class for your custom subcommand extension classes. It also documents the interface you are expected to implement in your class and it provides some convenience methods.
|Parameters:||arguments (argparse.Namespace) – The command-line options passed to your subcommand in the form of a namespace instance as returned by argparse.ArgumentParser.parse_args().|
This gets called once per working copy to perform the subcommand’s task.
If you are only interested in the root-level working copy, you can stop the traversal by returning githelper.GitWorkingCopy.STOP_TRAVERSAL.
|Parameters:||wc (githelper.GitWorkingCopy) – The working copy to process.|
This method gets called on the root working copy after the traversal of a tree has finished. The subcommand class can return another subcommand instance that will be run next.
|Parameters:||root_wc (githelper.GitWorkingCopy) – The working copy to process.|
If you override this in your subclass, you can configure additional command line arguments for your subcommand’s arguments parser.
|Parameters:||parser (argparse.ArgumentParser) – The argument parser that you can configure.|
This method gets called on the root working copy only and lets you perform preparation steps that you want to do only once for the entire tree.
|Parameters:||root_wc (githelper.GitWorkingCopy) – The working copy to check.|
Return False to allow usage of your subcommand without a git working copy. The default is True.