@@ -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
0 commit comments