Welcome to githelper’s documentation!

Introduction

Githelper is both a module and a command line utility for working with git working copies, especially git-svn ones where svn:externals references are mapped to nested git-svn working copies.

Over time the utility also acquired a few features for pure SVN sandboxes, so its name doesn’t fully reflect its purpose.

Githelper 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/

Installation

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

Command Line Utility

This documentation does not cover the command line utility usage in detail because you can get that with the help option:

githelper.py -h

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. For example, you can type “sc” or “scf” for “svn-conflicts”.

Command Line Utility Examples

Below are some command line usage examples. The examples assume a gh shell alias for githelper:

alias gh githelper.py

Start out by cloning an SVN repository with svn:externals as nested git working copies:

$ gh clone-externals https://svn.example.com/repo/project my-great-project
...
$ cd my-great-project

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>
|--<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.

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.

To recursively update all git-svn sandboxes to the latest SVN state (i.e. perform a git svn rebase in all sub-working copies), use svnrebase:

$ gh svn-rebase
<Working copy /path/to/my-great-project/Foo>
    M       Widget/Foo/Foo.m
r1234 = a7fca99445fa4518cdc47b008656359c1d8ce188 (refs/remotes/svn)
    M       Engine/Bar/Bar.m
r1235 = d8faece12674ac8c670a15e10992c13876577834 (refs/remotes/svn)
First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/svn.

As a reminder, you could shorten the subcommand name and type just gh srb here.

To check out a certain point in time in the past in all nested sandboxes, you could use the each subcommand, which runs a shell command in each working copy:

$ gh each “git checkout $(git rev-list -n 1 –before=‘2012-01-01 00:00’ master)”

These are just a few examples, see the command line help for the remaining subcommands.

Usage as Toolkit Module

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 or git-svn 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[1])

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[1])
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[1])
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.

Extending with Plug-In Classes

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')

API Documentation

class githelper.GitWorkingCopy(path, parent=None)[source]

A class to represent a git or git-svn working copy.

Parameters:
  • path (str) – The file system path to the working copy.
  • parent (githelper.GitWorkingCopy) – A parent instance, you don’t usually use this yourself.
STOP_TRAVERSAL = False

returned from a __call__() implementation to stop further recursion by traverse().

__iter__()[source]

Returns an iterator over self and all of its nested git working copies.

See the example above.

ancestors()[source]

Returns a list of parent working copies.

If the receiver is the root working copy, this returns an empty list.

branch_names()[source]

Returns a list of git branch names.

chdir_to_path(*args, **kwds)[source]

A context manager for the with statement that temporarily switches the current working directory to the receiver’s working copy directory:

with wc.chdir_to_path():
    # do something useful here inside the working copy directory.
current_branch()[source]

Returns the name of the current git branch.

dirty_file_lines()[source]

Returns the output of git status for the files marked as modified, renamed etc.

hard_reset_current_branch(target)[source]

Hard-resets the current branch to the given ref

has_branch(branch_name)[source]

Returns True if the working copy has a git branch with the given name

is_dirty()[source]

Returns True if the receiver’s working copy has uncommitted modifications.

Many operations depend on a clean state.

is_git_svn()[source]

Returns True if the receiver’s git working copy is a git-svn working copy.

is_root()[source]

Returns True if the receiver does not have a parent working copy.

local_branch_names()[source]

Returns a list of git branch names not starting with remote/.

output_for_git_command(command, shell=False, filter_rules=None, header=None)[source]

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.
remote_branch_name_for_name_list(name_list)[source]

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:

['foo', 'bar']

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.

remote_branch_names()[source]

Returns a list of git branch names starting with remote/.

The leading remote/ part will be removed.

root_working_copy()[source]

Returns the root working copy, which could be self.

run_shell_command(command, filter_rules=None, shell=None, header=None, check_returncode=True)[source]

Runs the given shell command (array or string) in the receiver’s working directory using FilteringPopen.

Parameters:
self_or_descendants_are_dirty(list_dirty=False)[source]

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.
svn_externals()[source]

Returns a dictionary with the externals in the output of git svn show-externals.

svn_ignore_paths()[source]

Returns a dictionary with the items in the output of git svn show-ignore.

svn_info(key=None)[source]

Returns a dictionary containing the key/value pairs in the output of git svn info.

Parameters:key (str) – When present, returns just the one value associated with the given key.
switch_to_branch(branch_name)[source]

Checks out the given git branch

switched_to_branch(*args, **kwds)[source]

A context manager for the with statement that temporarily switches the current git branch to another one and afterwards restores the original one.

Example:

with wc.switched_to_branch('master'):
    # do something useful here on the 'master' branch.
traverse(iterator)[source]

Runs the given callable iterator on the receiver and all of its nested sub-working copies.

Before each call to iterator for a given working copy, the current directory is first set to that working copy’s path.

See the example above.

class githelper.FilteringPopen(*args, **kwargs)[source]

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.

returncode()[source]

Returns the command’s exit code.

Return type:int
run(filter=None, filter_rules=None, store_stdout=True, store_stderr=True, echo_stdout=True, echo_stderr=True, check_returncode=True, header=None)[source]

Run the command and capture its (potentially filtered) output, similar to subprocess.Popen.communicate().

Parameters:
  • filter (githelper.PopenOutputFilter) – An optional filter for stderr and stdout.
  • filter_rules (array) – Instead of a PopenOutputFilter instance, you can also pass a rule set directly.
  • store_stdout (bool) – If False, the command’s output will not be stored for later retrieval. If set to True, the output can be retrieved through the stdoutlines() method after it has finished executing.
  • store_stderr (bool) – If False, the command’s output will not be stored for later retrieval. If set to True, the output can be retrieved through the stderrlines() method after it has finished executing.
  • echo_stdout (bool) – If False, the command’s output will not be printed to stdout.
  • echo_stderr (bool) – If False, the command’s output will not be printed to stderr.
  • check_returncode (bool) – If True, the method raises an exception if the command terminates with a non-zero exit code.
  • header (object) – This value will be printed to the console exactly once if the subcommand produces any output that does not get filtered out. This is useful if you want to print something, but not if the command would not produce any output anyway.
stderrlines()[source]

Returns an array of the stderr lines that were not filtered, with trailing newlines removed.

stdoutlines()[source]

Returns an array of the stdout lines that were not filtered, with trailing newlines removed.

class githelper.PopenOutputFilter(stdout_rules, stderr_rules=None)[source]

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'),
    ('-', '.*')
]
class githelper.AbstractSubcommand(arguments)[source]

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().
__call__(wc=None)[source]

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.
check_for_git_svn_and_warn(wc)[source]

This returns False and warns if the given working copy is not a git-svn working copy.

Parameters:wc (githelper.GitWorkingCopy) – The working copy to check.
check_preconditions(wc)[source]

This method returns False if any of the working copies are dirty.

You can call this as a first step in your __call__() implementation and abort if your custom subcommand performs operations that require clean working copies.

Parameters:wc (githelper.GitWorkingCopy) – The working copy to check.
classmethod configure_argument_parser(parser)[source]

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.
prepare_for_root(root_wc)[source]

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:wc (githelper.GitWorkingCopy) – The working copy to check.
classmethod wants_working_copy()[source]

Return False to allow usage of your subcommand without a git working copy. The default is True.

Indices and tables