Imported Upstream version 0.1.6
SVN-Git Migration
8 years ago
0 | Michael Trier <mtrier _at_ gmail.com> | |
1 | Alan Briolat | |
2 | Florian Apolloner <florian _at_ apolloner.eu> | |
3 | David Aguilar <davvid _at_ gmail.com> | |
4 | Jelmer Vernooij <jelmer _at_ samba.org> | |
5 | Steve Frécinaux <code _at_ istique.net> | |
6 | Kai Lautaportti <kai _at_ lautaportti.fi> | |
0 | GitPython was originally written by Michael Trier. | |
1 | ||
2 | Contributors are: | |
3 | ||
4 | -Michael Trier <mtrier _at_ gmail.com> | |
5 | -Alan Briolat | |
6 | -Florian Apolloner <florian _at_ apolloner.eu> | |
7 | -David Aguilar <davvid _at_ gmail.com> | |
8 | -Jelmer Vernooij <jelmer _at_ samba.org> | |
9 | -Steve Frécinaux <code _at_ istique.net> | |
10 | -Kai Lautaportti <kai _at_ lautaportti.fi> | |
11 | -Paul Sowden <paul _at_ idontsmoke.co.uk> | |
12 | ||
13 | Portions derived from other open source works and are clearly marked. |
0 | 0 | ======= |
1 | 1 | CHANGES |
2 | 2 | ======= |
3 | ||
4 | 0.1.6 | |
5 | ===== | |
6 | ||
7 | General | |
8 | ------- | |
9 | * Added in Sphinx documentation. | |
10 | ||
11 | * Removed ambiguity between paths and treeishs. When calling commands that | |
12 | accept treeish and path arguments and there is a path with the same name as | |
13 | a treeish git cowardly refuses to pick one and asks for the command to use | |
14 | the unambiguous syntax where '--' seperates the treeish from the paths. | |
15 | ||
16 | * ``Repo.commits``, ``Repo.commits_between``, ``Reop.commits_since``, | |
17 | ``Repo.commit_count``, ``Repo.commit``, ``Commit.count`` and | |
18 | ``Commit.find_all`` all now optionally take a path argument which | |
19 | constrains the lookup by path. This changes the order of the positional | |
20 | arguments in ``Repo.commits`` and ``Repo.commits_since``. | |
21 | ||
22 | Commit | |
23 | ------ | |
24 | * ``Commit.message`` now contains the full commit message (rather than just | |
25 | the first line) and a new property ``Commit.summary`` contains the first | |
26 | line of the commit message. | |
27 | ||
28 | * Fixed a failure when trying to lookup the stats of a parentless commit from | |
29 | a bare repo. | |
30 | ||
31 | Diff | |
32 | ---- | |
33 | * The diff parser is now far faster and also addresses a bug where | |
34 | sometimes b_mode was not set. | |
35 | ||
36 | * Added support for parsing rename info to the diff parser. Addition of new | |
37 | properties ``Diff.renamed``, ``Diff.rename_from``, and ``Diff.rename_to``. | |
38 | ||
39 | Head | |
40 | ---- | |
41 | * Corrected problem where branches was only returning the last path component | |
42 | instead of the entire path component following refs/heads/. | |
43 | ||
44 | Repo | |
45 | ---- | |
46 | * Modified the gzip archive creation to use the python gzip module. | |
47 | ||
48 | * Corrected ``commits_between`` always returning None instead of the reversed | |
49 | list. | |
50 | ||
3 | 51 | |
4 | 52 | 0.1.5 |
5 | 53 | ===== |
0 | Copyright (c) 2008, Michael Trier and contributors | |
0 | Copyright (C) 2008, 2009 Michael Trier and contributors | |
1 | 1 | All rights reserved. |
2 | 2 | |
3 | 3 | Redistribution and use in source and binary forms, with or without |
0 | 0 | Metadata-Version: 1.0 |
1 | 1 | Name: GitPython |
2 | Version: 0.1.5 | |
2 | Version: 0.1.6 | |
3 | 3 | Summary: Python Git Library |
4 | 4 | Home-page: http://gitorious.org/projects/git-python/ |
5 | 5 | Author: Michael Trier |
18 | 18 | Classifier: Development Status :: 3 - Alpha |
19 | 19 | Classifier: Intended Audience :: Developers |
20 | 20 | Classifier: License :: OSI Approved :: BSD License |
21 | Classifier: Operating System :: OS Independent | |
21 | 22 | Classifier: Programming Language :: Python |
23 | Classifier: Programming Language :: Python :: 2.5 | |
24 | Classifier: Programming Language :: Python :: 2.6 | |
22 | 25 | Classifier: Topic :: Software Development :: Libraries :: Python Modules |
0 | ======== | |
1 | TUTORIAL | |
2 | ======== | |
3 | ||
4 | GitPython provides object model access to your git repository. Once you have | |
5 | created a repository object, you can traverse it to find parent commit(s), | |
6 | trees, blobs, etc. | |
7 | ||
8 | Initialize a Repo object | |
9 | ************************ | |
10 | ||
11 | The first step is to create a ``Repo`` object to represent your repository. | |
12 | ||
13 | >>> from git import * | |
14 | >>> repo = Repo("/Users/mtrier/Development/git-python") | |
15 | ||
16 | In the above example, the directory ``/Users/mtrier/Development/git-python`` | |
17 | is my working repository and contains the ``.git`` directory. You can also | |
18 | initialize GitPython with a bare repository. | |
19 | ||
20 | >>> repo = Repo.create("/var/git/git-python.git") | |
21 | ||
22 | Getting a list of commits | |
23 | ************************* | |
24 | ||
25 | From the ``Repo`` object, you can get a list of ``Commit`` | |
26 | objects. | |
27 | ||
28 | >>> repo.commits() | |
29 | [<git.Commit "207c0c4418115df0d30820ab1a9acd2ea4bf4431">, | |
30 | <git.Commit "a91c45eee0b41bf3cdaad3418ca3850664c4a4b4">, | |
31 | <git.Commit "e17c7e11aed9e94d2159e549a99b966912ce1091">, | |
32 | <git.Commit "bd795df2d0e07d10e0298670005c0e9d9a5ed867">] | |
33 | ||
34 | Called without arguments, ``Repo.commits`` returns a list of up to ten commits | |
35 | reachable by the master branch (starting at the latest commit). You can ask | |
36 | for commits beginning at a different branch, commit, tag, etc. | |
37 | ||
38 | >>> repo.commits('mybranch') | |
39 | >>> repo.commits('40d3057d09a7a4d61059bca9dca5ae698de58cbe') | |
40 | >>> repo.commits('v0.1') | |
41 | ||
42 | You can specify the maximum number of commits to return. | |
43 | ||
44 | >>> repo.commits('master', 100) | |
45 | ||
46 | If you need paging, you can specify a number of commits to skip. | |
47 | ||
48 | >>> repo.commits('master', 10, 20) | |
49 | ||
50 | The above will return commits 21-30 from the commit list. | |
51 | ||
52 | The Commit object | |
53 | ***************** | |
54 | ||
55 | Commit objects contain information about a specific commit. | |
56 | ||
57 | >>> head = repo.commits()[0] | |
58 | ||
59 | >>> head.id | |
60 | '207c0c4418115df0d30820ab1a9acd2ea4bf4431' | |
61 | ||
62 | >>> head.parents | |
63 | [<git.Commit "a91c45eee0b41bf3cdaad3418ca3850664c4a4b4">] | |
64 | ||
65 | >>> head.tree | |
66 | <git.Tree "563413aedbeda425d8d9dcbb744247d0c3e8a0ac"> | |
67 | ||
68 | >>> head.author | |
69 | <git.Actor "Michael Trier <mtrier@gmail.com>"> | |
70 | ||
71 | >>> head.authored_date | |
72 | (2008, 5, 7, 5, 0, 56, 2, 128, 0) | |
73 | ||
74 | >>> head.committer | |
75 | <git.Actor "Michael Trier <mtrier@gmail.com>"> | |
76 | ||
77 | >>> head.committed_date | |
78 | (2008, 5, 7, 5, 0, 56, 2, 128, 0) | |
79 | ||
80 | >>> head.message | |
81 | 'cleaned up a lot of test information. Fixed escaping so it works with | |
82 | subprocess.' | |
83 | ||
84 | Note: date time is represented in a `struct_time`_ format. Conversion to | |
85 | human readable form can be accomplished with the various time module methods. | |
86 | ||
87 | >>> import time | |
88 | >>> time.asctime(head.committed_date) | |
89 | 'Wed May 7 05:56:02 2008' | |
90 | ||
91 | >>> time.strftime("%a, %d %b %Y %H:%M", head.committed_date) | |
92 | 'Wed, 7 May 2008 05:56' | |
93 | ||
94 | .. _struct_time: http://docs.python.org/lib/module-time.html | |
95 | ||
96 | You can traverse a commit's ancestry by chaining calls to ``parents``. | |
97 | ||
98 | >>> repo.commits()[0].parents[0].parents[0].parents[0] | |
99 | ||
100 | The above corresponds to ``master^^^`` or ``master~3`` in git parlance. | |
101 | ||
102 | The Tree object | |
103 | *************** | |
104 | ||
105 | A tree records pointers to the contents of a directory. Let's say you want | |
106 | the root tree of the latest commit on the master branch. | |
107 | ||
108 | >>> tree = repo.commits()[0].tree | |
109 | <git.Tree "a006b5b1a8115185a228b7514cdcd46fed90dc92"> | |
110 | ||
111 | >>> tree.id | |
112 | 'a006b5b1a8115185a228b7514cdcd46fed90dc92' | |
113 | ||
114 | Once you have a tree, you can get the contents. | |
115 | ||
116 | >>> contents = tree.contents | |
117 | [<git.Blob "6a91a439ea968bf2f5ce8bb1cd8ddf5bf2cad6c7">, | |
118 | <git.Blob "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391">, | |
119 | <git.Tree "eaa0090ec96b054e425603480519e7cf587adfc3">, | |
120 | <git.Blob "980e72ae16b5378009ba5dfd6772b59fe7ccd2df">] | |
121 | ||
122 | This tree contains three ``Blob`` objects and one ``Tree`` object. The trees | |
123 | are subdirectories and the blobs are files. Trees below the root have | |
124 | additional attributes. | |
125 | ||
126 | >>> contents = tree["lib"] | |
127 | <git.Tree "c1c7214dde86f76bc3e18806ac1f47c38b2b7a3"> | |
128 | ||
129 | >>> contents.name | |
130 | 'test' | |
131 | ||
132 | >>> contents.mode | |
133 | '040000' | |
134 | ||
135 | There is a convenience method that allows you to get a named sub-object | |
136 | from a tree with a syntax similar to how paths are written in an unix | |
137 | system. | |
138 | ||
139 | >>> tree/"lib" | |
140 | <git.Tree "c1c7214dde86f76bc3e18806ac1f47c38b2b7a30"> | |
141 | ||
142 | You can also get a tree directly from the repository if you know its name. | |
143 | ||
144 | >>> repo.tree() | |
145 | <git.Tree "master"> | |
146 | ||
147 | >>> repo.tree("c1c7214dde86f76bc3e18806ac1f47c38b2b7a30") | |
148 | <git.Tree "c1c7214dde86f76bc3e18806ac1f47c38b2b7a30"> | |
149 | ||
150 | The Blob object | |
151 | *************** | |
152 | ||
153 | A blob represents a file. Trees often contain blobs. | |
154 | ||
155 | >>> blob = tree.contents[-1] | |
156 | <git.Blob "b19574431a073333ea09346eafd64e7b1908ef49"> | |
157 | ||
158 | A blob has certain attributes. | |
159 | ||
160 | >>> blob.name | |
161 | 'urls.py' | |
162 | ||
163 | >>> blob.mode | |
164 | '100644' | |
165 | ||
166 | >>> blob.mime_type | |
167 | 'text/x-python' | |
168 | ||
169 | >>> blob.size | |
170 | 415 | |
171 | ||
172 | You can get the data of a blob as a string. | |
173 | ||
174 | >>> blob.data | |
175 | "from django.conf.urls.defaults import *\nfrom django.conf..." | |
176 | ||
177 | You can also get a blob directly from the repo if you know its name. | |
178 | ||
179 | >>> repo.blob("b19574431a073333ea09346eafd64e7b1908ef49") | |
180 | <git.Blob "b19574431a073333ea09346eafd64e7b1908ef49"> | |
181 | ||
182 | What Else? | |
183 | ********** | |
184 | ||
185 | There is more stuff in there, like the ability to tar or gzip repos, stats, | |
186 | log, blame, and probably a few other things. Additionally calls to the git | |
187 | instance are handled through a ``__getattr__`` construct, which makes | |
188 | available any git commands directly, with a nice conversion of Python dicts | |
189 | to command line parameters. | |
190 | ||
191 | Check the unit tests, they're pretty exhaustive. |
0 | 0 | Metadata-Version: 1.0 |
1 | 1 | Name: GitPython |
2 | Version: 0.1.5 | |
2 | Version: 0.1.6 | |
3 | 3 | Summary: Python Git Library |
4 | 4 | Home-page: http://gitorious.org/projects/git-python/ |
5 | 5 | Author: Michael Trier |
18 | 18 | Classifier: Development Status :: 3 - Alpha |
19 | 19 | Classifier: Intended Audience :: Developers |
20 | 20 | Classifier: License :: OSI Approved :: BSD License |
21 | Classifier: Operating System :: OS Independent | |
21 | 22 | Classifier: Programming Language :: Python |
23 | Classifier: Programming Language :: Python :: 2.5 | |
24 | Classifier: Programming Language :: Python :: 2.6 | |
22 | 25 | Classifier: Topic :: Software Development :: Libraries :: Python Modules |
4 | 4 | README |
5 | 5 | VERSION |
6 | 6 | setup.py |
7 | doc/tutorial.txt | |
8 | 7 | lib/GitPython.egg-info/PKG-INFO |
9 | 8 | lib/GitPython.egg-info/SOURCES.txt |
10 | 9 | lib/GitPython.egg-info/dependency_links.txt |
Binary diff not shown
0 | 0 | # __init__.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
6 | 6 | import os |
7 | 7 | import inspect |
8 | 8 | |
9 | __version__ = '0.1.5' | |
9 | __version__ = '0.1.6' | |
10 | 10 | |
11 | 11 | from git.actor import Actor |
12 | 12 | from git.blob import Blob |
0 | 0 | # actor.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
0 | 0 | # blob.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
0 | 0 | # cmd.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
0 | 0 | # commit.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
40 | 40 | is the committed DateTime |
41 | 41 | |
42 | 42 | ``message`` |
43 | is the first line of the commit message | |
43 | is the commit message | |
44 | 44 | |
45 | 45 | ``parents`` |
46 | 46 | is the list of the parents of the commit |
80 | 80 | def id_abbrev(self): |
81 | 81 | return self.id[0:7] |
82 | 82 | |
83 | @classmethod | |
84 | def count(cls, repo, ref): | |
83 | @property | |
84 | def summary(self): | |
85 | return self.message.split('\n', 1)[0] | |
86 | ||
87 | @classmethod | |
88 | def count(cls, repo, ref, path=''): | |
85 | 89 | """ |
86 | 90 | Count the number of commits reachable from this ref |
87 | 91 | |
91 | 95 | ``ref`` |
92 | 96 | is the ref from which to begin (SHA1 or name) |
93 | 97 | |
98 | ``path`` | |
99 | is an optinal path | |
100 | ||
94 | 101 | Returns |
95 | 102 | int |
96 | 103 | """ |
97 | return len(repo.git.rev_list(ref).strip().splitlines()) | |
98 | ||
99 | @classmethod | |
100 | def find_all(cls, repo, ref, **kwargs): | |
104 | return len(repo.git.rev_list(ref, '--', path).strip().splitlines()) | |
105 | ||
106 | @classmethod | |
107 | def find_all(cls, repo, ref, path='', **kwargs): | |
101 | 108 | """ |
102 | 109 | Find all commits matching the given criteria. |
103 | 110 | ``repo`` |
105 | 112 | |
106 | 113 | ``ref`` |
107 | 114 | is the ref from which to begin (SHA1 or name) |
115 | ||
116 | ``path`` | |
117 | is an optinal path | |
108 | 118 | |
109 | 119 | ``options`` |
110 | 120 | is a Hash of optional arguments to git where |
117 | 127 | options = {'pretty': 'raw'} |
118 | 128 | options.update(kwargs) |
119 | 129 | |
120 | output = repo.git.rev_list(ref, **options) | |
130 | output = repo.git.rev_list(ref, '--', path, **options) | |
121 | 131 | return cls.list_from_string(repo, output) |
122 | 132 | |
123 | 133 | @classmethod |
152 | 162 | while lines and lines[0].startswith(' '): |
153 | 163 | messages.append(lines.pop(0).strip()) |
154 | 164 | |
155 | message = messages and messages[0] or '' | |
156 | ||
157 | commits.append(Commit(repo, id=id, parents=parents, tree=tree, author=author, authored_date=authored_date, | |
165 | message = '\n'.join(messages) | |
166 | ||
167 | commits.append(Commit(repo, id=id, parents=parents, tree=tree, author=author, authored_date=authored_date, | |
158 | 168 | committer=committer, committed_date=committed_date, message=message)) |
159 | 169 | |
160 | 170 | return commits |
161 | 171 | |
162 | 172 | @classmethod |
163 | def diff(cls, repo, a, b = None, paths = None): | |
173 | def diff(cls, repo, a, b=None, paths=None): | |
164 | 174 | """ |
165 | 175 | Show diffs between two trees: |
166 | 176 | |
193 | 203 | if b: |
194 | 204 | paths.insert(0, b) |
195 | 205 | paths.insert(0, a) |
196 | text = repo.git.diff(full_index=True, *paths) | |
206 | text = repo.git.diff('-M', full_index=True, *paths) | |
197 | 207 | return diff.Diff.list_from_string(repo, text) |
198 | 208 | |
199 | 209 | @property |
200 | 210 | def diffs(self): |
201 | 211 | if not self.parents: |
202 | d = self.repo.git.show(self.id, full_index=True, pretty='raw') | |
212 | d = self.repo.git.show(self.id, '-M', full_index=True, pretty='raw') | |
203 | 213 | if re.search(r'diff --git a', d): |
204 | 214 | if not re.search(r'^diff --git a', d): |
205 | 215 | p = re.compile(r'.+?(diff --git a)', re.MULTILINE | re.DOTALL) |
213 | 223 | @property |
214 | 224 | def stats(self): |
215 | 225 | if not self.parents: |
216 | text = self.repo.git.diff(self.id, numstat=True) | |
226 | text = self.repo.git.diff_tree(self.id, '--', numstat=True, root=True) | |
217 | 227 | text2 = "" |
218 | for line in text.splitlines(): | |
228 | for line in text.splitlines()[1:]: | |
219 | 229 | (insertions, deletions, filename) = line.split("\t") |
220 | text2 += "%s\t%s\t%s\n" % (deletions, insertions, filename) | |
230 | text2 += "%s\t%s\t%s\n" % (insertions, deletions, filename) | |
221 | 231 | text = text2 |
222 | 232 | else: |
223 | text = self.repo.git.diff(self.parents[0].id, self.id, numstat=True) | |
233 | text = self.repo.git.diff(self.parents[0].id, self.id, '--', numstat=True) | |
224 | 234 | return stats.Stats.list_from_string(self.repo, text) |
225 | 235 | |
226 | 236 | def __str__(self): |
0 | 0 | # diff.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
11 | 11 | A Diff contains diff information between two commits. |
12 | 12 | """ |
13 | 13 | |
14 | def __init__(self, repo, a_path, b_path, a_commit, b_commit, a_mode, b_mode, new_file, deleted_file, diff): | |
14 | def __init__(self, repo, a_path, b_path, a_commit, b_commit, a_mode, | |
15 | b_mode, new_file, deleted_file, rename_from, | |
16 | rename_to, diff): | |
15 | 17 | self.repo = repo |
16 | 18 | self.a_path = a_path |
17 | 19 | self.b_path = b_path |
29 | 31 | self.b_mode = b_mode |
30 | 32 | self.new_file = new_file |
31 | 33 | self.deleted_file = deleted_file |
34 | self.rename_from = rename_from | |
35 | self.rename_to = rename_to | |
36 | self.renamed = rename_from != rename_to | |
32 | 37 | self.diff = diff |
33 | 38 | |
34 | 39 | @classmethod |
35 | 40 | def list_from_string(cls, repo, text): |
36 | lines = text.splitlines() | |
37 | a_mode = None | |
38 | b_mode = None | |
39 | 41 | diffs = [] |
40 | while lines: | |
41 | m = re.search(r'^diff --git a/(\S+) b/(\S+)$', lines.pop(0)) | |
42 | if m: | |
43 | a_path, b_path = m.groups() | |
44 | if re.search(r'^old mode', lines[0]): | |
45 | m = re.search(r'^old mode (\d+)', lines.pop(0)) | |
46 | if m: | |
47 | a_mode, = m.groups() | |
48 | m = re.search(r'^new mode (\d+)', lines.pop(0)) | |
49 | if m: | |
50 | b_mode, = m.groups() | |
51 | if re.search(r'^diff --git', lines[0]): | |
52 | diffs.append(Diff(repo, a_path, b_path, None, None, a_mode, b_mode, False, False, None)) | |
53 | continue | |
54 | 42 | |
55 | new_file = False | |
56 | deleted_file = False | |
43 | diff_header = re.compile(r""" | |
44 | #^diff[ ]--git | |
45 | [ ]a/(?P<a_path>\S+)[ ]b/(?P<b_path>\S+)\n | |
46 | (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n | |
47 | ^rename[ ]from[ ](?P<rename_from>\S+)\n | |
48 | ^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))? | |
49 | (?:^old[ ]mode[ ](?P<old_mode>\d+)\n | |
50 | ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))? | |
51 | (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))? | |
52 | (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))? | |
53 | (?:^index[ ](?P<a_commit>[0-9A-Fa-f]+) | |
54 | \.\.(?P<b_commit>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))? | |
55 | """, re.VERBOSE | re.MULTILINE).match | |
57 | 56 | |
58 | if re.search(r'^new file', lines[0]): | |
59 | m = re.search(r'^new file mode (.+)', lines.pop(0)) | |
60 | if m: | |
61 | b_mode, = m.groups() | |
62 | a_mode = None | |
63 | new_file = True | |
64 | elif re.search(r'^deleted file', lines[0]): | |
65 | m = re.search(r'^deleted file mode (.+)$', lines.pop(0)) | |
66 | if m: | |
67 | a_mode, = m.groups() | |
68 | b_mode = None | |
69 | deleted_file = True | |
57 | for diff in ('\n' + text).split('\ndiff --git')[1:]: | |
58 | header = diff_header(diff) | |
70 | 59 | |
71 | m = re.search(r'^index ([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+) ?(.+)?$', lines.pop(0)) | |
72 | if m: | |
73 | a_commit, b_commit, b_mode = m.groups() | |
74 | if b_mode: | |
75 | b_mode = b_mode.strip() | |
60 | a_path, b_path, similarity_index, rename_from, rename_to, \ | |
61 | old_mode, new_mode, new_file_mode, deleted_file_mode, \ | |
62 | a_commit, b_commit, b_mode = header.groups() | |
63 | new_file, deleted_file = bool(new_file_mode), bool(deleted_file_mode) | |
76 | 64 | |
77 | diff_lines = [] | |
78 | while lines and not re.search(r'^diff', lines[0]): | |
79 | diff_lines.append(lines.pop(0)) | |
80 | ||
81 | diff = "\n".join(diff_lines) | |
82 | diffs.append(Diff(repo, a_path, b_path, a_commit, b_commit, a_mode, b_mode, new_file, deleted_file, diff)) | |
65 | diffs.append(Diff(repo, a_path, b_path, a_commit, b_commit, | |
66 | old_mode or deleted_file_mode, new_mode or new_file_mode or b_mode, | |
67 | new_file, deleted_file, rename_from, rename_to, diff[header.end():])) | |
83 | 68 | |
84 | 69 | return diffs |
70 |
0 | 0 | # errors.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
0 | 0 | # head.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
103 | 103 | git.Head |
104 | 104 | """ |
105 | 105 | full_name, ids = line.split("\x00") |
106 | name = full_name.split("/")[-1] | |
106 | ||
107 | if full_name.startswith('refs/heads/'): | |
108 | name = full_name[len('refs/heads/'):] | |
109 | else: | |
110 | name = full_name | |
111 | ||
107 | 112 | c = commit.Commit(repo, id=ids) |
108 | 113 | return Head(name, c) |
109 | 114 |
0 | 0 | # lazy.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
0 | 0 | # repo.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
5 | 5 | |
6 | 6 | import os |
7 | 7 | import re |
8 | import gzip | |
9 | import StringIO | |
8 | 10 | from errors import InvalidGitRepositoryError, NoSuchPathError |
9 | 11 | from utils import touch, is_git_dir |
10 | 12 | from cmd import Git |
99 | 101 | """ |
100 | 102 | return Tag.find_all(self) |
101 | 103 | |
102 | def commits(self, start = 'master', max_count = 10, skip = 0): | |
104 | def commits(self, start='master', path='', max_count=10, skip=0): | |
103 | 105 | """ |
104 | 106 | A list of Commit objects representing the history of a given ref/commit |
105 | 107 | |
106 | 108 | ``start`` |
107 | 109 | is the branch/commit name (default 'master') |
108 | 110 | |
111 | ``path`` | |
112 | is an optional path | |
113 | ||
109 | 114 | ``max_count`` |
110 | 115 | is the maximum number of commits to return (default 10) |
111 | 116 | |
118 | 123 | options = {'max_count': max_count, |
119 | 124 | 'skip': skip} |
120 | 125 | |
121 | return Commit.find_all(self, start, **options) | |
122 | ||
123 | def commits_between(self, frm, to): | |
126 | return Commit.find_all(self, start, path, **options) | |
127 | ||
128 | def commits_between(self, frm, to, path = ''): | |
124 | 129 | """ |
125 | 130 | The Commits objects that are reachable via ``to`` but not via ``frm`` |
126 | 131 | Commits are returned in chronological order. |
131 | 136 | ``to`` |
132 | 137 | is the branch/commit name of the older item |
133 | 138 | |
139 | ``path`` | |
140 | is an optional path | |
141 | ||
134 | 142 | Returns |
135 | 143 | ``git.Commit[]`` |
136 | 144 | """ |
137 | return Commit.find_all(self, "%s..%s" % (frm, to)).reverse() | |
138 | ||
139 | def commits_since(self, start = 'master', since = '1970-01-01'): | |
145 | return reversed(Commit.find_all(self, "%s..%s" % (frm, to))) | |
146 | ||
147 | def commits_since(self, start='master', path='', since='1970-01-01'): | |
140 | 148 | """ |
141 | 149 | The Commits objects that are newer than the specified date. |
142 | 150 | Commits are returned in chronological order. |
144 | 152 | ``start`` |
145 | 153 | is the branch/commit name (default 'master') |
146 | 154 | |
155 | ``path`` | |
156 | is an optinal path | |
157 | ||
147 | 158 | ``since`` |
148 | 159 | is a string represeting a date/time |
149 | 160 | |
152 | 163 | """ |
153 | 164 | options = {'since': since} |
154 | 165 | |
155 | return Commit.find_all(self, start, **options) | |
156 | ||
157 | def commit_count(self, start = 'master'): | |
166 | return Commit.find_all(self, start, path, **options) | |
167 | ||
168 | def commit_count(self, start='master', path=''): | |
158 | 169 | """ |
159 | 170 | The number of commits reachable by the given branch/commit |
160 | 171 | |
161 | 172 | ``start`` |
162 | 173 | is the branch/commit name (default 'master') |
163 | 174 | |
175 | ``path`` | |
176 | is an optinal path | |
177 | ||
164 | 178 | Returns |
165 | 179 | int |
166 | 180 | """ |
167 | return Commit.count(self, start) | |
168 | ||
169 | def commit(self, id): | |
181 | return Commit.count(self, start, path) | |
182 | ||
183 | def commit(self, id, path = ''): | |
170 | 184 | """ |
171 | 185 | The Commit object for the specified id |
172 | 186 | |
173 | 187 | ``id`` |
174 | 188 | is the SHA1 identifier of the commit |
175 | 189 | |
190 | ``path`` | |
191 | is an optinal path | |
192 | ||
176 | 193 | Returns |
177 | 194 | git.Commit |
178 | 195 | """ |
179 | 196 | options = {'max_count': 1} |
180 | 197 | |
181 | commits = Commit.find_all(self, id, **options) | |
198 | commits = Commit.find_all(self, id, path, **options) | |
182 | 199 | |
183 | 200 | if not commits: |
184 | 201 | raise ValueError, 'Invalid identifier %s' % id |
185 | 202 | return commits[0] |
186 | 203 | |
187 | def commit_deltas_from(self, other_repo, ref = 'master', other_ref = 'master'): | |
204 | def commit_deltas_from(self, other_repo, ref='master', other_ref='master'): | |
188 | 205 | """ |
189 | 206 | Returns a list of commits that is in ``other_repo`` but not in self |
190 | 207 | |
191 | 208 | Returns |
192 | 209 | ``git.Commit[]`` |
193 | 210 | """ |
194 | repo_refs = self.git.rev_list(ref).strip().splitlines() | |
195 | other_repo_refs = other_repo.git.rev_list(other_ref).strip().splitlines() | |
211 | repo_refs = self.git.rev_list(ref, '--').strip().splitlines() | |
212 | other_repo_refs = other_repo.git.rev_list(other_ref, '--').strip().splitlines() | |
196 | 213 | |
197 | 214 | diff_refs = list(set(other_repo_refs) - set(repo_refs)) |
198 | 215 | return map(lambda ref: Commit.find_all(other_repo, ref, max_count=1)[0], diff_refs) |
199 | 216 | |
200 | def tree(self, treeish = 'master'): | |
217 | def tree(self, treeish='master'): | |
201 | 218 | """ |
202 | 219 | The Tree object for the given treeish reference |
203 | 220 | |
226 | 243 | """ |
227 | 244 | return Blob(self, id=id) |
228 | 245 | |
229 | def log(self, commit = 'master', path = None, **kwargs): | |
246 | def log(self, commit='master', path=None, **kwargs): | |
230 | 247 | """ |
231 | 248 | The commit log for a treeish |
232 | 249 | |
235 | 252 | """ |
236 | 253 | options = {'pretty': 'raw'} |
237 | 254 | options.update(kwargs) |
255 | arg = [commit, '--'] | |
238 | 256 | if path: |
239 | arg = [commit, '--', path] | |
240 | else: | |
241 | arg = [commit] | |
257 | arg.append(path) | |
242 | 258 | commits = self.git.log(*arg, **options) |
243 | 259 | return Commit.list_from_string(self, commits) |
244 | 260 | |
315 | 331 | self.git.clone(self.path, path, **options) |
316 | 332 | return Repo(path) |
317 | 333 | |
318 | def archive_tar(self, treeish = 'master', prefix = None): | |
334 | def archive_tar(self, treeish='master', prefix=None): | |
319 | 335 | """ |
320 | 336 | Archive the given treeish |
321 | 337 | |
344 | 360 | options['prefix'] = prefix |
345 | 361 | return self.git.archive(treeish, **options) |
346 | 362 | |
347 | def archive_tar_gz(self, treeish = 'master', prefix = None): | |
363 | def archive_tar_gz(self, treeish='master', prefix=None): | |
348 | 364 | """ |
349 | 365 | Archive and gzip the given treeish |
350 | 366 | |
371 | 387 | kwargs = {} |
372 | 388 | if prefix: |
373 | 389 | kwargs['prefix'] = prefix |
374 | self.git.archive(treeish, "| gzip", **kwargs) | |
390 | resultstr = self.git.archive(treeish, **kwargs) | |
391 | sio = StringIO.StringIO() | |
392 | gf = gzip.GzipFile(fileobj=sio, mode ='wb') | |
393 | gf.write(resultstr) | |
394 | gf.close() | |
395 | return sio.getvalue() | |
375 | 396 | |
376 | 397 | def _get_daemon_export(self): |
377 | 398 | filename = os.path.join(self.path, self.DAEMON_EXPORT_FILE) |
449 | 470 | # always consired to be clean. |
450 | 471 | return False |
451 | 472 | |
452 | return len(self.git.diff('HEAD').strip()) > 0 | |
473 | return len(self.git.diff('HEAD', '--').strip()) > 0 | |
453 | 474 | |
454 | 475 | @property |
455 | 476 | def active_branch(self): |
456 | 477 | """ |
457 | 478 | The name of the currently active branch. |
458 | ||
479 | ||
459 | 480 | Returns |
460 | 481 | str (the branch name) |
461 | 482 | """ |
0 | 0 | # stats.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
0 | 0 | # tag.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
0 | 0 | # tree.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
0 | 0 | # utils.py |
1 | # Copyright (C) 2008 Michael Trier (mtrier@gmail.com) and contributors | |
1 | # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors | |
2 | 2 | # |
3 | 3 | # This module is part of GitPython and is released under |
4 | 4 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
73 | 73 | "Development Status :: 3 - Alpha", |
74 | 74 | "Intended Audience :: Developers", |
75 | 75 | "License :: OSI Approved :: BSD License", |
76 | "Operating System :: OS Independent", | |
76 | 77 | "Programming Language :: Python", |
78 | "Programming Language :: Python :: 2.5", | |
79 | "Programming Language :: Python :: 2.6", | |
77 | 80 | "Topic :: Software Development :: Libraries :: Python Modules", |
78 | 81 | ] |
79 | 82 | ) |