Skip to content

Merge/Rebase In Progress #128

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion LibGit2Sharp.Tests/BranchFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ public void CanCheckoutAnArbitraryCommit(string commitPointer)

Assert.False(detachedHead.IsRemote);
Assert.Equal(detachedHead.Name, detachedHead.CanonicalName);
Assert.Equal("(no branch)", detachedHead.CanonicalName);
Assert.True(detachedHead.Name.EndsWith("...)"));
Assert.Equal(repo.Lookup(commitPointer).Sha, detachedHead.Tip.Sha);

Assert.Equal(repo.Head, detachedHead);
Expand Down
75 changes: 75 additions & 0 deletions LibGit2Sharp.Tests/InteractiveFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;
using Xunit.Extensions;

namespace LibGit2Sharp.Tests
{
public class InteractiveFixture : BaseFixture
{
[Theory]
[InlineData(true)]
[InlineData(false)]
public void InteractiveStateHasExpectedValuesForNewRepo(bool isBare)
{
SelfCleaningDirectory scd = BuildSelfCleaningDirectory();
using (var repo = Repository.Init(scd.DirectoryPath, isBare))
{
Assert.Equal("master", repo.Head.Name);
Assert.Equal(PendingOperation.None, repo.Info.PendingOperation);
}
}

[Fact]
public void InteractiveStateHasExpectedValuesForABareRepo()
{
using (var repo = new Repository(BareTestRepoPath))
{
Assert.Equal("master", repo.Head.Name);
Assert.Equal(PendingOperation.None, repo.Info.PendingOperation);
}
}

[Fact]
public void InteractiveStateHasExpectedValuesForStandardRepo()
{
var path = BuildTemporaryCloneOfTestRepo(StandardTestRepoPath);
using (var repo = new Repository(path.RepositoryPath))
{
Assert.Equal("master", repo.Head.Name);
Assert.Equal(PendingOperation.None, repo.Info.PendingOperation);

repo.Checkout("track-local");
Assert.Equal("track-local", repo.Head.Name);
}
}

[Fact]
public void InteractiveStateHasExpectedValuesForDetachedHead()
{
var path = BuildTemporaryCloneOfTestRepo(StandardTestRepoPath);
using (var repo = new Repository(path.RepositoryPath))
{
repo.Checkout(repo.Head.Tip.Sha);

Assert.Equal("(32eab9c...)", repo.Head.Name);
Assert.Equal(PendingOperation.None, repo.Info.PendingOperation);
}
}

[Fact]
public void InteractiveStateHasExpectedValuesForInteractiveRebase()
{
var path = BuildTemporaryCloneOfTestRepo(StandardTestRepoPath);
path.Touch("rebase-merge", "interactive");
path.Touch("rebase-merge", "head-name", "refs/heads/master");

using (var repo = new Repository(path.RepositoryPath))
{
repo.Checkout(repo.Head.Tip.Sha);

Assert.Equal("master", repo.Head.Name);
Assert.Equal(PendingOperation.RebaseInteractive, repo.Info.PendingOperation);
}
}
}
}
1 change: 1 addition & 0 deletions LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
<Compile Include="NoteFixture.cs" />
<Compile Include="DiffBlobToBlobFixture.cs" />
<Compile Include="DiffTreeToTargetFixture.cs" />
<Compile Include="InteractiveFixture.cs" />
<Compile Include="ObjectDatabaseFixture.cs" />
<Compile Include="DiffTreeToTreeFixture.cs" />
<Compile Include="RepositoryOptionsFixture.cs" />
Expand Down
44 changes: 33 additions & 11 deletions LibGit2Sharp.Tests/ResetHeadFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,41 @@ public void ResettingWithBadParamsThrows()
public void SoftResetSetsTheHeadToTheSpecifiedCommit()
{
/* Make the Head point to a branch through its name */
AssertSoftReset(b => b.Name, false, b => b.Name);
SelfCleaningDirectory scd = BuildSelfCleaningDirectory();

using (var repo = Repository.Init(scd.DirectoryPath))
{
FeedTheRepository(repo);

Tag tag = repo.Tags["mytag"];
Branch branch = repo.Branches["mybranch"];

repo.Checkout(branch.Name);
Assert.Equal(false, repo.Info.IsHeadDetached);

Assert.Equal(branch.Name, repo.Head.Name);
Assert.Equal(branch.Tip.Sha, repo.Head.Tip.Sha);

/* Reset --soft the Head to a tag through its canonical name */
repo.Reset(ResetOptions.Soft, tag.CanonicalName);
Assert.Equal(branch.Name, repo.Head.Name);
Assert.Equal(tag.Target.Id, repo.Head.Tip.Id);

Assert.Equal(FileStatus.Staged, repo.Index.RetrieveStatus("a.txt"));

/* Reset --soft the Head to a commit through its sha */
repo.Reset(ResetOptions.Soft, branch.Tip.Sha);
Assert.Equal(branch.Name, repo.Head.Name);
Assert.Equal(branch.Tip.Sha, repo.Head.Tip.Sha);

Assert.Equal(FileStatus.Unaltered, repo.Index.RetrieveStatus("a.txt"));
}
}

