@@ -3628,19 +3628,63 @@ def cmd_diagram(parser, options):
36283628 )
36293629
36303630
3631+ def reparent_recursively (git , start_commit , parents , end_commit ):
3632+ """Change the parents of start_commit and its descendants.
3633+
3634+ Change start_commit to have the specified parents, and reparent
3635+ all commits on the ancestry path between start_commit and
3636+ end_commit accordingly. Return the replacement end_commit.
3637+ start_commit, parents, and end_commit must all be resolved OIDs.
3638+
3639+ """
3640+
3641+ # A map {old_oid : new_oid} keeping track of which replacements
3642+ # have to be made:
3643+ replacements = {}
3644+
3645+ # Reparent start_commit:
3646+ replacements [start_commit ] = git .reparent (start_commit , parents )
3647+
3648+ for (commit , parents ) in git .rev_list_with_parents (
3649+ '--ancestry-path' , '--topo-order' , '--reverse' ,
3650+ '%s..%s' % (start_commit , end_commit )
3651+ ):
3652+ parents = [replacements .get (p , p ) for p in parents ]
3653+ replacements [commit ] = git .reparent (commit , parents )
3654+
3655+ try :
3656+ return replacements [end_commit ]
3657+ except KeyError :
3658+ raise ValueError (
3659+ "%s is not an ancestor of %s" % (start_commit , end_commit ),
3660+ )
3661+
3662+
36313663def cmd_reparent (parser , options ):
36323664 git = GitRepository ()
36333665 try :
3634- commit_sha1 = git .get_commit_sha1 ('HEAD' )
3666+ commit = git .get_commit_sha1 (options .commit )
3667+ except ValueError :
3668+ sys .exit ('%s is not a valid commit' , options .commit )
3669+
3670+ try :
3671+ head = git .get_commit_sha1 ('HEAD' )
36353672 except ValueError :
36363673 sys .exit ('HEAD is not a valid commit' )
36373674
36383675 try :
3639- parent_sha1s = [git .get_commit_sha1 (p ) for p in options .parents ]
3676+ parents = [git .get_commit_sha1 (p ) for p in options .parents ]
3677+ except ValueError as e :
3678+ sys .exit (e .message )
3679+
3680+ sys .stderr .write ('Reparenting %s..HEAD\n ' % (options .commit ,))
3681+
3682+ try :
3683+ new_head = reparent_recursively (git , commit , parents , head )
36403684 except ValueError as e :
36413685 sys .exit (e .message )
36423686
3643- sys .stdout .write ('%s\n ' % (git . reparent ( commit_sha1 , parent_sha1s ) ,))
3687+ sys .stdout .write ('%s\n ' % (new_head ,))
36443688
36453689
36463690def main (args ):
@@ -3927,10 +3971,24 @@ def main(args):
39273971
39283972 subparser = subparsers .add_parser (
39293973 'reparent' ,
3930- help = 'change the parents of the HEAD commit' ,
3974+ help = (
3975+ 'change the parents of the specified commit and propagate the '
3976+ 'change to HEAD'
3977+ ),
39313978 )
39323979 subparser .add_argument (
3933- 'parents' , nargs = '*' , help = '[PARENT...]' ,
3980+ '--commit' , metavar = 'COMMIT' , default = 'HEAD' ,
3981+ help = (
3982+ 'target commit to reparent. Create a new commit identical to '
3983+ 'this one, but having the specified parents. Then create '
3984+ 'new versions of all descendants of this commit all the way to '
3985+ 'HEAD, incorporating the modified commit. Output the SHA-1 of '
3986+ 'the replacement HEAD commit.'
3987+ ),
3988+ )
3989+ subparser .add_argument (
3990+ 'parents' , nargs = '*' , metavar = 'PARENT' ,
3991+ help = 'a list of commits' ,
39343992 )
39353993
39363994 options = parser .parse_args (args )
0 commit comments