Skip to content

Commit 826cf16

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 826cf16

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

git/objects/commit.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,24 @@ 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+
stream = BytesIO()
142+
commit._serialize(stream)
143+
streamlen = stream.tell()
144+
stream.seek(0)
145+
146+
istream = repo.odb.store(IStream(cls.type, streamlen, stream))
147+
return istream.binsha
148+
149+
def replace(self, **kwargs):
150+
attrs = {k: getattr(self, k) for k in self.__slots__}
151+
attrs.update(kwargs)
152+
new_commit = self.__class__(self.repo, self.__class__.NULL_BIN_SHA, **attrs)
153+
new_commit.binsha = self._calculate_sha_(self.repo, new_commit)
154+
155+
return new_commit
156+
139157
def _set_cache_(self, attr):
140158
if attr in Commit.__slots__:
141159
# read the data in a chunk, its faster - then provide a file wrapper
@@ -375,13 +393,7 @@ def create_from_tree(cls, repo, tree, message, parent_commits=None, head=False,
375393
committer, committer_time, committer_offset,
376394
message, parent_commits, conf_encoding)
377395

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
396+
new_commit.binsha = cls._calculate_sha_(repo, new_commit)
385397

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

test/test_commit.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,20 @@ 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+
104118
def test_stats(self):
105119
commit = self.rorepo.commit('33ebe7acec14b25c5f84f35a664803fcab2f7781')
106120
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