[Fact]
public void SoftResetSetsTheDetachedHeadToTheSpecifiedCommit()
{
/* Make the Head point to a commit through its sha (Detaches the Head) */
AssertSoftReset(b => b.Tip.Sha, true, b => "(no branch)");
}

private void AssertSoftReset(Func<Branch, string> branchIdentifierRetriever, bool shouldHeadBeDetached, Func<Branch, string> expectedHeadNameRetriever)
{
SelfCleaningDirectory scd = BuildSelfCleaningDirectory();

using (var repo = Repository.Init(scd.DirectoryPath))
Expand All @@ -83,17 +106,16 @@ private void AssertSoftReset(Func<Branch, string> branchIdentifierRetriever, boo
Tag tag = repo.Tags["mytag"];
Branch branch = repo.Branches["mybranch"];

string branchIdentifier = branchIdentifierRetriever(branch);
repo.Checkout(branchIdentifier);
Assert.Equal(shouldHeadBeDetached, repo.Info.IsHeadDetached);
repo.Checkout(branch.Tip.Sha);
Assert.Equal(true, repo.Info.IsHeadDetached);

string expectedHeadName = expectedHeadNameRetriever(branch);
const string expectedHeadName = "(a5ed7f8...)";
Assert.Equal(expectedHeadName, repo.Head.Name);
Assert.Equal(branch.Tip.Sha, repo.Head.Tip.Sha);

/* Reset --soft the Head to a tag through its canonical name */
repo.Reset(ResetOptions.Soft, tag.CanonicalName);
Assert.Equal(expectedHeadName, repo.Head.Name);
Assert.Equal("(653c177...)", repo.Head.Name);
Assert.Equal(tag.Target.Id, repo.Head.Tip.Id);

Assert.Equal(FileStatus.Staged, repo.Index.RetrieveStatus("a.txt"));
Expand Down
9 changes: 9 additions & 0 deletions LibGit2Sharp.Tests/TestHelpers/TemporaryCloneOfTestRepo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.IO;
using System.Text;

namespace LibGit2Sharp.Tests.TestHelpers
{
Expand Down Expand Up @@ -31,5 +32,13 @@ public TemporaryCloneOfTestRepo(IPostTestDirectoryRemover directoryRemover, stri
}

public string RepositoryPath { get; private set; }

public void Touch(string parent, string file, string content = null)
{
var parentPath = Path.Combine(RepositoryPath, parent);
Directory.CreateDirectory(parentPath);
var filePath = Path.Combine(parentPath, file);
File.WriteAllText(filePath, content ?? "", Encoding.ASCII);
}
}
}
13 changes: 4 additions & 9 deletions LibGit2Sharp/Branch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ public class Branch : ReferenceWrapper<Commit>
/// </summary>
/// <param name = "repo">The repo.</param>
/// <param name = "reference">The reference.</param>
/// <param name = "canonicalName">The full name of the reference</param>
internal Branch(Repository repo, Reference reference, string canonicalName)
: this(repo, reference, _ => canonicalName)
/// <param name = "canonicalNameSelector">Provider of full name of the reference</param>
internal Branch(Repository repo, Reference reference, Func<Reference, string> canonicalNameSelector)
: base(repo, reference, canonicalNameSelector)
{
trackedBranch = new Lazy<Branch>(ResolveTrackedBranch);
}

/// <summary>
Expand All @@ -36,12 +37,6 @@ internal Branch(Repository repo, Reference reference)
{
}

private Branch(Repository repo, Reference reference, Func<Reference, string> canonicalNameSelector)
: base(repo, reference, canonicalNameSelector)
{
trackedBranch = new Lazy<Branch>(ResolveTrackedBranch);
}

/// <summary>
/// Gets the <see cref = "TreeEntry" /> pointed at by the <paramref name = "relativePath" /> in the <see cref = "Tip" />.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion LibGit2Sharp/BranchCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ private static string ShortToRemoteName(string name)
private Branch BuildFromReferenceName(string canonicalName)
{
var reference = repo.Refs.Resolve<Reference>(canonicalName);
return reference == null ? null : new Branch(repo, reference, canonicalName);
return reference == null ? null : new Branch(repo, reference, _ => canonicalName);
}

#region IEnumerable<Branch> Members
Expand Down
19 changes: 16 additions & 3 deletions LibGit2Sharp/DetachedHead.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
namespace LibGit2Sharp
using System.IO;

namespace LibGit2Sharp
{
internal class DetachedHead : Branch
{
internal DetachedHead(Repository repo, Reference reference)
: base(repo, reference, "(no branch)")
: base(repo, reference, r => HeadName(repo, r))
{
}

protected override string Shorten(string branchName)
{
return branchName;
}

public static string HeadName(Repository repo, Reference reference)
{
var rebaseMergeHeadName = Path.Combine(repo.Info.Path, "rebase-merge/head-name");
if (File.Exists(rebaseMergeHeadName))
{
return File.ReadAllText(rebaseMergeHeadName).Replace("refs/heads/", "");
}

return string.Format("({0}...)", reference.TargetIdentifier.Substring(0, 7));
}
}
}
}
1 change: 1 addition & 0 deletions LibGit2Sharp/LibGit2Sharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
<Compile Include="TreeChanges.cs" />
<Compile Include="TreeEntryChanges.cs" />
<Compile Include="LibGit2SharpException.cs" />
<Compile Include="PendingOperation.cs" />
<Compile Include="Core\Handles\ConfigurationSafeHandle.cs" />
<Compile Include="Core\Ensure.cs" />
<Compile Include="Core\Epoch.cs" />
Expand Down
15 changes: 15 additions & 0 deletions LibGit2Sharp/PendingOperation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace LibGit2Sharp
{
public enum PendingOperation
{
None = 0,
RebaseInteractive = 1,
RebaseMerge = 2,
Rebase = 3,
ApplyMailbox = 4,
ApplyMailboxOrRebase = 5,
Merge = 6,
CherryPick = 7,
Bisect = 8,
}
}
3 changes: 1 addition & 2 deletions LibGit2Sharp/ReferenceWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public abstract class ReferenceWrapper<TObject> : IEquatable<ReferenceWrapper<TO
protected internal ReferenceWrapper(Repository repo, Reference reference, Func<Reference, string> canonicalNameSelector)
{
Ensure.ArgumentNotNull(repo, "repo");
Ensure.ArgumentNotNull(reference, "reference");
Ensure.ArgumentNotNull(canonicalNameSelector, "canonicalNameSelector");

this.repo = repo;
Expand Down Expand Up @@ -71,8 +72,6 @@ protected TObject TargetObject

private TObject RetrieveTargetObject(Reference reference)
{
Ensure.ArgumentNotNull(reference, "reference");

var directReference = reference.ResolveToDirectReference();
if (directReference == null)
{
Expand Down
52 changes: 51 additions & 1 deletion LibGit2Sharp/RepositoryInformation.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using LibGit2Sharp.Core;
using System.IO;
using LibGit2Sharp.Core;

namespace LibGit2Sharp
{
Expand Down Expand Up @@ -57,5 +58,54 @@ public bool IsHeadDetached
{
get { return NativeMethods.RepositoryStateChecker(repo.Handle, NativeMethods.git_repository_head_detached); }
}

/// <summary>
/// Gets the pending interactive operation.
/// </summary>
public PendingOperation PendingOperation
{
get { return DetermineCurrentInteractiveState(); }
}

private PendingOperation DetermineCurrentInteractiveState()
{
if (!IsHeadDetached)
return PendingOperation.None;

if (DirectoryExists("rebase-merge"))
if (Exists("rebase-merge/interactive"))
return PendingOperation.RebaseInteractive;
else
return PendingOperation.Merge;

if (DirectoryExists("rebase-apply"))
if (Exists("rebase-apply/rebasing"))
return PendingOperation.Rebase;
else if (Exists("rebase-apply/applying"))
return PendingOperation.ApplyMailbox;
else
return PendingOperation.ApplyMailboxOrRebase;

if (Exists("MERGE_HEAD"))
return PendingOperation.Merge;

if (Exists("CHERRY_PICK_HEAD"))
return PendingOperation.CherryPick;

if (Exists("BISECT_LOG"))
return PendingOperation.Bisect;

return PendingOperation.None;
}

private bool DirectoryExists(string relativePath)
{
return Directory.Exists(System.IO.Path.Combine(Path, relativePath));
}

private bool Exists(string relativePath)
{
return File.Exists(System.IO.Path.Combine(Path, relativePath));
}
}
}