diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
index e98f150ac..6ffe97c52 100644
--- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
+++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
@@ -18,12 +18,16 @@
-
-
+
+
-
-
-
+
+
+
+
+
+
+
diff --git a/LibGit2Sharp.Tests/RebaseFixture.cs b/LibGit2Sharp.Tests/RebaseFixture.cs
index 28c49738e..b6deba946 100644
--- a/LibGit2Sharp.Tests/RebaseFixture.cs
+++ b/LibGit2Sharp.Tests/RebaseFixture.cs
@@ -78,7 +78,7 @@ public void CanRebase(string initialBranchName,
},
};
- RebaseResult rebaseResult = repo.Rebase.Start(branch, upstream, onto, Constants.Identity, options);
+ RebaseResult rebaseResult = Commands.Rebase.Start(repo, branch, upstream, onto, Constants.Identity, options);
// Validation:
Assert.True(afterRebaseStepCountCorrect, "Unexpected CompletedStepIndex value in RebaseStepCompleted");
@@ -130,7 +130,7 @@ public void CanRebaseBranchOntoItself()
Commands.Checkout(repo, topicBranch2Name);
Branch b = repo.Branches[topicBranch2Name];
- RebaseResult result = repo.Rebase.Start(b, b, null, Constants.Identity, new RebaseOptions());
+ RebaseResult result = Commands.Rebase.Start(repo, b, b, null, Constants.Identity, new RebaseOptions());
Assert.Equal(0, result.TotalStepCount);
Assert.Equal(RebaseStatus.Complete, result.Status);
Assert.Equal(0, result.CompletedStepCount);
@@ -251,7 +251,7 @@ public void VerifyRebaseDetailed(string attributes, string lineEnding, string[]
};
- repo.Rebase.Start(null, upstreamBranch, null, Constants.Identity2, options);
+ Commands.Rebase.Start(repo, null, upstreamBranch, null, Constants.Identity2, options);
Assert.Equal(true, wasCheckoutNotifyCalledForResetingHead);
Assert.Equal(true, wasCheckoutProgressCalledForResetingHead);
@@ -317,7 +317,7 @@ public void CanContinueRebase()
CheckoutNotifyFlags = CheckoutNotifyFlags.Updated,
};
- RebaseResult rebaseResult = repo.Rebase.Start(branch, upstream, onto, Constants.Identity, options);
+ RebaseResult rebaseResult = Commands.Rebase.Start(repo, branch, upstream, onto, Constants.Identity, options);
// Verify that we have a conflict.
Assert.Equal(CurrentOperation.RebaseMerge, repo.Info.CurrentOperation);
@@ -345,7 +345,7 @@ public void CanContinueRebase()
// Clear the flags:
wasCheckoutProgressCalled = false; wasCheckoutNotifyCalled = false;
- RebaseResult continuedRebaseResult = repo.Rebase.Continue(Constants.Identity, options);
+ RebaseResult continuedRebaseResult = Commands.Rebase.Continue(repo, Constants.Identity, options);
Assert.NotNull(continuedRebaseResult);
Assert.Equal(RebaseStatus.Complete, continuedRebaseResult.Status);
@@ -377,7 +377,7 @@ public void ContinuingRebaseWithUnstagedChangesThrows()
Branch upstream = repo.Branches[conflictBranch1Name];
Branch onto = repo.Branches[conflictBranch1Name];
- RebaseResult rebaseResult = repo.Rebase.Start(branch, upstream, onto, Constants.Identity, null);
+ RebaseResult rebaseResult = Commands.Rebase.Start(repo, branch, upstream, onto, Constants.Identity, null);
// Verify that we have a conflict.
Assert.Equal(CurrentOperation.RebaseMerge, repo.Info.CurrentOperation);
@@ -388,7 +388,7 @@ public void ContinuingRebaseWithUnstagedChangesThrows()
Assert.Equal(3, rebaseResult.TotalStepCount);
Assert.Throws(() =>
- repo.Rebase.Continue(Constants.Identity, null));
+ Commands.Rebase.Continue(repo, Constants.Identity, null));
// Resolve the conflict
foreach (Conflict conflict in repo.Index.Conflicts)
@@ -404,7 +404,7 @@ public void ContinuingRebaseWithUnstagedChangesThrows()
"Unstaged content");
Assert.Throws(() =>
- repo.Rebase.Continue(Constants.Identity, null));
+ Commands.Rebase.Continue(repo, Constants.Identity, null));
Assert.True(repo.Index.IsFullyMerged);
}
@@ -431,7 +431,7 @@ public void CanSpecifyFileConflictStrategy()
FileConflictStrategy = CheckoutFileConflictStrategy.Ours,
};
- RebaseResult rebaseResult = repo.Rebase.Start(branch, upstream, onto, Constants.Identity, options);
+ RebaseResult rebaseResult = Commands.Rebase.Start(repo, branch, upstream, onto, Constants.Identity, options);
// Verify that we have a conflict.
Assert.Equal(CurrentOperation.RebaseMerge, repo.Info.CurrentOperation);
@@ -473,7 +473,7 @@ public void CanQueryRebaseOperation()
Branch upstream = repo.Branches[conflictBranch1Name];
Branch onto = repo.Branches[conflictBranch1Name];
- RebaseResult rebaseResult = repo.Rebase.Start(branch, upstream, onto, Constants.Identity, null);
+ RebaseResult rebaseResult = Commands.Rebase.Start(repo, branch, upstream, onto, Constants.Identity, null);
// Verify that we have a conflict.
Assert.Equal(RebaseStatus.Conflicts, rebaseResult.Status);
@@ -482,10 +482,10 @@ public void CanQueryRebaseOperation()
Assert.Equal(0, rebaseResult.CompletedStepCount);
Assert.Equal(3, rebaseResult.TotalStepCount);
- RebaseStepInfo info = repo.Rebase.GetCurrentStepInfo();
+ RebaseStepInfo info = Commands.Rebase.GetCurrentStepInfo(repo);
- Assert.Equal(0, repo.Rebase.GetCurrentStepIndex());
- Assert.Equal(3, repo.Rebase.GetTotalStepCount());
+ Assert.Equal(0, Commands.Rebase.GetCurrentStepIndex(repo));
+ Assert.Equal(3, Commands.Rebase.GetTotalStepCount(repo));
Assert.Equal(RebaseStepOperation.Pick, info.Type);
}
}
@@ -506,7 +506,7 @@ public void CanAbortRebase()
Branch upstream = repo.Branches[conflictBranch1Name];
Branch onto = repo.Branches[conflictBranch1Name];
- RebaseResult rebaseResult = repo.Rebase.Start(branch, upstream, onto, Constants.Identity, null);
+ RebaseResult rebaseResult = Commands.Rebase.Start(repo, branch, upstream, onto, Constants.Identity, null);
// Verify that we have a conflict.
Assert.Equal(RebaseStatus.Conflicts, rebaseResult.Status);
@@ -526,7 +526,7 @@ public void CanAbortRebase()
CheckoutNotifyFlags = CheckoutNotifyFlags.Updated,
};
- repo.Rebase.Abort(options);
+ Commands.Rebase.Abort(repo, options);
Assert.False(repo.RetrieveStatus().IsDirty, "Repository workdir is dirty after Rebase.Abort.");
Assert.True(repo.Index.IsFullyMerged, "Repository index is not fully merged after Rebase.Abort.");
Assert.Equal(CurrentOperation.None, repo.Info.CurrentOperation);
@@ -552,7 +552,7 @@ public void RebaseWhileAlreadyRebasingThrows()
Branch upstream = repo.Branches[conflictBranch1Name];
Branch onto = repo.Branches[conflictBranch1Name];
- RebaseResult rebaseResult = repo.Rebase.Start(branch, upstream, onto, Constants.Identity, null);
+ RebaseResult rebaseResult = Commands.Rebase.Start(repo, branch, upstream, onto, Constants.Identity, null);
// Verify that we have a conflict.
Assert.Equal(RebaseStatus.Conflicts, rebaseResult.Status);
@@ -560,7 +560,7 @@ public void RebaseWhileAlreadyRebasingThrows()
Assert.Equal(CurrentOperation.RebaseMerge, repo.Info.CurrentOperation);
Assert.Throws(() =>
- repo.Rebase.Start(branch, upstream, onto, Constants.Identity, null));
+ Commands.Rebase.Start(repo, branch, upstream, onto, Constants.Identity, null));
}
}
@@ -576,10 +576,10 @@ public void RebaseOperationsWithoutRebasingThrow()
Commands.Checkout(repo, topicBranch1Name);
Assert.Throws(() =>
- repo.Rebase.Continue(Constants.Identity, new RebaseOptions()));
+ Commands.Rebase.Continue(repo, Constants.Identity, new RebaseOptions()));
Assert.Throws(() =>
- repo.Rebase.Abort());
+ Commands.Rebase.Abort(repo));
}
}
@@ -593,7 +593,7 @@ public void CurrentStepInfoIsNullWhenNotRebasing()
ConstructRebaseTestRepository(repo);
Commands.Checkout(repo, topicBranch1Name);
- Assert.Null(repo.Rebase.GetCurrentStepInfo());
+ Assert.Null(Commands.Rebase.GetCurrentStepInfo(repo));
}
}
@@ -642,7 +642,7 @@ public void CanRebaseHandlePatchAlreadyApplied(string attributes, string lineEnd
}
};
- repo.Rebase.Start(null, upstreamBranch, null, Constants.Identity2, options);
+ Commands.Rebase.Start(repo, null, upstreamBranch, null, Constants.Identity2, options);
ObjectId secondCommitExpectedTreeId = new ObjectId(expectedShaText);
Signature secondCommitAuthorSignature = Constants.Signature;
Identity secondCommitCommiterIdentity = Constants.Identity2;
@@ -670,9 +670,9 @@ public void RebasingInBareRepositoryThrows()
Branch rebaseUpstreamBranch = repo.Branches["refs/heads/test"];
Assert.NotNull(rebaseUpstreamBranch);
- Assert.Throws(() => repo.Rebase.Start(null, rebaseUpstreamBranch, null, Constants.Identity, new RebaseOptions()));
- Assert.Throws(() => repo.Rebase.Continue(Constants.Identity, new RebaseOptions()));
- Assert.Throws(() => repo.Rebase.Abort());
+ Assert.Throws(() => Commands.Rebase.Start(repo, null, rebaseUpstreamBranch, null, Constants.Identity, new RebaseOptions()));
+ Assert.Throws(() => Commands.Rebase.Continue(repo, Constants.Identity, new RebaseOptions()));
+ Assert.Throws(() => Commands.Rebase.Abort(repo));
}
}
diff --git a/LibGit2Sharp.Tests/RemoveFixture.cs b/LibGit2Sharp.Tests/RemoveFixture.cs
index a89977fce..6ceef6045 100644
--- a/LibGit2Sharp.Tests/RemoveFixture.cs
+++ b/LibGit2Sharp.Tests/RemoveFixture.cs
@@ -28,14 +28,14 @@ public class RemoveFixture : BaseFixture
* 'git rm ' fails ("error: '' has local modifications").
*/
[InlineData(false, "modified_unstaged_file.txt", false, FileStatus.ModifiedInWorkdir, true, true, FileStatus.NewInWorkdir | FileStatus.DeletedFromIndex)]
- [InlineData(true, "modified_unstaged_file.txt", true, FileStatus.ModifiedInWorkdir, true, true, 0)]
+ [InlineData(true, "modified_unstaged_file.txt", true, FileStatus.ModifiedInWorkdir, true, true, FileStatus.Unaltered)]
/***
* Test case: modified file in wd, the modifications have already been promoted to the index.
* 'git rm --cached ' works (removes the file from the index)
* 'git rm ' fails ("error: '' has changes staged in the index")
*/
[InlineData(false, "modified_staged_file.txt", false, FileStatus.ModifiedInIndex, true, true, FileStatus.NewInWorkdir | FileStatus.DeletedFromIndex)]
- [InlineData(true, "modified_staged_file.txt", true, FileStatus.ModifiedInIndex, true, true, 0)]
+ [InlineData(true, "modified_staged_file.txt", true, FileStatus.ModifiedInIndex, true, true, FileStatus.Unaltered)]
/***
* Test case: modified file in wd, the modifications have already been promoted to the index, and
* the file does not exist in the HEAD.
@@ -43,7 +43,7 @@ public class RemoveFixture : BaseFixture
* 'git rm ' throws ("error: '' has changes staged in the index")
*/
[InlineData(false, "new_tracked_file.txt", false, FileStatus.NewInIndex, true, true, FileStatus.NewInWorkdir)]
- [InlineData(true, "new_tracked_file.txt", true, FileStatus.NewInIndex, true, true, 0)]
+ [InlineData(true, "new_tracked_file.txt", true, FileStatus.NewInIndex, true, true, FileStatus.Unaltered)]
public void CanRemoveAnUnalteredFileFromTheIndexWithoutRemovingItFromTheWorkingDirectory(
bool removeFromWorkdir, string filename, bool throws, FileStatus initialStatus, bool existsBeforeRemove, bool existsAfterRemove, FileStatus lastStatus)
{
diff --git a/LibGit2Sharp/Commands/Rebase.cs b/LibGit2Sharp/Commands/Rebase.cs
new file mode 100644
index 000000000..fc2673124
--- /dev/null
+++ b/LibGit2Sharp/Commands/Rebase.cs
@@ -0,0 +1,277 @@
+using System;
+using LibGit2Sharp;
+using LibGit2Sharp.Core;
+using LibGit2Sharp.Core.Handles;
+
+namespace LibGit2Sharp
+{
+ public static partial class Commands
+ {
+ ///
+ /// Begin, continue or abort a rebase operation in a repository.
+ ///
+ public static class Rebase
+ {
+ private unsafe static AnnotatedCommitHandle AnnotatedCommitHandleFromRefHandle(Repository repository, ReferenceHandle refHandle)
+ {
+ return (refHandle == null) ?
+ new AnnotatedCommitHandle(null, false) :
+ Proxy.git_annotated_commit_from_ref(repository.Handle, refHandle);
+ }
+
+ ///
+ /// Start a rebase operation.
+ ///
+ /// The to start a rebase in.
+ /// The branch to rebase.
+ /// The starting commit to rebase.
+ /// The branch to rebase onto.
+ /// The of who added the change to the repository.
+ /// The that specify the rebase behavior.
+ /// true if completed successfully, false if conflicts encountered.
+ public static RebaseResult Start(Repository repository, Branch branch, Branch upstream, Branch onto, Identity committer, RebaseOptions options)
+ {
+ Ensure.ArgumentNotNull(repository, "repository");
+ Ensure.ArgumentNotNull(upstream, "upstream");
+
+ options = options ?? new RebaseOptions();
+
+ EnsureNonBareRepo(repository);
+
+ if (repository.Info.CurrentOperation != CurrentOperation.None)
+ {
+ throw new LibGit2SharpException("A {0} operation is already in progress.",
+ repository.Info.CurrentOperation);
+ }
+
+ Func RefHandleFromBranch = (Branch b) =>
+ {
+ return (b == null) ?
+ null :
+ repository.Refs.RetrieveReferencePtr(b.CanonicalName);
+ };
+
+ using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options))
+ {
+ GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
+ {
+ version = 1,
+ checkout_options = checkoutOptionsWrapper.Options,
+ };
+
+ using (ReferenceHandle branchRefPtr = RefHandleFromBranch(branch))
+ using (ReferenceHandle upstreamRefPtr = RefHandleFromBranch(upstream))
+ using (ReferenceHandle ontoRefPtr = RefHandleFromBranch(onto))
+ using (AnnotatedCommitHandle annotatedBranchCommitHandle = AnnotatedCommitHandleFromRefHandle(repository, branchRefPtr))
+ using (AnnotatedCommitHandle upstreamRefAnnotatedCommitHandle = AnnotatedCommitHandleFromRefHandle(repository, upstreamRefPtr))
+ using (AnnotatedCommitHandle ontoRefAnnotatedCommitHandle = AnnotatedCommitHandleFromRefHandle(repository, ontoRefPtr))
+ using (RebaseHandle rebaseOperationHandle = Proxy.git_rebase_init(repository.Handle,
+ annotatedBranchCommitHandle,
+ upstreamRefAnnotatedCommitHandle,
+ ontoRefAnnotatedCommitHandle,
+ gitRebaseOptions))
+ {
+ RebaseResult rebaseResult = RebaseOperationImpl.Run(rebaseOperationHandle,
+ repository,
+ committer,
+ options);
+ return rebaseResult;
+ }
+ }
+ }
+
+ ///
+ /// Continue the current rebase.
+ ///
+ /// The to continue a rebase in.
+ /// The of who added the change to the repository.
+ /// The that specify the rebase behavior.
+ public static unsafe RebaseResult Continue(Repository repository, Identity committer, RebaseOptions options)
+ {
+ Ensure.ArgumentNotNull(committer, "committer");
+
+ options = options ?? new RebaseOptions();
+
+ EnsureNonBareRepo(repository);
+
+ using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options))
+ {
+ GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
+ {
+ version = 1,
+ checkout_options = checkoutOptionsWrapper.Options,
+ };
+
+ using (RebaseHandle rebase = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
+ {
+ // TODO: Should we check the pre-conditions for committing here
+ // for instance - what if we had failed on the git_rebase_finish call,
+ // do we want continue to be able to restart afterwords...
+ var rebaseCommitResult = Proxy.git_rebase_commit(rebase, null, committer, null);
+
+ // Report that we just completed the step
+ if (options.RebaseStepCompleted != null)
+ {
+ // Get information on the current step
+ long currentStepIndex = Proxy.git_rebase_operation_current(rebase);
+ long totalStepCount = Proxy.git_rebase_operation_entrycount(rebase);
+ git_rebase_operation* gitRebasestepInfo = Proxy.git_rebase_operation_byindex(rebase, currentStepIndex);
+
+ var stepInfo = new RebaseStepInfo(gitRebasestepInfo->type,
+ repository.Lookup(ObjectId.BuildFromPtr(&gitRebasestepInfo->id)),
+ LaxUtf8NoCleanupMarshaler.FromNative(gitRebasestepInfo->exec));
+
+ if (rebaseCommitResult.WasPatchAlreadyApplied)
+ {
+ options.RebaseStepCompleted(new AfterRebaseStepInfo(stepInfo, currentStepIndex, totalStepCount));
+ }
+ else
+ {
+ options.RebaseStepCompleted(new AfterRebaseStepInfo(stepInfo,
+ repository.Lookup(new ObjectId(rebaseCommitResult.CommitId)),
+ currentStepIndex,
+ totalStepCount));
+ }
+ }
+
+ RebaseResult rebaseResult = RebaseOperationImpl.Run(rebase, repository, committer, options);
+ return rebaseResult;
+ }
+ }
+ }
+
+ ///
+ /// Abort the rebase operation.
+ ///
+ /// The to abort a rebase in.
+ public static void Abort(Repository repository)
+ {
+ Abort(repository, null);
+ }
+
+ ///
+ /// Abort the rebase operation.
+ ///
+ /// The to abort a rebase in.
+ /// The that specify the rebase behavior.
+ public static void Abort(Repository repository, RebaseOptions options)
+ {
+ options = options ?? new RebaseOptions();
+
+ EnsureNonBareRepo(repository);
+
+ using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options))
+ {
+ GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
+ {
+ checkout_options = checkoutOptionsWrapper.Options,
+ };
+
+ using (RebaseHandle rebase = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
+ {
+ Proxy.git_rebase_abort(rebase);
+ }
+ }
+ }
+
+ ///
+ /// The info on the current step.
+ /// The to get the information about.
+ ///
+ public static unsafe RebaseStepInfo GetCurrentStepInfo(Repository repository)
+ {
+ if (repository.Info.CurrentOperation != LibGit2Sharp.CurrentOperation.RebaseMerge)
+ {
+ return null;
+ }
+
+ GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
+ {
+ version = 1,
+ };
+
+ using (RebaseHandle rebaseHandle = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
+ {
+ long currentStepIndex = Proxy.git_rebase_operation_current(rebaseHandle);
+ git_rebase_operation* gitRebasestepInfo = Proxy.git_rebase_operation_byindex(rebaseHandle, currentStepIndex);
+ var stepInfo = new RebaseStepInfo(gitRebasestepInfo->type,
+ repository.Lookup(ObjectId.BuildFromPtr(&gitRebasestepInfo->id)),
+ LaxUtf8Marshaler.FromNative(gitRebasestepInfo->exec));
+ return stepInfo;
+ }
+ }
+
+ ///
+ /// Get info on the specified step
+ ///
+ /// The to get the information about.
+ /// The step number to get information about.
+ ///
+ public static unsafe RebaseStepInfo GetStepInfo(Repository repository, long stepIndex)
+ {
+ if (repository.Info.CurrentOperation != LibGit2Sharp.CurrentOperation.RebaseMerge)
+ {
+ return null;
+ }
+
+ GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
+ {
+ version = 1,
+ };
+
+ using (RebaseHandle rebaseHandle = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
+ {
+ git_rebase_operation* gitRebasestepInfo = Proxy.git_rebase_operation_byindex(rebaseHandle, stepIndex);
+ var stepInfo = new RebaseStepInfo(gitRebasestepInfo->type,
+ repository.Lookup(ObjectId.BuildFromPtr(&gitRebasestepInfo->id)),
+ LaxUtf8Marshaler.FromNative(gitRebasestepInfo->exec));
+ return stepInfo;
+ }
+ }
+
+ ///
+ /// Get the index of the current step in the rebase process.
+ ///
+ /// The to get the information about.
+ /// The index
+ public static long GetCurrentStepIndex(Repository repository)
+ {
+ GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
+ {
+ version = 1,
+ };
+
+ using (RebaseHandle rebaseHandle = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
+ {
+ return Proxy.git_rebase_operation_current(rebaseHandle);
+ }
+ }
+
+ ///
+ /// Get the number of steps in the rebase process.
+ ///
+ /// The to get the information about.
+ /// The number of steps in the rebase operation.
+ public static long GetTotalStepCount(Repository repository)
+ {
+ GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
+ {
+ version = 1,
+ };
+
+ using (RebaseHandle rebaseHandle = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
+ {
+ return Proxy.git_rebase_operation_entrycount(rebaseHandle);
+ }
+ }
+
+ private static void EnsureNonBareRepo(Repository repository)
+ {
+ if (repository.Info.IsBare)
+ {
+ throw new BareRepositoryException("Rebase operations in a bare repository are not supported.");
+ }
+ }
+ }
+ }
+}
diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs
index d28a7aceb..c0ada0a14 100644
--- a/LibGit2Sharp/Core/NativeMethods.cs
+++ b/LibGit2Sharp/Core/NativeMethods.cs
@@ -208,8 +208,8 @@ internal static extern unsafe int git_rebase_commit(
git_rebase* rebase,
git_signature* author,
git_signature* committer,
- IntPtr message_encoding,
- IntPtr message);
+ [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string message_encoding,
+ [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string message);
[DllImport(libgit2)]
internal static extern unsafe int git_rebase_abort(
diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs
index 02ae4a1c5..25a0dc966 100644
--- a/LibGit2Sharp/Core/Proxy.cs
+++ b/LibGit2Sharp/Core/Proxy.cs
@@ -1792,7 +1792,8 @@ private static UIntPtr GIT_REBASE_NO_OPERATION
public static unsafe GitRebaseCommitResult git_rebase_commit(
RebaseHandle rebase,
Identity author,
- Identity committer)
+ Identity committer,
+ string message)
{
Ensure.ArgumentNotNull(rebase, "rebase");
Ensure.ArgumentNotNull(committer, "committer");
@@ -1802,7 +1803,7 @@ public static unsafe GitRebaseCommitResult git_rebase_commit(
{
GitRebaseCommitResult commitResult = new GitRebaseCommitResult();
- int result = NativeMethods.git_rebase_commit(ref commitResult.CommitId, rebase, authorHandle, committerHandle, IntPtr.Zero, IntPtr.Zero);
+ int result = NativeMethods.git_rebase_commit(ref commitResult.CommitId, rebase, authorHandle, committerHandle, null, message);
if (result == (int)GitErrorCode.Applied)
{
diff --git a/LibGit2Sharp/IRepository.cs b/LibGit2Sharp/IRepository.cs
index e97a84c92..d50703c51 100644
--- a/LibGit2Sharp/IRepository.cs
+++ b/LibGit2Sharp/IRepository.cs
@@ -188,11 +188,6 @@ public interface IRepository : IDisposable
/// The of the merge.
MergeResult Merge(string committish, Signature merger, MergeOptions options);
- ///
- /// Access to Rebase functionality.
- ///
- Rebase Rebase { get; }
-
///
/// Merge the reference that was recently fetched. This will merge
/// the branch on the fetched remote that corresponded to the
diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj
index 0b37bf6af..2530874b7 100644
--- a/LibGit2Sharp/LibGit2Sharp.csproj
+++ b/LibGit2Sharp/LibGit2Sharp.csproj
@@ -34,10 +34,14 @@
-
+
+
+
+
+
diff --git a/LibGit2Sharp/ObjectDatabase.cs b/LibGit2Sharp/ObjectDatabase.cs
index 1f42d82dc..155e23b5e 100644
--- a/LibGit2Sharp/ObjectDatabase.cs
+++ b/LibGit2Sharp/ObjectDatabase.cs
@@ -819,7 +819,7 @@ public virtual MergeTreeResult MergeCommits(Commit ours, Commit theirs, MergeTre
return mergeResult;
}
}
-
+
///
/// Packs all the objects in the and write a pack (.pack) and index (.idx) files for them.
///
diff --git a/LibGit2Sharp/Rebase.cs b/LibGit2Sharp/Rebase.cs
index 00dc3f267..4b002459f 100644
--- a/LibGit2Sharp/Rebase.cs
+++ b/LibGit2Sharp/Rebase.cs
@@ -1,103 +1,27 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
using LibGit2Sharp.Core;
using LibGit2Sharp.Core.Handles;
-using System.Globalization;
namespace LibGit2Sharp
{
- ///
- /// The type of operation to be performed in a rebase step.
- ///
- public enum RebaseStepOperation
- {
- ///
- /// Commit is to be cherry-picked.
- ///
- Pick = 0,
-
- ///
- /// Cherry-pick the commit and edit the commit message.
- ///
- Reword,
-
- ///
- /// Cherry-pick the commit but allow user to edit changes.
- ///
- Edit,
-
- ///
- /// Commit is to be squashed into previous commit. The commit
- /// message will be merged with the previous message.
- ///
- Squash,
-
- ///
- /// Commit is to be squashed into previous commit. The commit
- /// message will be discarded.
- ///
- Fixup,
-
- //
- // No commit to cherry-pick. Run the given command and continue
- // if successful.
- //
- // Exec
- }
-
- ///
- /// Encapsulates a rebase operation.
- ///
- public class Rebase
+ public class Rebase : IDisposable
{
- internal readonly Repository repository;
-
- ///
- /// Needed for mocking purposes.
- ///
- protected Rebase()
- { }
-
- internal Rebase(Repository repo)
- {
- this.repository = repo;
- }
+ private readonly Repository repository;
+ private readonly RebaseHandle handle;
+ private bool disposed = false;
- unsafe AnnotatedCommitHandle AnnotatedCommitHandleFromRefHandle(ReferenceHandle refHandle)
- {
- return (refHandle == null) ?
- new AnnotatedCommitHandle(null, false) :
- Proxy.git_annotated_commit_from_ref(this.repository.Handle, refHandle);
- }
-
- ///
- /// Start a rebase operation.
- ///
- /// The branch to rebase.
- /// The starting commit to rebase.
- /// The branch to rebase onto.
- /// The of who added the change to the repository.
- /// The that specify the rebase behavior.
- /// true if completed successfully, false if conflicts encountered.
- public virtual RebaseResult Start(Branch branch, Branch upstream, Branch onto, Identity committer, RebaseOptions options)
+ public Rebase(Repository repository, Branch branch, Branch upstream, Branch onto, RebaseOptions options)
{
+ Ensure.ArgumentNotNull(repository, "repository");
Ensure.ArgumentNotNull(upstream, "upstream");
- options = options ?? new RebaseOptions();
-
- EnsureNonBareRepo();
-
- if (this.repository.Info.CurrentOperation != CurrentOperation.None)
- {
- throw new LibGit2SharpException("A {0} operation is already in progress.",
- this.repository.Info.CurrentOperation);
- }
+ this.repository = repository;
- Func RefHandleFromBranch = (Branch b) =>
- {
- return (b == null) ?
- null :
- this.repository.Refs.RetrieveReferencePtr(b.CanonicalName);
- };
+ options = options ?? new RebaseOptions();
using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options))
{
@@ -107,211 +31,133 @@ public virtual RebaseResult Start(Branch branch, Branch upstream, Branch onto, I
checkout_options = checkoutOptionsWrapper.Options,
};
- using (ReferenceHandle branchRefPtr = RefHandleFromBranch(branch))
- using (ReferenceHandle upstreamRefPtr = RefHandleFromBranch(upstream))
- using (ReferenceHandle ontoRefPtr = RefHandleFromBranch(onto))
- using (AnnotatedCommitHandle annotatedBranchCommitHandle = AnnotatedCommitHandleFromRefHandle(branchRefPtr))
- using (AnnotatedCommitHandle upstreamRefAnnotatedCommitHandle = AnnotatedCommitHandleFromRefHandle(upstreamRefPtr))
- using (AnnotatedCommitHandle ontoRefAnnotatedCommitHandle = AnnotatedCommitHandleFromRefHandle(ontoRefPtr))
- using (RebaseHandle rebaseOperationHandle = Proxy.git_rebase_init(this.repository.Handle,
- annotatedBranchCommitHandle,
- upstreamRefAnnotatedCommitHandle,
- ontoRefAnnotatedCommitHandle,
- gitRebaseOptions))
+ using (ReferenceHandle branchRefPtr = RefHandleFromBranch(repository, branch))
+ using (ReferenceHandle upstreamRefPtr = RefHandleFromBranch(repository, upstream))
+ using (ReferenceHandle ontoRefPtr = RefHandleFromBranch(repository, onto))
+ using (AnnotatedCommitHandle annotatedBranchCommitHandle = AnnotatedCommitHandleFromRefHandle(repository, branchRefPtr))
+ using (AnnotatedCommitHandle upstreamRefAnnotatedCommitHandle = AnnotatedCommitHandleFromRefHandle(repository, upstreamRefPtr))
+ using (AnnotatedCommitHandle ontoRefAnnotatedCommitHandle = AnnotatedCommitHandleFromRefHandle(repository, ontoRefPtr))
{
- RebaseResult rebaseResult = RebaseOperationImpl.Run(rebaseOperationHandle,
- this.repository,
- committer,
- options);
- return rebaseResult;
+ handle = Proxy.git_rebase_init(repository.Handle,
+ annotatedBranchCommitHandle,
+ upstreamRefAnnotatedCommitHandle,
+ ontoRefAnnotatedCommitHandle,
+ gitRebaseOptions);
}
}
}
- ///
- /// Continue the current rebase.
- ///
- /// The of who added the change to the repository.
- /// The that specify the rebase behavior.
- public virtual unsafe RebaseResult Continue(Identity committer, RebaseOptions options)
+ private static ReferenceHandle RefHandleFromBranch(Repository repository, Branch branch)
{
- Ensure.ArgumentNotNull(committer, "committer");
+ return (branch == null) ?
+ null :
+ repository.Refs.RetrieveReferencePtr(branch.CanonicalName);
+ }
- options = options ?? new RebaseOptions();
+ private unsafe static AnnotatedCommitHandle AnnotatedCommitHandleFromRefHandle(Repository repository, ReferenceHandle refHandle)
+ {
+ return (refHandle == null) ?
+ new AnnotatedCommitHandle(null, false) :
+ Proxy.git_annotated_commit_from_ref(repository.Handle, refHandle);
+ }
- EnsureNonBareRepo();
+ public virtual unsafe RebaseStepInfo Next()
+ {
+ git_rebase_operation* rebaseOp = Proxy.git_rebase_next(handle);
- using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options))
+ if (rebaseOp == null)
{
- GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
- {
- version = 1,
- checkout_options = checkoutOptionsWrapper.Options,
- };
-
- using (RebaseHandle rebase = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
- {
- // TODO: Should we check the pre-conditions for committing here
- // for instance - what if we had failed on the git_rebase_finish call,
- // do we want continue to be able to restart afterwords...
- var rebaseCommitResult = Proxy.git_rebase_commit(rebase, null, committer);
-
- // Report that we just completed the step
- if (options.RebaseStepCompleted != null)
- {
- // Get information on the current step
- long currentStepIndex = Proxy.git_rebase_operation_current(rebase);
- long totalStepCount = Proxy.git_rebase_operation_entrycount(rebase);
- git_rebase_operation* gitRebasestepInfo = Proxy.git_rebase_operation_byindex(rebase, currentStepIndex);
+ return null;
+ }
- var stepInfo = new RebaseStepInfo(gitRebasestepInfo->type,
- repository.Lookup(ObjectId.BuildFromPtr(&gitRebasestepInfo->id)),
- LaxUtf8NoCleanupMarshaler.FromNative(gitRebasestepInfo->exec));
+ return new RebaseStepInfo(rebaseOp->type,
+ repository.Lookup(ObjectId.BuildFromPtr(&rebaseOp->id)),
+ LaxUtf8NoCleanupMarshaler.FromNative(rebaseOp->exec));
+ }
- if (rebaseCommitResult.WasPatchAlreadyApplied)
- {
- options.RebaseStepCompleted(new AfterRebaseStepInfo(stepInfo, currentStepIndex, totalStepCount));
- }
- else
- {
- options.RebaseStepCompleted(new AfterRebaseStepInfo(stepInfo,
- repository.Lookup(new ObjectId(rebaseCommitResult.CommitId)),
- currentStepIndex,
- totalStepCount));
- }
- }
+ public virtual ObjectId Commit(Identity author, Identity committer, string message)
+ {
+ Ensure.ArgumentNotNull(committer, "committer");
- RebaseResult rebaseResult = RebaseOperationImpl.Run(rebase, repository, committer, options);
- return rebaseResult;
- }
- }
+ Proxy.GitRebaseCommitResult rebaseResult = Proxy.git_rebase_commit(handle, author, committer, message);
+ return rebaseResult.WasPatchAlreadyApplied ? null : new ObjectId(rebaseResult.CommitId);
}
- ///
- /// Abort the rebase operation.
- ///
public virtual void Abort()
{
- Abort(null);
+ Proxy.git_rebase_abort(handle);
}
///
- /// Abort the rebase operation.
+ /// Get the index of the current step in the rebase process.
///
- /// The that specify the rebase behavior.
- public virtual void Abort(RebaseOptions options)
+ /// The to get the information about.
+ /// The index
+ public virtual long CurrentStep
{
- options = options ?? new RebaseOptions();
-
- EnsureNonBareRepo();
-
- using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(options))
+ get
{
- GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
- {
- checkout_options = checkoutOptionsWrapper.Options,
- };
-
- using (RebaseHandle rebase = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
- {
- Proxy.git_rebase_abort(rebase);
- }
+ return Proxy.git_rebase_operation_current(handle);
}
}
///
- /// The info on the current step.
+ /// Get the number of steps in the rebase process.
///
- public virtual unsafe RebaseStepInfo GetCurrentStepInfo()
+ /// The to get the information about.
+ /// The number of steps in the rebase operation.
+ public virtual long TotalSteps
{
- if (repository.Info.CurrentOperation != LibGit2Sharp.CurrentOperation.RebaseMerge)
- {
- return null;
- }
-
- GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
- {
- version = 1,
- };
-
- using (RebaseHandle rebaseHandle = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
+ get
{
- long currentStepIndex = Proxy.git_rebase_operation_current(rebaseHandle);
- git_rebase_operation* gitRebasestepInfo = Proxy.git_rebase_operation_byindex(rebaseHandle, currentStepIndex);
- var stepInfo = new RebaseStepInfo(gitRebasestepInfo->type,
- repository.Lookup(ObjectId.BuildFromPtr(&gitRebasestepInfo->id)),
- LaxUtf8Marshaler.FromNative(gitRebasestepInfo->exec));
- return stepInfo;
+ return Proxy.git_rebase_operation_entrycount(handle);
}
}
///
- /// Get info on the specified step
+ /// The info on the current step.
+ /// The to get the information about.
///
- ///
- ///
- public virtual unsafe RebaseStepInfo GetStepInfo(long stepIndex)
+ public virtual unsafe RebaseStepInfo CurrentStepInfo
{
- if (repository.Info.CurrentOperation != LibGit2Sharp.CurrentOperation.RebaseMerge)
+ get
{
- return null;
- }
-
- GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
- {
- version = 1,
- };
-
- using (RebaseHandle rebaseHandle = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
- {
- git_rebase_operation* gitRebasestepInfo = Proxy.git_rebase_operation_byindex(rebaseHandle, stepIndex);
- var stepInfo = new RebaseStepInfo(gitRebasestepInfo->type,
- repository.Lookup(ObjectId.BuildFromPtr(&gitRebasestepInfo->id)),
- LaxUtf8Marshaler.FromNative(gitRebasestepInfo->exec));
- return stepInfo;
+ return GetStepInfo(CurrentStep);
}
}
///
- ///
+ /// Get info on the specified step
///
+ /// The to get the information about.
+ /// The step number to get information about.
///
- public virtual long GetCurrentStepIndex()
+ public virtual unsafe RebaseStepInfo GetStepInfo(long stepIndex)
{
- GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
- {
- version = 1,
- };
+ git_rebase_operation* gitRebasestepInfo = Proxy.git_rebase_operation_byindex(handle, stepIndex);
+ return new RebaseStepInfo(gitRebasestepInfo->type,
+ repository.Lookup(ObjectId.BuildFromPtr(&gitRebasestepInfo->id)),
+ LaxUtf8Marshaler.FromNative(gitRebasestepInfo->exec));
+ }
- using (RebaseHandle rebaseHandle = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!disposed)
{
- return Proxy.git_rebase_operation_current(rebaseHandle);
+ handle.SafeDispose();
+ disposed = true;
}
}
- ///
- ///
- ///
- ///
- public virtual long GetTotalStepCount()
+ public void Dispose()
{
- GitRebaseOptions gitRebaseOptions = new GitRebaseOptions()
- {
- version = 1,
- };
-
- using (RebaseHandle rebaseHandle = Proxy.git_rebase_open(repository.Handle, gitRebaseOptions))
- {
- return Proxy.git_rebase_operation_entrycount(rebaseHandle);
- }
+ Dispose(true);
+ GC.SuppressFinalize(this);
}
- private void EnsureNonBareRepo()
+ ~Rebase()
{
- if (this.repository.Info.IsBare)
- {
- throw new BareRepositoryException("Rebase operations in a bare repository are not supported.");
- }
+ Dispose(false);
}
}
}
diff --git a/LibGit2Sharp/RebaseOperationImpl.cs b/LibGit2Sharp/RebaseOperationImpl.cs
index c35564573..43d54d3fe 100644
--- a/LibGit2Sharp/RebaseOperationImpl.cs
+++ b/LibGit2Sharp/RebaseOperationImpl.cs
@@ -161,7 +161,7 @@ private static RebaseStepResult ApplyPickStep(RebaseHandle rebaseOperationHandle
// commit and continue.
if (repository.Index.IsFullyMerged)
{
- Proxy.GitRebaseCommitResult rebase_commit_result = Proxy.git_rebase_commit(rebaseOperationHandle, null, committer);
+ Proxy.GitRebaseCommitResult rebase_commit_result = Proxy.git_rebase_commit(rebaseOperationHandle, null, committer, null);
if (rebase_commit_result.WasPatchAlreadyApplied)
{
diff --git a/LibGit2Sharp/RebaseResult.cs b/LibGit2Sharp/RebaseResult.cs
index bee2254af..1b5564a4a 100644
--- a/LibGit2Sharp/RebaseResult.cs
+++ b/LibGit2Sharp/RebaseResult.cs
@@ -19,12 +19,6 @@ public enum RebaseStatus
/// The rebase operation hit a conflict and stopped.
///
Conflicts,
-
- ///
- /// The rebase operation has hit a user requested stop point
- /// (edit, reword, ect.)
- ///
- Stop,
};
///
diff --git a/LibGit2Sharp/RebaseStepOperation.cs b/LibGit2Sharp/RebaseStepOperation.cs
new file mode 100644
index 000000000..a2d55573e
--- /dev/null
+++ b/LibGit2Sharp/RebaseStepOperation.cs
@@ -0,0 +1,41 @@
+namespace LibGit2Sharp
+{
+ ///
+ /// The type of operation to be performed in a rebase step.
+ ///
+ public enum RebaseStepOperation
+ {
+ ///
+ /// Commit is to be cherry-picked.
+ ///
+ Pick = 0,
+
+ ///
+ /// Cherry-pick the commit and edit the commit message.
+ ///
+ Reword,
+
+ ///
+ /// Cherry-pick the commit but allow user to edit changes.
+ ///
+ Edit,
+
+ ///
+ /// Commit is to be squashed into previous commit. The commit
+ /// message will be merged with the previous message.
+ ///
+ Squash,
+
+ ///
+ /// Commit is to be squashed into previous commit. The commit
+ /// message will be discarded.
+ ///
+ Fixup,
+
+ ///
+ /// No commit to cherry-pick. Run the given command and continue
+ /// if successful.
+ ///
+ Exec
+ }
+}
diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs
index 84110f409..a156fe4a2 100644
--- a/LibGit2Sharp/Repository.cs
+++ b/LibGit2Sharp/Repository.cs
@@ -31,7 +31,6 @@ public sealed class Repository : IRepository
private readonly NoteCollection notes;
private readonly Lazy odb;
private readonly Lazy network;
- private readonly Lazy rebaseOperation;
private readonly Stack toCleanup = new Stack();
private readonly Ignore ignore;
private readonly SubmoduleCollection submodules;
@@ -177,7 +176,6 @@ private Repository(string path, RepositoryOptions options, RepositoryRequiredPar
notes = new NoteCollection(this);
ignore = new Ignore(this);
network = new Lazy(() => new Network(this));
- rebaseOperation = new Lazy(() => new Rebase(this));
pathCase = new Lazy(() => new PathCase(this));
submodules = new SubmoduleCollection(this);
@@ -304,17 +302,6 @@ public Network Network
get { return network.Value; }
}
- ///
- /// Provides access to rebase functionality for a repository.
- ///
- public Rebase Rebase
- {
- get
- {
- return rebaseOperation.Value;
- }
- }
-
///
/// Gets the database.
///