Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 63 additions & 5 deletions git-imerge
Original file line number Diff line number Diff line change
Expand Up @@ -3628,19 +3628,63 @@ def cmd_diagram(parser, options):
)


def reparent_recursively(git, start_commit, parents, end_commit):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this isn't a recursive process but rather an iterative process

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is in fact recursive; it's just that the recursion is built into git log --topo-order --reverse rather than coded explicitly here. But this is just an internal name so I don't think the distinction matters much.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense.

"""Change the parents of start_commit and its descendants.

Change start_commit to have the specified parents, and reparent
all commits on the ancestry path between start_commit and
end_commit accordingly. Return the replacement end_commit.
start_commit, parents, and end_commit must all be resolved OIDs.

"""

# A map {old_oid : new_oid} keeping track of which replacements
# have to be made:
replacements = {}

# Reparent start_commit:
replacements[start_commit] = git.reparent(start_commit, parents)

for (commit, parents) in git.rev_list_with_parents(
'--ancestry-path', '--topo-order', '--reverse',
'%s..%s' % (start_commit, end_commit)
):
parents = [replacements.get(p, p) for p in parents]
replacements[commit] = git.reparent(commit, parents)

try:
return replacements[end_commit]
except KeyError:
raise ValueError(
"%s is not an ancestor of %s" % (start_commit, end_commit),
)


def cmd_reparent(parser, options):
git = GitRepository()
try:
commit_sha1 = git.get_commit_sha1('HEAD')
commit = git.get_commit_sha1(options.commit)
except ValueError:
sys.exit('%s is not a valid commit', options.commit)

try:
head = git.get_commit_sha1('HEAD')
except ValueError:
sys.exit('HEAD is not a valid commit')

try:
parent_sha1s = [git.get_commit_sha1(p) for p in options.parents]
parents = [git.get_commit_sha1(p) for p in options.parents]
except ValueError as e:
sys.exit(e.message)

sys.stderr.write('Reparenting %s..HEAD\n' % (options.commit,))

try:
new_head = reparent_recursively(git, commit, parents, head)
except ValueError as e:
sys.exit(e.message)

sys.stdout.write('%s\n' % (git.reparent(commit_sha1, parent_sha1s),))
sys.stdout.write('%s\n' % (new_head,))


def main(args):
Expand Down Expand Up @@ -3927,10 +3971,24 @@ def main(args):

subparser = subparsers.add_parser(
'reparent',
help='change the parents of the HEAD commit',
help=(
'change the parents of the specified commit and propagate the '
'change to HEAD'
),
)
subparser.add_argument(
'parents', nargs='*', help='[PARENT...]',
'--commit', metavar='COMMIT', default='HEAD',
help=(
'target commit to reparent. Create a new commit identical to '
'this one, but having the specified parents. Then create '
'new versions of all descendants of this commit all the way to '
'HEAD, incorporating the modified commit. Output the SHA-1 of '
'the replacement HEAD commit.'
),
)
subparser.add_argument(
'parents', nargs='*', metavar='PARENT',
help='a list of commits',
)

options = parser.parse_args(args)
Expand Down