8000 Merge branch 'revparse' · codepongo/GitPython@ca288d4 · GitHub
[go: up one dir, main page]

Skip to content

Commit ca288d4

Browse files
committed
Merge branch 'revparse'
2 parents a4287f6 + 01ab5b9 commit ca288d4

File tree

14 files changed

+936
-490
lines changed
  • objects
  • repo
  • test/git
  • 14 files changed

    +936
    -490
    lines changed

    lib/git/db.py

    Lines changed: 27 additions & 3 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,11 +1,18 @@
    1-
    """Module with our own gitdb implementation - it uses the git command"""
    1+
    """Module with our own gitdb implementation - it uses the git command"""
    2+
    from exc import (
    3+
    GitCommandError,
    4+
    BadObject
    5+
    )
    6+
    27
    from gitdb.base import (
    38
    OInfo,
    49
    OStream
    510
    )
    611

    7-
    from gitdb.util import bin_to_hex
    8-
    12+
    from gitdb.util import (
    13+
    bin_to_hex,
    14+
    hex_to_bin
    15+
    )
    916
    from gitdb.db import GitDB
    1017
    from gitdb.db import LooseObjectDB
    1118

    @@ -35,3 +42,20 @@ def stream(self, sha):
    3542
    t = self._git.stream_object_data(bin_to_hex(sha))
    3643
    return OStream(*t)
    3744

    45+
    46+
    # { Interface
    47+
    48+
    def partial_to_complete_sha_hex(self, partial_hexsha):
    49+
    """:return: Full binary 20 byte sha from the given partial hexsha
    50+
    :raise AmbiguousObjectName:
    51+
    :raise BadObject:
    52+
    :note: currently we only raise BadObject as git does not communicate
    53+
    AmbiguousObjects separately"""
    54+
    try:
    55+
    hexsha, typename, size = self._git.get_object_header(partial_hexsha)
    56+
    return hex_to_bin(hexsha)
    57+
    except (GitCommandError, ValueError):
    58+
    raise BadObject(partial_hexsha)
    59+
    # END handle exceptions
    60+
    61+
    #} END interface

    lib/git/exc.py

    Lines changed: 3 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -1,10 +1,12 @@
    1-
    # errors.py
    1+
    # exc.py
    22
    # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors
    33
    #
    44
    # This module is part of GitPython and is released under
    55
    # the BSD License: http://www.opensource.org/licenses/bsd-license.php
    66
    """ Module containing all exceptions thrown througout the git package, """
    77

    8+
    from gitdb.exc import *
    9+
    810
    class InvalidGitRepositoryError(Exception):
    911
    """ Thrown if the given repository appears to have an invalid format. """
    1012

    lib/git/ext/gitdb

    Submodule gitdb updated from 6c8721a to ac7d475

    lib/git/index/__init__.py

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -1,4 +1,4 @@
    1-
    """Initialize the index module"""
    1+
    """Initialize the index package"""
    22

    33
    from base import *
    44
    from typ import *

    lib/git/index/base.py

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -1122,7 +1122,7 @@ def diff(self, other=diff.Diffable.Index, paths=None, create_patch=False, **kwar
    11221122
    # item. Handle existing -R flags properly. Transform strings to the object
    11231123
    # so that we can call diff on it
    11241124
    if isinstance(other, basestring):
    1125-
    other = Object.new(self.repo, other)
    1125+
    other = self.repo.rev_parse(other)
    11261126
    # END object conversion
    11271127

    11281128
    if isinstance(other, Object):

    lib/git/objects/base.py

    Lines changed: 12 additions & 4 deletions
    Original file line numberDiff line numberDiff line change
    @@ -49,10 +49,18 @@ def new(cls, repo, id):
    4949
    5050
    :note: This cannot be a __new__ method as it would always call __init__
    5151
    with the input id which is not necessarily a binsha."""
    52-
    hexsha, typename, size = repo.git.get_object_header(id)
    53-
    inst = get_object_type_by_name(typename)(repo, hex_to_bin(hexsha))
    54-
    inst.size = size
    55-
    return inst
    52+
    return repo.rev_parse(str(id))
    53+
    54+
    @classmethod
    55+
    def new_from_sha(cls, repo, sha1):
    56+
    """
    57+
    :return: new object instance of a type appropriate to represent the given
    58+
    binary sha1
    59+
    :param sha1: 20 byte binary sha1"""
    60+
    oinfo = repo.odb.info(sha1)
    61+
    inst = get_object_type_by_name(oinfo.type)(repo, oinfo.binsha)
    62+
    inst.size = oinfo.size
    63+
    return inst
    5664

    5765
    def _set_self_from_args_(self, args_dict):
    5866
    """Initialize attributes on self from the given dict that was retrieved

    lib/git/refs.py

    Lines changed: 17 additions & 5 deletions
    Original file line numberDiff line numberDiff line change
    @@ -68,7 +68,7 @@ def name(self):
    6868
    :return:
    6969
    In case of symbolic references, the shortest assumable name
    7070
    is the path itself."""
    71-
    return self.path
    71+
    return self.path
    7272

    7373
    def _abs_path(self):
    7474
    return join_path_native(self.repo.git_dir, self.path)
    @@ -109,6 +109,19 @@ def _iter_packed_refs(cls, repo):
    109109
    # I believe files are closing themselves on destruction, so it is
    110110
    # alright.
    111111

    112+
    @classmethod
    113+
    def dereference_recursive(cls, repo, ref_path):
    114+
    """
    115+
    :return: hexsha stored in the reference at the given ref_path, recursively dereferencing all
    116+
    intermediate references as required
    117+
    :param repo: the repository containing the reference at ref_path"""
    118+
    while True:
    119+
    ref = cls(repo, ref_path)
    120+
    hexsha, ref_path = ref._get_ref_info()
    121+
    if hexsha is not None:
    122+
    return hexsha
    123+
    # END recursive dereferencing
    124+
    112125
    def _get_ref_info(self):
    113126
    """Return: (sha, target_ref_path) if available, the sha the file at
    114127
    rela_path points to, or None. target_ref_path is the reference we
    @@ -195,9 +208,8 @@ def _set_reference(self, ref):
    195208
    try:
    196209
    write_value = ref.commit.hexsha
    197210
    except AttributeError:
    198-
    sha = str(ref)
    199211
    try:
    200-
    obj = Object.new(self.repo, sha)
    212+
    obj = self.repo.rev_parse(ref+"^{}") # optionally deref tags
    201213
    if obj.type != "commit":
    202214
    raise TypeError("Invalid object type behind sha: %s" % sha)
    203215
    write_value = obj.hexsha
    @@ -333,7 +345,7 @@ def _create(cls, repo, path, resolve, reference, force):
    333345
    # figure out target data
    334346
    target = reference
    335347
    if resolve:
    336-
    target = Object.new(repo, reference)
    348+
    target = repo.rev_parse(str(reference))
    337349

    338350
    if not force and isfile(abs_ref_path):
    339351
    target_data = str(target)
    @@ -523,7 +535,7 @@ def _get_object(self):
    523535
    always point to the actual object as it gets re-created on each query"""
    524536
    # have to be dynamic here as we may be a tag which can point to anything
    525537
    # Our path will be resolved to the hexsha which will be used accordingly
    526-
    return Object.new(self.repo, self.path)
    538+
    return Object.new_from_sha(self.repo, hex_to_bin(self.dereference_recursive(self.repo, self.path)))
    527539

    528540
    def _set_object(self, ref):
    529541
    """

    lib/git/remote.py

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -391,7 +391,7 @@ def _from_line(cls, repo, line, fetch_line):
    391391
    split_token = '...'
    392392
    if control_character == ' ':
    393393
    split_token = split_token[:-1]
    394-
    old_commit = Commit.new(repo, operation.split(split_token)[0])
    394+
    old_commit = repo.rev_parse(operation.split(split_token)[0])
    395395
    # END handle refspec
    396396
    # END reference flag handling
    397397

    lib/git/repo/__init__.py

    Lines changed: 3 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,3 @@
    1+
    """Initialize the Repo package"""
    2+
    3+
    from base import *

    lib/git/repo.py renamed to lib/git/repo/base.py

    Lines changed: 39 additions & 55 deletions
    Original file line numberDiff line numberDiff line change
    @@ -4,51 +4,39 @@
    44
    # This module is part of GitPython and is released under
    55
    # the BSD License: http://www.opensource.org/licenses/bsd-license.php
    66

    7-
    from exc import InvalidGitRepositoryError, NoSuchPathError
    8-
    from cmd import Git
    9-
    from objects import Actor
    10-
    from refs import *
    11-
    from index import IndexFile
    12-
    from objects import *
    13-
    from config import GitConfigParser
    14-
    from remote import Remote
    15-
    16-
    from db import (
    7+
    from git.exc import InvalidGitRepositoryError, NoSuchPathError
    8+
    from git.cmd import Git
    9+
    from git.objects import Actor
    10+
    from git.refs import *
    11+
    from git.index import IndexFile
    12+
    from git.objects import *
    13+
    from git.config import GitConfigParser
    14+
    from git.remote import Remote
    15+
    from git.db import (
    1716
    GitCmdObjectDB,
    1817
    GitDB
    1918
    )
    2019

    20+
    2121
    from gitdb.util import (
    2222
    join,
    23-
    isdir,
    2423
    isfile,
    25-
    join,
    2624
    hex_to_bin
    2725
    )
    26+
    27+
    from fun import (
    28+
    rev_parse,
    29+
    is_git_dir,
    30+
    touch
    31+
    )
    32+
    2833
    import os
    2934
    import sys
    3035
    import re
    3136

    3237

    3338
    __all__ = ('Repo', )
    3439

    35-
    def touch(filename):
    36-
    fp = open(filename, "a")
    37-
    fp.close()
    38-
    39-
    def is_git_dir(d):
    40-
    """ This is taken from the git setup.c:is_git_directory
    41-
    function."""
    42-
    43-
    if isdir(d) and \
    44-
    isdir(join(d, 'objects')) and \
    45-
    isdir(join(d, 'refs')):
    46-
    headref = join(d, 'HEAD')
    47-
    return isfile(headref) or \
    48-
    (os.path.islink(headref) and
    49-
    os.readlink(headref).startswith('refs'))
    50-
    return False
    51-
    5240

    5341
    class Repo(object):
    5442
    """Represents a git repository and allows you to query references,
    @@ -70,6 +58,7 @@ class Repo(object):
    7058
    # precompiled regex
    7159
    re_whitespace = re.compile(r'\s+')
    7260
    re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$')
    61+
    re_hexsha_shortened = re.compile('^[0-9A-Fa-f]{4,40}$')
    7362
    re_author_committer_start = re.compile(r'^(author|committer)')
    7463
    re_tab_full_line = re.compile(r'^\t(.*)$')
    7564

    @@ -109,7 +98,7 @@ def __init__(self, path=None, odbt = GitDB):
    10998
    self.git_dir = curpath
    11099
    self._working_tree_dir = os.path.dirname(curpath)
    111100
    break
    112-
    gitpath = os.path.join(curpath, '.git')
    101+
    gitpath = join(curpath, '.git')
    113102
    if is_git_dir(gitpath):
    114103
    self.git_dir = gitpath
    115104
    self._working_tree_dir = curpath
    @@ -139,7 +128,7 @@ def __init__(self, path=None, odbt = GitDB):
    139128
    self.git = Git(self.working_dir)
    140129

    141130
    # special handling, in special times
    142-
    args = [os.path.join(self.git_dir, 'objects')]
    131+
    args = [join(self.git_dir, 'objects')]
    143132
    if issubclass(odbt, GitCmdObjectDB):
    144133
    args.append(self.git)
    145134
    self.odb = odbt(*args)
    @@ -160,11 +149,11 @@ def __repr__(self):
    160149

    161150
    # Description property
    162151
    def _get_description(self):
    163-
    filename = os.path.join(self.git_dir, 'description')
    152+
    filename = join(self.git_dir, 'description')
    164153
    return file(filename).read().rstrip()
    165154

    166155
    def _set_description(self, descr):
    167-
    filename = os.path.join(self.git_dir, 'description')
    156+
    filename = join(self.git_dir, 'description')
    168157
    file(filename, 'w').write(descr+'\n')
    169158

    170159
    description = property(_get_description, _set_description,
    @@ -334,11 +323,9 @@ def commit(self, rev=None):
    334323
    :param rev: revision specifier, see git-rev-parse for viable options.
    335324
    :return: ``git.Commit``"""
    336325
    if rev is None:
    337-
    rev = self.active_branch
    338-
    339-
    c = Object.new(self, rev)
    340-
    assert c.type == "commit", "Revision %s did not point to a commit, but to %s" % (rev, c)
    341-
    return c
    326+
    return self.active_branch.commit
    327+
    else:
    328+
    return self.rev_parse(str(rev)+"^0")
    342329

    343330
    def iter_trees(self, *args, **kwargs):
    344331
    """:return: Iterator yielding Tree objects
    @@ -359,14 +346,9 @@ def tree(self, rev=None):
    359346
    it cannot know about its path relative to the repository root and subsequent
    360347
    operations might have unexpected results."""
    361348
    if rev is None:
    362-
    rev = self.active_branch
    363-
    364-
    c = Object.new(self, rev)
    365-
    if c.type == "commit":
    366-
    return c.tree
    367-
    elif c.type == "tree":
    368-
    return c
    369-
    raise ValueError( "Revision %s did not point to a treeish, but to %s" % (rev, c))
    349+
    return self.active_branch.commit.tree
    350+
    else:
    351+
    return self.rev_parse(str(rev)+"^{tree}")
    370352

    371353
    def iter_commits(self, rev=None, paths='', **kwargs):
    372354
    """A list of Commit objects representing the history of a given ref/commit
    @@ -393,11 +375,11 @@ def iter_commits(self, rev=None, paths='', **kwargs):
    393375
    return Commit.iter_items(self, rev, paths, **kwargs)
    394376

    395377
    def _get_daemon_export(self):
    396-
    filename = os.path.join(self.git_dir, self.DAEMON_EXPORT_FILE)
    378+
    filename = join(self.git_dir, self.DAEMON_EXPORT_FILE)
    397379
    return os.path.exists(filename)
    398380

    399381
    def _set_daemon_export(self, value):
    400-
    filename = os.path.join(self.git_dir, self.DAEMON_EXPORT_FILE)
    382+
    filename = join(self.git_dir, self.DAEMON_EXPORT_FILE)
    401383
    fileexists = os.path.exists(filename)
    402384
    if value and not fileexists:
    403385
    touch(filename)
    @@ -413,7 +395,7 @@ def _get_alternates(self):
    413395
    """The list of alternates for this repo from which objects can be retrieved
    414396
    415397
    :return: list of strings being pathnames of alternates"""
    416-
    alternates_path = os.path.join(self.git_dir, 'objects', 'info', 'alternates')
    398+
    alternates_path = join(self.git_dir, 'objects', 'info', 'alternates')
    417399

    418400
    if os.path.exists(alternates_path):
    419401
    try:
    @@ -436,9 +418,9 @@ def _set_alternates(self, alts):
    436418
    :note:
    437419
    The method does not check for the existance of the paths in alts
    438420
    as the caller is responsible."""
    439-
    alternates_path = os.path.join(self.git_dir, 'objects', 'info', 'alternates')
    421+
    alternates_path = join(self.git_dir, 'objects', 'info', 'alternates')
    440422
    if not alts:
    441-
    if os.path.isfile(alternates_path):
    423+
    if isfile(alternates_path):
    442424
    os.remove(alternates_path)
    443425
    else:
    444426
    try:
    @@ -466,7 +448,7 @@ def is_dirty(self, index=True, working_tree=True, untracked_files=False):
    466448
    default_args = ('--abbrev=40', '--full-index', '--raw')
    467449
    if index:
    468450
    # diff index against HEAD
    469-
    if os.path.isfile(self.index.path) and self.head.is_valid() and \
    451+
    if isfile(self.index.path) and self.head.is_valid() and \
    470452
    len(self.git.diff('HEAD', '--cached', *default_args)):
    471453
    return True
    472454
    # END index handling
    @@ -674,7 +656,7 @@ def clone(self, path, **kwargs):
    674656
    # our git command could have a different working dir than our actual
    675657
    # environment, hence we prepend its working dir if required
    676658
    if not os.path.isabs(path) and self.git.working_dir:
    677-
    path = os.path.join(self.git._working_dir, path)
    659+
    path = join(self.git._working_dir, path)
    678660
    return Repo(os.path.abspath(path), odbt = odbt)
    679661

    680662

    @@ -693,11 +675,13 @@ def archive(self, ostream, treeish=None, prefix=None, **kwargs):
    693675
    if treeish is None:
    694676
    treeish = self.active_branch
    695677
    if prefix and 'prefix' not in kwargs:
    696-
    kwargs['prefix'] = prefix
    678+
    kwargs['prefix'] = prefix
    697679
    kwargs['output_stream'] = ostream
    698680

    699681
    self.git.archive(treeish, **kwargs)
    700682
    return self
    701-
    683+
    684+
    rev_parse = rev_parse
    685+
    702686
    def __repr__(self):
    703687
    return '<git.Repo "%s">' % self.git_dir

    0 commit comments

    Comments
     (0)
    0