Skip to content

Commit 36811a2

Browse files
committed
add replace method to git.Commit
This adds a replace method to git.Commit. The replace method returns a copy of the Commit object with attributes replaced from keyword arguments. For example: >>> old = repo.head.commit >>> new = old.replace(message='This is a test') closes #1123
1 parent e1cd58b commit 36811a2

File tree

2 files changed

+56
-7
lines changed

2 files changed

+56
-7
lines changed

git/objects/commit.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,41 @@ def __init__(self, repo, binsha, tree=None, author=None, authored_date=None, aut
136136
def _get_intermediate_items(cls, commit):
137137
return commit.parents
138138

139+
@classmethod
140+
def _calculate_sha_(cls, repo, commit):
141+
'''Calculate the sha of a commit.
142+
143+
:param repo: Repo object the commit should be part of
144+
:param commit: Commit object for which to generate the sha
145+
'''
146+
147+
stream = BytesIO()
148+
commit._serialize(stream)
149+
streamlen = stream.tell()
150+
stream.seek(0)
151+
152+
istream = repo.odb.store(IStream(cls.type, streamlen, stream))
153+
return istream.binsha
154+
155+
def replace(self, **kwargs):
156+
'''Create new commit object from existing commit object.
157+
158+
Any values provided as keyword arguments will replace the
159+
corresponding attribute in the new object.
160+
'''
161+
162+
attrs = {k: getattr(self, k) for k in self.__slots__}
163+
164+
for attrname in kwargs:
165+
if attrname not in self.__slots__:
166+
raise ValueError('invalid attribute name')
167+
168+
attrs.update(kwargs)
169+
new_commit = self.__class__(self.repo, self.NULL_BIN_SHA, **attrs)
170+
new_commit.binsha = self._calculate_sha_(self.repo, new_commit)
171+
172+
return new_commit
173+
139174
def _set_cache_(self, attr):
140175
if attr in Commit.__slots__:
141176
# read the data in a chunk, its faster - then provide a file wrapper
@@ -375,13 +410,7 @@ def create_from_tree(cls, repo, tree, message, parent_commits=None, head=False,
375410
committer, committer_time, committer_offset,
376411
message, parent_commits, conf_encoding)
377412

378-
stream = BytesIO()
379-
new_commit._serialize(stream)
380-
streamlen = stream.tell()
381-
stream.seek(0)
382-
383-
istream = repo.odb.store(IStream(cls.type, streamlen, stream))
384-
new_commit.binsha = istream.binsha
413+
new_commit.binsha = cls._calculate_sha_(repo, new_commit)
385414

386415
if head:
387416
# need late import here, importing git at the very beginning throws

test/test_commit.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,26 @@ def test_bake(self):
101101
assert isinstance(commit.author_tz_offset, int) and isinstance(commit.committer_tz_offset, int)
102102
self.assertEqual(commit.message, "Added missing information to docstrings of commit and stats module\n")
103103

104+
def test_replace_no_changes(self):
105+
old_commit = self.rorepo.commit('2454ae89983a4496a445ce347d7a41c0bb0ea7ae')
106+
new_commit = old_commit.replace()
107+
108+
for attr in old_commit.__slots__:
109+
assert getattr(new_commit, attr) == getattr(old_commit, attr)
110+
111+
def test_replace_new_sha(self):
112+
commit = self.rorepo.commit('2454ae89983a4496a445ce347d7a41c0bb0ea7ae')
113+
new_commit = commit.replace(message='Added replace method')
114+
115+
assert new_commit.hexsha == 'fc84cbecac1bd4ba4deaac07c1044889edd536e6'
116+
assert new_commit.message == 'Added replace method'
117+
118+
def test_replace_invalid_attribute(self):
119+
commit = self.rorepo.commit('2454ae89983a4496a445ce347d7a41c0bb0ea7ae')
120+
121+
with self.assertRaises(ValueError):
122+
commit.replace(badattr='This will never work')
123+
104124
def test_stats(self):
105125
commit = self.rorepo.commit('33ebe7acec14b25c5f84f35a664803fcab2f7781')
106126
stats = commit.stats

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy