Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a parameter --commit-to-reparent for the reparent command so #130

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

make1980-zz
Copy link

that a list of commits starting from a specified commit to HEAD can be reparented in a cascading manner.

@mhagger

that a list of commits starting from a specified commit to HEAD can be reparented in a cascading manner.
reparent operation should use individual commit's parent to reconstruct
the parents.
Copy link
Owner

@mhagger mhagger left a comment

Choose a reason for hiding this comment

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

Thanks for the patch! Sorry it took so long for me to review it. I left a bunch of comments on it.

I will write up a modified version of your patch that works correctly for more complicated commit topologies. I'm curious if it works for you.

@@ -3717,6 +3749,18 @@ def main(args):
help='the tip of the branch to be merged into HEAD',
)

def add_commit_to_reparent_argument(subparser):
Copy link
Owner

Choose a reason for hiding this comment

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

There's no need for this to be in a function, since it is only called once. (add_*_option() functions are used when the same option applies to multiple commands.)

@@ -3717,6 +3749,18 @@ def main(args):
help='the tip of the branch to be merged into HEAD',
)

def add_commit_to_reparent_argument(subparser):
subparser.add_argument(
'--commit-to-reparent', dest='commit_to_reparent', action='store', default=None,
Copy link
Owner

Choose a reason for hiding this comment

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

  • I think it would be ok to name this option --commit.
  • dest is redundant because that's the default.
  • action is redundant because 'store' is the default action.
  • default=None is redundant because that is the default. However, don't you actually want default='HEAD' here? That would remove the need for cmd_reparent to check this argument and set it to HEAD if it was missing.

'reparent operation creates a new commit object like the original commit, but with the specified parents. '
'reparent command first executes the reparent operation on the commit specified by the --commit-to-reparent argument to generate a new commit object, '
'then it uses this object to replace the first parent of its child commit on the path towards the HEAD commit.\n'
'the command repeats this process till the HEAD commit so that a list of new commit objects are created.'
Copy link
Owner

Choose a reason for hiding this comment

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

Please limit lines to 79 characters.

help=(
'[PARENT...] \n'
'parents is a list of SHA1.\n'
),
Copy link
Owner

Choose a reason for hiding this comment

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

Newline characters don't have an effect in help strings. And instead of starting the help string with [PARENT...], you can set metavar='PARENT'.

@@ -3629,9 +3629,22 @@ def cmd_diagram(parser, options):


def cmd_reparent(parser, options):
if len(options.parents) == 0:
parser.error('Parent is not specified, please specify at least one parent.')
Copy link
Owner

Choose a reason for hiding this comment

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

Why do you add this new restriction? It is perfectly sensible to set a commit to have zero parents; in that case, the commit becomes an orphan commit (i.e., like the first commit made in a fresh repository).

@@ -3640,8 +3653,27 @@ def cmd_reparent(parser, options):
except ValueError as e:
sys.exit(e.message)

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

Choose a reason for hiding this comment

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

It is not OK to remove this output or complicate it. The reparent command is pretty useless if you don't do anything with its output (because it doesn't change any references itself). And likely people want to use the output directly; e.g.,

git update-ref refs/heads/mynewbranch $(git imerge reparent $PARENT)

This works with the old code because the only thing that it outputs to stdout is the final SHA-1. But it won't work with your changes.

@@ -3629,9 +3629,22 @@ def cmd_diagram(parser, options):


def cmd_reparent(parser, options):
if len(options.parents) == 0:
parser.error('Parent is not specified, please specify at least one parent.')
sys.stdout.write('Reparenting from HEAD to %s...\n' % options.commit_to_reparent)
Copy link
Owner

Choose a reason for hiding this comment

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

It is not appropriate to emit progress messages to stdout. They should go to stderr so that the stdout can be piped to another program.

def iterative_reparent(head, commit_to_reparent, parents, git):
commit_list = [head];
current_commit = head;
while current_commit != commit_to_reparent:
Copy link
Owner

Choose a reason for hiding this comment

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

This loop will totally fail (with an IndexError, I believe) if commit_to_reparent is not a first-parent ancestor of head. I understand that this will never be the case the way you want to use the program, but other people might want to use it other ways, and it shouldn't crash for them.

It's not very much harder to rewrite this so that it works for any ancestor of head (not just first-parent ancestors). I'll try to implement that.

current_parents = parents
else:
current_parents = git.get_commit_parents(commit_list[i])
current_parents = [new_commit] + current_parents[1:len(current_parents)]
Copy link
Owner

Choose a reason for hiding this comment

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

This is going to do something screwy if there is more than one ancestry path between commit_to_reparent and head. For example, suppose that there was a merge in between:

o---A---C---D---E---F---H
       /     \     /
  o---B       X---Y

and you run git imerge reparent --commit-to-reparent C A. This algorithm will only rewrite commits C, D, E, F, and H, but won't rewrite X or Y. The result will not be the hoped-for

o---A---C'--D'--E'--F'--H'
             \     /
              X'--Y'

but I think will look like this instead:

      C'--D'--E'------F'--H'
     /               /
o---A---C---D       /
       /     \     /
  o---B       X---Y

I understand that you are not interested in this case, but it's not that much harder to handle it correctly.

mhagger added a commit that referenced this pull request Jun 24, 2018
Add an option `git imerge reparent --commit=COMMIT`, which allows the
parents of an arbitrary commit to be changed. Moreover, the
descendants of COMMIT are also rewritten all the way to HEAD.

This feature was suggested by Ke Ma <[email protected]>, and the
implementation is partly derived from PR #130 submitted by Ke Ma.
mhagger added a commit that referenced this pull request Jun 24, 2018
Add an option `git imerge reparent --commit=COMMIT`, which allows the
parents of an arbitrary commit to be changed. Moreover, the
descendants of COMMIT are also rewritten all the way to HEAD.

This feature was suggested by Ke Ma <[email protected]>, and the
implementation is partly derived from PR #130 submitted by Ke Ma.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants