Skip to content

Initial Rebase implementation #964

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

Merged
merged 1 commit into from
Jun 23, 2015
Merged

Initial Rebase implementation #964

merged 1 commit into from
Jun 23, 2015

Conversation

jamill
Copy link
Member

@jamill jamill commented Feb 17, 2015

Getting closer to completion

Includes:

  • Initiate a Rebase (merge strategy)
  • Abort a Rebase (merge strategy)
  • Continue a Rebase (merge strategy)
  • Progress reporting
    • Before / After each rebase step
    • Checkout progress during each rebase step

Does not include:

  • Interactive Rebase support, of any kind
  • Support for rebases not using the merge strategy
  • Ability to execute rebase "commands"

TODO:

  • Expand test coverage
    • Tests for checkout progress
    • Tests for FileConflictStrategy

To Think About:

  • Ref inputs: I think it would be nice if methods such as merge, rebase could take in a "generic" object or interface that can be peeled to a commit, but still have information about where it came from. For instance, rebase takes 3 "ref" inputs. Instead of adding overloads for each permutation of ref input (commit, string, branch, tag...). I suspect this could be similar to the git_annotated_commit concept in libgit2.

Related issue: #714

@jamill jamill self-assigned this Feb 17, 2015
@jamill jamill added this to the v0.22 milestone Feb 17, 2015
/// <summary>
/// Access to Rebase functionality.
/// </summary>
Rebase RebaseOperation { get; }
Copy link
Member

Choose a reason for hiding this comment

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

How do you foresee to use this?

Copy link
Member

Choose a reason for hiding this comment

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

Found it. Not sure I'm a fan of having the Rebase() method in the main namespace and the other methods under RebaseOperation. How about exposing a separate repo.Rebase namespace (à la repo.Diff)?

We could replace repo.Rebase() with something like repo.Rebase.Start(), Initiate(), ...

Copy link
Member Author

Choose a reason for hiding this comment

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

yes - that seems reasonable. Thinking about the larger picture, cherry-pick and revert both have a similar "sequenced" capability. If we put rebase in its own namespace, then we would we have repo.CherryPick.Start(...), and repo.Revert.Start(...)? These (and Merge) all seem to be similar types of operations, would Merge also move into a repo.Merge.Start(...) type of structure? One option is that we could do this, and then have extension methods to expose these on the repository object directly?

@nulltoken
Copy link
Member

How does the code behave when

  • One initiates a new Rebase() whereas one is already started?
  • One tries to continue (or abort) when no rebase is in progress?

@jamill
Copy link
Member Author

jamill commented Feb 23, 2015

How does the code behave when...

The code should throw an exception in these cases. There is already a test case that covers initiating a rebase while one is already started RebaseWhileAlreadyRebasingThrows(). I can add test coverage to assert we throw in the other case as well.

@jamill
Copy link
Member Author

jamill commented Feb 24, 2015

  1. I moved the entry point for rebase into the Rebase namespace.
  2. I added tests to assert the behavior when attempting to abort, continue a rebase when one is not in progress. This is currently returning a NotFoundException (as it can't find the rebase operation). This is a bit weird, we could return a specificly typed exception here.

/// <param name="committer"></param>
/// <param name="options"></param>
/// <returns>true if completed successfully, false if conflicts encountered.</returns>
public virtual RebaseResult Start(Branch branch, Branch upstream, Branch onto, Signature committer, RebaseOptions options)
Copy link
Contributor

Choose a reason for hiding this comment

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

In the long run, I think it would be more flexible to take a commit rather than a branch, at least for the onto argument. I often use rebase -i some_commit_id to clean up before a push. This could be added as an overload later though.

Copy link
Member

Choose a reason for hiding this comment

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

We probably don't want to take a bare commit here - these things end up influencing the messages that we produce in the reflog and the markers in the conflict files. Do we have the equivalent of an AnnotatedCommit in libgit2sharp?

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, to expand on that a little bit more: I mean we probably shouldn't only take a commit id (but we should perhaps allow it). Although a Branch is going to be convertible to a commit ID at some point, if you let libgit2 handle that conversion it will keep around the information of where that commit ID came from (as an "annotated commit"). Without that your conflict markers will look like:

<<<< ab1dc99f...
change on one side
===== ab1cdde
common ancestor
=====
change on the other side
>>>>> 9acca3a

Which is quite hard to read (I think) compared to having the branch names / etc.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could it just take GitAnnotatedCommitHandles as arguments? The branch args are getting converted into these anyways.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks @rcorre - GitAnnotatedCommitHandle is a lower level concept between lg2# and lg2 - it does not get exposed on the lg2# API. I agree with the idea that the API should be more flexible in the inputs it accepts (this is one of the items I had called out in my To Think About section in the PR description).

@jamill jamill force-pushed the jamill/rebase branch 2 times, most recently from 03a04d8 to 339a9c7 Compare March 12, 2015 18:41
@nulltoken
Copy link
Member

Rebased this PR. Ah, the irony...


using (ThreadAffinity())
{
int result = NativeMethods.git_rebase_abort(rebase);
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we Ensure here?

Copy link
Member Author

Choose a reason for hiding this comment

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

We now Ensure the result - thanks for pointing this out!

@jamill
Copy link
Member Author

jamill commented Apr 13, 2015

@Therzok I have some changes for moving more of the code into using the using construct - will push it up shortly

@Therzok
Copy link
Member

Therzok commented Apr 13, 2015

❤️


// Verify the chain of commits that resulted from the rebase.
Commit expectedParent = expectedOntoCommit;
foreach(CompletedRebaseStepInfo stepInfo in PostRebaseResults)
Copy link
Member

Choose a reason for hiding this comment

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

Nit: missing spaaaaace.

/// <summary>
/// Command to execute, if any.
/// </summary>
public virtual string Exec { get; private set; }
Copy link
Member

Choose a reason for hiding this comment

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

Similarly do we need to expose this yet?

@jamill jamill force-pushed the jamill/rebase branch 3 times, most recently from 9a55a2c to 3a03ef3 Compare May 29, 2015 20:57
@jamill
Copy link
Member Author

jamill commented Jun 18, 2015

@nulltoken tests are green, rebased on top of vNext.

@jamill
Copy link
Member Author

jamill commented Jun 22, 2015

@nulltoken - anything else here? 😄

@nulltoken
Copy link
Member

:shipit:

/cc @Therzok @dahlbyk

@Therzok
Copy link
Member

Therzok commented Jun 22, 2015

LGTM! 🚀 🚢 🇮🇹

nulltoken added a commit that referenced this pull request Jun 23, 2015
Initial Rebase implementation
@nulltoken nulltoken merged commit 87dccce into vNext Jun 23, 2015
@nulltoken nulltoken deleted the jamill/rebase branch June 23, 2015 16:07
@nulltoken
Copy link
Member

@jamill 💯 ‼️

@whoisj
Copy link

whoisj commented Jun 23, 2015

@jamill 💯 ‼️

Agreed. This is awesome - I am super excited to finally have rebase support. Oh the wonderful things we can bring to the world with this. 😃

@dahlbyk dahlbyk mentioned this pull request Jun 23, 2015
@carlosmn carlosmn mentioned this pull request Mar 7, 2016
@cortex-pg
Copy link

Is it possible in git2sharp to rebase individual commits such as in this example http://blog.dennisrobinson.name/reorder-commits-with-git/ ? I am trying to do this in order to squash them into one commit which can then be cherrypicked.

@dahlbyk
Copy link
Member

dahlbyk commented Mar 30, 2016

If you just need to squash, you'll have an easier time with:

  1. Soft reset (leave index intact) to merge base.
  2. Commit.
  3. Rebase/cherry-pick.

@cortex-pg
Copy link

Thanks for that, this is actually what I have done at the moment. However there can be additional commits mixed in that I don't want to merge which was why I was looking at rebase. Alternatively if I could cherrypick multiple commits it would avoid the need to merge them at all but it seems Git2Sharp only supports picking 1 at a time.

@ethomson
Copy link
Member

Alternatively if I could cherrypick multiple commits it would avoid the need to merge them at all but it seems Git2Sharp only supports picking 1 at a time.

I'm not sure that I understand what you mean. You can only ever cherry-pick one at a time - git (for example) will simply apply them in serial. (It doesn't create some strange multi-patch and try to apply them all at once).

So you should be able to just call cherry-pick in a loop...

@dahlbyk
Copy link
Member

dahlbyk commented Mar 30, 2016

Maybe referring to cherry-pick -n, which will apply multiple in serial but leaves all changes staged but uncommitted?

@cortex-pg
Copy link

Thanks for that, I was considering using a loop but I can do
git cherry-pick 51959c1 fc5f375 --no-commit or
git cherry-pick 51959c1 --no-commit
git cherry-pick fc5f375 --no-commit and these work as expected.

However if I use
_repository.CherryPick(commit, author, new CherryPickOptions() { CommitOnSuccess = false }); on each of these commits the 2nd call throws LibGit2Sharp.CheckoutConflictException 1 uncommitted change would be overwritten by merge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants