summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2010-11-24 19:48:59 +0100
committerSebastian Thiel <byronimo@gmail.com>2010-11-24 19:48:59 +0100
commit3175b5b21194bcc8f4448abe0a03a98d3a4a1360 (patch)
treef1a098c4b38ae3b7cf52600e9fc9c357cdd7c353
parentfca367548e365f93c58c47dea45507025269f59a (diff)
parent3203cd7629345d32806f470a308975076b2b4686 (diff)
downloadgitpython-3175b5b21194bcc8f4448abe0a03a98d3a4a1360.tar.gz
Merge branch 'reflog'
-rw-r--r--__init__.py3
-rw-r--r--doc/source/changes.rst33
-rw-r--r--doc/source/conf.py2
-rw-r--r--doc/source/reference.rst41
-rw-r--r--doc/source/tutorial.rst8
-rw-r--r--index/base.py2
-rw-r--r--index/fun.py7
-rw-r--r--objects/__init__.py2
-rw-r--r--objects/base.py4
-rw-r--r--objects/commit.py27
-rw-r--r--objects/submodule/base.py10
-rw-r--r--objects/submodule/root.py3
-rw-r--r--objects/util.py75
-rw-r--r--refs.py1052
-rw-r--r--refs/__init__.py21
-rw-r--r--refs/head.py246
-rw-r--r--refs/log.py282
-rw-r--r--refs/reference.py84
-rw-r--r--refs/remote.py63
-rw-r--r--refs/symbolic.py618
-rw-r--r--refs/tag.py91
-rw-r--r--remote.py3
-rw-r--r--repo/base.py1
-rw-r--r--repo/fun.py69
-rw-r--r--test/fixtures/reflog_HEAD460
-rw-r--r--test/fixtures/reflog_invalid_date2
-rw-r--r--test/fixtures/reflog_invalid_email2
-rw-r--r--test/fixtures/reflog_invalid_newsha2
-rw-r--r--test/fixtures/reflog_invalid_oldsha2
-rw-r--r--test/fixtures/reflog_invalid_sep2
-rw-r--r--test/fixtures/reflog_master124
-rw-r--r--test/test_blob.py17
-rw-r--r--test/test_commit.py2
-rw-r--r--test/test_index.py1
-rw-r--r--test/test_reflog.py102
-rw-r--r--test/test_refs.py86
-rw-r--r--test/test_remote.py2
-rw-r--r--test/test_repo.py30
-rw-r--r--test/test_submodule.py1
-rw-r--r--test/test_tree.py3
-rw-r--r--test/test_util.py8
-rw-r--r--util.py143
42 files changed, 2511 insertions, 1225 deletions
diff --git a/__init__.py b/__init__.py
index 7f275b44..483ac091 100644
--- a/__init__.py
+++ b/__init__.py
@@ -37,7 +37,8 @@ from git.index import *
from git.util import (
LockFile,
BlockingLockFile,
- Stats
+ Stats,
+ Actor
)
#} END imports
diff --git a/doc/source/changes.rst b/doc/source/changes.rst
index 563fb46b..7b959532 100644
--- a/doc/source/changes.rst
+++ b/doc/source/changes.rst
@@ -2,16 +2,45 @@
Changelog
=========
-0.3.2 Beta 1
+0.3.1 Beta 2
============
-* Flattened directory structure to make development more convenient.
+* Added **reflog support** ( reading and writing )
+
+ * New types: ``RefLog`` and ``RefLogEntry``
+ * Reflog is maintained automatically when creating references and deleting them
+ * Non-intrusive changes to ``SymbolicReference``, these don't require your code to change. They allow to append messages to the reflog.
+
+ * ``abspath`` property added, similar to ``abspath`` of Object instances
+ * ``log()`` method added
+ * ``log_append(...)`` method added
+ * ``set_reference(...)`` method added (reflog support)
+ * ``set_commit(...)`` method added (reflog support)
+ * ``set_object(...)`` method added (reflog support)
+
+ * Intrusive Changes to ``Head`` type
+
+ * ``create(...)`` method now supports the reflog, but will not raise ``GitCommandError`` anymore as it is a pure python implementation now. Instead, it raises ``OSError``.
+
+* Repo.rev_parse now supports the [ref]@{n} syntax, where n is the number of steps to look into the reference's past
+
+* **BugFixes**
+
+ * Removed incorrect ORIG_HEAD handling
+
+* **Flattened directory** structure to make development more convenient.
* .. note:: This alters the way projects using git-python as a submodule have to adjust their sys.path to be able to import git-python successfully.
+ * Misc smaller changes and bugfixes
0.3.1 Beta 1
============
* Full Submodule-Support
* Added unicode support for author names. Commit.author.name is now unicode instead of string.
+* Head Type changes
+
+ * config_reader() & config_writer() methods added for access to head specific options.
+ * tracking_branch() & set_tracking_branch() methods addded for easy configuration of tracking branches.
+
0.3.0 Beta 2
============
diff --git a/doc/source/conf.py b/doc/source/conf.py
index e80bd0aa..469ab3b3 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -20,7 +20,7 @@ import sys, os
# is relative to the documentation root, use os.path.abspath to make it
# absolute, like shown here.
#sys.path.append(os.path.abspath('.'))
-sys.path.insert(0, os.path.abspath('../../lib'))
+sys.path.insert(0, os.path.abspath('../../../'))
# General configuration
# ---------------------
diff --git a/doc/source/reference.rst b/doc/source/reference.rst
index 75e712a8..7adc5328 100644
--- a/doc/source/reference.rst
+++ b/doc/source/reference.rst
@@ -131,13 +131,48 @@ Exceptions
:undoc-members:
-Refs
-----
+Refs.symbolic
+-------------
+
+.. automodule:: git.refs.symbolic
+ :members:
+ :undoc-members:
+
+Refs.reference
+--------------
-.. automodule:: git.refs
+.. automodule:: git.refs.reference
:members:
:undoc-members:
+Refs.head
+---------
+
+.. automodule:: git.refs.head
+ :members:
+ :undoc-members:
+
+Refs.tag
+------------
+
+.. automodule:: git.refs.tag
+ :members:
+ :undoc-members:
+
+Refs.remote
+------------
+
+.. automodule:: git.refs.remote
+ :members:
+ :undoc-members:
+
+Refs.log
+------------
+
+.. automodule:: git.refs.log
+ :members:
+ :undoc-members:
+
Remote
------
diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst
index 9aadae47..642136ab 100644
--- a/doc/source/tutorial.rst
+++ b/doc/source/tutorial.rst
@@ -88,6 +88,14 @@ A symbolic reference is a special case of a reference as it points to another re
head = repo.head # the head points to the active branch/ref
master = head.reference # retrieve the reference the head points to
master.commit # from here you use it as any other reference
+
+Access the reflog easily::
+
+ log = master.log()
+ log[0] # first (i.e. oldest) reflog entry
+ log[-1] # last (i.e. most recent) reflog entry
+
+For more information on the reflog, see the ``RefLog`` type's documentation.
Modifying References
********************
diff --git a/index/base.py b/index/base.py
index 05caa06d..a63dbb26 100644
--- a/index/base.py
+++ b/index/base.py
@@ -3,8 +3,6 @@
#
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
-"""Module containing Index implementation, allowing to perform all kinds of index
-manipulations such as querying and merging."""
import tempfile
import os
import sys
diff --git a/index/fun.py b/index/fun.py
index 87fdf1a9..9b35bf04 100644
--- a/index/fun.py
+++ b/index/fun.py
@@ -1,7 +1,6 @@
-"""
-Contains standalone functions to accompany the index implementation and make it
-more versatile
-"""
+# Contains standalone functions to accompany the index implementation and make it
+# more versatile
+# NOTE: Autodoc hates it if this is a docstring
from stat import (
S_IFDIR,
S_IFLNK,
diff --git a/objects/__init__.py b/objects/__init__.py
index e8e0ef39..77f69d29 100644
--- a/objects/__init__.py
+++ b/objects/__init__.py
@@ -7,6 +7,7 @@ from base import *
# imported by the submodule.base
import submodule.util
submodule.util.IndexObject = IndexObject
+submodule.util.Object = Object
from submodule.base import *
from submodule.root import *
@@ -15,7 +16,6 @@ from tag import *
from blob import *
from commit import *
from tree import *
-from util import Actor
__all__ = [ name for name, obj in locals().items()
if not (name.startswith('_') or inspect.ismodule(obj)) ] \ No newline at end of file
diff --git a/objects/base.py b/objects/base.py
index b8cec47f..5f2f7809 100644
--- a/objects/base.py
+++ b/objects/base.py
@@ -57,6 +57,10 @@ class Object(LazyMixin):
:return: new object instance of a type appropriate to represent the given
binary sha1
:param sha1: 20 byte binary sha1"""
+ if sha1 == cls.NULL_BIN_SHA:
+ # the NULL binsha is always the root commit
+ return get_object_type_by_name('commit')(repo, sha1)
+ #END handle special case
oinfo = repo.odb.info(sha1)
inst = get_object_type_by_name(oinfo.type)(repo, oinfo.binsha)
inst.size = oinfo.size
diff --git a/objects/commit.py b/objects/commit.py
index a2b6c554..9c7e66a3 100644
--- a/objects/commit.py
+++ b/objects/commit.py
@@ -4,7 +4,8 @@
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
-from git.util import (
+from git.util import (
+ Actor,
Iterable,
Stats,
)
@@ -20,9 +21,7 @@ from gitdb.util import (
from util import (
Traversable,
Serializable,
- get_user_id,
parse_date,
- Actor,
altz_to_utctz_str,
parse_actor_and_date
)
@@ -43,17 +42,10 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
# ENVIRONMENT VARIABLES
# read when creating new commits
- env_author_name = "GIT_AUTHOR_NAME"
- env_author_email = "GIT_AUTHOR_EMAIL"
env_author_date = "GIT_AUTHOR_DATE"
- env_committer_name = "GIT_COMMITTER_NAME"
- env_committer_email = "GIT_COMMITTER_EMAIL"
env_committer_date = "GIT_COMMITTER_DATE"
- env_email = "EMAIL"
# CONFIGURATION KEYS
- conf_name = 'name'
- conf_email = 'email'
conf_encoding = 'i18n.commitencoding'
# INVARIANTS
@@ -306,17 +298,9 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
# COMMITER AND AUTHOR INFO
cr = repo.config_reader()
env = os.environ
- default_email = get_user_id()
- default_name = default_email.split('@')[0]
- conf_name = cr.get_value('user', cls.conf_name, default_name)
- conf_email = cr.get_value('user', cls.conf_email, default_email)
-
- author_name = env.get(cls.env_author_name, conf_name)
- author_email = env.get(cls.env_author_email, conf_email)
-
- committer_name = env.get(cls.env_committer_name, conf_name)
- committer_email = env.get(cls.env_committer_email, conf_email)
+ committer = Actor.committer(cr)
+ author = Actor.author(cr)
# PARSE THE DATES
unix_time = int(time())
@@ -340,9 +324,6 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
enc_section, enc_option = cls.conf_encoding.split('.')
conf_encoding = cr.get_value(enc_section, enc_option, cls.default_encoding)
- author = Actor(author_name, author_email)
- committer = Actor(committer_name, committer_email)
-
# if the tree is no object, make sure we create one - otherwise
# the created commit object is invalid
diff --git a/objects/submodule/base.py b/objects/submodule/base.py
index 4f4223b6..5d32d600 100644
--- a/objects/submodule/base.py
+++ b/objects/submodule/base.py
@@ -14,6 +14,7 @@ from git.util import (
join_path_native,
to_native_path_linux
)
+
from git.config import SectionConstraint
from git.exc import (
InvalidGitRepositoryError,
@@ -339,14 +340,7 @@ class Submodule(util.IndexObject, Iterable, Traversable):
# have a valid branch, but no checkout - make sure we can figure
# that out by marking the commit with a null_sha
- # have to write it directly as .commit = NULLSHA tries to resolve the sha
- # This will bring the branch into existance
- refpath = join_path_native(mrepo.git_dir, local_branch.path)
- refdir = os.path.dirname(refpath)
- if not os.path.isdir(refdir):
- os.makedirs(refdir)
- #END handle directory
- open(refpath, 'w').write(self.NULL_HEX_SHA)
+ local_branch.set_object(util.Object(mrepo, self.NULL_BIN_SHA))
# END initial checkout + branch creation
# make sure HEAD is not detached
diff --git a/objects/submodule/root.py b/objects/submodule/root.py
index 2e3cc775..d194cd5b 100644
--- a/objects/submodule/root.py
+++ b/objects/submodule/root.py
@@ -48,8 +48,7 @@ class RootModule(Submodule):
:param previous_commit: If set to a commit'ish, the commit we should use
as the previous commit the HEAD pointed to before it was set to the commit it points to now.
- If None, it defaults to ORIG_HEAD otherwise, or the parent of the current
- commit if it is not given
+ If None, it defaults to HEAD@{1} otherwise
:param recursive: if True, the children of submodules will be updated as well
using the same technique
:param force_remove: If submodules have been deleted, they will be forcibly removed.
diff --git a/objects/util.py b/objects/util.py
index a9e1143c..4c9323b8 100644
--- a/objects/util.py
+++ b/objects/util.py
@@ -4,19 +4,21 @@
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
"""Module for general utility functions"""
-from git.util import IterableList
+from git.util import (
+ IterableList,
+ Actor
+ )
import re
from collections import deque as Deque
-import platform
from string import digits
import time
import os
-__all__ = ('get_object_type_by_name', 'get_user_id', 'parse_date', 'parse_actor_and_date',
+__all__ = ('get_object_type_by_name', 'parse_date', 'parse_actor_and_date',
'ProcessStreamAdapter', 'Traversable', 'altz_to_utctz_str', 'utctz_to_altz',
- 'verify_utctz')
+ 'verify_utctz', 'Actor')
#{ Functions
@@ -57,21 +59,9 @@ def get_object_type_by_name(object_type_name):
else:
raise ValueError("Cannot handle unknown object type: %s" % object_type_name)
-
-def get_user_id():
- """:return: string identifying the currently active system user as name@node
- :note: user can be set with the 'USER' environment variable, usually set on windows"""
- ukn = 'UNKNOWN'
- username = os.environ.get('USER', os.environ.get('USERNAME', ukn))
- if username == ukn and hasattr(os, 'getlogin'):
- username = os.getlogin()
- # END get username from login
- return "%s@%s" % (username, platform.node())
-
-
def utctz_to_altz(utctz):
"""we convert utctz to the timezone in seconds, it is the format time.altzone
- returns. Git stores it as UTC timezon which has the opposite sign as well,
+ returns. Git stores it as UTC timezone which has the opposite sign as well,
which explains the -1 * ( that was made explicit here )
:param utctz: git utc timezone string, i.e. +0200"""
return -1 * int(float(utctz)/100*3600)
@@ -193,56 +183,6 @@ def parse_actor_and_date(line):
#{ Classes
-
-class Actor(object):
- """Actors hold information about a person acting on the repository. They
- can be committers and authors or anything with a name and an email as
- mentioned in the git log entries."""
- # precompiled regex
- name_only_regex = re.compile( r'<(.+)>' )
- name_email_regex = re.compile( r'(.*) <(.+?)>' )
-
- def __init__(self, name, email):
- self.name = name
- self.email = email
-
- def __eq__(self, other):
- return self.name == other.name and self.email == other.email
-
- def __ne__(self, other):
- return not (self == other)
-
- def __hash__(self):
- return hash((self.name, self.email))
-
- def __str__(self):
- return self.name
-
- def __repr__(self):
- return '<git.Actor "%s <%s>">' % (self.name, self.email)
-
- @classmethod
- def _from_string(cls, string):
- """Create an Actor from a string.
- :param string: is the string, which is expected to be in regular git format
-
- John Doe <jdoe@example.com>
-
- :return: Actor """
- m = cls.name_email_regex.search(string)
- if m:
- name, email = m.groups()
- return Actor(name, email)
- else:
- m = cls.name_only_regex.search(string)
- if m:
- return Actor(m.group(1), None)
- else:
- # assume best and use the whole string as name
- return Actor(string, None)
- # END special case name
- # END handle name/email matching
-
class ProcessStreamAdapter(object):
"""Class wireing all calls to the contained Process instance.
@@ -359,6 +299,7 @@ class Traversable(object):
class Serializable(object):
"""Defines methods to serialize and deserialize objects from and into a data stream"""
+ __slots__ = tuple()
def _serialize(self, stream):
"""Serialize the data of this object into the given data stream
diff --git a/refs.py b/refs.py
deleted file mode 100644
index 451cc3a5..00000000
--- a/refs.py
+++ /dev/null
@@ -1,1052 +0,0 @@
-# refs.py
-# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
-#
-# This module is part of GitPython and is released under
-# the BSD License: http://www.opensource.org/licenses/bsd-license.php
-""" Module containing all ref based objects """
-
-import os
-from objects import (
- Object,
- Commit
- )
-from objects.util import get_object_type_by_name
-from util import (
- LazyMixin,
- Iterable,
- join_path,
- join_path_native,
- to_native_path_linux
- )
-
-from gitdb.util import (
- join,
- dirname,
- isdir,
- exists,
- isfile,
- rename,
- hex_to_bin
- )
-
-from config import (
- GitConfigParser,
- SectionConstraint
- )
-
-from exc import GitCommandError
-
-__all__ = ("SymbolicReference", "Reference", "HEAD", "Head", "TagReference",
- "RemoteReference", "Tag" )
-
-class SymbolicReference(object):
- """Represents a special case of a reference such that this reference is symbolic.
- It does not point to a specific commit, but to another Head, which itself
- specifies a commit.
-
- A typical example for a symbolic reference is HEAD."""
- __slots__ = ("repo", "path")
- _common_path_default = ""
- _id_attribute_ = "name"
-
- def __init__(self, repo, path):
- self.repo = repo
- self.path = path
-
- def __str__(self):
- return self.path
-
- def __repr__(self):
- return '<git.%s "%s">' % (self.__class__.__name__, self.path)
-
- def __eq__(self, other):
- return self.path == other.path
-
- def __ne__(self, other):
- return not ( self == other )
-
- def __hash__(self):
- return hash(self.path)
-
- @property
- def name(self):
- """
- :return:
- In case of symbolic references, the shortest assumable name
- is the path itself."""
- return self.path
-
- def _abs_path(self):
- return join_path_native(self.repo.git_dir, self.path)
-
- @classmethod
- def _get_packed_refs_path(cls, repo):
- return join(repo.git_dir, 'packed-refs')
-
- @classmethod
- def _iter_packed_refs(cls, repo):
- """Returns an iterator yielding pairs of sha1/path pairs for the corresponding refs.
- :note: The packed refs file will be kept open as long as we iterate"""
- try:
- fp = open(cls._get_packed_refs_path(repo), 'r')
- for line in fp:
- line = line.strip()
- if not line:
- continue
- if line.startswith('#'):
- if line.startswith('# pack-refs with:') and not line.endswith('peeled'):
- raise TypeError("PackingType of packed-Refs not understood: %r" % line)
- # END abort if we do not understand the packing scheme
- continue
- # END parse comment
-
- # skip dereferenced tag object entries - previous line was actual
- # tag reference for it
- if line[0] == '^':
- continue
-
- yield tuple(line.split(' ', 1))
- # END for each line
- except (OSError,IOError):
- raise StopIteration
- # END no packed-refs file handling
- # NOTE: Had try-finally block around here to close the fp,
- # but some python version woudn't allow yields within that.
- # I believe files are closing themselves on destruction, so it is
- # alright.
-
- @classmethod
- def dereference_recursive(cls, repo, ref_path):
- """
- :return: hexsha stored in the reference at the given ref_path, recursively dereferencing all
- intermediate references as required
- :param repo: the repository containing the reference at ref_path"""
- while True:
- ref = cls(repo, ref_path)
- hexsha, ref_path = ref._get_ref_info()
- if hexsha is not None:
- return hexsha
- # END recursive dereferencing
-
- def _get_ref_info(self):
- """Return: (sha, target_ref_path) if available, the sha the file at
- rela_path points to, or None. target_ref_path is the reference we
- point to, or None"""
- tokens = None
- try:
- fp = open(self._abs_path(), 'r')
- value = fp.read().rstrip()
- fp.close()
- tokens = value.split(" ")
- except (OSError,IOError):
- # Probably we are just packed, find our entry in the packed refs file
- # NOTE: We are not a symbolic ref if we are in a packed file, as these
- # are excluded explictly
- for sha, path in self._iter_packed_refs(self.repo):
- if path != self.path: continue
- tokens = (sha, path)
- break
- # END for each packed ref
- # END handle packed refs
-
- if tokens is None:
- raise ValueError("Reference at %r does not exist" % self.path)
-
- # is it a reference ?
- if tokens[0] == 'ref:':
- return (None, tokens[1])
-
- # its a commit
- if self.repo.re_hexsha_only.match(tokens[0]):
- return (tokens[0], None)
-
- raise ValueError("Failed to parse reference information from %r" % self.path)
-
- def _get_commit(self):
- """
- :return:
- Commit object we point to, works for detached and non-detached
- SymbolicReferences"""
- # we partially reimplement it to prevent unnecessary file access
- hexsha, target_ref_path = self._get_ref_info()
-
- # it is a detached reference
- if hexsha:
- return Commit(self.repo, hex_to_bin(hexsha))
-
- return self.from_path(self.repo, target_ref_path).commit
-
- def _set_commit(self, commit):
- """Set our commit, possibly dereference our symbolic reference first.
- If the reference does not exist, it will be created"""
- is_detached = True
- try:
- is_detached = self.is_detached
- except ValueError:
- pass
- # END handle non-existing ones
- if is_detached:
- return self._set_reference(commit)
-
- # set the commit on our reference
- self._get_reference().commit = commit
-
- commit = property(_get_commit, _set_commit, doc="Query or set commits directly")
-
- def _get_reference(self):
- """:return: Reference Object we point to"""
- sha, target_ref_path = self._get_ref_info()
- if target_ref_path is None:
- raise TypeError("%s is a detached symbolic reference as it points to %r" % (self, sha))
- return self.from_path(self.repo, target_ref_path)
-
- def _set_reference(self, ref):
- """Set ourselves to the given ref. It will stay a symbol if the ref is a Reference.
- Otherwise we try to get a commit from it using our interface.
-
- Strings are allowed but will be checked to be sure we have a commit"""
- write_value = None
- if isinstance(ref, SymbolicReference):
- write_value = "ref: %s" % ref.path
- elif isinstance(ref, Commit):
- write_value = ref.hexsha
- else:
- try:
- write_value = ref.commit.hexsha
- except AttributeError:
- try:
- obj = self.repo.rev_parse(ref+"^{}") # optionally deref tags
- if obj.type != "commit":
- raise TypeError("Invalid object type behind sha: %s" % sha)
- write_value = obj.hexsha
- except Exception:
- raise ValueError("Could not extract object from %s" % ref)
- # END end try string
- # END try commit attribute
-
- # maintain the orig-head if we are currently checked-out
- head = HEAD(self.repo)
- try:
- if head.ref == self:
- try:
- # TODO: implement this atomically, if we fail below, orig_head is at an incorrect spot
- # Enforce the creation of ORIG_HEAD
- SymbolicReference.create(self.repo, head.orig_head().name, self.commit, force=True)
- except ValueError:
- pass
- #END exception handling
- # END if we are checked-out
- except TypeError:
- pass
- # END handle detached heads
-
- # if we are writing a ref, use symbolic ref to get the reflog and more
- # checking
- # Otherwise we detach it and have to do it manually. Besides, this works
- # recursively automaitcally, but should be replaced with a python implementation
- # soon
- if write_value.startswith('ref:'):
- self.repo.git.symbolic_ref(self.path, write_value[5:])
- return
- # END non-detached handling
-
- path = self._abs_path()
- directory = dirname(path)
- if not isdir(directory):
- os.makedirs(directory)
-
- fp = open(path, "wb")
- try:
- fp.write(write_value)
- finally:
- fp.close()
- # END writing
-
-
- # aliased reference
- reference = property(_get_reference, _set_reference, doc="Returns the Reference we point to")
- ref = reference
-
- def is_valid(self):
- """
- :return:
- True if the reference is valid, hence it can be read and points to
- a valid object or reference."""
- try:
- self.commit
- except (OSError, ValueError):
- return False
- else:
- return True
-
- @property
- def is_detached(self):
- """
- :return:
- True if we are a detached reference, hence we point to a specific commit
- instead to another reference"""
- try:
- self.reference
- return False
- except TypeError:
- return True
-
-
- @classmethod
- def to_full_path(cls, path):
- """
- :return: string with a full repository-relative path which can be used to initialize
- a Reference instance, for instance by using ``Reference.from_path``"""
- if isinstance(path, SymbolicReference):
- path = path.path
- full_ref_path = path
- if not cls._common_path_default:
- return full_ref_path
- if not path.startswith(cls._common_path_default+"/"):
- full_ref_path = '%s/%s' % (cls._common_path_default, path)
- return full_ref_path
-
- @classmethod
- def delete(cls, repo, path):
- """Delete the reference at the given path
-
- :param repo:
- Repository to delete the reference from
-
- :param path:
- Short or full path pointing to the reference, i.e. refs/myreference
- or just "myreference", hence 'refs/' is implied.
- Alternatively the symbolic reference to be deleted"""
- full_ref_path = cls.to_full_path(path)
- abs_path = join(repo.git_dir, full_ref_path)
- if exists(abs_path):
- os.remove(abs_path)
- else:
- # check packed refs
- pack_file_path = cls._get_packed_refs_path(repo)
- try:
- reader = open(pack_file_path)
- except (OSError,IOError):
- pass # it didnt exist at all
- else:
- new_lines = list()
- made_change = False
- dropped_last_line = False
- for line in reader:
- # keep line if it is a comment or if the ref to delete is not
- # in the line
- # If we deleted the last line and this one is a tag-reference object,
- # we drop it as well
- if ( line.startswith('#') or full_ref_path not in line ) and \
- ( not dropped_last_line or dropped_last_line and not line.startswith('^') ):
- new_lines.append(line)
- dropped_last_line = False
- continue
- # END skip comments and lines without our path
-
- # drop this line
- made_change = True
- dropped_last_line = True
- # END for each line in packed refs
- reader.close()
-
- # write the new lines
- if made_change:
- open(pack_file_path, 'w').writelines(new_lines)
- # END open exception handling
- # END handle deletion
-
- @classmethod
- def _create(cls, repo, path, resolve, reference, force):
- """internal method used to create a new symbolic reference.
- If resolve is False,, the reference will be taken as is, creating
- a proper symbolic reference. Otherwise it will be resolved to the
- corresponding object and a detached symbolic reference will be created
- instead"""
- full_ref_path = cls.to_full_path(path)
- abs_ref_path = join(repo.git_dir, full_ref_path)
-
- # figure out target data
- target = reference
- if resolve:
- target = repo.rev_parse(str(reference))
-
- if not force and isfile(abs_ref_path):
- target_data = str(target)
- if isinstance(target, SymbolicReference):
- target_data = target.path
- if not resolve:
- target_data = "ref: " + target_data
- if open(abs_ref_path, 'rb').read().strip() != target_data:
- raise OSError("Reference at %s does already exist" % full_ref_path)
- # END no force handling
-
- ref = cls(repo, full_ref_path)
- ref.reference = target
- return ref
-
- @classmethod
- def create(cls, repo, path, reference='HEAD', force=False ):
- """Create a new symbolic reference, hence a reference pointing to another reference.
-
- :param repo:
- Repository to create the reference in
-
- :param path:
- full path at which the new symbolic reference is supposed to be
- created at, i.e. "NEW_HEAD" or "symrefs/my_new_symref"
-
- :param reference:
- The reference to which the new symbolic reference should point to
-
- :param force:
- if True, force creation even if a symbolic reference with that name already exists.
- Raise OSError otherwise
-
- :return: Newly created symbolic Reference
-
- :raise OSError:
- If a (Symbolic)Reference with the same name but different contents
- already exists.
-
- :note: This does not alter the current HEAD, index or Working Tree"""
- return cls._create(repo, path, False, reference, force)
-
- def rename(self, new_path, force=False):
- """Rename self to a new path
-
- :param new_path:
- Either a simple name or a full path, i.e. new_name or features/new_name.
- The prefix refs/ is implied for references and will be set as needed.
- In case this is a symbolic ref, there is no implied prefix
-
- :param force:
- If True, the rename will succeed even if a head with the target name
- already exists. It will be overwritten in that case
-
- :return: self
- :raise OSError: In case a file at path but a different contents already exists """
- new_path = self.to_full_path(new_path)
- if self.path == new_path:
- return self
-
- new_abs_path = join(self.repo.git_dir, new_path)
- cur_abs_path = join(self.repo.git_dir, self.path)
- if isfile(new_abs_path):
- if not force:
- # if they point to the same file, its not an error
- if open(new_abs_path,'rb').read().strip() != open(cur_abs_path,'rb').read().strip():
- raise OSError("File at path %r already exists" % new_abs_path)
- # else: we could remove ourselves and use the otherone, but
- # but clarity we just continue as usual
- # END not force handling
- os.remove(new_abs_path)
- # END handle existing target file
-
- dname = dirname(new_abs_path)
- if not isdir(dname):
- os.makedirs(dname)
- # END create directory
-
- rename(cur_abs_path, new_abs_path)
- self.path = new_path
-
- return self
-
- @classmethod
- def _iter_items(cls, repo, common_path = None):
- if common_path is None:
- common_path = cls._common_path_default
- rela_paths = set()
-
- # walk loose refs
- # Currently we do not follow links
- for root, dirs, files in os.walk(join_path_native(repo.git_dir, common_path)):
- if 'refs/' not in root: # skip non-refs subfolders
- refs_id = [ i for i,d in enumerate(dirs) if d == 'refs' ]
- if refs_id:
- dirs[0:] = ['refs']
- # END prune non-refs folders
-
- for f in files:
- abs_path = to_native_path_linux(join_path(root, f))
- rela_paths.add(abs_path.replace(to_native_path_linux(repo.git_dir) + '/', ""))
- # END for each file in root directory
- # END for each directory to walk
-
- # read packed refs
- for sha, rela_path in cls._iter_packed_refs(repo):
- if rela_path.startswith(common_path):
- rela_paths.add(rela_path)
- # END relative path matches common path
- # END packed refs reading
-
- # return paths in sorted order
- for path in sorted(rela_paths):
- try:
- yield cls.from_path(repo, path)
- except ValueError:
- continue
- # END for each sorted relative refpath
-
- @classmethod
- def iter_items(cls, repo, common_path = None):
- """Find all refs in the repository
-
- :param repo: is the Repo
-
- :param common_path:
- Optional keyword argument to the path which is to be shared by all
- returned Ref objects.
- Defaults to class specific portion if None assuring that only
- refs suitable for the actual class are returned.
-
- :return:
- git.SymbolicReference[], each of them is guaranteed to be a symbolic
- ref which is not detached.
-
- List is lexigraphically sorted
- The returned objects represent actual subclasses, such as Head or TagReference"""
- return ( r for r in cls._iter_items(repo, common_path) if r.__class__ == SymbolicReference or not r.is_detached )
-
- @classmethod
- def from_path(cls, repo, path):
- """
- :param path: full .git-directory-relative path name to the Reference to instantiate
- :note: use to_full_path() if you only have a partial path of a known Reference Type
- :return:
- Instance of type Reference, Head, or Tag
- depending on the given path"""
- if not path:
- raise ValueError("Cannot create Reference from %r" % path)
-
- for ref_type in (HEAD, Head, RemoteReference, TagReference, Reference, SymbolicReference):
- try:
- instance = ref_type(repo, path)
- if instance.__class__ == SymbolicReference and instance.is_detached:
- raise ValueError("SymbolRef was detached, we drop it")
- return instance
- except ValueError:
- pass
- # END exception handling
- # END for each type to try
- raise ValueError("Could not find reference type suitable to handle path %r" % path)
-
-
-class Reference(SymbolicReference, LazyMixin, Iterable):
- """Represents a named reference to any object. Subclasses may apply restrictions though,
- i.e. Heads can only point to commits."""
- __slots__ = tuple()
- _common_path_default = "refs"
-
- def __init__(self, repo, path):
- """Initialize this instance
- :param repo: Our parent repository
-
- :param path:
- Path relative to the .git/ directory pointing to the ref in question, i.e.
- refs/heads/master"""
- if not path.startswith(self._common_path_default+'/'):
- raise ValueError("Cannot instantiate %r from path %s" % ( self.__class__.__name__, path ))
- super(Reference, self).__init__(repo, path)
-
-
- def __str__(self):
- return self.name
-
- def _get_object(self):
- """
- :return:
- The object our ref currently refers to. Refs can be cached, they will
- always point to the actual object as it gets re-created on each query"""
- # have to be dynamic here as we may be a tag which can point to anything
- # Our path will be resolved to the hexsha which will be used accordingly
- return Object.new_from_sha(self.repo, hex_to_bin(self.dereference_recursive(self.repo, self.path)))
-
- def _set_object(self, ref):
- """
- Set our reference to point to the given ref. It will be converted
- to a specific hexsha.
- If the reference does not exist, it will be created.
-
- :note:
- TypeChecking is done by the git command"""
- abs_path = self._abs_path()
- existed = True
- if not isfile(abs_path):
- existed = False
- open(abs_path, 'wb').write(Object.NULL_HEX_SHA)
- # END quick create
-
- # do it safely by specifying the old value
- try:
- self.repo.git.update_ref(self.path, ref, (existed and self._get_object().hexsha) or None)
- except:
- if not existed:
- os.remove(abs_path)
- # END remove file on error if it didn't exist before
- raise
- # END exception handling
-
- object = property(_get_object, _set_object, doc="Return the object our ref currently refers to")
-
- @property
- def name(self):
- """:return: (shortest) Name of this reference - it may contain path components"""
- # first two path tokens are can be removed as they are
- # refs/heads or refs/tags or refs/remotes
- tokens = self.path.split('/')
- if len(tokens) < 3:
- return self.path # could be refs/HEAD
- return '/'.join(tokens[2:])
-
-
- @classmethod
- def create(cls, repo, path, commit='HEAD', force=False ):
- """Create a new reference.
-
- :param repo: Repository to create the reference in
- :param path:
- The relative path of the reference, i.e. 'new_branch' or
- feature/feature1. The path prefix 'refs/' is implied if not
- given explicitly
-
- :param commit:
- Commit to which the new reference should point, defaults to the
- current HEAD
-
- :param force:
- if True, force creation even if a reference with that name already exists.
- Raise OSError otherwise
-
- :return: Newly created Reference
-
- :note: This does not alter the current HEAD, index or Working Tree"""
- return cls._create(repo, path, True, commit, force)
-
- @classmethod
- def iter_items(cls, repo, common_path = None):
- """Equivalent to SymbolicReference.iter_items, but will return non-detached
- references as well."""
- return cls._iter_items(repo, common_path)
-
-
-class HEAD(SymbolicReference):
- """Special case of a Symbolic Reference as it represents the repository's
- HEAD reference."""
- _HEAD_NAME = 'HEAD'
- _ORIG_HEAD_NAME = 'ORIG_HEAD'
- __slots__ = tuple()
-
- def __init__(self, repo, path=_HEAD_NAME):
- if path != self._HEAD_NAME:
- raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, path))
- super(HEAD, self).__init__(repo, path)
-
- def orig_head(self):
- """
- :return: SymbolicReference pointing at the ORIG_HEAD, which is maintained
- to contain the previous value of HEAD"""
- return SymbolicReference(self.repo, self._ORIG_HEAD_NAME)
-
- def _set_reference(self, ref):
- """If someone changes the reference through us, we must manually update
- the ORIG_HEAD if we are detached. The underlying implementation can only
- handle un-detached heads as it has to check whether the current head
- is the checked-out one"""
- if self.is_detached:
- prev_commit = self.commit
- super(HEAD, self)._set_reference(ref)
- SymbolicReference.create(self.repo, self._ORIG_HEAD_NAME, prev_commit, force=True)
- else:
- super(HEAD, self)._set_reference(ref)
- # END handle detached mode
-
- # aliased reference
- reference = property(SymbolicReference._get_reference, _set_reference, doc="Returns the Reference we point to")
- ref = reference
-
- def reset(self, commit='HEAD', index=True, working_tree = False,
- paths=None, **kwargs):
- """Reset our HEAD to the given commit optionally synchronizing
- the index and working tree. The reference we refer to will be set to
- commit as well.
-
- :param commit:
- Commit object, Reference Object or string identifying a revision we
- should reset HEAD to.
-
- :param index:
- If True, the index will be set to match the given commit. Otherwise
- it will not be touched.
-
- :param working_tree:
- If True, the working tree will be forcefully adjusted to match the given
- commit, possibly overwriting uncommitted changes without warning.
- If working_tree is True, index must be true as well
-
- :param paths:
- Single path or list of paths relative to the git root directory
- that are to be reset. This allows to partially reset individual files.
-
- :param kwargs:
- Additional arguments passed to git-reset.
-
- :return: self"""
- mode = "--soft"
- add_arg = None
- if index:
- mode = "--mixed"
-
- # it appears, some git-versions declare mixed and paths deprecated
- # see http://github.com/Byron/GitPython/issues#issue/2
- if paths:
- mode = None
- # END special case
- # END handle index
-
- if working_tree:
- mode = "--hard"
- if not index:
- raise ValueError( "Cannot reset the working tree if the index is not reset as well")
-
- # END working tree handling
-
- if paths:
- add_arg = "--"
- # END nicely separate paths from rest
-
- try:
- self.repo.git.reset(mode, commit, add_arg, paths, **kwargs)
- except GitCommandError, e:
- # git nowadays may use 1 as status to indicate there are still unstaged
- # modifications after the reset
- if e.status != 1:
- raise
- # END handle exception
-
- return self
-
-
-class Head(Reference):
- """A Head is a named reference to a Commit. Every Head instance contains a name
- and a Commit object.
-
- Examples::
-
- >>> repo = Repo("/path/to/repo")
- >>> head = repo.heads[0]
-
- >>> head.name
- 'master'
-
- >>> head.commit
- <git.Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455">
-
- >>> head.commit.hexsha
- '1c09f116cbc2cb4100fb6935bb162daa4723f455'"""
- _common_path_default = "refs/heads"
- k_config_remote = "remote"
- k_config_remote_ref = "merge" # branch to merge from remote
-
- @classmethod
- def create(cls, repo, path, commit='HEAD', force=False, **kwargs):
- """Create a new head.
- :param repo: Repository to create the head in
- :param path:
- The name or path of the head, i.e. 'new_branch' or
- feature/feature1. The prefix refs/heads is implied.
-
- :param commit:
- Commit to which the new head should point, defaults to the
- current HEAD
-
- :param force:
- if True, force creation even if branch with that name already exists.
-
- :param kwargs:
- Additional keyword arguments to be passed to git-branch, i.e.
- track, no-track, l
-
- :return: Newly created Head
- :note: This does not alter the current HEAD, index or Working Tree"""
- if cls is not Head:
- raise TypeError("Only Heads can be created explicitly, not objects of type %s" % cls.__name__)
-
- args = ( path, commit )
- if force:
- kwargs['f'] = True
-
- repo.git.branch(*args, **kwargs)
- return cls(repo, "%s/%s" % ( cls._common_path_default, path))
-
-
- @classmethod
- def delete(cls, repo, *heads, **kwargs):
- """Delete the given heads
- :param force:
- If True, the heads will be deleted even if they are not yet merged into
- the main development stream.
- Default False"""
- force = kwargs.get("force", False)
- flag = "-d"
- if force:
- flag = "-D"
- repo.git.branch(flag, *heads)
-
-
- def set_tracking_branch(self, remote_reference):
- """
- Configure this branch to track the given remote reference. This will alter
- this branch's configuration accordingly.
-
- :param remote_reference: The remote reference to track or None to untrack
- any references
- :return: self"""
- if remote_reference is not None and not isinstance(remote_reference, RemoteReference):
- raise ValueError("Incorrect parameter type: %r" % remote_reference)
- # END handle type
-
- writer = self.config_writer()
- if remote_reference is None:
- writer.remove_option(self.k_config_remote)
- writer.remove_option(self.k_config_remote_ref)
- if len(writer.options()) == 0:
- writer.remove_section()
- # END handle remove section
- else:
- writer.set_value(self.k_config_remote, remote_reference.remote_name)
- writer.set_value(self.k_config_remote_ref, Head.to_full_path(remote_reference.remote_head))
- # END handle ref value
-
- return self
-
-
- def tracking_branch(self):
- """
- :return: The remote_reference we are tracking, or None if we are
- not a tracking branch"""
- reader = self.config_reader()
- if reader.has_option(self.k_config_remote) and reader.has_option(self.k_config_remote_ref):
- ref = Head(self.repo, Head.to_full_path(reader.get_value(self.k_config_remote_ref)))
- remote_refpath = RemoteReference.to_full_path(join_path(reader.get_value(self.k_config_remote), ref.name))
- return RemoteReference(self.repo, remote_refpath)
- # END handle have tracking branch
-
- # we are not a tracking branch
- return None
-
- def rename(self, new_path, force=False):
- """Rename self to a new path
-
- :param new_path:
- Either a simple name or a path, i.e. new_name or features/new_name.
- The prefix refs/heads is implied
-
- :param force:
- If True, the rename will succeed even if a head with the target name
- already exists.
-
- :return: self
- :note: respects the ref log as git commands are used"""
- flag = "-m"
- if force:
- flag = "-M"
-
- self.repo.git.branch(flag, self, new_path)
- self.path = "%s/%s" % (self._common_path_default, new_path)
- return self
-
- def checkout(self, force=False, **kwargs):
- """Checkout this head by setting the HEAD to this reference, by updating the index
- to reflect the tree we point to and by updating the working tree to reflect
- the latest index.
-
- The command will fail if changed working tree files would be overwritten.
-
- :param force:
- If True, changes to the index and the working tree will be discarded.
- If False, GitCommandError will be raised in that situation.
-
- :param kwargs:
- Additional keyword arguments to be passed to git checkout, i.e.
- b='new_branch' to create a new branch at the given spot.
-
- :return:
- The active branch after the checkout operation, usually self unless
- a new branch has been created.
-
- :note:
- By default it is only allowed to checkout heads - everything else
- will leave the HEAD detached which is allowed and possible, but remains
- a special state that some tools might not be able to handle."""
- args = list()
- kwargs['f'] = force
- if kwargs['f'] == False:
- kwargs.pop('f')
-
- self.repo.git.checkout(self, **kwargs)
- return self.repo.active_branch
-
- #{ Configruation
-
- def _config_parser(self, read_only):
- if read_only:
- parser = self.repo.config_reader()
- else:
- parser = self.repo.config_writer()
- # END handle parser instance
-
- return SectionConstraint(parser, 'branch "%s"' % self.name)
-
- def config_reader(self):
- """
- :return: A configuration parser instance constrained to only read
- this instance's values"""
- return self._config_parser(read_only=True)
-
- def config_writer(self):
- """
- :return: A configuration writer instance with read-and write acccess
- to options of this head"""
- return self._config_parser(read_only=False)
-
- #} END configuration
-
-
-class TagReference(Reference):
- """Class representing a lightweight tag reference which either points to a commit
- ,a tag object or any other object. In the latter case additional information,
- like the signature or the tag-creator, is available.
-
- This tag object will always point to a commit object, but may carray additional
- information in a tag object::
-
- tagref = TagReference.list_items(repo)[0]
- print tagref.commit.message
- if tagref.tag is not None:
- print tagref.tag.message"""
-
- __slots__ = tuple()
- _common_path_default = "refs/tags"
-
- @property
- def commit(self):
- """:return: Commit object the tag ref points to"""
- obj = self.object
- if obj.type == "commit":
- return obj
- elif obj.type == "tag":
- # it is a tag object which carries the commit as an object - we can point to anything
- return obj.object
- else:
- raise ValueError( "Tag %s points to a Blob or Tree - have never seen that before" % self )
-
- @property
- def tag(self):
- """
- :return: Tag object this tag ref points to or None in case
- we are a light weight tag"""
- obj = self.object
- if obj.type == "tag":
- return obj
- return None
-
- # make object read-only
- # It should be reasonably hard to adjust an existing tag
- object = property(Reference._get_object)
-
- @classmethod
- def create(cls, repo, path, ref='HEAD', message=None, force=False, **kwargs):
- """Create a new tag reference.
-
- :param path:
- The name of the tag, i.e. 1.0 or releases/1.0.
- The prefix refs/tags is implied
-
- :param ref:
- A reference to the object you want to tag. It can be a commit, tree or
- blob.
-
- :param message:
- If not None, the message will be used in your tag object. This will also
- create an additional tag object that allows to obtain that information, i.e.::
-
- tagref.tag.message
-
- :param force:
- If True, to force creation of a tag even though that tag already exists.
-
- :param kwargs:
- Additional keyword arguments to be passed to git-tag
-
- :return: A new TagReference"""
- args = ( path, ref )
- if message:
- kwargs['m'] = message
- if force:
- kwargs['f'] = True
-
- repo.git.tag(*args, **kwargs)
- return TagReference(repo, "%s/%s" % (cls._common_path_default, path))
-
- @classmethod
- def delete(cls, repo, *tags):
- """Delete the given existing tag or tags"""
- repo.git.tag("-d", *tags)
-
-
-
-
-
-# provide an alias
-Tag = TagReference
-
-class RemoteReference(Head):
- """Represents a reference pointing to a remote head."""
- _common_path_default = "refs/remotes"
-
-
- @classmethod
- def iter_items(cls, repo, common_path = None, remote=None):
- """Iterate remote references, and if given, constrain them to the given remote"""
- common_path = common_path or cls._common_path_default
- if remote is not None:
- common_path = join_path(common_path, str(remote))
- # END handle remote constraint
- return super(RemoteReference, cls).iter_items(repo, common_path)
-
- @property
- def remote_name(self):
- """
- :return:
- Name of the remote we are a reference of, such as 'origin' for a reference
- named 'origin/master'"""
- tokens = self.path.split('/')
- # /refs/remotes/<remote name>/<branch_name>
- return tokens[2]
-
- @property
- def remote_head(self):
- """:return: Name of the remote head itself, i.e. master.
- :note: The returned name is usually not qualified enough to uniquely identify
- a branch"""
- tokens = self.path.split('/')
- return '/'.join(tokens[3:])
-
- @classmethod
- def delete(cls, repo, *refs, **kwargs):
- """Delete the given remote references.
- :note:
- kwargs are given for compatability with the base class method as we
- should not narrow the signature."""
- repo.git.branch("-d", "-r", *refs)
- # the official deletion method will ignore remote symbolic refs - these
- # are generally ignored in the refs/ folder. We don't though
- # and delete remainders manually
- for ref in refs:
- try:
- os.remove(join(repo.git_dir, ref.path))
- except OSError:
- pass
- # END for each ref
diff --git a/refs/__init__.py b/refs/__init__.py
new file mode 100644
index 00000000..fc8ce644
--- /dev/null
+++ b/refs/__init__.py
@@ -0,0 +1,21 @@
+
+# import all modules in order, fix the names they require
+from symbolic import *
+from reference import *
+from head import *
+from tag import *
+from remote import *
+
+# name fixes
+import head
+head.RemoteReference = RemoteReference
+del(head)
+
+
+import symbolic
+for item in (HEAD, Head, RemoteReference, TagReference, Reference, SymbolicReference):
+ setattr(symbolic, item.__name__, item)
+del(symbolic)
+
+
+from log import *
diff --git a/refs/head.py b/refs/head.py
new file mode 100644
index 00000000..d8729434
--- /dev/null
+++ b/refs/head.py
@@ -0,0 +1,246 @@
+from symbolic import SymbolicReference
+from reference import Reference
+
+from git.config import SectionConstraint
+
+from git.util import join_path
+
+from git.exc import GitCommandError
+
+__all__ = ["HEAD", "Head"]
+
+
+
+class HEAD(SymbolicReference):
+ """Special case of a Symbolic Reference as it represents the repository's
+ HEAD reference."""
+ _HEAD_NAME = 'HEAD'
+ _ORIG_HEAD_NAME = 'ORIG_HEAD'
+ __slots__ = tuple()
+
+ def __init__(self, repo, path=_HEAD_NAME):
+ if path != self._HEAD_NAME:
+ raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, path))
+ super(HEAD, self).__init__(repo, path)
+
+ def orig_head(self):
+ """
+ :return: SymbolicReference pointing at the ORIG_HEAD, which is maintained
+ to contain the previous value of HEAD"""
+ return SymbolicReference(self.repo, self._ORIG_HEAD_NAME)
+
+ def reset(self, commit='HEAD', index=True, working_tree = False,
+ paths=None, **kwargs):
+ """Reset our HEAD to the given commit optionally synchronizing
+ the index and working tree. The reference we refer to will be set to
+ commit as well.
+
+ :param commit:
+ Commit object, Reference Object or string identifying a revision we
+ should reset HEAD to.
+
+ :param index:
+ If True, the index will be set to match the given commit. Otherwise
+ it will not be touched.
+
+ :param working_tree:
+ If True, the working tree will be forcefully adjusted to match the given
+ commit, possibly overwriting uncommitted changes without warning.
+ If working_tree is True, index must be true as well
+
+ :param paths:
+ Single path or list of paths relative to the git root directory
+ that are to be reset. This allows to partially reset individual files.
+
+ :param kwargs:
+ Additional arguments passed to git-reset.
+
+ :return: self"""
+ mode = "--soft"
+ add_arg = None
+ if index:
+ mode = "--mixed"
+
+ # it appears, some git-versions declare mixed and paths deprecated
+ # see http://github.com/Byron/GitPython/issues#issue/2
+ if paths:
+ mode = None
+ # END special case
+ # END handle index
+
+ if working_tree:
+ mode = "--hard"
+ if not index:
+ raise ValueError( "Cannot reset the working tree if the index is not reset as well")
+
+ # END working tree handling
+
+ if paths:
+ add_arg = "--"
+ # END nicely separate paths from rest
+
+ try:
+ self.repo.git.reset(mode, commit, add_arg, paths, **kwargs)
+ except GitCommandError, e:
+ # git nowadays may use 1 as status to indicate there are still unstaged
+ # modifications after the reset
+ if e.status != 1:
+ raise
+ # END handle exception
+
+ return self
+
+
+class Head(Reference):
+ """A Head is a named reference to a Commit. Every Head instance contains a name
+ and a Commit object.
+
+ Examples::
+
+ >>> repo = Repo("/path/to/repo")
+ >>> head = repo.heads[0]
+
+ >>> head.name
+ 'master'
+
+ >>> head.commit
+ <git.Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455">
+
+ >>> head.commit.hexsha
+ '1c09f116cbc2cb4100fb6935bb162daa4723f455'"""
+ _common_path_default = "refs/heads"
+ k_config_remote = "remote"
+ k_config_remote_ref = "merge" # branch to merge from remote
+
+ @classmethod
+ def delete(cls, repo, *heads, **kwargs):
+ """Delete the given heads
+ :param force:
+ If True, the heads will be deleted even if they are not yet merged into
+ the main development stream.
+ Default False"""
+ force = kwargs.get("force", False)
+ flag = "-d"
+ if force:
+ flag = "-D"
+ repo.git.branch(flag, *heads)
+
+ def set_tracking_branch(self, remote_reference):
+ """
+ Configure this branch to track the given remote reference. This will alter
+ this branch's configuration accordingly.
+
+ :param remote_reference: The remote reference to track or None to untrack
+ any references
+ :return: self"""
+ if remote_reference is not None and not isinstance(remote_reference, RemoteReference):
+ raise ValueError("Incorrect parameter type: %r" % remote_reference)
+ # END handle type
+
+ writer = self.config_writer()
+ if remote_reference is None:
+ writer.remove_option(self.k_config_remote)
+ writer.remove_option(self.k_config_remote_ref)
+ if len(writer.options()) == 0:
+ writer.remove_section()
+ # END handle remove section
+ else:
+ writer.set_value(self.k_config_remote, remote_reference.remote_name)
+ writer.set_value(self.k_config_remote_ref, Head.to_full_path(remote_reference.remote_head))
+ # END handle ref value
+
+ return self
+
+
+ def tracking_branch(self):
+ """
+ :return: The remote_reference we are tracking, or None if we are
+ not a tracking branch"""
+ reader = self.config_reader()
+ if reader.has_option(self.k_config_remote) and reader.has_option(self.k_config_remote_ref):
+ ref = Head(self.repo, Head.to_full_path(reader.get_value(self.k_config_remote_ref)))
+ remote_refpath = RemoteReference.to_full_path(join_path(reader.get_value(self.k_config_remote), ref.name))
+ return RemoteReference(self.repo, remote_refpath)
+ # END handle have tracking branch
+
+ # we are not a tracking branch
+ return None
+
+ def rename(self, new_path, force=False):
+ """Rename self to a new path
+
+ :param new_path:
+ Either a simple name or a path, i.e. new_name or features/new_name.
+ The prefix refs/heads is implied
+
+ :param force:
+ If True, the rename will succeed even if a head with the target name
+ already exists.
+
+ :return: self
+ :note: respects the ref log as git commands are used"""
+ flag = "-m"
+ if force:
+ flag = "-M"
+
+ self.repo.git.branch(flag, self, new_path)
+ self.path = "%s/%s" % (self._common_path_default, new_path)
+ return self
+
+ def checkout(self, force=False, **kwargs):
+ """Checkout this head by setting the HEAD to this reference, by updating the index
+ to reflect the tree we point to and by updating the working tree to reflect
+ the latest index.
+
+ The command will fail if changed working tree files would be overwritten.
+
+ :param force:
+ If True, changes to the index and the working tree will be discarded.
+ If False, GitCommandError will be raised in that situation.
+
+ :param kwargs:
+ Additional keyword arguments to be passed to git checkout, i.e.
+ b='new_branch' to create a new branch at the given spot.
+
+ :return:
+ The active branch after the checkout operation, usually self unless
+ a new branch has been created.
+
+ :note:
+ By default it is only allowed to checkout heads - everything else
+ will leave the HEAD detached which is allowed and possible, but remains
+ a special state that some tools might not be able to handle."""
+ args = list()
+ kwargs['f'] = force
+ if kwargs['f'] == False:
+ kwargs.pop('f')
+
+ self.repo.git.checkout(self, **kwargs)
+ return self.repo.active_branch
+
+ #{ Configruation
+
+ def _config_parser(self, read_only):
+ if read_only:
+ parser = self.repo.config_reader()
+ else:
+ parser = self.repo.config_writer()
+ # END handle parser instance
+
+ return SectionConstraint(parser, 'branch "%s"' % self.name)
+
+ def config_reader(self):
+ """
+ :return: A configuration parser instance constrained to only read
+ this instance's values"""
+ return self._config_parser(read_only=True)
+
+ def config_writer(self):
+ """
+ :return: A configuration writer instance with read-and write acccess
+ to options of this head"""
+ return self._config_parser(read_only=False)
+
+ #} END configuration
+
+
diff --git a/refs/log.py b/refs/log.py
new file mode 100644
index 00000000..f49c07fd
--- /dev/null
+++ b/refs/log.py
@@ -0,0 +1,282 @@
+from git.util import (
+ join_path,
+ Actor,
+ LockedFD,
+ LockFile,
+ assure_directory_exists,
+ to_native_path,
+ )
+
+from gitdb.util import (
+ bin_to_hex,
+ join,
+ file_contents_ro_filepath,
+ )
+
+from git.objects.util import (
+ parse_date,
+ Serializable,
+ utctz_to_altz,
+ altz_to_utctz_str,
+ )
+
+import time
+import os
+import re
+
+__all__ = ["RefLog", "RefLogEntry"]
+
+
+class RefLogEntry(tuple):
+ """Named tuple allowing easy access to the revlog data fields"""
+ _fmt = "%s %s %s <%s> %i %s\t%s\n"
+ _re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$')
+ __slots__ = tuple()
+
+ def __repr__(self):
+ """Representation of ourselves in git reflog format"""
+ act = self.actor
+ time = self.time
+ return self._fmt % (self.oldhexsha, self.newhexsha, act.name, act.email,
+ time[0], altz_to_utctz_str(time[1]), self.message)
+
+ @property
+ def oldhexsha(self):
+ """The hexsha to the commit the ref pointed to before the change"""
+ return self[0]
+
+ @property
+ def newhexsha(self):
+ """The hexsha to the commit the ref now points to, after the change"""
+ return self[1]
+
+ @property
+ def actor(self):
+ """Actor instance, providing access"""
+ return self[2]
+
+ @property
+ def time(self):
+ """time as tuple:
+
+ * [0] = int(time)
+ * [1] = int(timezone_offset) in time.altzone format """
+ return self[3]
+
+ @property
+ def message(self):
+ """Message describing the operation that acted on the reference"""
+ return self[4]
+
+ @classmethod
+ def new(self, oldhexsha, newhexsha, actor, time, tz_offset, message):
+ """:return: New instance of a RefLogEntry"""
+ if not isinstance(actor, Actor):
+ raise ValueError("Need actor instance, got %s" % actor)
+ # END check types
+ return RefLogEntry((oldhexsha, newhexsha, actor, (time, tz_offset), message))
+
+ @classmethod
+ def from_line(cls, line):
+ """:return: New RefLogEntry instance from the given revlog line.
+ :param line: line without trailing newline
+ :raise ValueError: If line could not be parsed"""
+ try:
+ info, msg = line.split('\t', 2)
+ except ValueError:
+ raise ValueError("line is missing tab separator")
+ #END handle first plit
+ oldhexsha = info[:40]
+ newhexsha = info[41:81]
+ for hexsha in (oldhexsha, newhexsha):
+ if not cls._re_hexsha_only.match(hexsha):
+ raise ValueError("Invalid hexsha: %s" % hexsha)
+ # END if hexsha re doesn't match
+ #END for each hexsha
+
+ email_end = info.find('>', 82)
+ if email_end == -1:
+ raise ValueError("Missing token: >")
+ #END handle missing end brace
+
+ actor = Actor._from_string(info[82:email_end+1])
+ time, tz_offset = parse_date(info[email_end+2:])
+
+ return RefLogEntry((oldhexsha, newhexsha, actor, (time, tz_offset), msg))
+
+
+class RefLog(list, Serializable):
+ """A reflog contains reflog entries, each of which defines a certain state
+ of the head in question. Custom query methods allow to retrieve log entries
+ by date or by other criteria.
+
+ Reflog entries are orded, the first added entry is first in the list, the last
+ entry, i.e. the last change of the head or reference, is last in the list."""
+
+ __slots__ = ('_path', )
+
+ def __new__(cls, filepath=None):
+ inst = super(RefLog, cls).__new__(cls)
+ return inst
+
+ def __init__(self, filepath=None):
+ """Initialize this instance with an optional filepath, from which we will
+ initialize our data. The path is also used to write changes back using
+ the write() method"""
+ self._path = filepath
+ if filepath is not None:
+ self._read_from_file()
+ # END handle filepath
+
+ def _read_from_file(self):
+ fmap = file_contents_ro_filepath(self._path, stream=False, allow_mmap=True)
+ try:
+ self._deserialize(fmap)
+ finally:
+ fmap.close()
+ #END handle closing of handle
+
+ #{ Interface
+
+ @classmethod
+ def from_file(cls, filepath):
+ """
+ :return: a new RefLog instance containing all entries from the reflog
+ at the given filepath
+ :param filepath: path to reflog
+ :raise ValueError: If the file could not be read or was corrupted in some way"""
+ return cls(filepath)
+
+ @classmethod
+ def path(cls, ref):
+ """
+ :return: string to absolute path at which the reflog of the given ref
+ instance would be found. The path is not guaranteed to point to a valid
+ file though.
+ :param ref: SymbolicReference instance"""
+ return join(ref.repo.git_dir, "logs", to_native_path(ref.path))
+
+ @classmethod
+ def iter_entries(cls, stream):
+ """
+ :return: Iterator yielding RefLogEntry instances, one for each line read
+ sfrom the given stream.
+ :param stream: file-like object containing the revlog in its native format
+ or basestring instance pointing to a file to read"""
+ new_entry = RefLogEntry.from_line
+ if isinstance(stream, basestring):
+ stream = file_contents_ro_filepath(stream)
+ #END handle stream type
+ while True:
+ line = stream.readline()
+ if not line:
+ return
+ yield new_entry(line.strip())
+ #END endless loop
+
+ @classmethod
+ def entry_at(cls, filepath, index):
+ """:return: RefLogEntry at the given index
+ :param filepath: full path to the index file from which to read the entry
+ :param index: python list compatible index, i.e. it may be negative to
+ specifiy an entry counted from the end of the list
+
+ :raise IndexError: If the entry didn't exist
+
+ .. note:: This method is faster as it only parses the entry at index, skipping
+ all other lines. Nonetheless, the whole file has to be read if
+ the index is negative
+ """
+ fp = open(filepath, 'rb')
+ if index < 0:
+ return RefLogEntry.from_line(fp.readlines()[index].strip())
+ else:
+ # read until index is reached
+ for i in xrange(index+1):
+ line = fp.readline()
+ if not line:
+ break
+ #END abort on eof
+ #END handle runup
+
+ if i != index or not line:
+ raise IndexError
+ #END handle exception
+
+ return RefLogEntry.from_line(line.strip())
+ #END handle index
+
+ def to_file(self, filepath):
+ """Write the contents of the reflog instance to a file at the given filepath.
+ :param filepath: path to file, parent directories are assumed to exist"""
+ lfd = LockedFD(filepath)
+ assure_directory_exists(filepath, is_file=True)
+
+ fp = lfd.open(write=True, stream=True)
+ try:
+ self._serialize(fp)
+ lfd.commit()
+ except:
+ # on failure it rolls back automatically, but we make it clear
+ lfd.rollback()
+ raise
+ #END handle change
+
+ @classmethod
+ def append_entry(cls, config_reader, filepath, oldbinsha, newbinsha, message):
+ """Append a new log entry to the revlog at filepath.
+
+ :param config_reader: configuration reader of the repository - used to obtain
+ user information. May be None
+ :param filepath: full path to the log file
+ :param oldbinsha: binary sha of the previous commit
+ :param newbinsha: binary sha of the current commit
+ :param message: message describing the change to the reference
+ :param write: If True, the changes will be written right away. Otherwise
+ the change will not be written
+ :return: RefLogEntry objects which was appended to the log
+ :note: As we are append-only, concurrent access is not a problem as we
+ do not interfere with readers."""
+ if len(oldbinsha) != 20 or len(newbinsha) != 20:
+ raise ValueError("Shas need to be given in binary format")
+ #END handle sha type
+ assure_directory_exists(filepath, is_file=True)
+ entry = RefLogEntry((bin_to_hex(oldbinsha), bin_to_hex(newbinsha), Actor.committer(config_reader), (int(time.time()), time.altzone), message))
+
+ lf = LockFile(filepath)
+ lf._obtain_lock_or_raise()
+
+ fd = open(filepath, 'a')
+ try:
+ fd.write(repr(entry))
+ finally:
+ fd.close()
+ lf._release_lock()
+ #END handle write operation
+
+ return entry
+
+ def write(self):
+ """Write this instance's data to the file we are originating from
+ :return: self"""
+ if self._path is None:
+ raise ValueError("Instance was not initialized with a path, use to_file(...) instead")
+ #END assert path
+ self.to_file(self._path)
+ return self
+
+ #} END interface
+
+ #{ Serializable Interface
+ def _serialize(self, stream):
+ lm1 = len(self) - 1
+ write = stream.write
+
+ # write all entries
+ for e in self:
+ write(repr(e))
+ #END for each entry
+
+ def _deserialize(self, stream):
+ self.extend(self.iter_entries(stream))
+ #} END serializable interface
diff --git a/refs/reference.py b/refs/reference.py
new file mode 100644
index 00000000..1a745ee9
--- /dev/null
+++ b/refs/reference.py
@@ -0,0 +1,84 @@
+from symbolic import SymbolicReference
+import os
+from git.objects import Object
+from git.util import (
+ LazyMixin,
+ Iterable,
+ )
+
+from gitdb.util import (
+ isfile,
+ hex_to_bin
+ )
+
+__all__ = ["Reference"]
+
+
+class Reference(SymbolicReference, LazyMixin, Iterable):
+ """Represents a named reference to any object. Subclasses may apply restrictions though,
+ i.e. Heads can only point to commits."""
+ __slots__ = tuple()
+ _points_to_commits_only = False
+ _resolve_ref_on_create = True
+ _common_path_default = "refs"
+
+ def __init__(self, repo, path):
+ """Initialize this instance
+ :param repo: Our parent repository
+
+ :param path:
+ Path relative to the .git/ directory pointing to the ref in question, i.e.
+ refs/heads/master"""
+ if not path.startswith(self._common_path_default+'/'):
+ raise ValueError("Cannot instantiate %r from path %s" % ( self.__class__.__name__, path ))
+ super(Reference, self).__init__(repo, path)
+
+
+ def __str__(self):
+ return self.name
+
+ def set_object(self, object, logmsg = None):
+ """Special version which checks if the head-log needs an update as well"""
+ oldbinsha = None
+ if logmsg is not None:
+ head = self.repo.head
+ if not head.is_detached and head.ref == self:
+ oldbinsha = self.commit.binsha
+ #END handle commit retrieval
+ #END handle message is set
+
+ super(Reference, self).set_object(object, logmsg)
+
+ if oldbinsha is not None:
+ # /* from refs.c in git-source
+ # * Special hack: If a branch is updated directly and HEAD
+ # * points to it (may happen on the remote side of a push
+ # * for example) then logically the HEAD reflog should be
+ # * updated too.
+ # * A generic solution implies reverse symref information,
+ # * but finding all symrefs pointing to the given branch
+ # * would be rather costly for this rare event (the direct
+ # * update of a branch) to be worth it. So let's cheat and
+ # * check with HEAD only which should cover 99% of all usage
+ # * scenarios (even 100% of the default ones).
+ # */
+ self.repo.head.log_append(oldbinsha, logmsg)
+ #END check if the head
+
+ # NOTE: Don't have to overwrite properties as the will only work without a the log
+
+ @property
+ def name(self):
+ """:return: (shortest) Name of this reference - it may contain path components"""
+ # first two path tokens are can be removed as they are
+ # refs/heads or refs/tags or refs/remotes
+ tokens = self.path.split('/')
+ if len(tokens) < 3:
+ return self.path # could be refs/HEAD
+ return '/'.join(tokens[2:])
+
+ @classmethod
+ def iter_items(cls, repo, common_path = None):
+ """Equivalent to SymbolicReference.iter_items, but will return non-detached
+ references as well."""
+ return cls._iter_items(repo, common_path)
diff --git a/refs/remote.py b/refs/remote.py
new file mode 100644
index 00000000..b7b07d4b
--- /dev/null
+++ b/refs/remote.py
@@ -0,0 +1,63 @@
+from head import Head
+from git.util import join_path
+from gitdb.util import join
+
+import os
+
+
+__all__ = ["RemoteReference"]
+
+
+class RemoteReference(Head):
+ """Represents a reference pointing to a remote head."""
+ _common_path_default = "refs/remotes"
+
+
+ @classmethod
+ def iter_items(cls, repo, common_path = None, remote=None):
+ """Iterate remote references, and if given, constrain them to the given remote"""
+ common_path = common_path or cls._common_path_default
+ if remote is not None:
+ common_path = join_path(common_path, str(remote))
+ # END handle remote constraint
+ return super(RemoteReference, cls).iter_items(repo, common_path)
+
+ @property
+ def remote_name(self):
+ """
+ :return:
+ Name of the remote we are a reference of, such as 'origin' for a reference
+ named 'origin/master'"""
+ tokens = self.path.split('/')
+ # /refs/remotes/<remote name>/<branch_name>
+ return tokens[2]
+
+ @property
+ def remote_head(self):
+ """:return: Name of the remote head itself, i.e. master.
+ :note: The returned name is usually not qualified enough to uniquely identify
+ a branch"""
+ tokens = self.path.split('/')
+ return '/'.join(tokens[3:])
+
+ @classmethod
+ def delete(cls, repo, *refs, **kwargs):
+ """Delete the given remote references.
+ :note:
+ kwargs are given for compatability with the base class method as we
+ should not narrow the signature."""
+ repo.git.branch("-d", "-r", *refs)
+ # the official deletion method will ignore remote symbolic refs - these
+ # are generally ignored in the refs/ folder. We don't though
+ # and delete remainders manually
+ for ref in refs:
+ try:
+ os.remove(join(repo.git_dir, ref.path))
+ except OSError:
+ pass
+ # END for each ref
+
+ @classmethod
+ def create(cls, *args, **kwargs):
+ """Used to disable this method"""
+ raise TypeError("Cannot explicitly create remote references")
diff --git a/refs/symbolic.py b/refs/symbolic.py
new file mode 100644
index 00000000..9937cf0c
--- /dev/null
+++ b/refs/symbolic.py
@@ -0,0 +1,618 @@
+import os
+from git.objects import Object, Commit
+from git.util import (
+ join_path,
+ join_path_native,
+ to_native_path_linux,
+ assure_directory_exists
+ )
+
+from gitdb.exc import BadObject
+from gitdb.util import (
+ join,
+ dirname,
+ isdir,
+ exists,
+ isfile,
+ rename,
+ hex_to_bin,
+ LockedFD
+ )
+
+from log import RefLog
+
+__all__ = ["SymbolicReference"]
+
+class SymbolicReference(object):
+ """Represents a special case of a reference such that this reference is symbolic.
+ It does not point to a specific commit, but to another Head, which itself
+ specifies a commit.
+
+ A typical example for a symbolic reference is HEAD."""
+ __slots__ = ("repo", "path")
+ _resolve_ref_on_create = False
+ _points_to_commits_only = True
+ _common_path_default = ""
+ _id_attribute_ = "name"
+
+ def __init__(self, repo, path):
+ self.repo = repo
+ self.path = path
+
+ def __str__(self):
+ return self.path
+
+ def __repr__(self):
+ return '<git.%s "%s">' % (self.__class__.__name__, self.path)
+
+ def __eq__(self, other):
+ return self.path == other.path
+
+ def __ne__(self, other):
+ return not ( self == other )
+
+ def __hash__(self):
+ return hash(self.path)
+
+ @property
+ def name(self):
+ """
+ :return:
+ In case of symbolic references, the shortest assumable name
+ is the path itself."""
+ return self.path
+
+ @property
+ def abspath(self):
+ return join_path_native(self.repo.git_dir, self.path)
+
+ @classmethod
+ def _get_packed_refs_path(cls, repo):
+ return join(repo.git_dir, 'packed-refs')
+
+ @classmethod
+ def _iter_packed_refs(cls, repo):
+ """Returns an iterator yielding pairs of sha1/path pairs for the corresponding refs.
+ :note: The packed refs file will be kept open as long as we iterate"""
+ try:
+ fp = open(cls._get_packed_refs_path(repo), 'r')
+ for line in fp:
+ line = line.strip()
+ if not line:
+ continue
+ if line.startswith('#'):
+ if line.startswith('# pack-refs with:') and not line.endswith('peeled'):
+ raise TypeError("PackingType of packed-Refs not understood: %r" % line)
+ # END abort if we do not understand the packing scheme
+ continue
+ # END parse comment
+
+ # skip dereferenced tag object entries - previous line was actual
+ # tag reference for it
+ if line[0] == '^':
+ continue
+
+ yield tuple(line.split(' ', 1))
+ # END for each line
+ except (OSError,IOError):
+ raise StopIteration
+ # END no packed-refs file handling
+ # NOTE: Had try-finally block around here to close the fp,
+ # but some python version woudn't allow yields within that.
+ # I believe files are closing themselves on destruction, so it is
+ # alright.
+
+ @classmethod
+ def dereference_recursive(cls, repo, ref_path):
+ """
+ :return: hexsha stored in the reference at the given ref_path, recursively dereferencing all
+ intermediate references as required
+ :param repo: the repository containing the reference at ref_path"""
+ while True:
+ hexsha, ref_path = cls._get_ref_info(repo, ref_path)
+ if hexsha is not None:
+ return hexsha
+ # END recursive dereferencing
+
+ @classmethod
+ def _get_ref_info(cls, repo, ref_path):
+ """Return: (sha, target_ref_path) if available, the sha the file at
+ rela_path points to, or None. target_ref_path is the reference we
+ point to, or None"""
+ tokens = None
+ try:
+ fp = open(join(repo.git_dir, ref_path), 'r')
+ value = fp.read().rstrip()
+ fp.close()
+ tokens = value.split(" ")
+ except (OSError,IOError):
+ # Probably we are just packed, find our entry in the packed refs file
+ # NOTE: We are not a symbolic ref if we are in a packed file, as these
+ # are excluded explictly
+ for sha, path in cls._iter_packed_refs(repo):
+ if path != ref_path: continue
+ tokens = (sha, path)
+ break
+ # END for each packed ref
+ # END handle packed refs
+ if tokens is None:
+ raise ValueError("Reference at %r does not exist" % ref_path)
+
+ # is it a reference ?
+ if tokens[0] == 'ref:':
+ return (None, tokens[1])
+
+ # its a commit
+ if repo.re_hexsha_only.match(tokens[0]):
+ return (tokens[0], None)
+
+ raise ValueError("Failed to parse reference information from %r" % ref_path)
+
+ def _get_object(self):
+ """
+ :return:
+ The object our ref currently refers to. Refs can be cached, they will
+ always point to the actual object as it gets re-created on each query"""
+ # have to be dynamic here as we may be a tag which can point to anything
+ # Our path will be resolved to the hexsha which will be used accordingly
+ return Object.new_from_sha(self.repo, hex_to_bin(self.dereference_recursive(self.repo, self.path)))
+
+ def _get_commit(self):
+ """
+ :return:
+ Commit object we point to, works for detached and non-detached
+ SymbolicReferences. The symbolic reference will be dereferenced recursively."""
+ obj = self._get_object()
+ if obj.type == 'tag':
+ obj = obj.object
+ #END dereference tag
+
+ if obj.type != Commit.type:
+ raise TypeError("Symbolic Reference pointed to object %r, commit was required" % obj)
+ #END handle type
+ return obj
+
+ def set_commit(self, commit, logmsg = None):
+ """As set_object, but restricts the type of object to be a Commit
+
+ :raise ValueError: If commit is not a Commit object or doesn't point to
+ a commit
+ :return: self"""
+ # check the type - assume the best if it is a base-string
+ invalid_type = False
+ if isinstance(commit, Object):
+ invalid_type = commit.type != Commit.type
+ elif isinstance(commit, SymbolicReference):
+ invalid_type = commit.object.type != Commit.type
+ else:
+ try:
+ invalid_type = self.repo.rev_parse(commit).type != Commit.type
+ except BadObject:
+ raise ValueError("Invalid object: %s" % commit)
+ #END handle exception
+ # END verify type
+
+ if invalid_type:
+ raise ValueError("Need commit, got %r" % commit)
+ #END handle raise
+
+ # we leave strings to the rev-parse method below
+ self.set_object(commit, logmsg)
+
+ return self
+
+
+ def set_object(self, object, logmsg = None):
+ """Set the object we point to, possibly dereference our symbolic reference first.
+ If the reference does not exist, it will be created
+
+ :param object: a refspec, a SymbolicReference or an Object instance. SymbolicReferences
+ will be dereferenced beforehand to obtain the object they point to
+ :param logmsg: If not None, the message will be used in the reflog entry to be
+ written. Otherwise the reflog is not altered
+ :note: plain SymbolicReferences may not actually point to objects by convention
+ :return: self"""
+ if isinstance(object, SymbolicReference):
+ object = object.object
+ #END resolve references
+
+ is_detached = True
+ try:
+ is_detached = self.is_detached
+ except ValueError:
+ pass
+ # END handle non-existing ones
+
+ if is_detached:
+ return self.set_reference(object, logmsg)
+
+ # set the commit on our reference
+ return self._get_reference().set_object(object, logmsg)
+
+ commit = property(_get_commit, set_commit, doc="Query or set commits directly")
+ object = property(_get_object, set_object, doc="Return the object our ref currently refers to")
+
+ def _get_reference(self):
+ """:return: Reference Object we point to
+ :raise TypeError: If this symbolic reference is detached, hence it doesn't point
+ to a reference, but to a commit"""
+ sha, target_ref_path = self._get_ref_info(self.repo, self.path)
+ if target_ref_path is None:
+ raise TypeError("%s is a detached symbolic reference as it points to %r" % (self, sha))
+ return self.from_path(self.repo, target_ref_path)
+
+ def set_reference(self, ref, logmsg = None):
+ """Set ourselves to the given ref. It will stay a symbol if the ref is a Reference.
+ Otherwise an Object, given as Object instance or refspec, is assumed and if valid,
+ will be set which effectively detaches the refererence if it was a purely
+ symbolic one.
+
+ :param ref: SymbolicReference instance, Object instance or refspec string
+ Only if the ref is a SymbolicRef instance, we will point to it. Everthiny
+ else is dereferenced to obtain the actual object.
+ :param logmsg: If set to a string, the message will be used in the reflog.
+ Otherwise, a reflog entry is not written for the changed reference.
+ The previous commit of the entry will be the commit we point to now.
+
+ See also: log_append()
+
+ :return: self
+ :note: This symbolic reference will not be dereferenced. For that, see
+ ``set_object(...)``"""
+ write_value = None
+ obj = None
+ if isinstance(ref, SymbolicReference):
+ write_value = "ref: %s" % ref.path
+ elif isinstance(ref, Object):
+ obj = ref
+ write_value = ref.hexsha
+ elif isinstance(ref, basestring):
+ try:
+ obj = self.repo.rev_parse(ref+"^{}") # optionally deref tags
+ write_value = obj.hexsha
+ except BadObject:
+ raise ValueError("Could not extract object from %s" % ref)
+ # END end try string
+ else:
+ raise ValueError("Unrecognized Value: %r" % ref)
+ # END try commit attribute
+
+ # typecheck
+ if obj is not None and self._points_to_commits_only and obj.type != Commit.type:
+ raise TypeError("Require commit, got %r" % obj)
+ #END verify type
+
+ oldbinsha = None
+ if logmsg is not None:
+ try:
+ oldbinsha = self.commit.binsha
+ except ValueError:
+ oldbinsha = Commit.NULL_BIN_SHA
+ #END handle non-existing
+ #END retrieve old hexsha
+
+ fpath = self.abspath
+ assure_directory_exists(fpath, is_file=True)
+
+ lfd = LockedFD(fpath)
+ fd = lfd.open(write=True, stream=True)
+ fd.write(write_value)
+ lfd.commit()
+
+ # Adjust the reflog
+ if logmsg is not None:
+ self.log_append(oldbinsha, logmsg)
+ #END handle reflog
+
+ return self
+
+
+ # aliased reference
+ reference = property(_get_reference, set_reference, doc="Returns the Reference we point to")
+ ref = reference
+
+ def is_valid(self):
+ """
+ :return:
+ True if the reference is valid, hence it can be read and points to
+ a valid object or reference."""
+ try:
+ self.object
+ except (OSError, ValueError):
+ return False
+ else:
+ return True
+
+ @property
+ def is_detached(self):
+ """
+ :return:
+ True if we are a detached reference, hence we point to a specific commit
+ instead to another reference"""
+ try:
+ self.ref
+ return False
+ except TypeError:
+ return True
+
+ def log(self):
+ """
+ :return: RefLog for this reference. Its last entry reflects the latest change
+ applied to this reference
+
+ .. note:: As the log is parsed every time, its recommended to cache it for use
+ instead of calling this method repeatedly. It should be considered read-only."""
+ return RefLog.from_file(RefLog.path(self))
+
+ def log_append(self, oldbinsha, message, newbinsha=None):
+ """Append a logentry to the logfile of this ref
+
+ :param oldbinsha: binary sha this ref used to point to
+ :param message: A message describing the change
+ :param newbinsha: The sha the ref points to now. If None, our current commit sha
+ will be used
+ :return: added RefLogEntry instance"""
+ return RefLog.append_entry(self.repo.config_reader(), RefLog.path(self), oldbinsha,
+ (newbinsha is None and self.commit.binsha) or newbinsha,
+ message)
+
+ def log_entry(self, index):
+ """:return: RefLogEntry at the given index
+ :param index: python list compatible positive or negative index
+
+ .. note:: This method must read part of the reflog during execution, hence
+ it should be used sparringly, or only if you need just one index.
+ In that case, it will be faster than the ``log()`` method"""
+ return RefLog.entry_at(RefLog.path(self), index)
+
+ @classmethod
+ def to_full_path(cls, path):
+ """
+ :return: string with a full repository-relative path which can be used to initialize
+ a Reference instance, for instance by using ``Reference.from_path``"""
+ if isinstance(path, SymbolicReference):
+ path = path.path
+ full_ref_path = path
+ if not cls._common_path_default:
+ return full_ref_path
+ if not path.startswith(cls._common_path_default+"/"):
+ full_ref_path = '%s/%s' % (cls._common_path_default, path)
+ return full_ref_path
+
+ @classmethod
+ def delete(cls, repo, path):
+ """Delete the reference at the given path
+
+ :param repo:
+ Repository to delete the reference from
+
+ :param path:
+ Short or full path pointing to the reference, i.e. refs/myreference
+ or just "myreference", hence 'refs/' is implied.
+ Alternatively the symbolic reference to be deleted"""
+ full_ref_path = cls.to_full_path(path)
+ abs_path = join(repo.git_dir, full_ref_path)
+ if exists(abs_path):
+ os.remove(abs_path)
+ else:
+ # check packed refs
+ pack_file_path = cls._get_packed_refs_path(repo)
+ try:
+ reader = open(pack_file_path)
+ except (OSError,IOError):
+ pass # it didnt exist at all
+ else:
+ new_lines = list()
+ made_change = False
+ dropped_last_line = False
+ for line in reader:
+ # keep line if it is a comment or if the ref to delete is not
+ # in the line
+ # If we deleted the last line and this one is a tag-reference object,
+ # we drop it as well
+ if ( line.startswith('#') or full_ref_path not in line ) and \
+ ( not dropped_last_line or dropped_last_line and not line.startswith('^') ):
+ new_lines.append(line)
+ dropped_last_line = False
+ continue
+ # END skip comments and lines without our path
+
+ # drop this line
+ made_change = True
+ dropped_last_line = True
+ # END for each line in packed refs
+ reader.close()
+
+ # write the new lines
+ if made_change:
+ open(pack_file_path, 'w').writelines(new_lines)
+ # END open exception handling
+ # END handle deletion
+
+ # delete the reflog
+ reflog_path = RefLog.path(cls(repo, full_ref_path))
+ if os.path.isfile(reflog_path):
+ os.remove(reflog_path)
+ #END remove reflog
+
+
+ @classmethod
+ def _create(cls, repo, path, resolve, reference, force, logmsg=None):
+ """internal method used to create a new symbolic reference.
+ If resolve is False, the reference will be taken as is, creating
+ a proper symbolic reference. Otherwise it will be resolved to the
+ corresponding object and a detached symbolic reference will be created
+ instead"""
+ full_ref_path = cls.to_full_path(path)
+ abs_ref_path = join(repo.git_dir, full_ref_path)
+
+ # figure out target data
+ target = reference
+ if resolve:
+ target = repo.rev_parse(str(reference))
+
+ if not force and isfile(abs_ref_path):
+ target_data = str(target)
+ if isinstance(target, SymbolicReference):
+ target_data = target.path
+ if not resolve:
+ target_data = "ref: " + target_data
+ existing_data = open(abs_ref_path, 'rb').read().strip()
+ if existing_data != target_data:
+ raise OSError("Reference at %r does already exist, pointing to %r, requested was %r" % (full_ref_path, existing_data, target_data))
+ # END no force handling
+
+ ref = cls(repo, full_ref_path)
+ ref.set_reference(target, logmsg)
+ return ref
+
+ @classmethod
+ def create(cls, repo, path, reference='HEAD', force=False, logmsg=None):
+ """Create a new symbolic reference, hence a reference pointing to another reference.
+
+ :param repo:
+ Repository to create the reference in
+
+ :param path:
+ full path at which the new symbolic reference is supposed to be
+ created at, i.e. "NEW_HEAD" or "symrefs/my_new_symref"
+
+ :param reference:
+ The reference to which the new symbolic reference should point to
+
+ :param force:
+ if True, force creation even if a symbolic reference with that name already exists.
+ Raise OSError otherwise
+
+ :param logmsg:
+ If not None, the message to append to the reflog. Otherwise no reflog
+ entry is written.
+
+ :return: Newly created symbolic Reference
+
+ :raise OSError:
+ If a (Symbolic)Reference with the same name but different contents
+ already exists.
+
+ :note: This does not alter the current HEAD, index or Working Tree"""
+ return cls._create(repo, path, cls._resolve_ref_on_create, reference, force, logmsg)
+
+ def rename(self, new_path, force=False):
+ """Rename self to a new path
+
+ :param new_path:
+ Either a simple name or a full path, i.e. new_name or features/new_name.
+ The prefix refs/ is implied for references and will be set as needed.
+ In case this is a symbolic ref, there is no implied prefix
+
+ :param force:
+ If True, the rename will succeed even if a head with the target name
+ already exists. It will be overwritten in that case
+
+ :return: self
+ :raise OSError: In case a file at path but a different contents already exists """
+ new_path = self.to_full_path(new_path)
+ if self.path == new_path:
+ return self
+
+ new_abs_path = join(self.repo.git_dir, new_path)
+ cur_abs_path = join(self.repo.git_dir, self.path)
+ if isfile(new_abs_path):
+ if not force:
+ # if they point to the same file, its not an error
+ if open(new_abs_path,'rb').read().strip() != open(cur_abs_path,'rb').read().strip():
+ raise OSError("File at path %r already exists" % new_abs_path)
+ # else: we could remove ourselves and use the otherone, but
+ # but clarity we just continue as usual
+ # END not force handling
+ os.remove(new_abs_path)
+ # END handle existing target file
+
+ dname = dirname(new_abs_path)
+ if not isdir(dname):
+ os.makedirs(dname)
+ # END create directory
+
+ rename(cur_abs_path, new_abs_path)
+ self.path = new_path
+
+ return self
+
+ @classmethod
+ def _iter_items(cls, repo, common_path = None):
+ if common_path is None:
+ common_path = cls._common_path_default
+ rela_paths = set()
+
+ # walk loose refs
+ # Currently we do not follow links
+ for root, dirs, files in os.walk(join_path_native(repo.git_dir, common_path)):
+ if 'refs/' not in root: # skip non-refs subfolders
+ refs_id = [ i for i,d in enumerate(dirs) if d == 'refs' ]
+ if refs_id:
+ dirs[0:] = ['refs']
+ # END prune non-refs folders
+
+ for f in files:
+ abs_path = to_native_path_linux(join_path(root, f))
+ rela_paths.add(abs_path.replace(to_native_path_linux(repo.git_dir) + '/', ""))
+ # END for each file in root directory
+ # END for each directory to walk
+
+ # read packed refs
+ for sha, rela_path in cls._iter_packed_refs(repo):
+ if rela_path.startswith(common_path):
+ rela_paths.add(rela_path)
+ # END relative path matches common path
+ # END packed refs reading
+
+ # return paths in sorted order
+ for path in sorted(rela_paths):
+ try:
+ yield cls.from_path(repo, path)
+ except ValueError:
+ continue
+ # END for each sorted relative refpath
+
+ @classmethod
+ def iter_items(cls, repo, common_path = None):
+ """Find all refs in the repository
+
+ :param repo: is the Repo
+
+ :param common_path:
+ Optional keyword argument to the path which is to be shared by all
+ returned Ref objects.
+ Defaults to class specific portion if None assuring that only
+ refs suitable for the actual class are returned.
+
+ :return:
+ git.SymbolicReference[], each of them is guaranteed to be a symbolic
+ ref which is not detached.
+
+ List is lexigraphically sorted
+ The returned objects represent actual subclasses, such as Head or TagReference"""
+ return ( r for r in cls._iter_items(repo, common_path) if r.__class__ == SymbolicReference or not r.is_detached )
+
+ @classmethod
+ def from_path(cls, repo, path):
+ """
+ :param path: full .git-directory-relative path name to the Reference to instantiate
+ :note: use to_full_path() if you only have a partial path of a known Reference Type
+ :return:
+ Instance of type Reference, Head, or Tag
+ depending on the given path"""
+ if not path:
+ raise ValueError("Cannot create Reference from %r" % path)
+
+ for ref_type in (HEAD, Head, RemoteReference, TagReference, Reference, SymbolicReference):
+ try:
+ instance = ref_type(repo, path)
+ if instance.__class__ == SymbolicReference and instance.is_detached:
+ raise ValueError("SymbolRef was detached, we drop it")
+ return instance
+ except ValueError:
+ pass
+ # END exception handling
+ # END for each type to try
+ raise ValueError("Could not find reference type suitable to handle path %r" % path)
diff --git a/refs/tag.py b/refs/tag.py
new file mode 100644
index 00000000..c09d814d
--- /dev/null
+++ b/refs/tag.py
@@ -0,0 +1,91 @@
+from reference import Reference
+
+__all__ = ["TagReference", "Tag"]
+
+
+
+class TagReference(Reference):
+ """Class representing a lightweight tag reference which either points to a commit
+ ,a tag object or any other object. In the latter case additional information,
+ like the signature or the tag-creator, is available.
+
+ This tag object will always point to a commit object, but may carray additional
+ information in a tag object::
+
+ tagref = TagReference.list_items(repo)[0]
+ print tagref.commit.message
+ if tagref.tag is not None:
+ print tagref.tag.message"""
+
+ __slots__ = tuple()
+ _common_path_default = "refs/tags"
+
+ @property
+ def commit(self):
+ """:return: Commit object the tag ref points to"""
+ obj = self.object
+ if obj.type == "commit":
+ return obj
+ elif obj.type == "tag":
+ # it is a tag object which carries the commit as an object - we can point to anything
+ return obj.object
+ else:
+ raise ValueError( "Tag %s points to a Blob or Tree - have never seen that before" % self )
+
+ @property
+ def tag(self):
+ """
+ :return: Tag object this tag ref points to or None in case
+ we are a light weight tag"""
+ obj = self.object
+ if obj.type == "tag":
+ return obj
+ return None
+
+ # make object read-only
+ # It should be reasonably hard to adjust an existing tag
+ object = property(Reference._get_object)
+
+ @classmethod
+ def create(cls, repo, path, ref='HEAD', message=None, force=False, **kwargs):
+ """Create a new tag reference.
+
+ :param path:
+ The name of the tag, i.e. 1.0 or releases/1.0.
+ The prefix refs/tags is implied
+
+ :param ref:
+ A reference to the object you want to tag. It can be a commit, tree or
+ blob.
+
+ :param message:
+ If not None, the message will be used in your tag object. This will also
+ create an additional tag object that allows to obtain that information, i.e.::
+
+ tagref.tag.message
+
+ :param force:
+ If True, to force creation of a tag even though that tag already exists.
+
+ :param kwargs:
+ Additional keyword arguments to be passed to git-tag
+
+ :return: A new TagReference"""
+ args = ( path, ref )
+ if message:
+ kwargs['m'] = message
+ if force:
+ kwargs['f'] = True
+
+ repo.git.tag(*args, **kwargs)
+ return TagReference(repo, "%s/%s" % (cls._common_path_default, path))
+
+ @classmethod
+ def delete(cls, repo, *tags):
+ """Delete the given existing tag or tags"""
+ repo.git.tag("-d", *tags)
+
+
+
+# provide an alias
+Tag = TagReference
diff --git a/remote.py b/remote.py
index 3edde175..2e596ca1 100644
--- a/remote.py
+++ b/remote.py
@@ -3,7 +3,8 @@
#
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
-"""Module implementing a remote object allowing easy access to git remotes"""
+
+# Module implementing a remote object allowing easy access to git remotes
from exc import GitCommandError
from objects import Commit
diff --git a/repo/base.py b/repo/base.py
index 6f401628..c8613878 100644
--- a/repo/base.py
+++ b/repo/base.py
@@ -6,6 +6,7 @@
from git.exc import InvalidGitRepositoryError, NoSuchPathError
from git.cmd import Git
+from git.util import Actor
from git.refs import *
from git.index import IndexFile
from git.objects import *
diff --git a/repo/fun.py b/repo/fun.py
index a0f66fe5..c523a3e1 100644
--- a/repo/fun.py
+++ b/repo/fun.py
@@ -1,5 +1,5 @@
"""Package with general repository related functions"""
-
+import os
from gitdb.exc import BadObject
from git.refs import SymbolicReference
from git.objects import Object
@@ -42,9 +42,13 @@ def short_to_long(odb, hexsha):
# END exception handling
-def name_to_object(repo, name):
- """:return: object specified by the given name, hexshas ( short and long )
- as well as references are supported"""
+def name_to_object(repo, name, return_ref=False):
+ """
+ :return: object specified by the given name, hexshas ( short and long )
+ as well as references are supported
+ :param return_ref: if name specifies a reference, we will return the reference
+ instead of the object. Otherwise it will raise BadObject
+ """
hexsha = None
# is it a hexsha ? Try the most common ones, which is 7 to 40
@@ -59,12 +63,20 @@ def name_to_object(repo, name):
for base in ('%s', 'refs/%s', 'refs/tags/%s', 'refs/heads/%s', 'refs/remotes/%s', 'refs/remotes/%s/HEAD'):
try:
hexsha = SymbolicReference.dereference_recursive(repo, base % name)
+ if return_ref:
+ return SymbolicReference(repo, base % name)
+ #END handle symbolic ref
break
except ValueError:
pass
# END for each base
# END handle hexsha
-
+
+ # didn't find any ref, this is an error
+ if return_ref:
+ raise BadObject("Couldn't find reference named %r" % name)
+ #END handle return ref
+
# tried everything ? fail
if hexsha is None:
raise BadObject(name)
@@ -101,9 +113,6 @@ def rev_parse(repo, rev):
:note: Currently there is no access to the rev-log, rev-specs may only contain
topological tokens such ~ and ^.
:raise BadObject: if the given revision could not be found"""
- if '@' in rev:
- raise ValueError("There is no rev-log support yet")
-
# colon search mode ?
if rev.startswith(':/'):
@@ -112,22 +121,37 @@ def rev_parse(repo, rev):
# END handle search
obj = None
+ ref = None
output_type = "commit"
start = 0
parsed_to = 0
lr = len(rev)
while start < lr:
- if rev[start] not in "^~:":
+ if rev[start] not in "^~:@":
start += 1
continue
# END handle start
+ token = rev[start]
+
if obj is None:
# token is a rev name
- obj = name_to_object(repo, rev[:start])
+ if start == 0:
+ ref = repo.head.ref
+ else:
+ if token == '@':
+ ref = name_to_object(repo, rev[:start], return_ref=True)
+ else:
+ obj = name_to_object(repo, rev[:start])
+ #END handle token
+ #END handle refname
+
+ if ref is not None:
+ obj = ref.commit
+ #END handle ref
# END initialize obj on first token
- token = rev[start]
+
start += 1
# try to parse {type}
@@ -153,6 +177,29 @@ def rev_parse(repo, rev):
# cannot do anything for non-tags
pass
# END handle tag
+ elif token == '@':
+ # try single int
+ assert ref is not None, "Requre Reference to access reflog"
+ revlog_index = None
+ try:
+ # transform reversed index into the format of our revlog
+ revlog_index = -(int(output_type)+1)
+ except ValueError:
+ # TODO: Try to parse the other date options, using parse_date
+ # maybe
+ raise NotImplementedError("Support for additional @{...} modes not implemented")
+ #END handle revlog index
+
+ try:
+ entry = ref.log_entry(revlog_index)
+ except IndexError:
+ raise BadObject("Invalid revlog index: %i" % revlog_index)
+ #END handle index out of bound
+
+ obj = Object.new_from_sha(repo, hex_to_bin(entry.newhexsha))
+
+ # make it pass the following checks
+ output_type = None
else:
raise ValueError("Invalid output type: %s ( in %s )" % (output_type, rev))
# END handle output type
diff --git a/test/fixtures/reflog_HEAD b/test/fixtures/reflog_HEAD
new file mode 100644
index 00000000..7b2272ac
--- /dev/null
+++ b/test/fixtures/reflog_HEAD
@@ -0,0 +1,460 @@
+501bf602abea7d21c3dbb409b435976e92033145 82b8902e033430000481eb355733cd7065342037 Sebastian Thiel <byronimo@gmail.com> 1270634931 +0200 commit: Used this release for a first beta of the 0.2 branch of development
+82b8902e033430000481eb355733cd7065342037 69361d96a59381fde0ac34d19df2d4aff05fb9a9 Sebastian Thiel <byronimo@gmail.com> 1271229940 +0200 commit: conf.py: Adjusted version to match with the actual version
+69361d96a59381fde0ac34d19df2d4aff05fb9a9 69361d96a59381fde0ac34d19df2d4aff05fb9a9 Sebastian Thiel <byronimo@gmail.com> 1272612605 +0200 checkout: moving from 69361d96a59381fde0ac34d19df2d4aff05fb9a9 to integration
+69361d96a59381fde0ac34d19df2d4aff05fb9a9 b75c3103a700ac65b6cd18f66e2d0a07cfc09797 Sebastian Thiel <byronimo@gmail.com> 1272612605 +0200 pull git://gitorious.org/git-python/mainline.git refs/merge-requests/14: Merge made by recursive.
+b75c3103a700ac65b6cd18f66e2d0a07cfc09797 0d6ceabf5b90e7c0690360fc30774d36644f563c Sebastian Thiel <byronimo@gmail.com> 1272614223 +0200 commit: Added additional tz_offset testing in performance test to call it more often.
+0d6ceabf5b90e7c0690360fc30774d36644f563c 69361d96a59381fde0ac34d19df2d4aff05fb9a9 Sebastian Thiel <byronimo@gmail.com> 1272614242 +0200 checkout: moving from integration to master
+69361d96a59381fde0ac34d19df2d4aff05fb9a9 0d6ceabf5b90e7c0690360fc30774d36644f563c Sebastian Thiel <byronimo@gmail.com> 1272614247 +0200 merge integration: Fast-forward
+0d6ceabf5b90e7c0690360fc30774d36644f563c 997b7611dc5ec41d0e3860e237b530f387f3524a Sebastian Thiel <byronimo@gmail.com> 1272874921 +0200 checkout: moving from master to 997b7611dc5ec41d0e3860e237b530f387f3524a
+997b7611dc5ec41d0e3860e237b530f387f3524a 0d6ceabf5b90e7c0690360fc30774d36644f563c Sebastian Thiel <byronimo@gmail.com> 1272919096 +0200 checkout: moving from 997b7611dc5ec41d0e3860e237b530f387f3524a to master
+22a0289972b365b7912340501b52ca3dd98be289 143b927307d46ccb8f1cc095739e9625c03c82ff Sebastian Thiel <byronimo@gmail.com> 1272988814 +0200 commit: TODO: Removed all entries but left a mesage about where to find the issuee on lighthouse.
+143b927307d46ccb8f1cc095739e9625c03c82ff e41c727be8dbf8f663e67624b109d9f8b135a4ab Sebastian Thiel <byronimo@gmail.com> 1273140152 +0200 commit: README: Added mailing list and issue tracker information
+c083f3d0b853e723d0d4b00ff2f1ec5f65f05cba c083f3d0b853e723d0d4b00ff2f1ec5f65f05cba Sebastian Thiel <byronimo@gmail.com> 1273522280 +0200 checkout: moving from c083f3d0b853e723d0d4b00ff2f1ec5f65f05cba to integration
+c083f3d0b853e723d0d4b00ff2f1ec5f65f05cba de5bc8f7076c5736ef1efa57345564fbc563bd19 Sebastian Thiel <byronimo@gmail.com> 1273522570 +0200 commit: Handle filenames with embedded spaces when generating diffs
+de5bc8f7076c5736ef1efa57345564fbc563bd19 8caeec1b15645fa53ec5ddc6e990e7030ffb7c5a Sebastian Thiel <byronimo@gmail.com> 1273529174 +0200 commit: IndexFile.add: Fixed incorrect path handling if path rewriting was desired and absolute paths were given
+600fcbc1a2d723f8d51e5f5ab6d9e4c389010e1c de5bc8f7076c5736ef1efa57345564fbc563bd19 Sebastian Thiel <byronimo@gmail.com> 1274808939 +0200 checkout: moving from master to master~2
+de5bc8f7076c5736ef1efa57345564fbc563bd19 600fcbc1a2d723f8d51e5f5ab6d9e4c389010e1c Sebastian Thiel <byronimo@gmail.com> 1274808999 +0200 checkout: moving from de5bc8f7076c5736ef1efa57345564fbc563bd19 to master
+600fcbc1a2d723f8d51e5f5ab6d9e4c389010e1c c083f3d0b853e723d0d4b00ff2f1ec5f65f05cba Sebastian Thiel <byronimo@gmail.com> 1274809635 +0200 checkout: moving from master to HEAD~3
+c083f3d0b853e723d0d4b00ff2f1ec5f65f05cba 600fcbc1a2d723f8d51e5f5ab6d9e4c389010e1c Sebastian Thiel <byronimo@gmail.com> 1274809694 +0200 checkout: moving from c083f3d0b853e723d0d4b00ff2f1ec5f65f05cba to master
+600fcbc1a2d723f8d51e5f5ab6d9e4c389010e1c 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af Sebastian Thiel <byronimo@gmail.com> 1274811103 +0200 commit: diff: by limiting the splitcount to 5, a subtle bug was introduced as the newline at the end of the split line was not split away automatically. Added test for this, and the trivial fix
+1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af 17af1f64d5f1e62d40e11b75b1dd48e843748b49 Sebastian Thiel <byronimo@gmail.com> 1274877948 +0200 commit: BlockingLockFile: added sanity check that raises IOError if the directory containing the lock was removed. This is unlikely to happen in a production envrironment, but may happen during testing, as folders are moved/deleted once the test is complete. Daemons might still be waiting for something, and they should be allowed to terminate instead of waiting for a possibly long time
+17af1f64d5f1e62d40e11b75b1dd48e843748b49 34ba8ffba0b3b4d21da7bcea594cc3631e422142 Sebastian Thiel <byronimo@gmail.com> 1274906080 +0200 commit: refs: a Reference can now be created by assigning a commit or object (for convenience)
+34ba8ffba0b3b4d21da7bcea594cc3631e422142 11dc82538cc1ebb537c866c8e76146e384cdfe24 Sebastian Thiel <byronimo@gmail.com> 1274906333 +0200 commit: refs: a Reference can now be created by assigning a commit or object (for convenience)
+11dc82538cc1ebb537c866c8e76146e384cdfe24 34ba8ffba0b3b4d21da7bcea594cc3631e422142 Sebastian Thiel <byronimo@gmail.com> 1274906338 +0200 HEAD~1: updating HEAD
+34ba8ffba0b3b4d21da7bcea594cc3631e422142 de84cbdd0f9ef97fcd3477b31b040c57192e28d9 Sebastian Thiel <byronimo@gmail.com> 1274906431 +0200 commit (amend): refs: a Reference can now be created by assigning a commit or object (for convenience)
+de84cbdd0f9ef97fcd3477b31b040c57192e28d9 ecf37a1b4c2f70f1fc62a6852f40178bf08b9859 Sebastian Thiel <byronimo@gmail.com> 1274910053 +0200 commit: index: index-add fixed to always append a newline after each item. In git has unified its way it reads from stdin, now it wants all items to be terminated by a newline usually. Previously, it could have been that it really didn't want to have a termination character when the last item was written to the file. Bumped the minimum requirements to 1.7.0 to be sure it is working as I think it will.
+ecf37a1b4c2f70f1fc62a6852f40178bf08b9859 1ee2afb00afaf77c883501eac8cd614c8229a444 Sebastian Thiel <byronimo@gmail.com> 1274914700 +0200 commit: cmd: By default, on linux, the parent file handles will be closed to leave the child less cluttered, and make it easier to debug as it will only have the file descriptors we set. It appears to be more stable regarding the stdin-is-closed-but-child-doesn't-realize-this issue
+1ee2afb00afaf77c883501eac8cd614c8229a444 bd45e9267ab0d3f37e59ecc8b87d0ad19abad4ad Sebastian Thiel <byronimo@gmail.com> 1275324366 +0200 commit: gitcmd: may now receive extra keyword arguments to be passed directly to the subproces.Popen invocation. It could be used to pass custom environments, without changing the own one
+bd45e9267ab0d3f37e59ecc8b87d0ad19abad4ad 6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e Sebastian Thiel <byronimo@gmail.com> 1275324409 +0200 commit (amend): gitcmd: may now receive extra keyword arguments to be passed directly to the subproces.Popen invocation. It could be used to pass custom environments, without changing the own one (#26)
+6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e 6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e Sebastian Thiel <byronimo@gmail.com> 1275417756 +0200 checkout: moving from master to commit
+6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e 14212649c0c48d0a7e5a83430873cae20aad4c83 Sebastian Thiel <byronimo@gmail.com> 1275432496 +0200 commit: commit: initial version of commit_from_tree which could create commit objects if it could serialize itself
+14212649c0c48d0a7e5a83430873cae20aad4c83 7f6aa55077819e04dace82bc3ffbdea641b3e9ce Sebastian Thiel <byronimo@gmail.com> 1275432507 +0200 commit: commit: initial version of commit_from_tree which could create commit objects if it could serialize itself
+7f6aa55077819e04dace82bc3ffbdea641b3e9ce 14212649c0c48d0a7e5a83430873cae20aad4c83 Sebastian Thiel <byronimo@gmail.com> 1275432513 +0200 HEAD~1: updating HEAD
+14212649c0c48d0a7e5a83430873cae20aad4c83 1a0ec7154ea961d68ecfd4dec50f9fc1718686a2 Sebastian Thiel <byronimo@gmail.com> 1275433336 +0200 commit (amend): commit: initial version of commit_from_tree which could create commit objects if it could serialize itself
+1a0ec7154ea961d68ecfd4dec50f9fc1718686a2 df0892351a394d768489b5647d47b73c24d3ef5f Sebastian Thiel <byronimo@gmail.com> 1275433456 +0200 commit (amend): commit: initial version of commit_from_tree which could create commit objects if it could serialize itself
+df0892351a394d768489b5647d47b73c24d3ef5f df0892351a394d768489b5647d47b73c24d3ef5f Sebastian Thiel <byronimo@gmail.com> 1275474032 +0200 checkout: moving from commit to odb
+df0892351a394d768489b5647d47b73c24d3ef5f 0e88ee839eaa5966f0d652372247fd14d80f9bb3 Sebastian Thiel <byronimo@gmail.com> 1275474633 +0200 commit: commit: refactored existing code to decode commits from streams - unfortunately this involves a little bit more python involvement currently, so performance might be slightly worse than before atm
+0e88ee839eaa5966f0d652372247fd14d80f9bb3 6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e Sebastian Thiel <byronimo@gmail.com> 1275474676 +0200 checkout: moving from odb to master
+6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e 0e88ee839eaa5966f0d652372247fd14d80f9bb3 Sebastian Thiel <byronimo@gmail.com> 1275474732 +0200 checkout: moving from master to odb
+0e88ee839eaa5966f0d652372247fd14d80f9bb3 714e42d6315806dff61d39d8750ef8b250fb8d82 Sebastian Thiel <byronimo@gmail.com> 1275475614 +0200 commit (amend): commit: refactored existing code to decode commits from streams - performance is slightly better
+714e42d6315806dff61d39d8750ef8b250fb8d82 8c1a87d11df666d308d14e4ae7ee0e9d614296b6 Sebastian Thiel <byronimo@gmail.com> 1275475865 +0200 commit (amend): commit: refactored existing code to decode commits from streams - performance is slightly better
+8c1a87d11df666d308d14e4ae7ee0e9d614296b6 6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e Sebastian Thiel <byronimo@gmail.com> 1275475911 +0200 checkout: moving from odb to master
+6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e 8c1a87d11df666d308d14e4ae7ee0e9d614296b6 Sebastian Thiel <byronimo@gmail.com> 1275475929 +0200 checkout: moving from master to odb
+8c1a87d11df666d308d14e4ae7ee0e9d614296b6 8c1a87d11df666d308d14e4ae7ee0e9d614296b6 Sebastian Thiel <byronimo@gmail.com> 1275476474 +0200 checkout: moving from odb to perftest
+8c1a87d11df666d308d14e4ae7ee0e9d614296b6 4a25347d7f4c371345da2348ac6cceec7a143da2 Sebastian Thiel <byronimo@gmail.com> 1275476487 +0200 commit: Added commit-iteration test
+4a25347d7f4c371345da2348ac6cceec7a143da2 4e1c89ec97ec90037583e85d0e9e71e9c845a19b Sebastian Thiel <byronimo@gmail.com> 1275488012 +0200 commit: Added performance testing foundation library, reworked existing performance tests to work on larger repositories
+4e1c89ec97ec90037583e85d0e9e71e9c845a19b ae5a69f67822d81bbbd8f4af93be68703e730b37 Sebastian Thiel <byronimo@gmail.com> 1275489688 +0200 commit: commit: redesigned revlist and commit parsing, commits are always retrieved from their object information directly. This is faster, and resolves issues with the rev-list format and empty commit messages
+ae5a69f67822d81bbbd8f4af93be68703e730b37 02004a7ea4d26dc45f194d3a34780a50634ef497 Sebastian Thiel <byronimo@gmail.com> 1275493157 +0200 commit: git.cmd: added test for stream section constraint used in git command, found bug of course which just didn't kick in yet
+02004a7ea4d26dc45f194d3a34780a50634ef497 ae5a69f67822d81bbbd8f4af93be68703e730b37 Sebastian Thiel <byronimo@gmail.com> 1275493169 +0200 HEAD~1: updating HEAD
+ae5a69f67822d81bbbd8f4af93be68703e730b37 538820055ce1bf9dd07ecda48210832f96194504 Sebastian Thiel <byronimo@gmail.com> 1275493189 +0200 commit: git.cmd: added test for stream section constraint used in git command, found bug of course which just didn't kick in yet
+538820055ce1bf9dd07ecda48210832f96194504 282018b79cc8df078381097cb3aeb29ff56e83c6 Sebastian Thiel <byronimo@gmail.com> 1275502260 +0200 commit: Added first design and frame for object database. In a first step, loose objects will be written using our utilities, and certain object retrieval functionality moves into the GitObjectDatabase which is used by the repo instance
+282018b79cc8df078381097cb3aeb29ff56e83c6 8c1a87d11df666d308d14e4ae7ee0e9d614296b6 Sebastian Thiel <byronimo@gmail.com> 1275502285 +0200 checkout: moving from perftest to odb
+8c1a87d11df666d308d14e4ae7ee0e9d614296b6 282018b79cc8df078381097cb3aeb29ff56e83c6 Sebastian Thiel <byronimo@gmail.com> 1275502288 +0200 merge perftest: Fast-forward
+282018b79cc8df078381097cb3aeb29ff56e83c6 8b86f9b399a8f5af792a04025fdeefc02883f3e5 Sebastian Thiel <byronimo@gmail.com> 1275511252 +0200 commit: initial version of loose object writing and simple cached object lookup appears to be working
+8b86f9b399a8f5af792a04025fdeefc02883f3e5 6f8ce8901e21587cd2320562df412e05b5ab1731 Sebastian Thiel <byronimo@gmail.com> 1275515609 +0200 commit: added frame for object reading, including simple test
+6f8ce8901e21587cd2320562df412e05b5ab1731 6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e Sebastian Thiel <byronimo@gmail.com> 1275549198 +0200 checkout: moving from odb to master
+6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e e79999c956e2260c37449139080d351db4aa3627 Sebastian Thiel <byronimo@gmail.com> 1275549608 +0200 commit: git.cmd: moved hardcoded chunksize when duplicating stream data into easy-to-change class member variable
+e79999c956e2260c37449139080d351db4aa3627 6f8ce8901e21587cd2320562df412e05b5ab1731 Sebastian Thiel <byronimo@gmail.com> 1275549707 +0200 checkout: moving from master to odb
+6f8ce8901e21587cd2320562df412e05b5ab1731 e79999c956e2260c37449139080d351db4aa3627 Sebastian Thiel <byronimo@gmail.com> 1275550120 +0200 checkout: moving from odb to master
+e79999c956e2260c37449139080d351db4aa3627 412632599479a8e5991a07ecb67bc52b85c60755 Sebastian Thiel <byronimo@gmail.com> 1275550524 +0200 commit: git.cmd: using communicate in the main branch of execution, which might not make a big difference, but perhaps its smarter about broken pipes.
+412632599479a8e5991a07ecb67bc52b85c60755 25dca42bac17d511b7e2ebdd9d1d679e7626db5f Sebastian Thiel <byronimo@gmail.com> 1275550670 +0200 commit (amend): git.cmd: using communicate in the main branch of execution, which might not make a big difference, but perhaps its smarter about broken pipes.
+25dca42bac17d511b7e2ebdd9d1d679e7626db5f 6f8ce8901e21587cd2320562df412e05b5ab1731 Sebastian Thiel <byronimo@gmail.com> 1275551315 +0200 checkout: moving from master to odb
+6f8ce8901e21587cd2320562df412e05b5ab1731 38d59fc8ccccae8882fa48671377bf40a27915a7 Sebastian Thiel <byronimo@gmail.com> 1275575735 +0200 commit: odb: implemented loose object streaming, which is impossible to do efficiently considering that it copies string buffers all the time
+38d59fc8ccccae8882fa48671377bf40a27915a7 26e138cb47dccc859ff219f108ce9b7d96cbcbcd Sebastian Thiel <byronimo@gmail.com> 1275582065 +0200 commit: odb: fixed streamed decompression reader ( specific tests would still be missing ) and added performance tests which are extremely promising
+26e138cb47dccc859ff219f108ce9b7d96cbcbcd 4295787b65d4a85ac1e0e20741aa59ec19a97353 Sebastian Thiel <byronimo@gmail.com> 1275584658 +0200 commit: Added performance comparison to cgit ... and yes, git-python is faster :)
+4295787b65d4a85ac1e0e20741aa59ec19a97353 4b4a514e51fbc7dc6ddcb27c188159d57b5d1fa9 Sebastian Thiel <byronimo@gmail.com> 1275590443 +0200 commit (amend): Added performance comparison to cgit ... and yes, git-python is faster :)
+4b4a514e51fbc7dc6ddcb27c188159d57b5d1fa9 1e2b46138ba58033738a24dadccc265748fce2ca Sebastian Thiel <byronimo@gmail.com> 1275600034 +0200 commit: commit.create_from_tree now uses pure python implementation, fixed message parsing which truncated newlines although it was ilegitimate. Its up to the reader to truncate therse, nowhere in the git code I could find anyone adding newlines to commits where it is written
+1e2b46138ba58033738a24dadccc265748fce2ca 1906ee4df9ae4e734288c5203cf79894dff76cab Sebastian Thiel <byronimo@gmail.com> 1275600429 +0200 commit: Fixed compatability issues with python 2.5, made sure all tests run
+1906ee4df9ae4e734288c5203cf79894dff76cab b01ca6a3e4ae9d944d799743c8ff774e2a7a82b6 Sebastian Thiel <byronimo@gmail.com> 1275602940 +0200 commit: db: implemented GitObjectDB using the git command to make sure we can lookup everything. Next is to implement pack-file reading, then alternates which should allow to resolve everything
+b01ca6a3e4ae9d944d799743c8ff774e2a7a82b6 b01ca6a3e4ae9d944d799743c8ff774e2a7a82b6 Sebastian Thiel <byronimo@gmail.com> 1275643039 +0200 checkout: moving from odb to asyncredesign
+b01ca6a3e4ae9d944d799743c8ff774e2a7a82b6 a1e80445ad5cb6da4c0070d7cb8af89da3b0803b Sebastian Thiel <byronimo@gmail.com> 1275655275 +0200 commit: initial version of new odb design to facilitate a channel based multi-threading implementation of all odb functions
+a1e80445ad5cb6da4c0070d7cb8af89da3b0803b e746f96bcc29238b79118123028ca170adc4ff0f Sebastian Thiel <byronimo@gmail.com> 1275664928 +0200 commit: Fixed implementation after design change to deal with it - all tests run, but next there will have to be more through testing
+e746f96bcc29238b79118123028ca170adc4ff0f b01ca6a3e4ae9d944d799743c8ff774e2a7a82b6 Sebastian Thiel <byronimo@gmail.com> 1275664939 +0200 checkout: moving from asyncredesign to odb
+b01ca6a3e4ae9d944d799743c8ff774e2a7a82b6 e746f96bcc29238b79118123028ca170adc4ff0f Sebastian Thiel <byronimo@gmail.com> 1275664943 +0200 merge asyncredesign: Fast-forward
+e746f96bcc29238b79118123028ca170adc4ff0f 25dca42bac17d511b7e2ebdd9d1d679e7626db5f Sebastian Thiel <byronimo@gmail.com> 1275664990 +0200 checkout: moving from odb to master
+25dca42bac17d511b7e2ebdd9d1d679e7626db5f 6fbb69306c0e14bacb8dcb92a89af27d3d5d631f Sebastian Thiel <byronimo@gmail.com> 1275665431 +0200 commit (merge): Merge branch 'odb'
+6fbb69306c0e14bacb8dcb92a89af27d3d5d631f a243827ab3346e188e99db2f9fc1f916941c9b1a Sebastian Thiel <byronimo@gmail.com> 1275685591 +0200 commit: Implemented stream tests, found a bug on the way, slowly a test-framework for streams starts to show up, but its not yet there
+a243827ab3346e188e99db2f9fc1f916941c9b1a 7c1169f6ea406fec1e26e99821e18e66437e65eb Sebastian Thiel <byronimo@gmail.com> 1275690001 +0200 commit: Removed compression flag from IStream and OStream types, as a valid object will always be compressed if generated by the system ( even future memory db's will compress it )
+7c1169f6ea406fec1e26e99821e18e66437e65eb c69b6b979e3d6bd01ec40e75b92b21f7a391f0ca Sebastian Thiel <byronimo@gmail.com> 1275746174 +0200 commit: Added basic channel implementation including test
+c69b6b979e3d6bd01ec40e75b92b21f7a391f0ca c69b6b979e3d6bd01ec40e75b92b21f7a391f0ca Sebastian Thiel <byronimo@gmail.com> 1275746191 +0200 checkout: moving from master to async
+c69b6b979e3d6bd01ec40e75b92b21f7a391f0ca c69b6b979e3d6bd01ec40e75b92b21f7a391f0ca Sebastian Thiel <byronimo@gmail.com> 1275746194 +0200 checkout: moving from async to master
+c69b6b979e3d6bd01ec40e75b92b21f7a391f0ca 7c1169f6ea406fec1e26e99821e18e66437e65eb Sebastian Thiel <byronimo@gmail.com> 1275746196 +0200 HEAD~1: updating HEAD
+7c1169f6ea406fec1e26e99821e18e66437e65eb c69b6b979e3d6bd01ec40e75b92b21f7a391f0ca Sebastian Thiel <byronimo@gmail.com> 1275746213 +0200 checkout: moving from master to async
+c69b6b979e3d6bd01ec40e75b92b21f7a391f0ca 65c9fe0baa579173afa5a2d463ac198d06ef4993 Sebastian Thiel <byronimo@gmail.com> 1275746839 +0200 commit: A code donation: Donating a worker thread implementation inclduding tests to Git-Python. I have the feeling it can do much good here :)
+65c9fe0baa579173afa5a2d463ac198d06ef4993 50e469109eed3a752d9a1b0297f16466ad92f8d2 Sebastian Thiel <byronimo@gmail.com> 1275755186 +0200 commit: Initial pool design added, allowing for lazy channel based evaluation of inter-dependent tasks
+50e469109eed3a752d9a1b0297f16466ad92f8d2 61138f2ece0cb864b933698174315c34a78835d1 Sebastian Thiel <byronimo@gmail.com> 1275760757 +0200 commit: Moved multiprocessing modules into own package, as they in fact have nothing to do with the object db. If that really works the way I want, it will become an own project, called async
+61138f2ece0cb864b933698174315c34a78835d1 ab59f78341f1dd188aaf4c30526f6295c63438b1 Sebastian Thiel <byronimo@gmail.com> 1275760989 +0200 commit: Renamed mp to async, as this is a much better name for what is actually going on. The default implementation uses threads, which ends up being nothing more than async, as they are all locked down by internal and the global interpreter lock
+ab59f78341f1dd188aaf4c30526f6295c63438b1 b72e2704022d889f116e49abf3e1e5d3e3192d3b Sebastian Thiel <byronimo@gmail.com> 1275778812 +0200 commit: Improved pool design and started rough implementation, top down to learn while going. Tests will be written soon for verification, its still quite theoretical
+b72e2704022d889f116e49abf3e1e5d3e3192d3b ec28ad575ce1d7bb6a616ffc404f32bbb1af67b2 Sebastian Thiel <byronimo@gmail.com> 1275821305 +0200 commit: thread: adjusted worker thread not to provide an output queue anymore - this is handled by the task system
+ec28ad575ce1d7bb6a616ffc404f32bbb1af67b2 b3cde0ee162b8f0cb67da981311c8f9c16050a62 Sebastian Thiel <byronimo@gmail.com> 1275840801 +0200 commit: First step of testing the pool - tasks have been separated into a new module including own tests, their design improved to prepare them for some specifics that would be needed for multiprocessing support
+b3cde0ee162b8f0cb67da981311c8f9c16050a62 8d74950510bbd74aa06afe4ec4c19e4739462d6a Sebastian Thiel <byronimo@gmail.com> 1275851713 +0200 commit: Plenty of fixes in the chunking routine, made possible by a serialized chunking test. Next up, actual async processing
+8d74950510bbd74aa06afe4ec4c19e4739462d6a 1b27292936c81637f6b9a7141dafaad1126f268e Sebastian Thiel <byronimo@gmail.com> 1275852711 +0200 commit (amend): Plenty of fixes in the chunking routine, made possible by a serialized chunking test. Next up, actual async processing
+1b27292936c81637f6b9a7141dafaad1126f268e 867129e2950458ab75523b920a5e227e3efa8bbc Sebastian Thiel <byronimo@gmail.com> 1275858486 +0200 commit: channel.read: enhanced to be sure we don't run into non-atomicity issues related to our channel closed flag, which is the only way not to block forever on read(0) channels which were closed by a thread 'in the meanwhile'
+867129e2950458ab75523b920a5e227e3efa8bbc 6335fe0abcedc99145dd1400509b7540568ac2cc Sebastian Thiel <byronimo@gmail.com> 1275860480 +0200 commit: pool: First version which works as expected in async mode. The task model is very simple still, but its getting there
+6335fe0abcedc99145dd1400509b7540568ac2cc 320c5329995cc8d364a88ba83103e1db584410ce Sebastian Thiel <byronimo@gmail.com> 1275860784 +0200 commit (amend): pool: First version which works as expected in async mode. The task model is very simple still, but its getting there
+320c5329995cc8d364a88ba83103e1db584410ce d759d0b97aaf5fd60a1df0ea0f60e67863a6c3d7 Sebastian Thiel <byronimo@gmail.com> 1275861899 +0200 commit (amend): pool: First version which works as expected in async mode. The task model is very simple still, but its getting there
+d759d0b97aaf5fd60a1df0ea0f60e67863a6c3d7 6a252661c3bf4202a4d571f9c41d2afa48d9d75f Sebastian Thiel <byronimo@gmail.com> 1275861909 +0200 commit (amend): pool: First version which works as expected in async mode. Its just using a single task for now, but next up are dependent tasks
+6a252661c3bf4202a4d571f9c41d2afa48d9d75f a8a448b7864e21db46184eab0f0a21d7725d074f Sebastian Thiel <byronimo@gmail.com> 1275899902 +0200 commit: pool.consumed_tasks: is now a queue to be thread safe, in preparation for multiple connected pools
+a8a448b7864e21db46184eab0f0a21d7725d074f 856af48fbffaf1b935d513429afeb319e4795d2d Sebastian Thiel <byronimo@gmail.com> 1275905456 +0200 commit: changed scheduling and chunksize calculation in respect to the task.min_count. Previously, it would possibly not produce enough items in case T1 wants to produce less items than t2 needs ... in fact, it would work even then, committing this anyway
+856af48fbffaf1b935d513429afeb319e4795d2d 619662a9138fd78df02c52cae6dc89db1d70a0e5 Sebastian Thiel <byronimo@gmail.com> 1275905984 +0200 commit (amend): changed scheduling and chunksize calculation in respect to the task.min_count, to fix theoretical option for a deadlock in serial mode, and unnecessary blocking in async mode
+619662a9138fd78df02c52cae6dc89db1d70a0e5 8c3c271b0d6b5f56b86e3f177caf3e916b509b52 Sebastian Thiel <byronimo@gmail.com> 1275908735 +0200 commit: Added task order cache, and a lock to prevent us walking the graph while changing tasks
+8c3c271b0d6b5f56b86e3f177caf3e916b509b52 edd9e23c766cfd51b3a6f6eee5aac0b791ef2fd0 Sebastian Thiel <byronimo@gmail.com> 1275923808 +0200 commit: added high-speed locking facilities, allowing our Queue to be faster, at least in tests, and with multiple threads. There is still an sync bug in regard to closed channels to be fixed, as the Task.set_done handling is incorrecft
+edd9e23c766cfd51b3a6f6eee5aac0b791ef2fd0 583cd8807259a69fc01874b798f657c1f9ab7828 Sebastian Thiel <byronimo@gmail.com> 1275930764 +0200 commit: Moved pool utilities into util module, fixed critical issue that caused havok - lets call this a safe-state
+583cd8807259a69fc01874b798f657c1f9ab7828 654e54d200135e665e07e9f0097d913a77f169da Sebastian Thiel <byronimo@gmail.com> 1275933662 +0200 commit: task: Fixed incorrect handling of channel closure. Performance is alright for up to 2 threads, but 4 are killing the queue
+654e54d200135e665e07e9f0097d913a77f169da be06e87433685b5ea9cfcc131ab89c56cf8292f2 Sebastian Thiel <byronimo@gmail.com> 1275940847 +0200 commit: improved testing to test the actual async handling of the pool. there are still inconsistencies that need to be fixed, but it already improved, especially the 4-thread performance which now is as fast as the dual-threaded performance
+be06e87433685b5ea9cfcc131ab89c56cf8292f2 be06e87433685b5ea9cfcc131ab89c56cf8292f2 Sebastian Thiel <byronimo@gmail.com> 1275945495 +0200 checkout: moving from async to stasks
+be06e87433685b5ea9cfcc131ab89c56cf8292f2 223701e19722afb0f57fc0de6e366ade542efdc0 Sebastian Thiel <byronimo@gmail.com> 1275945637 +0200 commit: introduced a new counter keeping track of the scheduled tasks - this prevent unnecessary tasks to be scheduled as we keep track of how many items will be produced for the task at hand. This introduces additional locking, but performns well in multithreaded mode. Performance of the master queue is still a huge issue, its currently the limiting factor, as bypassing the master queue in serial moode gives 15x performance, wich is what I would need
+223701e19722afb0f57fc0de6e366ade542efdc0 def0f73989047c4ddf9b11da05ad2c9c8e387331 Sebastian Thiel <byronimo@gmail.com> 1275946081 +0200 commit (amend): introduced a new counter keeping track of the scheduled tasks - this prevent unnecessary tasks to be scheduled as we keep track of how many items will be produced for the task at hand. This introduces additional locking, but performns well in multithreaded mode. Performance of the master queue is still a huge issue, its currently the limiting factor, as bypassing the master queue in serial moode gives 15x performance, wich is what I would need
+def0f73989047c4ddf9b11da05ad2c9c8e387331 be06e87433685b5ea9cfcc131ab89c56cf8292f2 Sebastian Thiel <byronimo@gmail.com> 1275946086 +0200 checkout: moving from stasks to async
+be06e87433685b5ea9cfcc131ab89c56cf8292f2 be06e87433685b5ea9cfcc131ab89c56cf8292f2 Sebastian Thiel <byronimo@gmail.com> 1275946311 +0200 checkout: moving from async to brute
+be06e87433685b5ea9cfcc131ab89c56cf8292f2 293fa4de92c789d67de6a663d7b14a6897b14181 Sebastian Thiel <byronimo@gmail.com> 1275946483 +0200 commit: Removed qsize dependency when reading , now it puts onto the queue everytime someone reads. This does not appear very stable for now as one can, for some reason, deplete the channel, which can only happen if its closed before all tasks finish, which should already be fixed
+293fa4de92c789d67de6a663d7b14a6897b14181 def0f73989047c4ddf9b11da05ad2c9c8e387331 Sebastian Thiel <byronimo@gmail.com> 1275946494 +0200 checkout: moving from brute to stasks
+def0f73989047c4ddf9b11da05ad2c9c8e387331 e825f8b69760e269218b1bf1991018baf3c16b04 Sebastian Thiel <byronimo@gmail.com> 1275946688 +0200 commit: Channel now uses the AsyncQueue, boosting performance by factor 4, its a start
+e825f8b69760e269218b1bf1991018baf3c16b04 898d47d1711accdfded8ee470520fdb96fb12d46 Sebastian Thiel <byronimo@gmail.com> 1275947226 +0200 commit: Task scheduled items lock now uses a dummy lock in serial mode, improving its performance considerably.
+898d47d1711accdfded8ee470520fdb96fb12d46 be06e87433685b5ea9cfcc131ab89c56cf8292f2 Sebastian Thiel <byronimo@gmail.com> 1275947355 +0200 checkout: moving from stasks to async
+be06e87433685b5ea9cfcc131ab89c56cf8292f2 3e2ba9c2028f21d11988558f3557905d21e93808 Sebastian Thiel <byronimo@gmail.com> 1275947360 +0200 merge stasks: Merge made by recursive.
+3e2ba9c2028f21d11988558f3557905d21e93808 7c1169f6ea406fec1e26e99821e18e66437e65eb Sebastian Thiel <byronimo@gmail.com> 1275948503 +0200 checkout: moving from async to master
+7c1169f6ea406fec1e26e99821e18e66437e65eb 3e2ba9c2028f21d11988558f3557905d21e93808 Sebastian Thiel <byronimo@gmail.com> 1275948509 +0200 checkout: moving from master to async
+3e2ba9c2028f21d11988558f3557905d21e93808 3e2ba9c2028f21d11988558f3557905d21e93808 Sebastian Thiel <byronimo@gmail.com> 1275948864 +0200 checkout: moving from async to queue
+3e2ba9c2028f21d11988558f3557905d21e93808 5d996892ac76199886ba3e2754ff9c9fac2456d6 Sebastian Thiel <byronimo@gmail.com> 1275949953 +0200 commit: test implementation of async-queue with everything stripped from it that didn't seem necessary - its a failure, something is wrong - performance not much better than the original one, its depending on the condition performance actually, which I don't get faster
+5d996892ac76199886ba3e2754ff9c9fac2456d6 3e2ba9c2028f21d11988558f3557905d21e93808 Sebastian Thiel <byronimo@gmail.com> 1275949960 +0200 checkout: moving from queue to async
+3e2ba9c2028f21d11988558f3557905d21e93808 5d996892ac76199886ba3e2754ff9c9fac2456d6 Sebastian Thiel <byronimo@gmail.com> 1275979377 +0200 checkout: moving from async to queue
+5d996892ac76199886ba3e2754ff9c9fac2456d6 3e2ba9c2028f21d11988558f3557905d21e93808 Sebastian Thiel <byronimo@gmail.com> 1275979426 +0200 checkout: moving from queue to async
+3e2ba9c2028f21d11988558f3557905d21e93808 5d996892ac76199886ba3e2754ff9c9fac2456d6 Sebastian Thiel <byronimo@gmail.com> 1275979446 +0200 checkout: moving from async to queue
+5d996892ac76199886ba3e2754ff9c9fac2456d6 f32ef32960ae8aa8a20c00cd3f7e78b441ee664b Sebastian Thiel <byronimo@gmail.com> 1275986714 +0200 commit: both versions of the async queue still have trouble in certain situations, at least with my totally overwritten version of the condition - the previous one was somewhat more stable it seems
+f32ef32960ae8aa8a20c00cd3f7e78b441ee664b 09c3f39ceb545e1198ad7a3f470d4ec896ce1add Sebastian Thiel <byronimo@gmail.com> 1275986721 +0200 commit (amend): both versions of the async queue still have trouble in certain situations, at least with my totally overwritten version of the condition - the previous one was somewhat more stable it seems. Nonetheless, this is the fastest version so far
+09c3f39ceb545e1198ad7a3f470d4ec896ce1add 3776f7a766851058f6435b9f606b16766425d7ca Sebastian Thiel <byronimo@gmail.com> 1275996284 +0200 commit: The new channeldesign actually works, but it also shows that its located at the wrong spot. The channel is nothing more than an adapter allowing to read multiple items from a thread-safe queue, the queue itself though must be 'closable' for writing, or needs something like a writable flag.
+3776f7a766851058f6435b9f606b16766425d7ca 53152a824f5186452504f0b68306d10ebebee416 Sebastian Thiel <byronimo@gmail.com> 1275999838 +0200 commit: queue: adjusted queue to be closable ( without own testing yet, except for the pool which runs it ) - its not yet stable, but should be solvable.
+53152a824f5186452504f0b68306d10ebebee416 619c11787742ce00a0ee8f841cec075897873c79 Sebastian Thiel <byronimo@gmail.com> 1276008468 +0200 commit: Its getting better already - intermediate commit before further chaning the task class
+619c11787742ce00a0ee8f841cec075897873c79 13dd59ba5b3228820841682b59bad6c22476ff66 Sebastian Thiel <byronimo@gmail.com> 1276010743 +0200 commit: task: now deletes itself once its done - for the test this doesn't change a thing as the task deletes itself too late - its time for a paradigm change, the task should be deleted with its RPoolChannel or explicitly by the user. The test needs to adapt, and shouldn't assume anything unless the RPoolChannel is gone
+13dd59ba5b3228820841682b59bad6c22476ff66 e5c0002d069382db1768349bf0c5ff40aafbf140 Sebastian Thiel <byronimo@gmail.com> 1276014012 +0200 commit: Revised task deletion works well, adjusted test to be creating new tasks all the time instead of reusing its own one, it was somewhat hard to manage its state over time and could cause bugs. It works okay, but it occasionally hangs, it appears to be an empty queue, have to gradually put certain things back in, although in the current mode of operation, it should never have empty queues from the pool to the user
+e5c0002d069382db1768349bf0c5ff40aafbf140 772b95631916223e472989b43f3a31f61e237f31 Sebastian Thiel <byronimo@gmail.com> 1276017933 +0200 commit: workerthread: adjusted to use a blocking queue, it will receive termination events only with its queue, with boosts performance into brigt green levels
+772b95631916223e472989b43f3a31f61e237f31 3e2ba9c2028f21d11988558f3557905d21e93808 Sebastian Thiel <byronimo@gmail.com> 1276017957 +0200 checkout: moving from queue to async
+3e2ba9c2028f21d11988558f3557905d21e93808 f78d4a28f307a9d7943a06be9f919304c25ac2d9 Sebastian Thiel <byronimo@gmail.com> 1276017963 +0200 merge queue: Merge made by recursive.
+f78d4a28f307a9d7943a06be9f919304c25ac2d9 15941ca090a2c3c987324fc911bbc6f89e941c47 Sebastian Thiel <byronimo@gmail.com> 1276072452 +0200 commit: queue: fixed critical bug in the notify method, as it was not at all thread-safe, causing locks to be released multiple times. Now it runs very fast, and very stable apparently.
+15941ca090a2c3c987324fc911bbc6f89e941c47 f2c8d26d3b25b864ad48e6de018757266b59f708 Sebastian Thiel <byronimo@gmail.com> 1276075717 +0200 commit: thread: fixed initialization problem if an empty iterable was handed in
+f2c8d26d3b25b864ad48e6de018757266b59f708 2054561da184955c4be4a92f0b4fa5c5c1c01350 Sebastian Thiel <byronimo@gmail.com> 1276075884 +0200 commit: HSCondition: using a deck to store waiters, for further speedup
+2054561da184955c4be4a92f0b4fa5c5c1c01350 1090701721888474d34f8a4af28ee1bb1c3fdaaa Sebastian Thiel <byronimo@gmail.com> 1276076141 +0200 commit: HSCondition: now deriving from deque, as the AsyncQeue does, to elimitate one more level of indirection. Clearly this not good from a design standpoint, as a Condition is no Deque, but it helps speeding things up which is what this is about. Could make it a hidden class to indicate how 'special' it is
+1090701721888474d34f8a4af28ee1bb1c3fdaaa a988e6985849e4f6a561b4a5468d525c25ce74fe Sebastian Thiel <byronimo@gmail.com> 1276076725 +0200 commit: HSCondition: now gets a lock even in the single-notify case, as it was required due to the non-atomiciy of the invovled operation. Removed one level of indirection for the lock, by refraining from calling my own 'wrapper' methods, which brought it back to the performance it had before the locking was introduced for the n==1 case
+a988e6985849e4f6a561b4a5468d525c25ce74fe 4e6bece08aea01859a232e99a1e1ad8cc1eb7d36 Sebastian Thiel <byronimo@gmail.com> 1276084911 +0200 commit: HSCondition: Fixed terrible bug which it inherited from its default python Condition implementation, related to the notify method not being treadsafe. Although I was aware of it, I missed the first check which tests for the size - the result could be incorrect if the whole method wasn't locked.
+4e6bece08aea01859a232e99a1e1ad8cc1eb7d36 ffb5b95cb2cec5c5a79234dfc47c3fcf1f724101 Sebastian Thiel <byronimo@gmail.com> 1276087661 +0200 commit: Channel: Read method revised - now it really really doesn't block anymore, and it runs faster as well, about 2/3 of the performance we have when being in serial mode
+ffb5b95cb2cec5c5a79234dfc47c3fcf1f724101 0974f8737a3c56a7c076f9d0b757c6cb106324fb Sebastian Thiel <byronimo@gmail.com> 1276087839 +0200 commit (amend): Channel: Read method revised - now it really really doesn't block anymore, and it runs faster as well, about 2/3 of the performance we have when being in serial mode
+0974f8737a3c56a7c076f9d0b757c6cb106324fb 57a4e09294230a36cc874a6272c71757c48139f2 Sebastian Thiel <byronimo@gmail.com> 1276090187 +0200 commit: Channel: removed pseudoconstructor, which clearly improves the design and makes it easier to constomize
+57a4e09294230a36cc874a6272c71757c48139f2 07996a1a1e53ffdd2680d4bfbc2f4059687859a5 Sebastian Thiel <byronimo@gmail.com> 1276090851 +0200 commit: task: removed scheduled task support, which at some point was introduced to improve performance, but which now hinders performance, besides being unnecessary ;)
+07996a1a1e53ffdd2680d4bfbc2f4059687859a5 ea81f14dafbfb24d70373c74b5f8dabf3f2225d9 Sebastian Thiel <byronimo@gmail.com> 1276094301 +0200 commit: Channel: Callbacks reviewed - they are now part of Subclasses of the default channel implementation, one of which is used as base by the Pool Read channel, releasing it of the duty to call these itself. The write channel with callback subclass allows the transformation of the item to be written
+ea81f14dafbfb24d70373c74b5f8dabf3f2225d9 365fb14ced88a5571d3287ff1698582ceacd80d6 Sebastian Thiel <byronimo@gmail.com> 1276095557 +0200 commit: task: redesigned write channel access to allow the task creator to set own write channels, possibly some with callbacks installed etc.. Pool.add_task will respect the users choice now, but provide defaults which are optimized for performance
+365fb14ced88a5571d3287ff1698582ceacd80d6 257a8a9441fca9a9bc384f673ba86ef5c3f1715d Sebastian Thiel <byronimo@gmail.com> 1276111194 +0200 commit: test: prepared task dependency test, which already helped to find bug in the reference counting mechanism, causing references to the pool to be kepts via cycles
+257a8a9441fca9a9bc384f673ba86ef5c3f1715d 3323464f85b986cba23176271da92a478b33ab9c Sebastian Thiel <byronimo@gmail.com> 1276122289 +0200 commit: messy first version of a properly working depth-first graph method, which allows the pool to work as expected. Many more tests need to be added, and there still is a problem with shutdown as sometimes it won't kill all threads, mainly because the process came up with worker threads started, which cannot be
+3323464f85b986cba23176271da92a478b33ab9c 3323464f85b986cba23176271da92a478b33ab9c Sebastian Thiel <byronimo@gmail.com> 1276122375 +0200 checkout: moving from async to async
+3323464f85b986cba23176271da92a478b33ab9c 257a8a9441fca9a9bc384f673ba86ef5c3f1715d Sebastian Thiel <byronimo@gmail.com> 1276122387 +0200 HEAD~1: updating HEAD
+257a8a9441fca9a9bc384f673ba86ef5c3f1715d 3323464f85b986cba23176271da92a478b33ab9c Sebastian Thiel <byronimo@gmail.com> 1276122419 +0200 checkout: moving from async to taskdep
+3323464f85b986cba23176271da92a478b33ab9c cfb278d74ad01f3f1edf5e0ad113974a9555038d Sebastian Thiel <byronimo@gmail.com> 1276157672 +0200 commit: InputChannelTask now has interface for properly handling the reading from the same and different pools
+cfb278d74ad01f3f1edf5e0ad113974a9555038d 01eac1a959c1fa5894a86bf11e6b92f96762bdd8 Sebastian Thiel <byronimo@gmail.com> 1276164376 +0200 commit: Added more dependency task tests, especially the single-reads are not yet fully deterministic as tasks still run into the problem that they try to write into a closed channel, it was closed by one of their task-mates who didn't know someone else was still computing
+01eac1a959c1fa5894a86bf11e6b92f96762bdd8 01eac1a959c1fa5894a86bf11e6b92f96762bdd8 Sebastian Thiel <byronimo@gmail.com> 1276166920 +0200 checkout: moving from taskdep to channel
+01eac1a959c1fa5894a86bf11e6b92f96762bdd8 01eac1a959c1fa5894a86bf11e6b92f96762bdd8 Sebastian Thiel <byronimo@gmail.com> 1276167802 +0200 checkout: moving from channel to taskdep
+01eac1a959c1fa5894a86bf11e6b92f96762bdd8 01eac1a959c1fa5894a86bf11e6b92f96762bdd8 Sebastian Thiel <byronimo@gmail.com> 1276169390 +0200 checkout: moving from taskdep to channel
+01eac1a959c1fa5894a86bf11e6b92f96762bdd8 55e757928e493ce93056822d510482e4ffcaac2d Sebastian Thiel <byronimo@gmail.com> 1276173597 +0200 commit: channel: Changed design to be more logical - a channel now has any amount of readers and writers, a ready is not connected to its writer anymore. This changes the refcounting of course, which is why the auto-cleanup for the pool is currently broken.
+55e757928e493ce93056822d510482e4ffcaac2d 7c36f3648e39ace752c67c71867693ce1eee52a3 Sebastian Thiel <byronimo@gmail.com> 1276177120 +0200 commit: Now tracking the amount of concurrent writers to assure the channel is closed only when there is no one else writing to it. This assures that all tasks can continue working, and put their results accordingly. Shutdown is still not working correctly, but that should be solvable as well. Its still not perfect though ...
+7c36f3648e39ace752c67c71867693ce1eee52a3 c34343d0b714d2c4657972020afea034a167a682 Sebastian Thiel <byronimo@gmail.com> 1276177952 +0200 commit: tasks can now terminate faster when no items were read, without neglecting their duty to close the channel if required. Code is a little less maintainable now, but faster, it appears
+c34343d0b714d2c4657972020afea034a167a682 4c2fa54d8122e9e5bc20a938ff8ccc5caf96dafe Sebastian Thiel <byronimo@gmail.com> 1276206673 +0200 commit: tasks can now terminate faster when no items were read, without neglecting their duty to close the channel if required. Code is a little less maintainable now, but faster, it appearsgst
+4c2fa54d8122e9e5bc20a938ff8ccc5caf96dafe c34343d0b714d2c4657972020afea034a167a682 Sebastian Thiel <byronimo@gmail.com> 1276206682 +0200 HEAD~1: updating HEAD
+c34343d0b714d2c4657972020afea034a167a682 fbe062bf6dacd3ad63dd827d898337fa542931ac Sebastian Thiel <byronimo@gmail.com> 1276206950 +0200 commit: Added dependency-task tests, and fixed plenty of ref-count related bugs, as well as concurrency issues. Now it works okay, but the thread-shutdown is still an issue, as it causes incorrect behaviour making the tests fail. Its good, as it hints at additional issues that need to be solved. There is just a little more left on the feature side, but its nearly there
+fbe062bf6dacd3ad63dd827d898337fa542931ac 6d1212e8c412b0b4802bc1080d38d54907db879d Sebastian Thiel <byronimo@gmail.com> 1276249921 +0200 commit: IMPORTANT: sometimes, when notifying waiters by releasing their lock, the lock is not actually released or they are not actually notifyied, staying in a beautysleep. This glitch is probably caused by some detail not treated correctly in the thread python module, which is something we cannot fix. It works most of the time as expected though - maybe some cleanup is not done correctly which causes this
+6d1212e8c412b0b4802bc1080d38d54907db879d 01eac1a959c1fa5894a86bf11e6b92f96762bdd8 Sebastian Thiel <byronimo@gmail.com> 1276249936 +0200 checkout: moving from channel to taskdep
+01eac1a959c1fa5894a86bf11e6b92f96762bdd8 18b14ade522c71000a69ff80569eda7335d6f64c Sebastian Thiel <byronimo@gmail.com> 1276249944 +0200 merge channel: Merge made by recursive.
+18b14ade522c71000a69ff80569eda7335d6f64c 583e6a25b0d891a2f531a81029f2bac0c237cbf9 Sebastian Thiel <byronimo@gmail.com> 1276258825 +0200 commit (amend): Merge branch 'channel' into taskdep
+583e6a25b0d891a2f531a81029f2bac0c237cbf9 5ff864138cd1e680a78522c26b583639f8f5e313 Sebastian Thiel <byronimo@gmail.com> 1276259871 +0200 commit: test.async: split test_pool up into task implenetations and related utilities, as well as the tests themselves. File became too large
+5ff864138cd1e680a78522c26b583639f8f5e313 18e3252a1f655f09093a4cffd5125342a8f94f3b Sebastian Thiel <byronimo@gmail.com> 1276261131 +0200 commit: Finished dependent task testing according to the features we would currently like to see
+18e3252a1f655f09093a4cffd5125342a8f94f3b 257a8a9441fca9a9bc384f673ba86ef5c3f1715d Sebastian Thiel <byronimo@gmail.com> 1276261137 +0200 checkout: moving from taskdep to async
+257a8a9441fca9a9bc384f673ba86ef5c3f1715d f606937a7a21237c866efafcad33675e6539c103 Sebastian Thiel <byronimo@gmail.com> 1276261142 +0200 merge taskdep: Merge made by recursive.
+f606937a7a21237c866efafcad33675e6539c103 f606937a7a21237c866efafcad33675e6539c103 Sebastian Thiel <byronimo@gmail.com> 1276261390 +0200 checkout: moving from async to cleanup
+f606937a7a21237c866efafcad33675e6539c103 02de401bc0b5ab5b97736265b18c7d1d6f53b9c1 Sebastian Thiel <byronimo@gmail.com> 1276266327 +0200 commit: Improved shutdown handling - although its impossible to prevent some stderr printing thanks to the underlying threading implementation, we can at least make sure that the interpreter doesn't block during shutdown. Now it appears to be running smoothly
+02de401bc0b5ab5b97736265b18c7d1d6f53b9c1 1873db442dc7511fc2c92fbaeb8d998d3e62723d Sebastian Thiel <byronimo@gmail.com> 1276266595 +0200 commit (amend): Improved shutdown handling - although its impossible to prevent some stderr printing thanks to the underlying threading implementation, we can at least make sure that the interpreter doesn't block during shutdown. Now it appears to be running smoothly
+1873db442dc7511fc2c92fbaeb8d998d3e62723d e14e3f143e7260de9581aee27e5a9b2645db72de Sebastian Thiel <byronimo@gmail.com> 1276267329 +0200 commit: Removed commented-out debug code and additional debug printings. Verified it works on py2.4, 2.5 and 2.6
+e14e3f143e7260de9581aee27e5a9b2645db72de f606937a7a21237c866efafcad33675e6539c103 Sebastian Thiel <byronimo@gmail.com> 1276267656 +0200 checkout: moving from cleanup to async
+f606937a7a21237c866efafcad33675e6539c103 29eb123beb1c55e5db4aa652d843adccbd09ae18 Sebastian Thiel <byronimo@gmail.com> 1276267660 +0200 merge cleanup: Merge made by recursive.
+29eb123beb1c55e5db4aa652d843adccbd09ae18 cac6e06cc9ef2903a15e594186445f3baa989a1a Sebastian Thiel <byronimo@gmail.com> 1276268324 +0200 commit: test_task: fixed import error, made all modules from x import * safe
+cac6e06cc9ef2903a15e594186445f3baa989a1a a28942bdf01f4ddb9d0b5a0489bd6f4e101dd775 Sebastian Thiel <byronimo@gmail.com> 1276280001 +0200 commit: Added performance test, improved iterator task which will now be usable by default. It shows that there must be the notion of a producer, which can work if there are no items read
+a28942bdf01f4ddb9d0b5a0489bd6f4e101dd775 9e7fbc06cbcb51efb8c88fedaeb257a435c0c162 Sebastian Thiel <byronimo@gmail.com> 1276334358 +0200 commit: Cleaned up channel design, Reader and Writer bases don't require a channel anymore, but are abstract.
+9e7fbc06cbcb51efb8c88fedaeb257a435c0c162 be8955a0fbb77d673587974b763f17c214904b57 Sebastian Thiel <byronimo@gmail.com> 1276334369 +0200 commit (amend): Cleaned up channel design, Reader and Writer bases don't require a channel anymore, but are abstract.
+be8955a0fbb77d673587974b763f17c214904b57 1d8a577ffc6ad7ce1465001ddebdc157aecc1617 Sebastian Thiel <byronimo@gmail.com> 1276335670 +0200 commit: channel: cleaned up inheritance hierarchy, adding mixing for callback functionality - previously the callback functionality was bound to channel based readers/writers
+1d8a577ffc6ad7ce1465001ddebdc157aecc1617 eded3fb0c820761d51d462e0d96187371c1758dc Sebastian Thiel <byronimo@gmail.com> 1276339082 +0200 commit: task: improved naming of task types, improved pool test to be less dependent on starting with just the main thread
+eded3fb0c820761d51d462e0d96187371c1758dc 7a0b79ee574999ecbc76696506352e4a5a0d7159 Sebastian Thiel <byronimo@gmail.com> 1276339207 +0200 commit (amend): task: improved naming of task types, improved pool test to be less dependent on starting with just the main thread
+7a0b79ee574999ecbc76696506352e4a5a0d7159 7c1169f6ea406fec1e26e99821e18e66437e65eb Sebastian Thiel <byronimo@gmail.com> 1276339273 +0200 checkout: moving from async to master
+7c1169f6ea406fec1e26e99821e18e66437e65eb f91495e271597034226f1b9651345091083172c4 Sebastian Thiel <byronimo@gmail.com> 1276339280 +0200 merge async: Merge made by recursive.
+f91495e271597034226f1b9651345091083172c4 5c631ca192848fed3068b31b1389cd92a0c0cdca Sebastian Thiel <byronimo@gmail.com> 1276340638 +0200 commit: Removed async from this repository, put it into own one which now comes in as external, using a git-submodule
+5c631ca192848fed3068b31b1389cd92a0c0cdca f91495e271597034226f1b9651345091083172c4 Sebastian Thiel <byronimo@gmail.com> 1276345979 +0200 HEAD~1: updating HEAD
+f91495e271597034226f1b9651345091083172c4 86ea63504f3e8a74cfb1d533be9d9602d2d17e27 Sebastian Thiel <byronimo@gmail.com> 1276346049 +0200 commit: Removed async from tree
+86ea63504f3e8a74cfb1d533be9d9602d2d17e27 6c1faef799095f3990e9970bc2cb10aa0221cf9c Sebastian Thiel <byronimo@gmail.com> 1276356043 +0200 commit: Removed odb from project, it is now used as a submodule named gitdb, which was added instead
+6c1faef799095f3990e9970bc2cb10aa0221cf9c 28ed48c93f4cc8b6dd23c951363e5bd4e6880992 Sebastian Thiel <byronimo@gmail.com> 1276503381 +0200 commit: Implemented initial version of tree serialization which appears to work according to a simple test
+28ed48c93f4cc8b6dd23c951363e5bd4e6880992 fe5289ed8311fecf39913ce3ae86b1011eafe5f7 Sebastian Thiel <byronimo@gmail.com> 1276506168 +0200 commit: tree now uses less memory for its cache as it stores the bare deserialized information - this also speeds up later serialization after changes. its clear though that retrieving actual objects is slower currently as these are not cached anymore. Its worth thinking about moving these encoding, decoding routines to gitdb
+fe5289ed8311fecf39913ce3ae86b1011eafe5f7 f8dabbf4f92a7023181777e9d40355562474f71a Sebastian Thiel <byronimo@gmail.com> 1276512508 +0200 commit: tree: added TreeModifier, allowing to adjust existing trees safely and or fast, while staying compatible with serialization which requires it to be sorted
+f8dabbf4f92a7023181777e9d40355562474f71a d9240918aa03e49feabe43af619019805ac76786 Sebastian Thiel <byronimo@gmail.com> 1276512707 +0200 commit (amend): tree: added TreeModifier, allowing to adjust existing trees safely and or fast, while staying compatible with serialization which requires it to be sorted
+d9240918aa03e49feabe43af619019805ac76786 d9240918aa03e49feabe43af619019805ac76786 Sebastian Thiel <byronimo@gmail.com> 1276520481 +0200 checkout: moving from master to index
+d9240918aa03e49feabe43af619019805ac76786 af32b6e0ad4ab244dc70a5ade0f8a27ab45942f8 Sebastian Thiel <byronimo@gmail.com> 1276524270 +0200 commit: index: split index file into multiple files of a single package. This didn't reduce the file size as much as I would have liked, but certainly is a start for further 'outsourcing'
+af32b6e0ad4ab244dc70a5ade0f8a27ab45942f8 0ad4af53d4704489f2fd8bd067241bf12c8ee35a Sebastian Thiel <byronimo@gmail.com> 1276525421 +0200 commit: Implemented the serializable interface - by refactoring code
+0ad4af53d4704489f2fd8bd067241bf12c8ee35a abaefc59a7f2986ab344a65ef2a3653ce7dd339f Sebastian Thiel <byronimo@gmail.com> 1276527582 +0200 commit (amend): Implemented the serializable interface - by refactoring code
+abaefc59a7f2986ab344a65ef2a3653ce7dd339f d9240918aa03e49feabe43af619019805ac76786 Sebastian Thiel <byronimo@gmail.com> 1276527605 +0200 checkout: moving from index to master
+d9240918aa03e49feabe43af619019805ac76786 38b3cfb9b24a108e0720f7a3f8d6355f7e0bb1a9 Sebastian Thiel <byronimo@gmail.com> 1276527612 +0200 merge index: Merge made by recursive.
+38b3cfb9b24a108e0720f7a3f8d6355f7e0bb1a9 c9dbf201b4f0b3c2b299464618cb4ecb624d272c Sebastian Thiel <byronimo@gmail.com> 1276529105 +0200 commit: Moved small types that had their own module into the utils module
+c9dbf201b4f0b3c2b299464618cb4ecb624d272c 45e87305bd4f050c2d0309c32fe5de499fc38df3 Sebastian Thiel <byronimo@gmail.com> 1276554725 +0200 commit: Reimplemented Lock handling to be conforming to the git lock protocol, which is actually more efficient than the previous implementation
+45e87305bd4f050c2d0309c32fe5de499fc38df3 06590aee389f4466e02407f39af1674366a74705 Sebastian Thiel <byronimo@gmail.com> 1276555536 +0200 commit (amend): Reimplemented Lock handling to be conforming to the git lock protocol, which is actually more efficient than the previous implementation
+06590aee389f4466e02407f39af1674366a74705 1d2307532d679393ae067326e4b6fa1a2ba5cc06 Sebastian Thiel <byronimo@gmail.com> 1276556905 +0200 commit: Moved LockedFD and its test into the gitdb project
+1d2307532d679393ae067326e4b6fa1a2ba5cc06 e837b901dcfac82e864f806c80f4a9cbfdb9c9f3 Sebastian Thiel <byronimo@gmail.com> 1276607908 +0200 commit: Move LazyMixin type to gitdb, index reading now uses file_contents_ro from gitdb as well
+e837b901dcfac82e864f806c80f4a9cbfdb9c9f3 b82dbf538ac0d03968a0f5b7e2318891abefafaa Sebastian Thiel <byronimo@gmail.com> 1276870827 +0200 commit: GitCmd implementation of gitdb base moved to git-python where it belongs. Previously it was located in gitdb, which doesn't have any facilities to use the git command
+b82dbf538ac0d03968a0f5b7e2318891abefafaa f164627a85ed7b816759871a76db258515b85678 Sebastian Thiel <byronimo@gmail.com> 1277057845 +0200 commit: db: added pure python git database
+f164627a85ed7b816759871a76db258515b85678 ac62760c52abf28d1fd863f0c0dd48bc4a23d223 Sebastian Thiel <byronimo@gmail.com> 1277117506 +0200 commit: index.add: now uses gitdb.store functionality instead of git-hash-file. The python version is about as fast, but could support multithreading using async
+ac62760c52abf28d1fd863f0c0dd48bc4a23d223 0fdf6c3aaff49494c47aaeb0caa04b3016e10a26 Sebastian Thiel <byronimo@gmail.com> 1277127929 +0200 commit: index: Entries are now using flags internally, instead of reducing the flag information to just the stage ( just to be closer to the git-original )
+0fdf6c3aaff49494c47aaeb0caa04b3016e10a26 0aeb491d3d8f53e07fb21f36251be4880170c5ab Sebastian Thiel <byronimo@gmail.com> 1277129321 +0200 commit: index.add does not need the git clt anymore
+0aeb491d3d8f53e07fb21f36251be4880170c5ab 91725f0fc59aa05ef68ab96e9b29009ce84668a5 Sebastian Thiel <byronimo@gmail.com> 1277129385 +0200 commit (amend): index.add does not need the git clt anymore
+91725f0fc59aa05ef68ab96e9b29009ce84668a5 91725f0fc59aa05ef68ab96e9b29009ce84668a5 Sebastian Thiel <byronimo@gmail.com> 1277132483 +0200 checkout: moving from master to writetree
+91725f0fc59aa05ef68ab96e9b29009ce84668a5 1044116d25f0311033e0951d2ab30579bba4b051 Sebastian Thiel <byronimo@gmail.com> 1277144182 +0200 commit: index: put serialization methods into new 'fun' module, this makes the calls faster as it removes one level of indirection, and makes the main file smaller, improving maintainability
+1044116d25f0311033e0951d2ab30579bba4b051 69dd8750be1fbf55010a738dc1ced4655e727f23 Sebastian Thiel <byronimo@gmail.com> 1277157937 +0200 commit: index.write_tree: initial version implemented, although its not yet working correctly, a test to explicitly compare the git version with the python implementation is still missing
+69dd8750be1fbf55010a738dc1ced4655e727f23 cadce432d8ef07e7293f8b760342d717bd350671 Sebastian Thiel <byronimo@gmail.com> 1277188932 +0200 commit: intermediate commit, rollback
+cadce432d8ef07e7293f8b760342d717bd350671 69dd8750be1fbf55010a738dc1ced4655e727f23 Sebastian Thiel <byronimo@gmail.com> 1277189427 +0200 HEAD~1: updating HEAD
+69dd8750be1fbf55010a738dc1ced4655e727f23 d2d9197cfe5d3b43cb8aee182b2e65c73ef9ab7b Sebastian Thiel <byronimo@gmail.com> 1277193172 +0200 commit: Tree-Writing now works after fixing an off-by-one error
+d2d9197cfe5d3b43cb8aee182b2e65c73ef9ab7b c4f49fb232acb2c02761a82acc12c4040699685d Sebastian Thiel <byronimo@gmail.com> 1277201017 +0200 commit: index.write_tree: now uses MemoryDB, making tree handling more efficient as IO will only be done when required. A possible disadvantage though is that time is spent on compressing the trees, although only the raw data and their shas would theoretically be needed. On the other hand, compressing their data uses less memory. An optimal implementation would just sha the data, check for existance, and compress it to write it to the database right away. This would mean more specialized code though, introducing redundancy. If IStreams would know whether they contain compressed or uncompressed data, and if there was a method to get a sha from data, this would work nicely in the existing framework though
+c4f49fb232acb2c02761a82acc12c4040699685d 91725f0fc59aa05ef68ab96e9b29009ce84668a5 Sebastian Thiel <byronimo@gmail.com> 1277201030 +0200 checkout: moving from writetree to master
+91725f0fc59aa05ef68ab96e9b29009ce84668a5 778234d544b3f58dd415aaf10679d15b01a5281f Sebastian Thiel <byronimo@gmail.com> 1277201033 +0200 merge writetree: Merge made by recursive.
+778234d544b3f58dd415aaf10679d15b01a5281f 778234d544b3f58dd415aaf10679d15b01a5281f Sebastian Thiel <byronimo@gmail.com> 1277209257 +0200 checkout: moving from master to fromtree
+778234d544b3f58dd415aaf10679d15b01a5281f be97c4558992a437cde235aafc7ae2bd6df84ac8 Sebastian Thiel <byronimo@gmail.com> 1277234627 +0200 commit: Initial frame for implementing read_tree using pure python. As git-read-tree can do much more than we can ( and faster assumably ), the .new method is used to create new index instances from up to 3 trees.
+be97c4558992a437cde235aafc7ae2bd6df84ac8 c0ef65b43688b1a4615a1e7332f6215f9a8abb19 Sebastian Thiel <byronimo@gmail.com> 1277245716 +0200 commit: Implemented simple tree merging and a simple test, more elaborate testing is in progress
+c0ef65b43688b1a4615a1e7332f6215f9a8abb19 aea0243840a46021e6f77c759c960a06151d91c9 Sebastian Thiel <byronimo@gmail.com> 1277293745 +0200 commit: Added test for aggressive_tree_merge
+aea0243840a46021e6f77c759c960a06151d91c9 1e2265a23ecec4e4d9ad60d788462e7f124f1bb7 Sebastian Thiel <byronimo@gmail.com> 1277300937 +0200 commit: fixed critical bug in traverse_trees_recursive, implemented IndexFile.new including simple test, it may be simple as the methods it uses are throroughly tested
+1e2265a23ecec4e4d9ad60d788462e7f124f1bb7 778234d544b3f58dd415aaf10679d15b01a5281f Sebastian Thiel <byronimo@gmail.com> 1277300988 +0200 checkout: moving from fromtree to master
+778234d544b3f58dd415aaf10679d15b01a5281f 57050184f3d962bf91511271af59ee20f3686c3f Sebastian Thiel <byronimo@gmail.com> 1277301014 +0200 merge fromtree: Merge made by recursive.
+57050184f3d962bf91511271af59ee20f3686c3f 129f90aa8d83d9b250c87b0ba790605c4a2bb06a Sebastian Thiel <byronimo@gmail.com> 1277334478 +0200 commit: Multiple partly critical bugfixes related to index handling
+129f90aa8d83d9b250c87b0ba790605c4a2bb06a a1adb421c2ee3e4868ea70d440dd82896219ed8f Sebastian Thiel <byronimo@gmail.com> 1277388148 +0200 commit: aggressive_tree_merge: fixed incorrect handling of one branch, it was just not implemented causing incorrect merge results. Added test to cover this issue
+a1adb421c2ee3e4868ea70d440dd82896219ed8f 55dcc17c331f580b3beeb4d5decf64d3baf94f2e Sebastian Thiel <byronimo@gmail.com> 1277395720 +0200 commit (amend): aggressive_tree_merge: fixed incorrect handling of one branch, it was just not implemented causing incorrect merge results. Added test to cover this issue
+55dcc17c331f580b3beeb4d5decf64d3baf94f2e ca131dd61e26f46f49ee3f70763f994cf9512665 Sebastian Thiel <byronimo@gmail.com> 1277401303 +0200 commit: GitCmdStreamReader: fixed terrible bug which only kicked in if the stream was actually empty. This is a rare case that can happen during stream testing. Theoretically there shouldn't be any empty streams of course, but practically they do exist sometimes ;)
+ca131dd61e26f46f49ee3f70763f994cf9512665 feb1ea0f4aacb9ea6dc4133900e65bf34c0ee02d Sebastian Thiel <byronimo@gmail.com> 1277401306 +0200 commit (amend): GitCmdStreamReader: fixed terrible bug which only kicked in if the stream was actually empty. This is a rare case that can happen during stream testing. Theoretically there shouldn't be any empty streams of course, but practically they do exist sometimes ;); fixed stream.seek implementation, which previously used seek on standard output
+feb1ea0f4aacb9ea6dc4133900e65bf34c0ee02d 402a6c2808db4333217aa300d0312836fd7923bd Sebastian Thiel <byronimo@gmail.com> 1277407147 +0200 commit: IndexFile.add: writing of the index file can now optionally be turned off. The default is to write the physical index, which is the behaviour you would expect
+402a6c2808db4333217aa300d0312836fd7923bd 402a6c2808db4333217aa300d0312836fd7923bd Sebastian Thiel <byronimo@gmail.com> 1277417929 +0200 checkout: moving from master to index
+402a6c2808db4333217aa300d0312836fd7923bd 4d30dfb07f78517b1ba20b88506e01678edd527c Sebastian Thiel <byronimo@gmail.com> 1277417979 +0200 commit: index.reset is now partly implemented using python, but in fact it resorts to using git-read-tree to keep the stat information when merging one tree in. After all this is what needed to be implemented in python as well
+4d30dfb07f78517b1ba20b88506e01678edd527c 58fb1187b7b8f1e62d3930bdba9be5aba47a52c6 Sebastian Thiel <byronimo@gmail.com> 1277473186 +0200 commit (amend): index.reset is now partly implemented using python, but in fact it resorts to using git-read-tree to keep the stat information when merging one tree in. After all this is what needed to be implemented in python as well
+58fb1187b7b8f1e62d3930bdba9be5aba47a52c6 402a6c2808db4333217aa300d0312836fd7923bd Sebastian Thiel <byronimo@gmail.com> 1277473192 +0200 checkout: moving from index to master
+402a6c2808db4333217aa300d0312836fd7923bd 58fb1187b7b8f1e62d3930bdba9be5aba47a52c6 Sebastian Thiel <byronimo@gmail.com> 1277473196 +0200 merge index: Fast-forward
+58fb1187b7b8f1e62d3930bdba9be5aba47a52c6 58fb1187b7b8f1e62d3930bdba9be5aba47a52c6 Sebastian Thiel <byronimo@gmail.com> 1277473218 +0200 checkout: moving from master to sha20
+58fb1187b7b8f1e62d3930bdba9be5aba47a52c6 47e3138ee978ce708a41f38a0d874376d7ae5c78 Sebastian Thiel <byronimo@gmail.com> 1277503104 +0200 commit: Adjusted all files to (hopefully) deal with the fact that all objects now use 20 byte sha's internally as it is closer to the GitDB implementation
+47e3138ee978ce708a41f38a0d874376d7ae5c78 7abe9065aab9dec56015ede5f2b0082837c5dc2e Sebastian Thiel <byronimo@gmail.com> 1277745342 +0200 commit: All tests adjusted to work with the changed internal sha representation
+7abe9065aab9dec56015ede5f2b0082837c5dc2e 1fe889ea0cb2547584075dc1eb77f52c54b9a8c4 Sebastian Thiel <byronimo@gmail.com> 1277745354 +0200 commit (amend): All tests adjusted to work with the changed internal sha representation
+1fe889ea0cb2547584075dc1eb77f52c54b9a8c4 58fb1187b7b8f1e62d3930bdba9be5aba47a52c6 Sebastian Thiel <byronimo@gmail.com> 1277745377 +0200 checkout: moving from sha20 to master
+58fb1187b7b8f1e62d3930bdba9be5aba47a52c6 8d2239f24f6a54d98201413d4f46256df0d6a5f3 Sebastian Thiel <byronimo@gmail.com> 1277745383 +0200 merge sha20: Merge made by recursive.
+8d2239f24f6a54d98201413d4f46256df0d6a5f3 f1401803ccf7db5d897a5ef4b27e2176627c430e Sebastian Thiel <byronimo@gmail.com> 1277756712 +0200 commit: Fixed performance tests which broke in the course of the sha1-20 byte changes
+f1401803ccf7db5d897a5ef4b27e2176627c430e 6917ae4ce9eaa0f5ea91592988c1ea830626ac3a Sebastian Thiel <byronimo@gmail.com> 1277806256 +0200 commit: Diff: fixed bug that caused a string to end up as a blob mode
+6917ae4ce9eaa0f5ea91592988c1ea830626ac3a 6917ae4ce9eaa0f5ea91592988c1ea830626ac3a Sebastian Thiel <byronimo@gmail.com> 1277819766 +0200 checkout: moving from master to docs
+6917ae4ce9eaa0f5ea91592988c1ea830626ac3a 160081b9a7ca191afbec077c4bf970cfd9070d2c Sebastian Thiel <byronimo@gmail.com> 1277828911 +0200 commit: Updated and fixed sphinx API docs, which included one quick skim-through
+160081b9a7ca191afbec077c4bf970cfd9070d2c 791765c0dc2d00a9ffa4bc857d09f615cfe3a759 Sebastian Thiel <byronimo@gmail.com> 1277830741 +0200 commit: Removed repo tests which for some reason left the 'repos' directory around, replaced them by a real test which actually executes code, and puts everything into the tmp directory
+791765c0dc2d00a9ffa4bc857d09f615cfe3a759 77cd6659b64cb1950a82e6a3cccdda94f15ae739 Sebastian Thiel <byronimo@gmail.com> 1277834446 +0200 commit: Renamed modules utils to util, and errors to exc to be more conforming to the submodules's naming conventions
+77cd6659b64cb1950a82e6a3cccdda94f15ae739 18be0972304dc7f1a2a509595de7da689bddbefa Sebastian Thiel <byronimo@gmail.com> 1277835397 +0200 commit: Removed blob.data property as there is no real reason for an exception to the rule of trying not to cache possibly heavy data. The data_stream method should be used instead
+18be0972304dc7f1a2a509595de7da689bddbefa 0369384c8b79c44c5369f1b6c05046899f8886da Sebastian Thiel <byronimo@gmail.com> 1277840971 +0200 commit: revised tutorial to match the changed usage, added basic information about object databases
+0369384c8b79c44c5369f1b6c05046899f8886da ee58d55133c571db6384acf916e4a1c3592be07b Sebastian Thiel <byronimo@gmail.com> 1277848046 +0200 commit: Added whatsnew and put it into the index
+ee58d55133c571db6384acf916e4a1c3592be07b 77d083040248deeccb3ac1ad125eb2969b5cb370 Sebastian Thiel <byronimo@gmail.com> 1277848184 +0200 commit (amend): Added whatsnew and put it into the index
+77d083040248deeccb3ac1ad125eb2969b5cb370 fde6522c40a346c8b1d588a2b8d4dd362ae1f58f Sebastian Thiel <byronimo@gmail.com> 1277848539 +0200 commit (amend): Added whatsnew and put it into the index
+fde6522c40a346c8b1d588a2b8d4dd362ae1f58f 28a33ca17ac5e0816a3e24febb47ffcefa663980 Sebastian Thiel <byronimo@gmail.com> 1277991925 +0200 commit: Added further information about the required submodules, and how to install them. Incremeneted version to 0.3.0 beta1
+28a33ca17ac5e0816a3e24febb47ffcefa663980 586aa65f772f69eb6d08224968c74dda1ca45612 Sebastian Thiel <byronimo@gmail.com> 1277993503 +0200 commit: Moved all source files into the source folder, separating the build from the source directory
+586aa65f772f69eb6d08224968c74dda1ca45612 d2ebc6193f7205fd1686678a5707262cb1c59bb0 Sebastian Thiel <byronimo@gmail.com> 1277993585 +0200 commit (amend): Moved all source files into the source folder, separating the build from the source directory
+d2ebc6193f7205fd1686678a5707262cb1c59bb0 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af Sebastian Thiel <byronimo@gmail.com> 1277994361 +0200 checkout: moving from docs to hub/0.2
+1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af 7bfca5efce8988e6070e7284bd409d1a731a3fbc Sebastian Thiel <byronimo@gmail.com> 1277994419 +0200 checkout: moving from 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af to hub/0.1
+7bfca5efce8988e6070e7284bd409d1a731a3fbc d2ebc6193f7205fd1686678a5707262cb1c59bb0 Sebastian Thiel <byronimo@gmail.com> 1277994469 +0200 checkout: moving from 7bfca5efce8988e6070e7284bd409d1a731a3fbc to docs
+d2ebc6193f7205fd1686678a5707262cb1c59bb0 c3bd05b426a0e3dec8224244c3c9c0431d1ff130 Sebastian Thiel <byronimo@gmail.com> 1277994911 +0200 commit: Added doc-index, which helps to keep documentation of prior but still somewhat supported versions alive
+c3bd05b426a0e3dec8224244c3c9c0431d1ff130 6917ae4ce9eaa0f5ea91592988c1ea830626ac3a Sebastian Thiel <byronimo@gmail.com> 1277999895 +0200 checkout: moving from docs to master
+6917ae4ce9eaa0f5ea91592988c1ea830626ac3a fd96cceded27d1372bdc1a851448d2d8613f60f3 Sebastian Thiel <byronimo@gmail.com> 1277999899 +0200 merge docs: Merge made by recursive.
+fd96cceded27d1372bdc1a851448d2d8613f60f3 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af Sebastian Thiel <byronimo@gmail.com> 1278082024 +0200 checkout: moving from master to 0.2.0-beta1
+1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af fd96cceded27d1372bdc1a851448d2d8613f60f3 Sebastian Thiel <byronimo@gmail.com> 1278082288 +0200 checkout: moving from 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af to master
+fd96cceded27d1372bdc1a851448d2d8613f60f3 f683c6623f73252645bb2819673046c9d397c567 Sebastian Thiel <byronimo@gmail.com> 1278082451 +0200 commit: Fixed broken 0.2 documentation, it didn't contain the API reference previously due to import errors and a somewhat inconsistent working tree that occurred when switching branches ...
+f683c6623f73252645bb2819673046c9d397c567 a4287f65878000b42d11704692f9ea3734014b4c Sebastian Thiel <byronimo@gmail.com> 1278092317 +0200 commit: win32 compatability adjustments
+a4287f65878000b42d11704692f9ea3734014b4c a4287f65878000b42d11704692f9ea3734014b4c Sebastian Thiel <byronimo@gmail.com> 1278315351 +0200 checkout: moving from master to revparse
+a4287f65878000b42d11704692f9ea3734014b4c f963881e53a9f0a2746a11cb9cdfa82eb1f90d8c Sebastian Thiel <byronimo@gmail.com> 1278369330 +0200 commit: Initial version of the rev-parse routine, which doesn't work too bad, but its still rather slow and many tests are not yet implemented
+f963881e53a9f0a2746a11cb9cdfa82eb1f90d8c 1c6d7830d9b87f47a0bfe82b3b5424a32e3164ad Sebastian Thiel <byronimo@gmail.com> 1278405962 +0200 commit: RevParse now generally works, but there are still some more specialized tests missing
+1c6d7830d9b87f47a0bfe82b3b5424a32e3164ad a32a6bcd784fca9cb2b17365591c29d15c2f638e Sebastian Thiel <byronimo@gmail.com> 1278407809 +0200 commit: Refs now use object.new_from_sha where possible, preventing git-batch-check to be started up for sha resolution
+a32a6bcd784fca9cb2b17365591c29d15c2f638e 355aa879cff8630c9eedaf151f90a229f2ba5135 Sebastian Thiel <byronimo@gmail.com> 1278410951 +0200 commit: Implemented main rev-parsing, including long hexshas, tags and refs. Short Shas still to be done
+355aa879cff8630c9eedaf151f90a229f2ba5135 73959f3a2d4f224fbda03c8a8850f66f53d8cb3b Sebastian Thiel <byronimo@gmail.com> 1278418771 +0200 commit (amend): Implemented main rev-parsing, including long hexshas, tags and refs. Short Shas still to be done
+73959f3a2d4f224fbda03c8a8850f66f53d8cb3b 9059525a75b91e6eb6a425f1edcc608739727168 Sebastian Thiel <byronimo@gmail.com> 1278440512 +0200 commit: Made repo.py a package to allow better localization of functions and utilities - the repo module got rather large
+9059525a75b91e6eb6a425f1edcc608739727168 f068cdc5a1a13539c4a1d756ae950aab65f5348b Sebastian Thiel <byronimo@gmail.com> 1278497773 +0200 commit: Initially working implementation of short-sha parsing and interpretation, thanks to new gitdb functionality
+f068cdc5a1a13539c4a1d756ae950aab65f5348b bc31651674648f026464fd4110858c4ffeac3c18 Sebastian Thiel <byronimo@gmail.com> 1278516647 +0200 commit: Adjusted previous object creators to use the rev_parse method directly. rev_parse could be adjusted not to return Objects anymore, providing better performance for those who just want a sha only. On the other hand, the method is high-level and should be convenient to use as well, its a starting point for more usually, hence its unlikely to call it in tight loops
+bc31651674648f026464fd4110858c4ffeac3c18 8a73805d9b26b5a6c54f2e8d53f948df7db8b3d4 Sebastian Thiel <byronimo@gmail.com> 1278517362 +0200 commit: Added test for GitCmdObjectDB in order to verify the method is working as expected with different input
+8a73805d9b26b5a6c54f2e8d53f948df7db8b3d4 01ab5b96e68657892695c99a93ef909165456689 Sebastian Thiel <byronimo@gmail.com> 1278517373 +0200 commit (amend): Added test for GitCmdObjectDB in order to verify the partial_to_complete_sha_hex is working as expected with different input ( it wasn't, of course ;) )
+01ab5b96e68657892695c99a93ef909165456689 a4287f65878000b42d11704692f9ea3734014b4c Sebastian Thiel <byronimo@gmail.com> 1278517411 +0200 checkout: moving from revparse to master
+a4287f65878000b42d11704692f9ea3734014b4c ca288d443f4fc9d790eecb6e1cdf82b6cdd8dc0d Sebastian Thiel <byronimo@gmail.com> 1278517416 +0200 merge revparse: Merge made by recursive.
+ca288d443f4fc9d790eecb6e1cdf82b6cdd8dc0d a4287f65878000b42d11704692f9ea3734014b4c Sebastian Thiel <byronimo@gmail.com> 1278525786 +0200 checkout: moving from master to master~1
+a4287f65878000b42d11704692f9ea3734014b4c ca288d443f4fc9d790eecb6e1cdf82b6cdd8dc0d Sebastian Thiel <byronimo@gmail.com> 1278525793 +0200 checkout: moving from a4287f65878000b42d11704692f9ea3734014b4c to master
+ca288d443f4fc9d790eecb6e1cdf82b6cdd8dc0d 01ab5b96e68657892695c99a93ef909165456689 Sebastian Thiel <byronimo@gmail.com> 1278525803 +0200 checkout: moving from master to master^2
+01ab5b96e68657892695c99a93ef909165456689 bc31651674648f026464fd4110858c4ffeac3c18 Sebastian Thiel <byronimo@gmail.com> 1278525815 +0200 checkout: moving from 01ab5b96e68657892695c99a93ef909165456689 to master^2~1
+bc31651674648f026464fd4110858c4ffeac3c18 f068cdc5a1a13539c4a1d756ae950aab65f5348b Sebastian Thiel <byronimo@gmail.com> 1278525821 +0200 checkout: moving from bc31651674648f026464fd4110858c4ffeac3c18 to master^2~2
+f068cdc5a1a13539c4a1d756ae950aab65f5348b 73959f3a2d4f224fbda03c8a8850f66f53d8cb3b Sebastian Thiel <byronimo@gmail.com> 1278525826 +0200 checkout: moving from f068cdc5a1a13539c4a1d756ae950aab65f5348b to master^2~4
+73959f3a2d4f224fbda03c8a8850f66f53d8cb3b ca288d443f4fc9d790eecb6e1cdf82b6cdd8dc0d Sebastian Thiel <byronimo@gmail.com> 1278525829 +0200 checkout: moving from 73959f3a2d4f224fbda03c8a8850f66f53d8cb3b to master
+ca288d443f4fc9d790eecb6e1cdf82b6cdd8dc0d 5fd6cc37fd07c25cb921b77b4f658b7e8fc132b3 Sebastian Thiel <byronimo@gmail.com> 1278536545 +0200 commit: Adjusted clone method to allow static classmethod clone ( using clone_from ) as well as the previous instance method clone to keep it compatible
+5fd6cc37fd07c25cb921b77b4f658b7e8fc132b3 76af62b3c5a26638fcad9a3fe401fba566fb7037 Sebastian Thiel <byronimo@gmail.com> 1278538933 +0200 commit (amend): Adjusted clone method to allow static classmethod clone ( using clone_from ) as well as the previous instance method clone to keep it compatible
+76af62b3c5a26638fcad9a3fe401fba566fb7037 b425301ad16f265157abdaf47f7af1c1ea879068 Sebastian Thiel <byronimo@gmail.com> 1278539147 +0200 commit (amend): Adjusted clone method to allow static classmethod clone ( using clone_from ) as well as the previous instance method clone to keep it compatible
+b425301ad16f265157abdaf47f7af1c1ea879068 3288a244428751208394d8137437878277ceb71f Sebastian Thiel <byronimo@gmail.com> 1278582561 +0200 commit: setup.py: fixed requirement - its interesting to see that there are two different keywords for distutils and setuptools, the latter one doesn't read the ones of the first one, unfortunately
+3288a244428751208394d8137437878277ceb71f 08457a7a6b6ad4f518fad0d5bca094a2b5b38fbe Sebastian Thiel <byronimo@gmail.com> 1278670718 +0200 commit: Added python 2.4 support: Repo will now use the original GitCmdObjectDB in python 2.4, as the pure python implementation cannot work without memory maps
+08457a7a6b6ad4f518fad0d5bca094a2b5b38fbe 258403da9c2a087b10082d26466528fce3de38d4 Sebastian Thiel <byronimo@gmail.com> 1278671744 +0200 commit: bumped verison to 0.3.0 beta2
+258403da9c2a087b10082d26466528fce3de38d4 55b67e8194b8b4d9e73e27feadbf9af6593e4600 Sebastian Thiel <byronimo@gmail.com> 1278927490 +0200 pull gitorious master: Fast-forward
+55b67e8194b8b4d9e73e27feadbf9af6593e4600 bcd37b68533d0cceb7e73dd1ed1428fa09f7dc17 Sebastian Thiel <byronimo@gmail.com> 1279007300 +0200 commit: Fixed incorrect use of Blob.data in performance test
+bcd37b68533d0cceb7e73dd1ed1428fa09f7dc17 24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 Sebastian Thiel <byronimo@gmail.com> 1279110447 +0200 commit: Added performance test to compare inst.__class__() vs type(inst)() class. The first one is faster, although I would have expected the latter one to be faster
+24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 Sebastian Thiel <byronimo@gmail.com> 1279130572 +0200 checkout: moving from master to integration
+24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 2603363b435a695f9bf1bbbd5c1c59c353ec0450 Sebastian Thiel <byronimo@gmail.com> 1279130575 +0200 pull git://gitorious.org/git-python/mainline.git refs/merge-requests/2104: Merge made by recursive.
+2603363b435a695f9bf1bbbd5c1c59c353ec0450 c9c8d48a42d45d22a120e2191ae2f838483caccc Sebastian Thiel <byronimo@gmail.com> 1279130613 +0200 HEAD^2: updating HEAD
+c9c8d48a42d45d22a120e2191ae2f838483caccc 24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 Sebastian Thiel <byronimo@gmail.com> 1279130629 +0200 checkout: moving from integration to master
+24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 a64c5f23c38f06c37a0ca64796368019dfb0d818 Sebastian Thiel <byronimo@gmail.com> 1279130658 +0200 commit: Correct Repo documentation in API reference
+a64c5f23c38f06c37a0ca64796368019dfb0d818 24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 Sebastian Thiel <byronimo@gmail.com> 1279130719 +0200 HEAD~1: updating HEAD
+24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 17a172920fde8c6688c8a1a39f258629b8b73757 Sebastian Thiel <byronimo@gmail.com> 1279131269 +0200 commit: Fixed the missing Repo type documentation thanks to a hint of gasche, fixed a few more resT syntax errors on the way
+17a172920fde8c6688c8a1a39f258629b8b73757 cbb58869063fe803d232f099888fe9c23510de7b Sebastian Thiel <byronimo@gmail.com> 1279197254 +0200 merge gitorious/master: Fast-forward
+cbb58869063fe803d232f099888fe9c23510de7b 89422841e46efa99bda49acfbe33ee1ca5122845 Sebastian Thiel <byronimo@gmail.com> 1279533542 +0200 pull gitorious master: Fast-forward
+89422841e46efa99bda49acfbe33ee1ca5122845 192472f9673b18c91ce618e64e935f91769c50e7 Sebastian Thiel <byronimo@gmail.com> 1279814094 +0200 merge gitorious/master: Fast-forward
+192472f9673b18c91ce618e64e935f91769c50e7 fa3fce80aeb57299633535b9e1c9d08db710ff05 Sebastian Thiel <byronimo@gmail.com> 1281701051 +0200 commit: unicode handling in messages and trees was improved. Messages are now written according to the encoding of the commit object, and decoded using that information as well. Trees will encode and decode their names with utf8
+fa3fce80aeb57299633535b9e1c9d08db710ff05 394ed7006ee5dc8bddfd132b64001d5dfc0ffdd3 Sebastian Thiel <byronimo@gmail.com> 1281702078 +0200 commit (amend): unicode handling in messages and trees was improved. Messages are now written according to the encoding of the commit object, and decoded using that information as well. Trees will encode and decode their names with utf8
+394ed7006ee5dc8bddfd132b64001d5dfc0ffdd3 394ed7006ee5dc8bddfd132b64001d5dfc0ffdd3 Sebastian Thiel <byronimo@gmail.com> 1283969667 +0200 checkout: moving from master to integration
+394ed7006ee5dc8bddfd132b64001d5dfc0ffdd3 c4d5caa79e6d88bb3f98bfbefa3bfa039c7e157a Sebastian Thiel <byronimo@gmail.com> 1283969669 +0200 pull git://gitorious.org/git-python/mainline.git refs/merge-requests/14: Fast-forward
+c4d5caa79e6d88bb3f98bfbefa3bfa039c7e157a 394ed7006ee5dc8bddfd132b64001d5dfc0ffdd3 Sebastian Thiel <byronimo@gmail.com> 1283969687 +0200 checkout: moving from integration to master
+394ed7006ee5dc8bddfd132b64001d5dfc0ffdd3 c4d5caa79e6d88bb3f98bfbefa3bfa039c7e157a Sebastian Thiel <byronimo@gmail.com> 1283969691 +0200 merge integration: Fast-forward
+c4d5caa79e6d88bb3f98bfbefa3bfa039c7e157a 741dfaadf732d4a2a897250c006d5ef3d3cd9f3a Sebastian Thiel <byronimo@gmail.com> 1287134990 +0200 commit: Fixed bug in http://byronimo.lighthouseapp.com/projects/51787/tickets/44-remoteref-fails-when-there-is-character-in-the-name using supplied patch ( which was manually applied ).
+741dfaadf732d4a2a897250c006d5ef3d3cd9f3a fc650aa6869639548435ce2760d42c9cdd909d99 Sebastian Thiel <byronimo@gmail.com> 1287135891 +0200 commit: Added test to verify the actor class can handle unicode names correctly. This works because regex can handle unicode, and will return unicode instances instead of strings if required. Its quite amazing actually.
+fc650aa6869639548435ce2760d42c9cdd909d99 741dfaadf732d4a2a897250c006d5ef3d3cd9f3a Sebastian Thiel <byronimo@gmail.com> 1287136504 +0200 HEAD~1: updating HEAD
+741dfaadf732d4a2a897250c006d5ef3d3cd9f3a 741dfaadf732d4a2a897250c006d5ef3d3cd9f3a Sebastian Thiel <byronimo@gmail.com> 1287136515 +0200 checkout: moving from master to unicode
+741dfaadf732d4a2a897250c006d5ef3d3cd9f3a 0f88fb96869b6ac3ed4dac7d23310a9327d3c89c Sebastian Thiel <byronimo@gmail.com> 1287136588 +0200 commit: Added test to verify the actor type can handle and parse unicode if it is passed in
+0f88fb96869b6ac3ed4dac7d23310a9327d3c89c d39889bcac1735e429ac640ac6838d0e56835afb Sebastian Thiel <byronimo@gmail.com> 1287138883 +0200 commit: Added unicode handling for author names. They will now be properly encoded into the byte stream, as well as decoded from it
+d39889bcac1735e429ac640ac6838d0e56835afb 741dfaadf732d4a2a897250c006d5ef3d3cd9f3a Sebastian Thiel <byronimo@gmail.com> 1287138889 +0200 checkout: moving from unicode to master
+741dfaadf732d4a2a897250c006d5ef3d3cd9f3a a88173281ec56cb378a293d0170e11a1bda96a55 Sebastian Thiel <byronimo@gmail.com> 1287138898 +0200 merge unicode: Merge made by recursive.
+a88173281ec56cb378a293d0170e11a1bda96a55 d39889bcac1735e429ac640ac6838d0e56835afb Sebastian Thiel <byronimo@gmail.com> 1287139063 +0200 checkout: moving from master to unicode
+d39889bcac1735e429ac640ac6838d0e56835afb a88173281ec56cb378a293d0170e11a1bda96a55 Sebastian Thiel <byronimo@gmail.com> 1287139078 +0200 checkout: moving from unicode to master
+a88173281ec56cb378a293d0170e11a1bda96a55 741dfaadf732d4a2a897250c006d5ef3d3cd9f3a Sebastian Thiel <byronimo@gmail.com> 1287139082 +0200 HEAD~1: updating HEAD
+741dfaadf732d4a2a897250c006d5ef3d3cd9f3a d39889bcac1735e429ac640ac6838d0e56835afb Sebastian Thiel <byronimo@gmail.com> 1287139092 +0200 checkout: moving from master to unicode
+d39889bcac1735e429ac640ac6838d0e56835afb 0019d7dc8c72839d238065473a62b137c3c350f5 Sebastian Thiel <byronimo@gmail.com> 1287139239 +0200 commit (amend): Added unicode handling for author names. They will now be properly encoded into the byte stream, as well as decoded from it
+0019d7dc8c72839d238065473a62b137c3c350f5 741dfaadf732d4a2a897250c006d5ef3d3cd9f3a Sebastian Thiel <byronimo@gmail.com> 1287139252 +0200 checkout: moving from unicode to master
+741dfaadf732d4a2a897250c006d5ef3d3cd9f3a 13647590f96fb5a22cb60f12c5a70e00065a7f3a Sebastian Thiel <byronimo@gmail.com> 1287139254 +0200 merge unicode: Merge made by recursive.
+13647590f96fb5a22cb60f12c5a70e00065a7f3a 94029ce1420ced83c3e5dcd181a2280b26574bc9 Sebastian Thiel <byronimo@gmail.com> 1287139994 +0200 commit: Adjusted regex to support whitespace - it was a little restrictive previously, although there was absolutely no need for that.
+94029ce1420ced83c3e5dcd181a2280b26574bc9 cfd2121eda5fadd18fba6819f90efb8868fad14a Sebastian Thiel <byronimo@gmail.com> 1287729183 +0200 checkout: moving from master to dotsenko/stable
+cfd2121eda5fadd18fba6819f90efb8868fad14a 7bfca5efce8988e6070e7284bd409d1a731a3fbc Sebastian Thiel <byronimo@gmail.com> 1287729293 +0200 checkout: moving from cfd2121eda5fadd18fba6819f90efb8868fad14a to HEAD~1
+7bfca5efce8988e6070e7284bd409d1a731a3fbc 94029ce1420ced83c3e5dcd181a2280b26574bc9 Sebastian Thiel <byronimo@gmail.com> 1287729331 +0200 checkout: moving from 7bfca5efce8988e6070e7284bd409d1a731a3fbc to master
+94029ce1420ced83c3e5dcd181a2280b26574bc9 8858a63cb33319f3e739edcbfafdae3ec0fefa33 Sebastian Thiel <byronimo@gmail.com> 1288000691 +0200 commit: .gitignore will now ignore netbeans projects
+8858a63cb33319f3e739edcbfafdae3ec0fefa33 a2b9ded87baf0f32ae94c10c5851a0468a45f003 Sebastian Thiel <byronimo@gmail.com> 1288198935 +0200 commit: docs: untracked_files is a property, but was used like a function, see http://groups.google.com/group/git-python/browse_thread/thread/84ed1835e26a5296?hl=en
+a2b9ded87baf0f32ae94c10c5851a0468a45f003 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af Sebastian Thiel <byronimo@gmail.com> 1288198941 +0200 checkout: moving from master to 0.2.0-beta1
+1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af a2b9ded87baf0f32ae94c10c5851a0468a45f003 Sebastian Thiel <byronimo@gmail.com> 1288198964 +0200 checkout: moving from 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af to master
+a2b9ded87baf0f32ae94c10c5851a0468a45f003 8858a63cb33319f3e739edcbfafdae3ec0fefa33 Sebastian Thiel <byronimo@gmail.com> 1288198984 +0200 HEAD~1: updating HEAD
+8858a63cb33319f3e739edcbfafdae3ec0fefa33 148eb761aeaa4c3913e1766db0a7df0a5b5c8b20 Sebastian Thiel <byronimo@gmail.com> 1288198991 +0200 commit: docs: untracked_files is a property, but was used like a function, see http://groups.google.com/group/git-python/browse_thread/thread/84ed1835e26a5296?hl=en
+148eb761aeaa4c3913e1766db0a7df0a5b5c8b20 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af Sebastian Thiel <byronimo@gmail.com> 1288198995 +0200 checkout: moving from master to 0.2.0-beta1
+1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af 148eb761aeaa4c3913e1766db0a7df0a5b5c8b20 Sebastian Thiel <byronimo@gmail.com> 1288199017 +0200 checkout: moving from 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af to master
+148eb761aeaa4c3913e1766db0a7df0a5b5c8b20 8858a63cb33319f3e739edcbfafdae3ec0fefa33 Sebastian Thiel <byronimo@gmail.com> 1288199023 +0200 HEAD~1: updating HEAD
+8858a63cb33319f3e739edcbfafdae3ec0fefa33 538e8265e04f69bb9bd73a10ddb4e8e9677fb140 Sebastian Thiel <byronimo@gmail.com> 1288199049 +0200 commit: docs: untracked_files is a property, but was used like a function, see http://groups.google.com/group/git-python/browse_thread/thread/84ed1835e26a5296?hl=en
+538e8265e04f69bb9bd73a10ddb4e8e9677fb140 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af Sebastian Thiel <byronimo@gmail.com> 1288199066 +0200 checkout: moving from master to 0.2.0-beta1
+1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af ec97ed84d114ef131fa98acee4ce7be32f8c591f Sebastian Thiel <byronimo@gmail.com> 1288199163 +0200 commit: docs: untracked_files is a property, but was used like a function, see http://groups.google.com/group/git-python/browse_thread/thread/84ed1835e26a5296?hl=en
+ec97ed84d114ef131fa98acee4ce7be32f8c591f ec97ed84d114ef131fa98acee4ce7be32f8c591f Sebastian Thiel <byronimo@gmail.com> 1288199260 +0200 checkout: moving from ec97ed84d114ef131fa98acee4ce7be32f8c591f to 0.2fixes
+ec97ed84d114ef131fa98acee4ce7be32f8c591f 538e8265e04f69bb9bd73a10ddb4e8e9677fb140 Sebastian Thiel <byronimo@gmail.com> 1288199399 +0200 checkout: moving from 0.2 to master
+538e8265e04f69bb9bd73a10ddb4e8e9677fb140 97ab197140b16027975c7465a5e8786e6cc8fea1 Sebastian Thiel <byronimo@gmail.com> 1288203452 +0200 commit (amend): docs: untracked_files is a property, but was used like a function, see http://groups.google.com/group/git-python/browse_thread/thread/84ed1835e26a5296?hl=en
+97ab197140b16027975c7465a5e8786e6cc8fea1 3da3837fe2ec8152e1460f747d18290b52304868 Sebastian Thiel <byronimo@gmail.com> 1288203532 +0200 commit: cmd: improved error handling and debug printing
+3da3837fe2ec8152e1460f747d18290b52304868 2c0b92e40ece170b59bced0cea752904823e06e7 Sebastian Thiel <byronimo@gmail.com> 1288203543 +0200 commit (amend): cmd: improved error handling and debug printing
+2c0b92e40ece170b59bced0cea752904823e06e7 1b6b9510e0724bfcb4250f703ddf99d1e4020bbc Sebastian Thiel <byronimo@gmail.com> 1288205467 +0200 commit: Fixed bug that would cause the author's email to be a generic default one, instead of the existing and valid. The rest of the ConfigParser handling is correct, as it reads all configuration files available to git
+1b6b9510e0724bfcb4250f703ddf99d1e4020bbc 0d5bfb5d6d22f8fe8c940f36e1fbe16738965d5f Sebastian Thiel <byronimo@gmail.com> 1288208986 +0200 commit: index.reset: updated parameter docs, but most importantly, the method now has better testing for the use of paths during reset. The IndexFile now implements this on its own, which also allows for something equivalent to git-reset --hard -- <paths>, which is not possible in the git command for some probably very good reason
+0d5bfb5d6d22f8fe8c940f36e1fbe16738965d5f 702f3909520d39e8c343dece7b1e2d72e1479bbe Sebastian Thiel <byronimo@gmail.com> 1289032478 +0100 checkout: moving from master to integration
+702f3909520d39e8c343dece7b1e2d72e1479bbe 0d5bfb5d6d22f8fe8c940f36e1fbe16738965d5f Sebastian Thiel <byronimo@gmail.com> 1289032798 +0100 checkout: moving from integration to master
+0d5bfb5d6d22f8fe8c940f36e1fbe16738965d5f 735b28bc65964da5b181dffcccb1d05555b5acab Sebastian Thiel <byronimo@gmail.com> 1289033220 +0100 commit: test_refs: fixed failing tests just by making it less strict. It is dependent on the setup of the surrounding repository, hence the amount of ref-types found is actually variable, as long as they get more
+735b28bc65964da5b181dffcccb1d05555b5acab 702f3909520d39e8c343dece7b1e2d72e1479bbe Sebastian Thiel <byronimo@gmail.com> 1289033228 +0100 checkout: moving from master to integration
+702f3909520d39e8c343dece7b1e2d72e1479bbe b14a52ae2f8d6e38f57c34f8be150541cf00dafa Sebastian Thiel <byronimo@gmail.com> 1289034355 +0100 commit: Some cleanup of Daniels contribution. Now it appears to be ready for a merge
+b14a52ae2f8d6e38f57c34f8be150541cf00dafa 90d73cd6ffa6e848da59cb2a35dec74e0fabd00a Sebastian Thiel <byronimo@gmail.com> 1289034615 +0100 commit (amend): Some cleanup of Daniels contribution. Now it appears to be ready for a merge
+90d73cd6ffa6e848da59cb2a35dec74e0fabd00a 7bfca5efce8988e6070e7284bd409d1a731a3fbc Sebastian Thiel <byronimo@gmail.com> 1289034647 +0100 checkout: moving from integration to 0.1
+7bfca5efce8988e6070e7284bd409d1a731a3fbc 90d73cd6ffa6e848da59cb2a35dec74e0fabd00a Sebastian Thiel <byronimo@gmail.com> 1289034656 +0100 merge integration: Fast-forward
+90d73cd6ffa6e848da59cb2a35dec74e0fabd00a 735b28bc65964da5b181dffcccb1d05555b5acab Sebastian Thiel <byronimo@gmail.com> 1289034706 +0100 checkout: moving from 0.1 to master
+735b28bc65964da5b181dffcccb1d05555b5acab bd7fb976ab0607592875b5697dc76c117a18dc73 Sebastian Thiel <byronimo@gmail.com> 1289034759 +0100 commit (amend): test_refs: fixed failing tests just by making it less strict. It is dependent on the setup of the surrounding repository, hence the amount of ref-types found is actually variable, as long as they get more
+bd7fb976ab0607592875b5697dc76c117a18dc73 258403da9c2a087b10082d26466528fce3de38d4 Sebastian Thiel <byronimo@gmail.com> 1289338336 +0100 checkout: moving from master to 0.3.0-beta2
+258403da9c2a087b10082d26466528fce3de38d4 bd7fb976ab0607592875b5697dc76c117a18dc73 Sebastian Thiel <byronimo@gmail.com> 1289338796 +0100 checkout: moving from 258403da9c2a087b10082d26466528fce3de38d4 to master
+bd7fb976ab0607592875b5697dc76c117a18dc73 a1d1d2cb421f16bd277d7c4ce88398ff0f5afb29 Sebastian Thiel <byronimo@gmail.com> 1289379557 +0100 commit: tutorial: Fixed incorrect initialization code for bare repo, thank you, Bryan Bishop
+a1d1d2cb421f16bd277d7c4ce88398ff0f5afb29 a1d1d2cb421f16bd277d7c4ce88398ff0f5afb29 Sebastian Thiel <byronimo@gmail.com> 1289385325 +0100 checkout: moving from master to submodule
+a1d1d2cb421f16bd277d7c4ce88398ff0f5afb29 a1e2f63e64875a29e8c01a7ae17f5744680167a5 Sebastian Thiel <byronimo@gmail.com> 1289817434 +0100 commit: submodule: Fleshed out interface, and a partial test which is not yet usable. It showed that the ConfigParser needs some work. If the root is set, it also needs to refer to the root_commit instead of to the root-tree, as it will have to decide whether it works on the working tree's version of the .gitmodules file or the one in the repository
+a1e2f63e64875a29e8c01a7ae17f5744680167a5 4d36f8ff4d1274a8815e932285ad6dbd6b2888af Sebastian Thiel <byronimo@gmail.com> 1289819639 +0100 commit: Improved GitConfigurationParser to better deal with streams and the corresponding locks. Submodule class now operates on parent_commits, the configuration is either streamed from the repository or written directly into a blob ( or file ) dependending on whether we have a working tree checkout or not which matches our parent_commit
+4d36f8ff4d1274a8815e932285ad6dbd6b2888af 00ce31ad308ff4c7ef874d2fa64374f47980c85c Sebastian Thiel <byronimo@gmail.com> 1289836392 +0100 commit: Objects: Constructor now manually checks and sets the input arguments to the local cache - previously a procedural approach was used, which was less code, but slower too. Especially in case of CommitObjects unrolling the loop manually makes a difference.
+00ce31ad308ff4c7ef874d2fa64374f47980c85c f97653aa06cf84bcf160be3786b6fce49ef52961 Sebastian Thiel <byronimo@gmail.com> 1289842964 +0100 commit: Repo: added submodule query and iteration methods similar to the ones provided for Remotes, including test
+f97653aa06cf84bcf160be3786b6fce49ef52961 624556eae1c292a1dc283d9dca1557e28abe8ee3 Sebastian Thiel <byronimo@gmail.com> 1289844233 +0100 commit: Optimized test-decorators, by completely removing with_bare_rw_repo, which was mainly copy-paste from with_rw_repo, what a shame
+624556eae1c292a1dc283d9dca1557e28abe8ee3 ceee7d7e0d98db12067744ac3cd0ab3a49602457 Sebastian Thiel <byronimo@gmail.com> 1289855525 +0100 commit: Added partial implementation of update, but realized that using refs in general may be contradicting if a tag is given there, as well as a commit sha of the submodule. Hence it should really be only a branch
+ceee7d7e0d98db12067744ac3cd0ab3a49602457 d923bce2a8964541cf804428ccf3953ebbbdcf7d Sebastian Thiel <byronimo@gmail.com> 1289863093 +0100 commit: Submodule now only supports branches to be given as hint that will svn-external like behaviour. Implemented first version of update, which works for now, but probably needs to see more features
+d923bce2a8964541cf804428ccf3953ebbbdcf7d d4fd7fca515ba9b088a7c811292f76f47d16cd7b Sebastian Thiel <byronimo@gmail.com> 1289863587 +0100 commit (amend): Submodule now only supports branches to be given as hint that will svn-external like behaviour. Implemented first version of update, which works for now, but probably needs to see more features
+d4fd7fca515ba9b088a7c811292f76f47d16cd7b af5abca21b56fcf641ff916bd567680888c364aa Sebastian Thiel <byronimo@gmail.com> 1289896210 +0100 commit: Added a few utility methods and improved the test. Refs need an improvement though to allow easy configuration of branch-specific settings
+af5abca21b56fcf641ff916bd567680888c364aa 38b81ad137e5f5486ce97a35702c84b9f869ccef Sebastian Thiel <byronimo@gmail.com> 1289901931 +0100 commit: remote: added methods to set and query the tracking branch status of normal heads, including test.
+38b81ad137e5f5486ce97a35702c84b9f869ccef 9f73e8ba55f33394161b403bf7b8c2e0e05f47b0 Sebastian Thiel <byronimo@gmail.com> 1289901972 +0100 commit (amend): remote: added methods to set and query the tracking branch status of normal heads, including test.
+9f73e8ba55f33394161b403bf7b8c2e0e05f47b0 3035781875f3004734ff5fe3be77f66b3cef299e Sebastian Thiel <byronimo@gmail.com> 1289903243 +0100 commit: Improved efficiency of the submodule.update process, improved test
+3035781875f3004734ff5fe3be77f66b3cef299e 21b4db556619db2ef25f0e0d90fef7e38e6713e5 Sebastian Thiel <byronimo@gmail.com> 1289903575 +0100 commit (amend): Improved efficiency of the submodule.update process, improved test
+21b4db556619db2ef25f0e0d90fef7e38e6713e5 78d2cd65b8b778f3b0cfef5268b0684314ca22ef Sebastian Thiel <byronimo@gmail.com> 1289905889 +0100 commit: implemented update to_last_revision option including test. Its now possible to update submodules such as svn-externals
+78d2cd65b8b778f3b0cfef5268b0684314ca22ef c750f599a1b05ac855b55abc771729a704119833 Sebastian Thiel <byronimo@gmail.com> 1289924204 +0100 commit: Implemented deletion of submodules including proper tests
+c750f599a1b05ac855b55abc771729a704119833 3d061a1a506b71234f783628ba54a7bdf79bbce9 Sebastian Thiel <byronimo@gmail.com> 1289924802 +0100 commit (amend): Implemented deletion of submodules including proper tests
+3d061a1a506b71234f783628ba54a7bdf79bbce9 98e6edb546116cd98abdc3b37c6744e859bbde5c Sebastian Thiel <byronimo@gmail.com> 1289930487 +0100 commit: Initial implementation of submodule.add without any tests. These are to come next
+98e6edb546116cd98abdc3b37c6744e859bbde5c 33964afb47ce3af8a32e6613b0834e5f94bdfe68 Sebastian Thiel <byronimo@gmail.com> 1289938053 +0100 commit: Added tests for all failure modes of submodule add ( except for one ), and fixed a few issues on the way
+33964afb47ce3af8a32e6613b0834e5f94bdfe68 7b3ef45167e1c2f7d1b7507c13fcedd914f87da9 Sebastian Thiel <byronimo@gmail.com> 1289938869 +0100 commit: The submodule's branch is now a branch instance, not a plain string anymore
+7b3ef45167e1c2f7d1b7507c13fcedd914f87da9 ef48ca5f54fe31536920ec4171596ff8468db5fe Sebastian Thiel <byronimo@gmail.com> 1289950137 +0100 commit: Added rest of submodule.add test code which should be pretty much 100% coverage for it
+ef48ca5f54fe31536920ec4171596ff8468db5fe e84d05f4bbf7090a9802e9cd198d1c383974cb12 Sebastian Thiel <byronimo@gmail.com> 1289989025 +0100 commit: Repo: scetched out submodule_update
+e84d05f4bbf7090a9802e9cd198d1c383974cb12 403c31fe3c7075652c892ecd3b6dc6d321bb1226 Sebastian Thiel <byronimo@gmail.com> 1290001921 +0100 commit: index: Sped up reading and writing of the index file by reducing the amount of attribute lookups considerably
+403c31fe3c7075652c892ecd3b6dc6d321bb1226 b03933057df80ea9f860cc616eb7733f140f866e Sebastian Thiel <byronimo@gmail.com> 1290001937 +0100 commit (amend): index: Sped up reading and writing of the index file by reducing the amount of attribute lookups considerably
+b03933057df80ea9f860cc616eb7733f140f866e a1e6234c27abf041e4c8cd1a799950e7cd9104f6 Sebastian Thiel <byronimo@gmail.com> 1290003888 +0100 commit: Inital implementation of Submodule.move including a very simple and to-be-improved test
+a1e6234c27abf041e4c8cd1a799950e7cd9104f6 abda960de327e922fd9eaa429bef9e92918c8387 Sebastian Thiel <byronimo@gmail.com> 1290010524 +0100 commit: submodule: removed module_path method as it is implemented in the abspath property alrdeady
+abda960de327e922fd9eaa429bef9e92918c8387 609a46a72764dc71104aa5d7b1ca5f53d4237a75 Sebastian Thiel <byronimo@gmail.com> 1290011090 +0100 commit (amend): submodule: removed module_path method as it is implemented in the abspath property alrdeady
+609a46a72764dc71104aa5d7b1ca5f53d4237a75 6066f04d529b04e96295b37b5cceb2556414a472 Sebastian Thiel <byronimo@gmail.com> 1290025995 +0100 commit: repo: Added create_submodule method which fits into the tradition of offering a create_* method for most important entities.
+6066f04d529b04e96295b37b5cceb2556414a472 609a46a72764dc71104aa5d7b1ca5f53d4237a75 Sebastian Thiel <byronimo@gmail.com> 1290026006 +0100 HEAD~1: updating HEAD
+609a46a72764dc71104aa5d7b1ca5f53d4237a75 7cc4d748a132377ffe63534e9777d7541a3253c5 Sebastian Thiel <byronimo@gmail.com> 1290026013 +0100 commit: repo: Added create_submodule method which fits into the tradition of offering a create_* method for most important entities.
+7cc4d748a132377ffe63534e9777d7541a3253c5 1687283c13caf7ff8d1959591541dff6a171ca1e Sebastian Thiel <byronimo@gmail.com> 1290029890 +0100 commit: RootModule.update: initial implementation of update method, which should be able to handle submodule removals, additions, path changes and branch changes. All this still needs to be tested though
+1687283c13caf7ff8d1959591541dff6a171ca1e 9a0c4009edb35bb81d7e41d7d235675ccdfcffba Sebastian Thiel <byronimo@gmail.com> 1290068415 +0100 commit: commit: when creating a new commit and advancing the head, it will now write the ORIG_HEAD reference as well
+9a0c4009edb35bb81d7e41d7d235675ccdfcffba 7a320abc52307b4d4010166bd899ac75024ec9a7 Sebastian Thiel <byronimo@gmail.com> 1290068612 +0100 commit (amend): commit: when creating a new commit and advancing the head, it will now write the ORIG_HEAD reference as well
+7a320abc52307b4d4010166bd899ac75024ec9a7 1185ee2c9cda379bada7e08694f13dc124b27e93 Sebastian Thiel <byronimo@gmail.com> 1290073216 +0100 commit: ORIG_HEAD handling is now implemented in the ref-class itself, instead of being a special case of the commit method; includes tests
+1185ee2c9cda379bada7e08694f13dc124b27e93 82849578e61a7dfb47fc76dcbe18b1e3b6a36951 Sebastian Thiel <byronimo@gmail.com> 1290073599 +0100 commit (amend): ORIG_HEAD handling is now implemented in the ref-class itself, instead of being a special case of the commit method; includes tests
+82849578e61a7dfb47fc76dcbe18b1e3b6a36951 0c1834134ce177cdbd30a56994fcc4bf8f5be8b2 Sebastian Thiel <byronimo@gmail.com> 1290076876 +0100 commit: Added test-setup which can test all aspects of the (smart) update method
+0c1834134ce177cdbd30a56994fcc4bf8f5be8b2 50095005bab7ffae14cb7d2ec8faeee7eed579ee Sebastian Thiel <byronimo@gmail.com> 1290096572 +0100 commit: first update test succeeds, so it verifies that existing repositories can be moved later if the configuration changed
+50095005bab7ffae14cb7d2ec8faeee7eed579ee ca86a09651674d4bd2c22fd7f2f2ae6ca1c1d3d6 Sebastian Thiel <byronimo@gmail.com> 1290097988 +0100 commit (amend): first update test succeeds, so it verifies that existing repositories can be moved later if the configuration changed
+ca86a09651674d4bd2c22fd7f2f2ae6ca1c1d3d6 bf2f7449beafcfb4578d08c90370d3953ff5f073 Sebastian Thiel <byronimo@gmail.com> 1290098006 +0100 commit (amend): first update test succeeds, so it verifies that existing repositories can be moved later if the configuration changed, and actually it also verifies that the url-change is handled correctly (as we changed the url from the default to the local path)
+bf2f7449beafcfb4578d08c90370d3953ff5f073 c0990b2a6dd2e777b46c1685ddb985b3c0ef59a2 Sebastian Thiel <byronimo@gmail.com> 1290098151 +0100 commit (amend): first update test succeeds, so it verifies that existing repositories can be moved later if the configuration changed, and actually it also verifies that the url-change is handled correctly (as we changed the url from the default to the local path)
+c0990b2a6dd2e777b46c1685ddb985b3c0ef59a2 cf5eaddde33e983bc7b496f458bdd49154f6f498 Sebastian Thiel <byronimo@gmail.com> 1290109461 +0100 commit: Updated tests and implementation to verify functionality for handling submodule removals, as well as url changes
+cf5eaddde33e983bc7b496f458bdd49154f6f498 3f2d76ba8e6d004ff5849ed8c7c34f6a4ac2e1e3 Sebastian Thiel <byronimo@gmail.com> 1290112561 +0100 commit: Added test for branch changes - it appears to work well, at least as far as the restricted tests are concerned
+3f2d76ba8e6d004ff5849ed8c7c34f6a4ac2e1e3 ebe8f644e751c1b2115301c1a961bef14d2cce89 Sebastian Thiel <byronimo@gmail.com> 1290114666 +0100 commit: Added test for the recursive code path.
+ebe8f644e751c1b2115301c1a961bef14d2cce89 ebe8f644e751c1b2115301c1a961bef14d2cce89 Sebastian Thiel <byronimo@gmail.com> 1290114835 +0100 checkout: moving from submodule to refactor
+ebe8f644e751c1b2115301c1a961bef14d2cce89 4c34d5c3f2a4ed7194276a026e0ec6437d339c67 Sebastian Thiel <byronimo@gmail.com> 1290116693 +0100 commit: Split big submodule file into smaller files. Tried to manually get imports right, but its not yet tested
+4c34d5c3f2a4ed7194276a026e0ec6437d339c67 9519f186ce757cdba217f222c95c20033d00f91d Sebastian Thiel <byronimo@gmail.com> 1290118223 +0100 commit: Fixed all imports, refactoring appears to be complete
+9519f186ce757cdba217f222c95c20033d00f91d ebe8f644e751c1b2115301c1a961bef14d2cce89 Sebastian Thiel <byronimo@gmail.com> 1290118281 +0100 checkout: moving from refactor to submodule
+ebe8f644e751c1b2115301c1a961bef14d2cce89 7cf2d5fcf0a3db793678dd6ba9fc1c24d4eeb36a Sebastian Thiel <byronimo@gmail.com> 1290118286 +0100 merge refactor: Merge made by recursive.
+7cf2d5fcf0a3db793678dd6ba9fc1c24d4eeb36a a1d1d2cb421f16bd277d7c4ce88398ff0f5afb29 Sebastian Thiel <byronimo@gmail.com> 1290118288 +0100 checkout: moving from submodule to master
+a1d1d2cb421f16bd277d7c4ce88398ff0f5afb29 f1545bd9cd6953c5b39c488bf7fe179676060499 Sebastian Thiel <byronimo@gmail.com> 1290118292 +0100 merge submodule: Merge made by recursive.
+f1545bd9cd6953c5b39c488bf7fe179676060499 f1545bd9cd6953c5b39c488bf7fe179676060499 Sebastian Thiel <byronimo@gmail.com> 1290119272 +0100 checkout: moving from master to docs
+f1545bd9cd6953c5b39c488bf7fe179676060499 75c75fa136f6181f6ba2e52b8b85a98d3fe1718e Sebastian Thiel <byronimo@gmail.com> 1290120222 +0100 commit: Changed name/id of gitdb submodule to something that doesn't look like a path
+75c75fa136f6181f6ba2e52b8b85a98d3fe1718e a25e1d4aa7e5898ab1224d0e5cc5ecfbe8ed8821 Sebastian Thiel <byronimo@gmail.com> 1290122817 +0100 commit: Updated tutorial with a brief introduction to submodules
+a25e1d4aa7e5898ab1224d0e5cc5ecfbe8ed8821 a8014d2ec56fd684dc81478dee73ca7eda0ab8a7 Sebastian Thiel <byronimo@gmail.com> 1290122851 +0100 commit: Updated gitdb submodule, and added note about how the submodule package manages its dependencies
+a8014d2ec56fd684dc81478dee73ca7eda0ab8a7 f1545bd9cd6953c5b39c488bf7fe179676060499 Sebastian Thiel <byronimo@gmail.com> 1290122855 +0100 checkout: moving from docs to master
+f1545bd9cd6953c5b39c488bf7fe179676060499 45c0f285a6d9d9214f8167742d12af2855f527fb Sebastian Thiel <byronimo@gmail.com> 1290122860 +0100 merge docs: Merge made by recursive.
+45c0f285a6d9d9214f8167742d12af2855f527fb 315c303214cef855499f0c7eda46b7ed82dceecb Sebastian Thiel <byronimo@gmail.com> 1290158850 +0100 commit: test_submodule: fixed failures that arose due to changes of the original submodule names. Also, a major bug was fixed that cased submodules to always being updated recursively when using the RootModule.update method
+315c303214cef855499f0c7eda46b7ed82dceecb 7dd618655c96ff32b5c30e41a5406c512bcbb65f Sebastian Thiel <byronimo@gmail.com> 1290158895 +0100 commit (amend): test_submodule: fixed failures that arose due to changes of the original submodule names. Also, a major bug was fixed that cased submodules to always being updated recursively when using the RootModule.update method
+7dd618655c96ff32b5c30e41a5406c512bcbb65f 2ab454f0ccf09773a4f51045329a69fd73559414 Sebastian Thiel <byronimo@gmail.com> 1290188727 +0100 commit: remote: parsing of fetch information now reacts to fatal errors. Previously it would just bump into an assertion
+2ab454f0ccf09773a4f51045329a69fd73559414 b00ad00130389f5b00da9dbfd89c3e02319d2999 Sebastian Thiel <byronimo@gmail.com> 1290196658 +0100 commit: submodule: When adding an existing submodule, when retrieving the binsha, we will now consider not only the tree, but the index too
+b00ad00130389f5b00da9dbfd89c3e02319d2999 8867348ca772cdce7434e76eed141f035b63e928 Sebastian Thiel <byronimo@gmail.com> 1290196804 +0100 commit: Bumped version number to 0.3.1
+8867348ca772cdce7434e76eed141f035b63e928 8d0aa1ef19e2c3babee458bd4504820f415148e0 Sebastian Thiel <byronimo@gmail.com> 1290271885 +0100 commit: Fixed performance tests which broke in the meanwhile - they definitely don't run often enough, which is because they intentionally don't have a package initialization file
+8d0aa1ef19e2c3babee458bd4504820f415148e0 8e0e315a371cdfc80993a1532f938d56ed7acee4 Sebastian Thiel <byronimo@gmail.com> 1290280591 +0100 commit: submodule: Fixed capital error when handling the submodule's branch, which was returned in the submodules super repository, not in the submodule's module
+8e0e315a371cdfc80993a1532f938d56ed7acee4 7c72b9a3eaabbe927ba77d4f69a62f35fbe60e2e Sebastian Thiel <byronimo@gmail.com> 1290286993 +0100 merge gitorious/win32: Merge made by recursive.
+7c72b9a3eaabbe927ba77d4f69a62f35fbe60e2e 7c72b9a3eaabbe927ba77d4f69a62f35fbe60e2e Sebastian Thiel <byronimo@gmail.com> 1290287857 +0100 checkout: moving from master to osx
+7c72b9a3eaabbe927ba77d4f69a62f35fbe60e2e 6c6223b854e4c7985b08493a027b47f668493832 Sebastian Thiel <byronimo@gmail.com> 1290287908 +0100 commit: testing:added special case for osx to solve a special issue with the temp directory
+6c6223b854e4c7985b08493a027b47f668493832 20b07fa542d2376a287435a26c967a5ee104667f Sebastian Thiel <byronimo@gmail.com> 1290288287 +0100 commit (amend): testing:added special case for osx to solve a special issue with the temp directory
+20b07fa542d2376a287435a26c967a5ee104667f 7c72b9a3eaabbe927ba77d4f69a62f35fbe60e2e Sebastian Thiel <byronimo@gmail.com> 1290288327 +0100 checkout: moving from osx to master
+7c72b9a3eaabbe927ba77d4f69a62f35fbe60e2e 517ae56f517f5e7253f878dd1dc3c7c49f53df1a Sebastian Thiel <byronimo@gmail.com> 1290288333 +0100 merge osx: Merge made by recursive.
+517ae56f517f5e7253f878dd1dc3c7c49f53df1a 22a88a7ec38e29827264f558f0c1691b99102e23 Sebastian Thiel <byronimo@gmail.com> 1290289085 +0100 commit: fixed performance tests ... again, previously I was just working on an incorrect repository
+22a88a7ec38e29827264f558f0c1691b99102e23 685760ab33b8f9d7455b18a9ecb8c4c5b3315d66 Sebastian Thiel <byronimo@gmail.com> 1290342054 +0100 commit: Added zip_safe info to setup.py file
+685760ab33b8f9d7455b18a9ecb8c4c5b3315d66 9d6310db456de9952453361c860c3ae61b8674ea Sebastian Thiel <byronimo@gmail.com> 1290342681 +0100 commit: docs: added final docs for version 0.3.0, started new release 0.3.1
+9d6310db456de9952453361c860c3ae61b8674ea 0b813371f5a8af95152cae109d28c7c97bfaf79f Sebastian Thiel <byronimo@gmail.com> 1290358083 +0100 commit: Fixed API reference docs as far as possible
+0b813371f5a8af95152cae109d28c7c97bfaf79f 0b813371f5a8af95152cae109d28c7c97bfaf79f Sebastian Thiel <byronimo@gmail.com> 1290363019 +0100 checkout: moving from master to structure
+0b813371f5a8af95152cae109d28c7c97bfaf79f fafe8a77db75083de3e7af92185ecdb7f2d542d3 Sebastian Thiel <byronimo@gmail.com> 1290363468 +0100 commit: moved all contents, incl. submodule gitdb, up to the root directory
+fafe8a77db75083de3e7af92185ecdb7f2d542d3 e6019e16d5a74dc49eb7129ee7fd78b4de51dac2 Sebastian Thiel <byronimo@gmail.com> 1290363544 +0100 commit: flattened test folder structure, didn't adjust any file content yet
+e6019e16d5a74dc49eb7129ee7fd78b4de51dac2 83a9e4a0dad595188ff3fb35bc3dfc4d931eff6d Sebastian Thiel <byronimo@gmail.com> 1290366107 +0100 commit: Fixed setup script to work with changed folder structure
+83a9e4a0dad595188ff3fb35bc3dfc4d931eff6d 557800a1eba3b9cface0f319d8e6aa6bd2ec188d Sebastian Thiel <byronimo@gmail.com> 1290367011 +0100 commit: Updated MANIFEST and setup to include fixtures. Adjusted includes in all tests to work with the new directory structure
+557800a1eba3b9cface0f319d8e6aa6bd2ec188d 9ca0f897376e765989e92e44628228514f431458 Sebastian Thiel <byronimo@gmail.com> 1290371673 +0100 commit (amend): Updated MANIFEST and setup to include fixtures. Adjusted includes in all tests to work with the new directory structure
+9ca0f897376e765989e92e44628228514f431458 0b813371f5a8af95152cae109d28c7c97bfaf79f Sebastian Thiel <byronimo@gmail.com> 1290372294 +0100 checkout: moving from structure to master
+0b813371f5a8af95152cae109d28c7c97bfaf79f 9ca0f897376e765989e92e44628228514f431458 Sebastian Thiel <byronimo@gmail.com> 1290372302 +0100 checkout: moving from master to structure
+9ca0f897376e765989e92e44628228514f431458 6befb28efd86556e45bb0b213bcfbfa866cac379 Sebastian Thiel <byronimo@gmail.com> 1290372430 +0100 commit: updated changelog
+6befb28efd86556e45bb0b213bcfbfa866cac379 0b813371f5a8af95152cae109d28c7c97bfaf79f Sebastian Thiel <byronimo@gmail.com> 1290372432 +0100 checkout: moving from structure to master
+0b813371f5a8af95152cae109d28c7c97bfaf79f 94140bbfc523ae13e1e8045ebfed8a76fe0a1872 Sebastian Thiel <byronimo@gmail.com> 1290372438 +0100 merge structure: Merge made by recursive.
+94140bbfc523ae13e1e8045ebfed8a76fe0a1872 d01b428dbac4103b4f7d7b8fca32e01f70746c53 Sebastian Thiel <byronimo@gmail.com> 1290372442 +0100 commit (amend): !!WARNING!!: Directory structure changed, see commit message for instructions
+d01b428dbac4103b4f7d7b8fca32e01f70746c53 db3423d1eab11d00c5475e36eae8952512b07f4e Sebastian Thiel <byronimo@gmail.com> 1290373147 +0100 commit (amend): !**WARNING**!: Directory structure changed, see commit message for instructions
+db3423d1eab11d00c5475e36eae8952512b07f4e 5ed5b2011ec7cf72f19e6d53b588eea4adca68e5 Sebastian Thiel <byronimo@gmail.com> 1290373168 +0100 commit (amend): *!*WARNING*!*: Directory structure changed, see commit message for instructions
+5ed5b2011ec7cf72f19e6d53b588eea4adca68e5 470d4a7cc865d2702c326d9d1d1b0ab7afb49f0e Sebastian Thiel <byronimo@gmail.com> 1290373186 +0100 commit (amend): !##WARNING##!: Directory structure changed, see commit message for instructions
+470d4a7cc865d2702c326d9d1d1b0ab7afb49f0e e088424eb01bd47c6f0d313f465a21ee742e6f4a Sebastian Thiel <byronimo@gmail.com> 1290373209 +0100 commit (amend): If you use git-python as a submodule of your own project, which alters the sys.path to import it,
+e088424eb01bd47c6f0d313f465a21ee742e6f4a 48a17c87c15b2fa7ce2e84afa09484f354d57a39 Sebastian Thiel <byronimo@gmail.com> 1290373245 +0100 commit (amend): -#######->WARNING<-####### Directory structure changed, see commit message
+48a17c87c15b2fa7ce2e84afa09484f354d57a39 fca367548e365f93c58c47dea45507025269f59a Sebastian Thiel <byronimo@gmail.com> 1290374761 +0100 commit: Changed version to 0.3.1 (removed beta1) so that other projects can actually depend on git-python using the setuptools. Previously it would claim the version did not exist, probably because the setuptools are just comparing strings
+fca367548e365f93c58c47dea45507025269f59a fca367548e365f93c58c47dea45507025269f59a Sebastian Thiel <byronimo@gmail.com> 1290435685 +0100 checkout: moving from master to refs
+fca367548e365f93c58c47dea45507025269f59a dec4663129f72321a14efd6de63f14a7419e3ed2 Sebastian Thiel <byronimo@gmail.com> 1290500057 +0100 commit: Split ref implementation up into multiple files, to make room for the log implementation
+dec4663129f72321a14efd6de63f14a7419e3ed2 fca367548e365f93c58c47dea45507025269f59a Sebastian Thiel <byronimo@gmail.com> 1290500094 +0100 checkout: moving from refs to master
+fca367548e365f93c58c47dea45507025269f59a dec4663129f72321a14efd6de63f14a7419e3ed2 Sebastian Thiel <byronimo@gmail.com> 1290500104 +0100 checkout: moving from master to refs
+dec4663129f72321a14efd6de63f14a7419e3ed2 739fa140235cc9d65c632eaf1f5cacc944d87cfb Sebastian Thiel <byronimo@gmail.com> 1290501284 +0100 commit: Fixed remaining tests - lets hope that everything is indeed working correctly - as imports changed, every line of code needs to be run to assure all names can be resolved
+739fa140235cc9d65c632eaf1f5cacc944d87cfb d89b2cbcd57ecd5600ecf0202b396141c1a856a3 Sebastian Thiel <byronimo@gmail.com> 1290512134 +0100 commit: Initial interface including some of the implementation of the RefLog. TestCase scetched out for now
+d89b2cbcd57ecd5600ecf0202b396141c1a856a3 6e5aae2fc8c3832bdae1cd5e0a269405fb059231 Sebastian Thiel <byronimo@gmail.com> 1290512159 +0100 commit (amend): Initial interface including some of the implementation of the RefLog. TestCase scetched out for now
diff --git a/test/fixtures/reflog_invalid_date b/test/fixtures/reflog_invalid_date
new file mode 100644
index 00000000..938e4f75
--- /dev/null
+++ b/test/fixtures/reflog_invalid_date
@@ -0,0 +1,2 @@
+501bf602abea7d21c3dbb409b435976e92033145 82b8902e033430000481eb355733cd7065342037 Sebastian Thiel <byronimo@gmail.com> 1270634931 +0200 commit: Used this release for a first beta of the 0.2 branch of development
+82b8902e033430000481eb355733cd7065342037 69361d96a59381fde0ac34d19df2d4aff05fb9a9 Sebastian Thiel <byronimo@gmail.com> 1271229940 commit: conf.py: Adjusted version to match with the actual version
diff --git a/test/fixtures/reflog_invalid_email b/test/fixtures/reflog_invalid_email
new file mode 100644
index 00000000..121096aa
--- /dev/null
+++ b/test/fixtures/reflog_invalid_email
@@ -0,0 +1,2 @@
+501bf602abea7d21c3dbb409b435976e92033145 82b8902e033430000481eb355733cd7065342037 Sebastian Thiel <byronimo@gmail.com> 1270634931 +0200 commit: Used this release for a first beta of the 0.2 branch of development
+82b8902e033430000481eb355733cd7065342037 69361d96a59381fde0ac34d19df2d4aff05fb9a9 Sebastian Thiel <byronimo@gmail. 1271229940 +0200 commit: conf.py: Adjusted version to match with the actual version
diff --git a/test/fixtures/reflog_invalid_newsha b/test/fixtures/reflog_invalid_newsha
new file mode 100644
index 00000000..0d45bb7a
--- /dev/null
+++ b/test/fixtures/reflog_invalid_newsha
@@ -0,0 +1,2 @@
+501bf602abea7d21c3dbb409b435976e92033145 82b8902e033430000481eb355733cd7065342037 Sebastian Thiel <byronimo@gmail.com> 1270634931 +0200 commit: Used this release for a first beta of the 0.2 branch of development
+82b8902e033430000481eb355733cd7065342037 69361d96a59381fde0ac34d19df2d Sebastian Thiel <byronimo@gmail.com> 1271229940 +0200 commit: conf.py: Adjusted version to match with the actual version
diff --git a/test/fixtures/reflog_invalid_oldsha b/test/fixtures/reflog_invalid_oldsha
new file mode 100644
index 00000000..b78605ff
--- /dev/null
+++ b/test/fixtures/reflog_invalid_oldsha
@@ -0,0 +1,2 @@
+501bf602abea7d21c3dbb409b435976e92033145 82b8902e033430000481eb355733cd7065342037 Sebastian Thiel <byronimo@gmail.com> 1270634931 +0200 commit: Used this release for a first beta of the 0.2 branch of development
+82b8902e033430000481eb3 69361d96a59381fde0ac34d19df2d4aff05fb9a9 Sebastian Thiel <byronimo@gmail.com> 1271229940 +0200 commit: conf.py: Adjusted version to match with the actual version
diff --git a/test/fixtures/reflog_invalid_sep b/test/fixtures/reflog_invalid_sep
new file mode 100644
index 00000000..fddcd6e5
--- /dev/null
+++ b/test/fixtures/reflog_invalid_sep
@@ -0,0 +1,2 @@
+501bf602abea7d21c3dbb409b435976e92033145 82b8902e033430000481eb355733cd7065342037 Sebastian Thiel <byronimo@gmail.com> 1270634931 +0200 commit: Used this release for a first beta of the 0.2 branch of development
+82b8902e033430000481eb355733cd7065342037 69361d96a59381fde0ac34d19df2d4aff05fb9a9 Sebastian Thiel <byronimo@gmail.com> 1271229940 +0200 commit: conf.py: Adjusted version to match with the actual version
diff --git a/test/fixtures/reflog_master b/test/fixtures/reflog_master
new file mode 100644
index 00000000..2fa13e21
--- /dev/null
+++ b/test/fixtures/reflog_master
@@ -0,0 +1,124 @@
+501bf602abea7d21c3dbb409b435976e92033145 82b8902e033430000481eb355733cd7065342037 Sebastian Thiel <byronimo@gmail.com> 1270634931 +0200 commit: Used this release for a first beta of the 0.2 branch of development
+82b8902e033430000481eb355733cd7065342037 69361d96a59381fde0ac34d19df2d4aff05fb9a9 Sebastian Thiel <byronimo@gmail.com> 1271229940 +0200 commit: conf.py: Adjusted version to match with the actual version
+69361d96a59381fde0ac34d19df2d4aff05fb9a9 0d6ceabf5b90e7c0690360fc30774d36644f563c Sebastian Thiel <byronimo@gmail.com> 1272614247 +0200 merge integration: Fast-forward
+22a0289972b365b7912340501b52ca3dd98be289 143b927307d46ccb8f1cc095739e9625c03c82ff Sebastian Thiel <byronimo@gmail.com> 1272988814 +0200 commit: TODO: Removed all entries but left a mesage about where to find the issuee on lighthouse.
+143b927307d46ccb8f1cc095739e9625c03c82ff e41c727be8dbf8f663e67624b109d9f8b135a4ab Sebastian Thiel <byronimo@gmail.com> 1273140152 +0200 commit: README: Added mailing list and issue tracker information
+c083f3d0b853e723d0d4b00ff2f1ec5f65f05cba de5bc8f7076c5736ef1efa57345564fbc563bd19 Sebastian Thiel <byronimo@gmail.com> 1273522570 +0200 commit: Handle filenames with embedded spaces when generating diffs
+de5bc8f7076c5736ef1efa57345564fbc563bd19 8caeec1b15645fa53ec5ddc6e990e7030ffb7c5a Sebastian Thiel <byronimo@gmail.com> 1273529174 +0200 commit: IndexFile.add: Fixed incorrect path handling if path rewriting was desired and absolute paths were given
+600fcbc1a2d723f8d51e5f5ab6d9e4c389010e1c 1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af Sebastian Thiel <byronimo@gmail.com> 1274811103 +0200 commit: diff: by limiting the splitcount to 5, a subtle bug was introduced as the newline at the end of the split line was not split away automatically. Added test for this, and the trivial fix
+1019d4cf68d1acdbb4d6c1abb7e71ac9c0f581af 17af1f64d5f1e62d40e11b75b1dd48e843748b49 Sebastian Thiel <byronimo@gmail.com> 1274877948 +0200 commit: BlockingLockFile: added sanity check that raises IOError if the directory containing the lock was removed. This is unlikely to happen in a production envrironment, but may happen during testing, as folders are moved/deleted once the test is complete. Daemons might still be waiting for something, and they should be allowed to terminate instead of waiting for a possibly long time
+17af1f64d5f1e62d40e11b75b1dd48e843748b49 34ba8ffba0b3b4d21da7bcea594cc3631e422142 Sebastian Thiel <byronimo@gmail.com> 1274906080 +0200 commit: refs: a Reference can now be created by assigning a commit or object (for convenience)
+34ba8ffba0b3b4d21da7bcea594cc3631e422142 11dc82538cc1ebb537c866c8e76146e384cdfe24 Sebastian Thiel <byronimo@gmail.com> 1274906333 +0200 commit: refs: a Reference can now be created by assigning a commit or object (for convenience)
+11dc82538cc1ebb537c866c8e76146e384cdfe24 34ba8ffba0b3b4d21da7bcea594cc3631e422142 Sebastian Thiel <byronimo@gmail.com> 1274906338 +0200 HEAD~1: updating HEAD
+34ba8ffba0b3b4d21da7bcea594cc3631e422142 de84cbdd0f9ef97fcd3477b31b040c57192e28d9 Sebastian Thiel <byronimo@gmail.com> 1274906431 +0200 commit (amend): refs: a Reference can now be created by assigning a commit or object (for convenience)
+de84cbdd0f9ef97fcd3477b31b040c57192e28d9 ecf37a1b4c2f70f1fc62a6852f40178bf08b9859 Sebastian Thiel <byronimo@gmail.com> 1274910053 +0200 commit: index: index-add fixed to always append a newline after each item. In git has unified its way it reads from stdin, now it wants all items to be terminated by a newline usually. Previously, it could have been that it really didn't want to have a termination character when the last item was written to the file. Bumped the minimum requirements to 1.7.0 to be sure it is working as I think it will.
+ecf37a1b4c2f70f1fc62a6852f40178bf08b9859 1ee2afb00afaf77c883501eac8cd614c8229a444 Sebastian Thiel <byronimo@gmail.com> 1274914700 +0200 commit: cmd: By default, on linux, the parent file handles will be closed to leave the child less cluttered, and make it easier to debug as it will only have the file descriptors we set. It appears to be more stable regarding the stdin-is-closed-but-child-doesn't-realize-this issue
+1ee2afb00afaf77c883501eac8cd614c8229a444 bd45e9267ab0d3f37e59ecc8b87d0ad19abad4ad Sebastian Thiel <byronimo@gmail.com> 1275324366 +0200 commit: gitcmd: may now receive extra keyword arguments to be passed directly to the subproces.Popen invocation. It could be used to pass custom environments, without changing the own one
+bd45e9267ab0d3f37e59ecc8b87d0ad19abad4ad 6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e Sebastian Thiel <byronimo@gmail.com> 1275324409 +0200 commit (amend): gitcmd: may now receive extra keyword arguments to be passed directly to the subproces.Popen invocation. It could be used to pass custom environments, without changing the own one (#26)
+6d9b1f4f9fa8c9f030e3207e7deacc5d5f8bba4e e79999c956e2260c37449139080d351db4aa3627 Sebastian Thiel <byronimo@gmail.com> 1275549608 +0200 commit: git.cmd: moved hardcoded chunksize when duplicating stream data into easy-to-change class member variable
+e79999c956e2260c37449139080d351db4aa3627 412632599479a8e5991a07ecb67bc52b85c60755 Sebastian Thiel <byronimo@gmail.com> 1275550524 +0200 commit: git.cmd: using communicate in the main branch of execution, which might not make a big difference, but perhaps its smarter about broken pipes.
+412632599479a8e5991a07ecb67bc52b85c60755 25dca42bac17d511b7e2ebdd9d1d679e7626db5f Sebastian Thiel <byronimo@gmail.com> 1275550670 +0200 commit (amend): git.cmd: using communicate in the main branch of execution, which might not make a big difference, but perhaps its smarter about broken pipes.
+25dca42bac17d511b7e2ebdd9d1d679e7626db5f 6fbb69306c0e14bacb8dcb92a89af27d3d5d631f Sebastian Thiel <byronimo@gmail.com> 1275665431 +0200 commit (merge): Merge branch 'odb'
+6fbb69306c0e14bacb8dcb92a89af27d3d5d631f a243827ab3346e188e99db2f9fc1f916941c9b1a Sebastian Thiel <byronimo@gmail.com> 1275685591 +0200 commit: Implemented stream tests, found a bug on the way, slowly a test-framework for streams starts to show up, but its not yet there
+a243827ab3346e188e99db2f9fc1f916941c9b1a 7c1169f6ea406fec1e26e99821e18e66437e65eb Sebastian Thiel <byronimo@gmail.com> 1275690001 +0200 commit: Removed compression flag from IStream and OStream types, as a valid object will always be compressed if generated by the system ( even future memory db's will compress it )
+7c1169f6ea406fec1e26e99821e18e66437e65eb c69b6b979e3d6bd01ec40e75b92b21f7a391f0ca Sebastian Thiel <byronimo@gmail.com> 1275746174 +0200 commit: Added basic channel implementation including test
+c69b6b979e3d6bd01ec40e75b92b21f7a391f0ca 7c1169f6ea406fec1e26e99821e18e66437e65eb Sebastian Thiel <byronimo@gmail.com> 1275746196 +0200 HEAD~1: updating HEAD
+7c1169f6ea406fec1e26e99821e18e66437e65eb f91495e271597034226f1b9651345091083172c4 Sebastian Thiel <byronimo@gmail.com> 1276339280 +0200 merge async: Merge made by recursive.
+f91495e271597034226f1b9651345091083172c4 5c631ca192848fed3068b31b1389cd92a0c0cdca Sebastian Thiel <byronimo@gmail.com> 1276340638 +0200 commit: Removed async from this repository, put it into own one which now comes in as external, using a git-submodule
+5c631ca192848fed3068b31b1389cd92a0c0cdca f91495e271597034226f1b9651345091083172c4 Sebastian Thiel <byronimo@gmail.com> 1276345979 +0200 HEAD~1: updating HEAD
+f91495e271597034226f1b9651345091083172c4 86ea63504f3e8a74cfb1d533be9d9602d2d17e27 Sebastian Thiel <byronimo@gmail.com> 1276346049 +0200 commit: Removed async from tree
+86ea63504f3e8a74cfb1d533be9d9602d2d17e27 6c1faef799095f3990e9970bc2cb10aa0221cf9c Sebastian Thiel <byronimo@gmail.com> 1276356043 +0200 commit: Removed odb from project, it is now used as a submodule named gitdb, which was added instead
+6c1faef799095f3990e9970bc2cb10aa0221cf9c 28ed48c93f4cc8b6dd23c951363e5bd4e6880992 Sebastian Thiel <byronimo@gmail.com> 1276503381 +0200 commit: Implemented initial version of tree serialization which appears to work according to a simple test
+28ed48c93f4cc8b6dd23c951363e5bd4e6880992 fe5289ed8311fecf39913ce3ae86b1011eafe5f7 Sebastian Thiel <byronimo@gmail.com> 1276506168 +0200 commit: tree now uses less memory for its cache as it stores the bare deserialized information - this also speeds up later serialization after changes. its clear though that retrieving actual objects is slower currently as these are not cached anymore. Its worth thinking about moving these encoding, decoding routines to gitdb
+fe5289ed8311fecf39913ce3ae86b1011eafe5f7 f8dabbf4f92a7023181777e9d40355562474f71a Sebastian Thiel <byronimo@gmail.com> 1276512508 +0200 commit: tree: added TreeModifier, allowing to adjust existing trees safely and or fast, while staying compatible with serialization which requires it to be sorted
+f8dabbf4f92a7023181777e9d40355562474f71a d9240918aa03e49feabe43af619019805ac76786 Sebastian Thiel <byronimo@gmail.com> 1276512707 +0200 commit (amend): tree: added TreeModifier, allowing to adjust existing trees safely and or fast, while staying compatible with serialization which requires it to be sorted
+d9240918aa03e49feabe43af619019805ac76786 38b3cfb9b24a108e0720f7a3f8d6355f7e0bb1a9 Sebastian Thiel <byronimo@gmail.com> 1276527612 +0200 merge index: Merge made by recursive.
+38b3cfb9b24a108e0720f7a3f8d6355f7e0bb1a9 c9dbf201b4f0b3c2b299464618cb4ecb624d272c Sebastian Thiel <byronimo@gmail.com> 1276529105 +0200 commit: Moved small types that had their own module into the utils module
+c9dbf201b4f0b3c2b299464618cb4ecb624d272c 45e87305bd4f050c2d0309c32fe5de499fc38df3 Sebastian Thiel <byronimo@gmail.com> 1276554725 +0200 commit: Reimplemented Lock handling to be conforming to the git lock protocol, which is actually more efficient than the previous implementation
+45e87305bd4f050c2d0309c32fe5de499fc38df3 06590aee389f4466e02407f39af1674366a74705 Sebastian Thiel <byronimo@gmail.com> 1276555536 +0200 commit (amend): Reimplemented Lock handling to be conforming to the git lock protocol, which is actually more efficient than the previous implementation
+06590aee389f4466e02407f39af1674366a74705 1d2307532d679393ae067326e4b6fa1a2ba5cc06 Sebastian Thiel <byronimo@gmail.com> 1276556905 +0200 commit: Moved LockedFD and its test into the gitdb project
+1d2307532d679393ae067326e4b6fa1a2ba5cc06 e837b901dcfac82e864f806c80f4a9cbfdb9c9f3 Sebastian Thiel <byronimo@gmail.com> 1276607908 +0200 commit: Move LazyMixin type to gitdb, index reading now uses file_contents_ro from gitdb as well
+e837b901dcfac82e864f806c80f4a9cbfdb9c9f3 b82dbf538ac0d03968a0f5b7e2318891abefafaa Sebastian Thiel <byronimo@gmail.com> 1276870827 +0200 commit: GitCmd implementation of gitdb base moved to git-python where it belongs. Previously it was located in gitdb, which doesn't have any facilities to use the git command
+b82dbf538ac0d03968a0f5b7e2318891abefafaa f164627a85ed7b816759871a76db258515b85678 Sebastian Thiel <byronimo@gmail.com> 1277057845 +0200 commit: db: added pure python git database
+f164627a85ed7b816759871a76db258515b85678 ac62760c52abf28d1fd863f0c0dd48bc4a23d223 Sebastian Thiel <byronimo@gmail.com> 1277117506 +0200 commit: index.add: now uses gitdb.store functionality instead of git-hash-file. The python version is about as fast, but could support multithreading using async
+ac62760c52abf28d1fd863f0c0dd48bc4a23d223 0fdf6c3aaff49494c47aaeb0caa04b3016e10a26 Sebastian Thiel <byronimo@gmail.com> 1277127929 +0200 commit: index: Entries are now using flags internally, instead of reducing the flag information to just the stage ( just to be closer to the git-original )
+0fdf6c3aaff49494c47aaeb0caa04b3016e10a26 0aeb491d3d8f53e07fb21f36251be4880170c5ab Sebastian Thiel <byronimo@gmail.com> 1277129321 +0200 commit: index.add does not need the git clt anymore
+0aeb491d3d8f53e07fb21f36251be4880170c5ab 91725f0fc59aa05ef68ab96e9b29009ce84668a5 Sebastian Thiel <byronimo@gmail.com> 1277129385 +0200 commit (amend): index.add does not need the git clt anymore
+91725f0fc59aa05ef68ab96e9b29009ce84668a5 778234d544b3f58dd415aaf10679d15b01a5281f Sebastian Thiel <byronimo@gmail.com> 1277201033 +0200 merge writetree: Merge made by recursive.
+778234d544b3f58dd415aaf10679d15b01a5281f 57050184f3d962bf91511271af59ee20f3686c3f Sebastian Thiel <byronimo@gmail.com> 1277301014 +0200 merge fromtree: Merge made by recursive.
+57050184f3d962bf91511271af59ee20f3686c3f 129f90aa8d83d9b250c87b0ba790605c4a2bb06a Sebastian Thiel <byronimo@gmail.com> 1277334478 +0200 commit: Multiple partly critical bugfixes related to index handling
+129f90aa8d83d9b250c87b0ba790605c4a2bb06a a1adb421c2ee3e4868ea70d440dd82896219ed8f Sebastian Thiel <byronimo@gmail.com> 1277388148 +0200 commit: aggressive_tree_merge: fixed incorrect handling of one branch, it was just not implemented causing incorrect merge results. Added test to cover this issue
+a1adb421c2ee3e4868ea70d440dd82896219ed8f 55dcc17c331f580b3beeb4d5decf64d3baf94f2e Sebastian Thiel <byronimo@gmail.com> 1277395720 +0200 commit (amend): aggressive_tree_merge: fixed incorrect handling of one branch, it was just not implemented causing incorrect merge results. Added test to cover this issue
+55dcc17c331f580b3beeb4d5decf64d3baf94f2e ca131dd61e26f46f49ee3f70763f994cf9512665 Sebastian Thiel <byronimo@gmail.com> 1277401303 +0200 commit: GitCmdStreamReader: fixed terrible bug which only kicked in if the stream was actually empty. This is a rare case that can happen during stream testing. Theoretically there shouldn't be any empty streams of course, but practically they do exist sometimes ;)
+ca131dd61e26f46f49ee3f70763f994cf9512665 feb1ea0f4aacb9ea6dc4133900e65bf34c0ee02d Sebastian Thiel <byronimo@gmail.com> 1277401306 +0200 commit (amend): GitCmdStreamReader: fixed terrible bug which only kicked in if the stream was actually empty. This is a rare case that can happen during stream testing. Theoretically there shouldn't be any empty streams of course, but practically they do exist sometimes ;); fixed stream.seek implementation, which previously used seek on standard output
+feb1ea0f4aacb9ea6dc4133900e65bf34c0ee02d 402a6c2808db4333217aa300d0312836fd7923bd Sebastian Thiel <byronimo@gmail.com> 1277407147 +0200 commit: IndexFile.add: writing of the index file can now optionally be turned off. The default is to write the physical index, which is the behaviour you would expect
+402a6c2808db4333217aa300d0312836fd7923bd 58fb1187b7b8f1e62d3930bdba9be5aba47a52c6 Sebastian Thiel <byronimo@gmail.com> 1277473196 +0200 merge index: Fast-forward
+58fb1187b7b8f1e62d3930bdba9be5aba47a52c6 8d2239f24f6a54d98201413d4f46256df0d6a5f3 Sebastian Thiel <byronimo@gmail.com> 1277745383 +0200 merge sha20: Merge made by recursive.
+8d2239f24f6a54d98201413d4f46256df0d6a5f3 f1401803ccf7db5d897a5ef4b27e2176627c430e Sebastian Thiel <byronimo@gmail.com> 1277756712 +0200 commit: Fixed performance tests which broke in the course of the sha1-20 byte changes
+f1401803ccf7db5d897a5ef4b27e2176627c430e 6917ae4ce9eaa0f5ea91592988c1ea830626ac3a Sebastian Thiel <byronimo@gmail.com> 1277806256 +0200 commit: Diff: fixed bug that caused a string to end up as a blob mode
+6917ae4ce9eaa0f5ea91592988c1ea830626ac3a fd96cceded27d1372bdc1a851448d2d8613f60f3 Sebastian Thiel <byronimo@gmail.com> 1277999899 +0200 merge docs: Merge made by recursive.
+fd96cceded27d1372bdc1a851448d2d8613f60f3 f683c6623f73252645bb2819673046c9d397c567 Sebastian Thiel <byronimo@gmail.com> 1278082451 +0200 commit: Fixed broken 0.2 documentation, it didn't contain the API reference previously due to import errors and a somewhat inconsistent working tree that occurred when switching branches ...
+f683c6623f73252645bb2819673046c9d397c567 a4287f65878000b42d11704692f9ea3734014b4c Sebastian Thiel <byronimo@gmail.com> 1278092317 +0200 commit: win32 compatability adjustments
+a4287f65878000b42d11704692f9ea3734014b4c ca288d443f4fc9d790eecb6e1cdf82b6cdd8dc0d Sebastian Thiel <byronimo@gmail.com> 1278517416 +0200 merge revparse: Merge made by recursive.
+ca288d443f4fc9d790eecb6e1cdf82b6cdd8dc0d 5fd6cc37fd07c25cb921b77b4f658b7e8fc132b3 Sebastian Thiel <byronimo@gmail.com> 1278536545 +0200 commit: Adjusted clone method to allow static classmethod clone ( using clone_from ) as well as the previous instance method clone to keep it compatible
+5fd6cc37fd07c25cb921b77b4f658b7e8fc132b3 76af62b3c5a26638fcad9a3fe401fba566fb7037 Sebastian Thiel <byronimo@gmail.com> 1278538933 +0200 commit (amend): Adjusted clone method to allow static classmethod clone ( using clone_from ) as well as the previous instance method clone to keep it compatible
+76af62b3c5a26638fcad9a3fe401fba566fb7037 b425301ad16f265157abdaf47f7af1c1ea879068 Sebastian Thiel <byronimo@gmail.com> 1278539147 +0200 commit (amend): Adjusted clone method to allow static classmethod clone ( using clone_from ) as well as the previous instance method clone to keep it compatible
+b425301ad16f265157abdaf47f7af1c1ea879068 3288a244428751208394d8137437878277ceb71f Sebastian Thiel <byronimo@gmail.com> 1278582561 +0200 commit: setup.py: fixed requirement - its interesting to see that there are two different keywords for distutils and setuptools, the latter one doesn't read the ones of the first one, unfortunately
+3288a244428751208394d8137437878277ceb71f 08457a7a6b6ad4f518fad0d5bca094a2b5b38fbe Sebastian Thiel <byronimo@gmail.com> 1278670718 +0200 commit: Added python 2.4 support: Repo will now use the original GitCmdObjectDB in python 2.4, as the pure python implementation cannot work without memory maps
+08457a7a6b6ad4f518fad0d5bca094a2b5b38fbe 258403da9c2a087b10082d26466528fce3de38d4 Sebastian Thiel <byronimo@gmail.com> 1278671744 +0200 commit: bumped verison to 0.3.0 beta2
+258403da9c2a087b10082d26466528fce3de38d4 55b67e8194b8b4d9e73e27feadbf9af6593e4600 Sebastian Thiel <byronimo@gmail.com> 1278927490 +0200 pull gitorious master: Fast-forward
+55b67e8194b8b4d9e73e27feadbf9af6593e4600 bcd37b68533d0cceb7e73dd1ed1428fa09f7dc17 Sebastian Thiel <byronimo@gmail.com> 1279007300 +0200 commit: Fixed incorrect use of Blob.data in performance test
+bcd37b68533d0cceb7e73dd1ed1428fa09f7dc17 24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 Sebastian Thiel <byronimo@gmail.com> 1279110447 +0200 commit: Added performance test to compare inst.__class__() vs type(inst)() class. The first one is faster, although I would have expected the latter one to be faster
+24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 a64c5f23c38f06c37a0ca64796368019dfb0d818 Sebastian Thiel <byronimo@gmail.com> 1279130658 +0200 commit: Correct Repo documentation in API reference
+a64c5f23c38f06c37a0ca64796368019dfb0d818 24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 Sebastian Thiel <byronimo@gmail.com> 1279130719 +0200 HEAD~1: updating HEAD
+24740f22c59c3bcafa7b2c1f2ec997e4e14f3615 17a172920fde8c6688c8a1a39f258629b8b73757 Sebastian Thiel <byronimo@gmail.com> 1279131269 +0200 commit: Fixed the missing Repo type documentation thanks to a hint of gasche, fixed a few more resT syntax errors on the way
+17a172920fde8c6688c8a1a39f258629b8b73757 cbb58869063fe803d232f099888fe9c23510de7b Sebastian Thiel <byronimo@gmail.com> 1279197254 +0200 merge gitorious/master: Fast-forward
+cbb58869063fe803d232f099888fe9c23510de7b 89422841e46efa99bda49acfbe33ee1ca5122845 Sebastian Thiel <byronimo@gmail.com> 1279533542 +0200 pull gitorious master: Fast-forward
+89422841e46efa99bda49acfbe33ee1ca5122845 192472f9673b18c91ce618e64e935f91769c50e7 Sebastian Thiel <byronimo@gmail.com> 1279814094 +0200 merge gitorious/master: Fast-forward
+192472f9673b18c91ce618e64e935f91769c50e7 fa3fce80aeb57299633535b9e1c9d08db710ff05 Sebastian Thiel <byronimo@gmail.com> 1281701051 +0200 commit: unicode handling in messages and trees was improved. Messages are now written according to the encoding of the commit object, and decoded using that information as well. Trees will encode and decode their names with utf8
+fa3fce80aeb57299633535b9e1c9d08db710ff05 394ed7006ee5dc8bddfd132b64001d5dfc0ffdd3 Sebastian Thiel <byronimo@gmail.com> 1281702078 +0200 commit (amend): unicode handling in messages and trees was improved. Messages are now written according to the encoding of the commit object, and decoded using that information as well. Trees will encode and decode their names with utf8
+394ed7006ee5dc8bddfd132b64001d5dfc0ffdd3 c4d5caa79e6d88bb3f98bfbefa3bfa039c7e157a Sebastian Thiel <byronimo@gmail.com> 1283969691 +0200 merge integration: Fast-forward
+c4d5caa79e6d88bb3f98bfbefa3bfa039c7e157a 741dfaadf732d4a2a897250c006d5ef3d3cd9f3a Sebastian Thiel <byronimo@gmail.com> 1287134990 +0200 commit: Fixed bug in http://byronimo.lighthouseapp.com/projects/51787/tickets/44-remoteref-fails-when-there-is-character-in-the-name using supplied patch ( which was manually applied ).
+741dfaadf732d4a2a897250c006d5ef3d3cd9f3a fc650aa6869639548435ce2760d42c9cdd909d99 Sebastian Thiel <byronimo@gmail.com> 1287135891 +0200 commit: Added test to verify the actor class can handle unicode names correctly. This works because regex can handle unicode, and will return unicode instances instead of strings if required. Its quite amazing actually.
+fc650aa6869639548435ce2760d42c9cdd909d99 741dfaadf732d4a2a897250c006d5ef3d3cd9f3a Sebastian Thiel <byronimo@gmail.com> 1287136504 +0200 HEAD~1: updating HEAD
+741dfaadf732d4a2a897250c006d5ef3d3cd9f3a a88173281ec56cb378a293d0170e11a1bda96a55 Sebastian Thiel <byronimo@gmail.com> 1287138898 +0200 merge unicode: Merge made by recursive.
+a88173281ec56cb378a293d0170e11a1bda96a55 741dfaadf732d4a2a897250c006d5ef3d3cd9f3a Sebastian Thiel <byronimo@gmail.com> 1287139082 +0200 HEAD~1: updating HEAD
+741dfaadf732d4a2a897250c006d5ef3d3cd9f3a 13647590f96fb5a22cb60f12c5a70e00065a7f3a Sebastian Thiel <byronimo@gmail.com> 1287139254 +0200 merge unicode: Merge made by recursive.
+13647590f96fb5a22cb60f12c5a70e00065a7f3a 94029ce1420ced83c3e5dcd181a2280b26574bc9 Sebastian Thiel <byronimo@gmail.com> 1287139994 +0200 commit: Adjusted regex to support whitespace - it was a little restrictive previously, although there was absolutely no need for that.
+94029ce1420ced83c3e5dcd181a2280b26574bc9 8858a63cb33319f3e739edcbfafdae3ec0fefa33 Sebastian Thiel <byronimo@gmail.com> 1288000691 +0200 commit: .gitignore will now ignore netbeans projects
+8858a63cb33319f3e739edcbfafdae3ec0fefa33 a2b9ded87baf0f32ae94c10c5851a0468a45f003 Sebastian Thiel <byronimo@gmail.com> 1288198935 +0200 commit: docs: untracked_files is a property, but was used like a function, see http://groups.google.com/group/git-python/browse_thread/thread/84ed1835e26a5296?hl=en
+a2b9ded87baf0f32ae94c10c5851a0468a45f003 8858a63cb33319f3e739edcbfafdae3ec0fefa33 Sebastian Thiel <byronimo@gmail.com> 1288198984 +0200 HEAD~1: updating HEAD
+8858a63cb33319f3e739edcbfafdae3ec0fefa33 148eb761aeaa4c3913e1766db0a7df0a5b5c8b20 Sebastian Thiel <byronimo@gmail.com> 1288198991 +0200 commit: docs: untracked_files is a property, but was used like a function, see http://groups.google.com/group/git-python/browse_thread/thread/84ed1835e26a5296?hl=en
+148eb761aeaa4c3913e1766db0a7df0a5b5c8b20 8858a63cb33319f3e739edcbfafdae3ec0fefa33 Sebastian Thiel <byronimo@gmail.com> 1288199023 +0200 HEAD~1: updating HEAD
+8858a63cb33319f3e739edcbfafdae3ec0fefa33 538e8265e04f69bb9bd73a10ddb4e8e9677fb140 Sebastian Thiel <byronimo@gmail.com> 1288199049 +0200 commit: docs: untracked_files is a property, but was used like a function, see http://groups.google.com/group/git-python/browse_thread/thread/84ed1835e26a5296?hl=en
+538e8265e04f69bb9bd73a10ddb4e8e9677fb140 97ab197140b16027975c7465a5e8786e6cc8fea1 Sebastian Thiel <byronimo@gmail.com> 1288203452 +0200 commit (amend): docs: untracked_files is a property, but was used like a function, see http://groups.google.com/group/git-python/browse_thread/thread/84ed1835e26a5296?hl=en
+97ab197140b16027975c7465a5e8786e6cc8fea1 3da3837fe2ec8152e1460f747d18290b52304868 Sebastian Thiel <byronimo@gmail.com> 1288203532 +0200 commit: cmd: improved error handling and debug printing
+3da3837fe2ec8152e1460f747d18290b52304868 2c0b92e40ece170b59bced0cea752904823e06e7 Sebastian Thiel <byronimo@gmail.com> 1288203543 +0200 commit (amend): cmd: improved error handling and debug printing
+2c0b92e40ece170b59bced0cea752904823e06e7 1b6b9510e0724bfcb4250f703ddf99d1e4020bbc Sebastian Thiel <byronimo@gmail.com> 1288205467 +0200 commit: Fixed bug that would cause the author's email to be a generic default one, instead of the existing and valid. The rest of the ConfigParser handling is correct, as it reads all configuration files available to git
+1b6b9510e0724bfcb4250f703ddf99d1e4020bbc 0d5bfb5d6d22f8fe8c940f36e1fbe16738965d5f Sebastian Thiel <byronimo@gmail.com> 1288208986 +0200 commit: index.reset: updated parameter docs, but most importantly, the method now has better testing for the use of paths during reset. The IndexFile now implements this on its own, which also allows for something equivalent to git-reset --hard -- <paths>, which is not possible in the git command for some probably very good reason
+0d5bfb5d6d22f8fe8c940f36e1fbe16738965d5f 735b28bc65964da5b181dffcccb1d05555b5acab Sebastian Thiel <byronimo@gmail.com> 1289033220 +0100 commit: test_refs: fixed failing tests just by making it less strict. It is dependent on the setup of the surrounding repository, hence the amount of ref-types found is actually variable, as long as they get more
+735b28bc65964da5b181dffcccb1d05555b5acab bd7fb976ab0607592875b5697dc76c117a18dc73 Sebastian Thiel <byronimo@gmail.com> 1289034759 +0100 commit (amend): test_refs: fixed failing tests just by making it less strict. It is dependent on the setup of the surrounding repository, hence the amount of ref-types found is actually variable, as long as they get more
+bd7fb976ab0607592875b5697dc76c117a18dc73 a1d1d2cb421f16bd277d7c4ce88398ff0f5afb29 Sebastian Thiel <byronimo@gmail.com> 1289379557 +0100 commit: tutorial: Fixed incorrect initialization code for bare repo, thank you, Bryan Bishop
+a1d1d2cb421f16bd277d7c4ce88398ff0f5afb29 f1545bd9cd6953c5b39c488bf7fe179676060499 Sebastian Thiel <byronimo@gmail.com> 1290118292 +0100 merge submodule: Merge made by recursive.
+f1545bd9cd6953c5b39c488bf7fe179676060499 45c0f285a6d9d9214f8167742d12af2855f527fb Sebastian Thiel <byronimo@gmail.com> 1290122860 +0100 merge docs: Merge made by recursive.
+45c0f285a6d9d9214f8167742d12af2855f527fb 315c303214cef855499f0c7eda46b7ed82dceecb Sebastian Thiel <byronimo@gmail.com> 1290158850 +0100 commit: test_submodule: fixed failures that arose due to changes of the original submodule names. Also, a major bug was fixed that cased submodules to always being updated recursively when using the RootModule.update method
+315c303214cef855499f0c7eda46b7ed82dceecb 7dd618655c96ff32b5c30e41a5406c512bcbb65f Sebastian Thiel <byronimo@gmail.com> 1290158895 +0100 commit (amend): test_submodule: fixed failures that arose due to changes of the original submodule names. Also, a major bug was fixed that cased submodules to always being updated recursively when using the RootModule.update method
+7dd618655c96ff32b5c30e41a5406c512bcbb65f 2ab454f0ccf09773a4f51045329a69fd73559414 Sebastian Thiel <byronimo@gmail.com> 1290188727 +0100 commit: remote: parsing of fetch information now reacts to fatal errors. Previously it would just bump into an assertion
+2ab454f0ccf09773a4f51045329a69fd73559414 b00ad00130389f5b00da9dbfd89c3e02319d2999 Sebastian Thiel <byronimo@gmail.com> 1290196658 +0100 commit: submodule: When adding an existing submodule, when retrieving the binsha, we will now consider not only the tree, but the index too
+b00ad00130389f5b00da9dbfd89c3e02319d2999 8867348ca772cdce7434e76eed141f035b63e928 Sebastian Thiel <byronimo@gmail.com> 1290196804 +0100 commit: Bumped version number to 0.3.1
+8867348ca772cdce7434e76eed141f035b63e928 8d0aa1ef19e2c3babee458bd4504820f415148e0 Sebastian Thiel <byronimo@gmail.com> 1290271885 +0100 commit: Fixed performance tests which broke in the meanwhile - they definitely don't run often enough, which is because they intentionally don't have a package initialization file
+8d0aa1ef19e2c3babee458bd4504820f415148e0 8e0e315a371cdfc80993a1532f938d56ed7acee4 Sebastian Thiel <byronimo@gmail.com> 1290280591 +0100 commit: submodule: Fixed capital error when handling the submodule's branch, which was returned in the submodules super repository, not in the submodule's module
+8e0e315a371cdfc80993a1532f938d56ed7acee4 7c72b9a3eaabbe927ba77d4f69a62f35fbe60e2e Sebastian Thiel <byronimo@gmail.com> 1290286993 +0100 merge gitorious/win32: Merge made by recursive.
+7c72b9a3eaabbe927ba77d4f69a62f35fbe60e2e 517ae56f517f5e7253f878dd1dc3c7c49f53df1a Sebastian Thiel <byronimo@gmail.com> 1290288333 +0100 merge osx: Merge made by recursive.
+517ae56f517f5e7253f878dd1dc3c7c49f53df1a 22a88a7ec38e29827264f558f0c1691b99102e23 Sebastian Thiel <byronimo@gmail.com> 1290289085 +0100 commit: fixed performance tests ... again, previously I was just working on an incorrect repository
+22a88a7ec38e29827264f558f0c1691b99102e23 685760ab33b8f9d7455b18a9ecb8c4c5b3315d66 Sebastian Thiel <byronimo@gmail.com> 1290342054 +0100 commit: Added zip_safe info to setup.py file
+685760ab33b8f9d7455b18a9ecb8c4c5b3315d66 9d6310db456de9952453361c860c3ae61b8674ea Sebastian Thiel <byronimo@gmail.com> 1290342681 +0100 commit: docs: added final docs for version 0.3.0, started new release 0.3.1
+9d6310db456de9952453361c860c3ae61b8674ea 0b813371f5a8af95152cae109d28c7c97bfaf79f Sebastian Thiel <byronimo@gmail.com> 1290358083 +0100 commit: Fixed API reference docs as far as possible
+0b813371f5a8af95152cae109d28c7c97bfaf79f 94140bbfc523ae13e1e8045ebfed8a76fe0a1872 Sebastian Thiel <byronimo@gmail.com> 1290372438 +0100 merge structure: Merge made by recursive.
+94140bbfc523ae13e1e8045ebfed8a76fe0a1872 d01b428dbac4103b4f7d7b8fca32e01f70746c53 Sebastian Thiel <byronimo@gmail.com> 1290372442 +0100 commit (amend): !!WARNING!!: Directory structure changed, see commit message for instructions
+d01b428dbac4103b4f7d7b8fca32e01f70746c53 db3423d1eab11d00c5475e36eae8952512b07f4e Sebastian Thiel <byronimo@gmail.com> 1290373147 +0100 commit (amend): !**WARNING**!: Directory structure changed, see commit message for instructions
+db3423d1eab11d00c5475e36eae8952512b07f4e 5ed5b2011ec7cf72f19e6d53b588eea4adca68e5 Sebastian Thiel <byronimo@gmail.com> 1290373168 +0100 commit (amend): *!*WARNING*!*: Directory structure changed, see commit message for instructions
+5ed5b2011ec7cf72f19e6d53b588eea4adca68e5 470d4a7cc865d2702c326d9d1d1b0ab7afb49f0e Sebastian Thiel <byronimo@gmail.com> 1290373186 +0100 commit (amend): !##WARNING##!: Directory structure changed, see commit message for instructions
+470d4a7cc865d2702c326d9d1d1b0ab7afb49f0e e088424eb01bd47c6f0d313f465a21ee742e6f4a Sebastian Thiel <byronimo@gmail.com> 1290373209 +0100 commit (amend): If you use git-python as a submodule of your own project, which alters the sys.path to import it,
+e088424eb01bd47c6f0d313f465a21ee742e6f4a 48a17c87c15b2fa7ce2e84afa09484f354d57a39 Sebastian Thiel <byronimo@gmail.com> 1290373245 +0100 commit (amend): -#######->WARNING<-####### Directory structure changed, see commit message
+48a17c87c15b2fa7ce2e84afa09484f354d57a39 fca367548e365f93c58c47dea45507025269f59a Sebastian Thiel <byronimo@gmail.com> 1290374761 +0100 commit: Changed version to 0.3.1 (removed beta1) so that other projects can actually depend on git-python using the setuptools. Previously it would claim the version did not exist, probably because the setuptools are just comparing strings
diff --git a/test/test_blob.py b/test/test_blob.py
index 8513328e..661c0501 100644
--- a/test/test_blob.py
+++ b/test/test_blob.py
@@ -9,12 +9,15 @@ from git import *
from gitdb.util import hex_to_bin
class TestBlob(TestBase):
-
- def test_mime_type_should_return_mime_type_for_known_types(self):
- blob = Blob(self.rorepo, **{'binsha': Blob.NULL_BIN_SHA, 'path': 'foo.png'})
- assert_equal("image/png", blob.mime_type)
+
+ def test_mime_type_should_return_mime_type_for_known_types(self):
+ blob = Blob(self.rorepo, **{'binsha': Blob.NULL_BIN_SHA, 'path': 'foo.png'})
+ assert_equal("image/png", blob.mime_type)
- def test_mime_type_should_return_text_plain_for_unknown_types(self):
- blob = Blob(self.rorepo, **{'binsha': Blob.NULL_BIN_SHA,'path': 'something'})
- assert_equal("text/plain", blob.mime_type)
+ def test_mime_type_should_return_text_plain_for_unknown_types(self):
+ blob = Blob(self.rorepo, **{'binsha': Blob.NULL_BIN_SHA,'path': 'something'})
+ assert_equal("text/plain", blob.mime_type)
+ def test_nodict(self):
+ self.failUnlessRaises(AttributeError, setattr, self.rorepo.tree()['AUTHORS'], 'someattr', 2)
+
diff --git a/test/test_commit.py b/test/test_commit.py
index a00a8de8..4a8d8b87 100644
--- a/test/test_commit.py
+++ b/test/test_commit.py
@@ -70,6 +70,8 @@ class TestCommit(TestBase):
def test_bake(self):
commit = self.rorepo.commit('2454ae89983a4496a445ce347d7a41c0bb0ea7ae')
+ # commits have no dict
+ self.failUnlessRaises(AttributeError, setattr, commit, 'someattr', 1)
commit.author # bake
assert_equal("Sebastian Thiel", commit.author.name)
diff --git a/test/test_index.py b/test/test_index.py
index 78a868c7..5d227897 100644
--- a/test/test_index.py
+++ b/test/test_index.py
@@ -422,7 +422,6 @@ class TestIndex(TestBase):
# same index, no parents
commit_message = "index without parents"
commit_no_parents = index.commit(commit_message, parent_commits=list(), head=True)
- assert SymbolicReference(rw_repo, 'ORIG_HEAD').commit == cur_commit
assert commit_no_parents.message == commit_message
assert len(commit_no_parents.parents) == 0
assert cur_head.commit == commit_no_parents
diff --git a/test/test_reflog.py b/test/test_reflog.py
new file mode 100644
index 00000000..3fdf1fae
--- /dev/null
+++ b/test/test_reflog.py
@@ -0,0 +1,102 @@
+from git.test.lib import *
+from git.objects import IndexObject
+from git.refs import *
+from git.util import Actor
+
+import tempfile
+import shutil
+import os
+
+class TestRefLog(TestBase):
+
+ def test_reflogentry(self):
+ nullhexsha = IndexObject.NULL_HEX_SHA
+ hexsha = 'F' * 40
+ actor = Actor('name', 'email')
+ msg = "message"
+
+ self.failUnlessRaises(ValueError, RefLogEntry.new, nullhexsha, hexsha, 'noactor', 0, 0, "")
+ e = RefLogEntry.new(nullhexsha, hexsha, actor, 0, 1, msg)
+
+ assert e.oldhexsha == nullhexsha
+ assert e.newhexsha == hexsha
+ assert e.actor == actor
+ assert e.time[0] == 0
+ assert e.time[1] == 1
+ assert e.message == msg
+
+ # check representation (roughly)
+ assert repr(e).startswith(nullhexsha)
+
+ def test_base(self):
+ rlp_head = fixture_path('reflog_HEAD')
+ rlp_master = fixture_path('reflog_master')
+ tdir = tempfile.mktemp(suffix="test_reflogs")
+ os.mkdir(tdir)
+
+ # verify we have a ref - with the creation of a new ref, the reflog
+ # will be created as well
+ rlp_master_ro = RefLog.path(self.rorepo.heads.master)
+ assert os.path.isfile(rlp_master_ro)
+
+ # simple read
+ reflog = RefLog.from_file(rlp_master_ro)
+ assert reflog._path is not None
+ assert isinstance(reflog, RefLog)
+ assert len(reflog)
+
+ # iter_entries works with path and with stream
+ assert len(list(RefLog.iter_entries(open(rlp_master))))
+ assert len(list(RefLog.iter_entries(rlp_master)))
+
+ # raise on invalid revlog
+ # TODO: Try multiple corrupted ones !
+ pp = 'reflog_invalid_'
+ for suffix in ('oldsha', 'newsha', 'email', 'date', 'sep'):
+ self.failUnlessRaises(ValueError, RefLog.from_file, fixture_path(pp+suffix))
+ #END for each invalid file
+
+ # cannot write an uninitialized reflog
+ self.failUnlessRaises(ValueError, RefLog().write)
+
+ # test serialize and deserialize - results must match exactly
+ binsha = chr(255)*20
+ msg = "my reflog message"
+ cr = self.rorepo.config_reader()
+ for rlp in (rlp_head, rlp_master):
+ reflog = RefLog.from_file(rlp)
+ tfile = os.path.join(tdir, os.path.basename(rlp))
+ reflog.to_file(tfile)
+ assert reflog.write() is reflog
+
+ # parsed result must match ...
+ treflog = RefLog.from_file(tfile)
+ assert treflog == reflog
+
+ # ... as well as each bytes of the written stream
+ assert open(tfile).read() == open(rlp).read()
+
+ # append an entry
+ entry = RefLog.append_entry(cr, tfile, IndexObject.NULL_BIN_SHA, binsha, msg)
+ assert entry.oldhexsha == IndexObject.NULL_HEX_SHA
+ assert entry.newhexsha == 'f'*40
+ assert entry.message == msg
+ assert RefLog.from_file(tfile)[-1] == entry
+
+ # index entry
+ # raises on invalid index
+ self.failUnlessRaises(IndexError, RefLog.entry_at, rlp, 10000)
+
+ # indices can be positive ...
+ assert isinstance(RefLog.entry_at(rlp, 0), RefLogEntry)
+ RefLog.entry_at(rlp, 23)
+
+ # ... and negative
+ for idx in (-1, -24):
+ RefLog.entry_at(rlp, idx)
+ #END for each index to read
+ # END for each reflog
+
+
+ # finally remove our temporary data
+ shutil.rmtree(tdir)
diff --git a/test/test_refs.py b/test/test_refs.py
index 700e5fac..52937de1 100644
--- a/test/test_refs.py
+++ b/test/test_refs.py
@@ -8,6 +8,7 @@ from mock import *
from git.test.lib import *
from git import *
import git.refs as refs
+from git.util import Actor
from git.objects.tag import TagObject
from itertools import chain
import os
@@ -33,6 +34,8 @@ class TestRefs(TestBase):
if tag.tag is not None:
tag_object_refs.append( tag )
tagobj = tag.tag
+ # have no dict
+ self.failUnlessRaises(AttributeError, setattr, tagobj, 'someattr', 1)
assert isinstance( tagobj, TagObject )
assert tagobj.tag == tag.name
assert isinstance( tagobj.tagger, Actor )
@@ -92,36 +95,47 @@ class TestRefs(TestBase):
assert head.tracking_branch() is None
# END for each head
- # verify ORIG_HEAD gets set for detached heads
+ # verify REFLOG gets altered
head = rwrepo.head
- orig_head = head.orig_head()
cur_head = head.ref
cur_commit = cur_head.commit
pcommit = cur_head.commit.parents[0].parents[0]
- head.ref = pcommit # detach head
- assert orig_head.commit == cur_commit
+ hlog_len = len(head.log())
+ blog_len = len(cur_head.log())
+ assert head.set_reference(pcommit, 'detached head') is head
+ # one new log-entry
+ thlog = head.log()
+ assert len(thlog) == hlog_len + 1
+ assert thlog[-1].oldhexsha == cur_commit.hexsha
+ assert thlog[-1].newhexsha == pcommit.hexsha
+
+ # the ref didn't change though
+ assert len(cur_head.log()) == blog_len
+
+ # head changes once again, cur_head doesn't change
+ head.set_reference(cur_head, 'reattach head')
+ assert len(head.log()) == hlog_len+2
+ assert len(cur_head.log()) == blog_len
+
+ # adjusting the head-ref also adjust the head, so both reflogs are
+ # altered
+ cur_head.set_commit(pcommit, 'changing commit')
+ assert len(cur_head.log()) == blog_len+1
+ assert len(head.log()) == hlog_len+3
- # even if we set it through its reference - chaning the ref
- # will adjust the orig_head, which still points to cur_commit
- head.ref = cur_head
- assert orig_head.commit == pcommit
- assert head.commit == cur_commit == cur_head.commit
-
- cur_head.commit = pcommit
- assert head.commit == pcommit
- assert orig_head.commit == cur_commit
# with automatic dereferencing
- head.commit = cur_commit
- assert orig_head.commit == pcommit
-
- # changing branches which are not checked out doesn't affect the ORIG_HEAD
- other_head = Head.create(rwrepo, 'mynewhead', pcommit)
- assert other_head.commit == pcommit
- assert orig_head.commit == pcommit
- other_head.commit = pcommit.parents[0]
- assert orig_head.commit == pcommit
-
+ assert head.set_commit(cur_commit, 'change commit once again') is head
+ assert len(head.log()) == hlog_len+4
+ assert len(cur_head.log()) == blog_len+2
+
+ # a new branch has just a single entry
+ other_head = Head.create(rwrepo, 'mynewhead', pcommit, logmsg='new head created')
+ log = other_head.log()
+ assert len(log) == 1
+ assert log[0].oldhexsha == pcommit.NULL_HEX_SHA
+ assert log[0].newhexsha == pcommit.hexsha
+
def test_refs(self):
types_found = set()
@@ -199,10 +213,14 @@ class TestRefs(TestBase):
for count, new_name in enumerate(("my_new_head", "feature/feature1")):
actual_commit = commit+"^"*count
new_head = Head.create(rw_repo, new_name, actual_commit)
+ assert new_head.is_detached
assert cur_head.commit == prev_head_commit
assert isinstance(new_head, Head)
- # already exists
- self.failUnlessRaises(GitCommandError, Head.create, rw_repo, new_name)
+ # already exists, but has the same value, so its fine
+ Head.create(rw_repo, new_name, new_head.commit)
+
+ # its not fine with a different value
+ self.failUnlessRaises(OSError, Head.create, rw_repo, new_name, new_head.commit.parents[0])
# force it
new_head = Head.create(rw_repo, new_name, actual_commit, force=True)
@@ -219,12 +237,16 @@ class TestRefs(TestBase):
tmp_head.rename(new_head, force=True)
assert tmp_head == new_head and tmp_head.object == new_head.object
+ logfile = RefLog.path(tmp_head)
+ assert os.path.isfile(logfile)
Head.delete(rw_repo, tmp_head)
+ # deletion removes the log as well
+ assert not os.path.isfile(logfile)
heads = rw_repo.heads
assert tmp_head not in heads and new_head not in heads
# force on deletion testing would be missing here, code looks okay though ;)
# END for each new head name
- self.failUnlessRaises(TypeError, RemoteReference.create, rw_repo, "some_name")
+ self.failUnlessRaises(TypeError, RemoteReference.create, rw_repo, "some_name")
# tag ref
tag_name = "1.0.2"
@@ -282,7 +304,11 @@ class TestRefs(TestBase):
head_tree = head.commit.tree
self.failUnlessRaises(ValueError, setattr, head, 'commit', head_tree)
assert head.commit == old_commit # and the ref did not change
- self.failUnlessRaises(GitCommandError, setattr, head, 'object', head_tree)
+ # we allow heds to point to any object
+ head.object = head_tree
+ assert head.object == head_tree
+ # cannot query tree as commit
+ self.failUnlessRaises(TypeError, getattr, head, 'commit')
# set the commit directly using the head. This would never detach the head
assert not cur_head.is_detached
@@ -478,7 +504,7 @@ class TestRefs(TestBase):
Reference.delete(ref.repo, ref.path)
assert not ref.is_valid()
- self.failUnlessRaises(GitCommandError, setattr, ref, 'object', "nonsense")
+ self.failUnlessRaises(ValueError, setattr, ref, 'object', "nonsense")
assert not ref.is_valid()
# END for each path
@@ -486,3 +512,7 @@ class TestRefs(TestBase):
def test_dereference_recursive(self):
# for now, just test the HEAD
assert SymbolicReference.dereference_recursive(self.rorepo, 'HEAD')
+
+ def test_reflog(self):
+ assert isinstance(self.rorepo.heads.master.log(), RefLog)
+
diff --git a/test/test_remote.py b/test/test_remote.py
index 108712a5..af6915a3 100644
--- a/test/test_remote.py
+++ b/test/test_remote.py
@@ -208,7 +208,7 @@ class TestRemote(TestBase):
assert tinfo.flags & tinfo.NEW_TAG
# adjust tag commit
- Reference._set_object(rtag, rhead.commit.parents[0].parents[0])
+ Reference.set_object(rtag, rhead.commit.parents[0].parents[0])
res = fetch_and_test(remote, tags=True)
tinfo = res[str(rtag)]
assert tinfo.commit == rtag.commit
diff --git a/test/test_repo.py b/test/test_repo.py
index 59a1f6bf..95b0750a 100644
--- a/test/test_repo.py
+++ b/test/test_repo.py
@@ -467,11 +467,12 @@ class TestRepo(TestBase):
def test_rev_parse(self):
rev_parse = self.rorepo.rev_parse
- # try special case: This one failed beforehand
+ # try special case: This one failed at some point, make sure its fixed
assert rev_parse("33ebe").hexsha == "33ebe7acec14b25c5f84f35a664803fcab2f7781"
# start from reference
num_resolved = 0
+
for ref in Reference.iter_items(self.rorepo):
path_tokens = ref.path.split("/")
for pt in range(len(path_tokens)):
@@ -546,9 +547,32 @@ class TestRepo(TestBase):
# missing starting brace
self.failUnlessRaises(ValueError, rev_parse, '0.1.4^tree}')
+ # REVLOG
+ #######
+ head = self.rorepo.head
+
+ # need to specify a ref when using the @ syntax
+ self.failUnlessRaises(BadObject, rev_parse, "%s@{0}" % head.commit.hexsha)
+
+ # uses HEAD.ref by default
+ assert rev_parse('@{0}') == head.commit
+ if not head.is_detached:
+ refspec = '%s@{0}' % head.ref.name
+ assert rev_parse(refspec) == head.ref.commit
+ # all additional specs work as well
+ assert rev_parse(refspec+"^{tree}") == head.commit.tree
+ assert rev_parse(refspec+":CHANGES").type == 'blob'
+ #END operate on non-detached head
+
+ # the last position
+ assert rev_parse('@{1}') != head.commit
+
+ # position doesn't exist
+ self.failUnlessRaises(BadObject, rev_parse, '@{10000}')
+
+ # currently, nothing more is supported
+ self.failUnlessRaises(NotImplementedError, rev_parse, "@{1 week ago}")
- # cannot handle rev-log for now
- self.failUnlessRaises(ValueError, rev_parse, "hi@there")
def test_repo_odbtype(self):
target_type = GitDB
diff --git a/test/test_submodule.py b/test/test_submodule.py
index c1fa2061..f69c27ea 100644
--- a/test/test_submodule.py
+++ b/test/test_submodule.py
@@ -107,6 +107,7 @@ class TestSubmodule(TestBase):
# currently there is only one submodule
assert len(list(rwrepo.iter_submodules())) == 1
+ assert sm.binsha != "\0"*20
# TEST ADD
###########
diff --git a/test/test_tree.py b/test/test_tree.py
index 80db2e4b..ec10e962 100644
--- a/test/test_tree.py
+++ b/test/test_tree.py
@@ -23,6 +23,9 @@ class TestTree(TestBase):
continue
# END skip non-trees
tree = item
+ # trees have no dict
+ self.failUnlessRaises(AttributeError, setattr, tree, 'someattr', 1)
+
orig_data = tree.data_stream.read()
orig_cache = tree._cache
diff --git a/test/test_util.py b/test/test_util.py
index 7a6eb27d..e55a6d15 100644
--- a/test/test_util.py
+++ b/test/test_util.py
@@ -16,7 +16,7 @@ from git.cmd import dashify
import time
-class TestUtils(TestCase):
+class TestUtils(TestBase):
def setup(self):
self.testdict = {
"string": "42",
@@ -102,4 +102,8 @@ class TestUtils(TestCase):
self.failUnlessRaises(ValueError, parse_date, '123456789 -02000')
self.failUnlessRaises(ValueError, parse_date, ' 123456789 -0200')
-
+ def test_actor(self):
+ for cr in (None, self.rorepo.config_reader()):
+ assert isinstance(Actor.committer(cr), Actor)
+ assert isinstance(Actor.author(cr), Actor)
+ #END assure config reader is handled
diff --git a/util.py b/util.py
index c945e6a3..42719233 100644
--- a/util.py
+++ b/util.py
@@ -5,8 +5,10 @@
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
import os
+import re
import sys
import time
+import platform
import tempfile
from gitdb.util import (
@@ -20,7 +22,9 @@ from gitdb.util import (
__all__ = ( "stream_copy", "join_path", "to_native_path_windows", "to_native_path_linux",
"join_path_native", "Stats", "IndexFileSHA1Writer", "Iterable", "IterableList",
- "BlockingLockFile", "LockFile" )
+ "BlockingLockFile", "LockFile", 'Actor', 'get_user_id', 'assure_directory_exists')
+
+#{ Utility Methods
def stream_copy(source, destination, chunk_size=512*1024):
"""Copy all data from the source stream into the destination stream in chunks
@@ -65,11 +69,140 @@ else:
to_native_path = to_native_path_linux
def join_path_native(a, *p):
- """As join path, but makes sure an OS native path is returned. This is only
- needed to play it safe on my dear windows and to assure nice paths that only
- use '\'"""
+ """
+ As join path, but makes sure an OS native path is returned. This is only
+ needed to play it safe on my dear windows and to assure nice paths that only
+ use '\'"""
return to_native_path(join_path(a, *p))
+
+def assure_directory_exists(path, is_file=False):
+ """Assure that the directory pointed to by path exists.
+ :param is_file: If True, path is assumed to be a file and handled correctly.
+ Otherwise it must be a directory
+ :return: True if the directory was created, False if it already existed"""
+ if is_file:
+ path = os.path.dirname(path)
+ #END handle file
+ if not os.path.isdir(path):
+ os.makedirs(path)
+ return True
+ return False
+
+
+def get_user_id():
+ """:return: string identifying the currently active system user as name@node
+ :note: user can be set with the 'USER' environment variable, usually set on windows"""
+ ukn = 'UNKNOWN'
+ username = os.environ.get('USER', os.environ.get('USERNAME', ukn))
+ if username == ukn and hasattr(os, 'getlogin'):
+ username = os.getlogin()
+ # END get username from login
+ return "%s@%s" % (username, platform.node())
+
+#} END utilities
+
+#{ Classes
+
+class Actor(object):
+ """Actors hold information about a person acting on the repository. They
+ can be committers and authors or anything with a name and an email as
+ mentioned in the git log entries."""
+ # PRECOMPILED REGEX
+ name_only_regex = re.compile( r'<(.+)>' )
+ name_email_regex = re.compile( r'(.*) <(.+?)>' )
+
+ # ENVIRONMENT VARIABLES
+ # read when creating new commits
+ env_author_name = "GIT_AUTHOR_NAME"
+ env_author_email = "GIT_AUTHOR_EMAIL"
+ env_committer_name = "GIT_COMMITTER_NAME"
+ env_committer_email = "GIT_COMMITTER_EMAIL"
+
+ # CONFIGURATION KEYS
+ conf_name = 'name'
+ conf_email = 'email'
+
+ __slots__ = ('name', 'email')
+
+ def __init__(self, name, email):
+ self.name = name
+ self.email = email
+ def __eq__(self, other):
+ return self.name == other.name and self.email == other.email
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __hash__(self):
+ return hash((self.name, self.email))
+
+ def __str__(self):
+ return self.name
+
+ def __repr__(self):
+ return '<git.Actor "%s <%s>">' % (self.name, self.email)
+
+ @classmethod
+ def _from_string(cls, string):
+ """Create an Actor from a string.
+ :param string: is the string, which is expected to be in regular git format
+
+ John Doe <jdoe@example.com>
+
+ :return: Actor """
+ m = cls.name_email_regex.search(string)
+ if m:
+ name, email = m.groups()
+ return Actor(name, email)
+ else:
+ m = cls.name_only_regex.search(string)
+ if m:
+ return Actor(m.group(1), None)
+ else:
+ # assume best and use the whole string as name
+ return Actor(string, None)
+ # END special case name
+ # END handle name/email matching
+
+ @classmethod
+ def _main_actor(cls, env_name, env_email, config_reader=None):
+ actor = Actor('', '')
+ default_email = get_user_id()
+ default_name = default_email.split('@')[0]
+
+ for attr, evar, cvar, default in (('name', env_name, cls.conf_name, default_name),
+ ('email', env_email, cls.conf_email, default_email)):
+ try:
+ setattr(actor, attr, os.environ[evar])
+ except KeyError:
+ if config_reader is not None:
+ setattr(actor, attr, config_reader.get_value('user', cvar, default))
+ #END config-reader handling
+ if not getattr(actor, attr):
+ setattr(actor, attr, default)
+ #END handle name
+ #END for each item to retrieve
+ return actor
+
+
+ @classmethod
+ def committer(cls, config_reader=None):
+ """
+ :return: Actor instance corresponding to the configured committer. It behaves
+ similar to the git implementation, such that the environment will override
+ configuration values of config_reader. If no value is set at all, it will be
+ generated
+ :param config_reader: ConfigReader to use to retrieve the values from in case
+ they are not set in the environment"""
+ return cls._main_actor(cls.env_committer_name, cls.env_committer_email, config_reader)
+
+ @classmethod
+ def author(cls, config_reader=None):
+ """Same as committer(), but defines the main author. It may be specified in the environment,
+ but defaults to the committer"""
+ return cls._main_actor(cls.env_author_name, cls.env_author_email, config_reader)
+
class Stats(object):
"""
@@ -345,4 +478,4 @@ class Iterable(object):
:return: iterator yielding Items"""
raise NotImplementedError("To be implemented by Subclass")
-
+#} END classes