Skip to content

Teach MergeOptions about CheckoutOptions #685

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
May 3, 2014
Merged
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
32 changes: 20 additions & 12 deletions LibGit2Sharp.Tests/CheckoutFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ public void CanForcefullyCheckoutWithConflictingStagedChanges()
Assert.Throws<MergeConflictException>(() => repo.Checkout(master.CanonicalName));

// Checkout with force option should succeed.
repo.Checkout(master.CanonicalName, CheckoutModifiers.Force, null, null);
repo.Checkout(master.CanonicalName, new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force});

// Assert that master branch is checked out.
Assert.True(repo.Branches["master"].IsCurrentRepositoryHead);
Expand Down Expand Up @@ -338,8 +338,14 @@ public void CanCancelCheckoutThroughNotifyCallback()

// Verify that we get called for the notify conflict cb
string conflictPath = string.Empty;
CheckoutNotificationOptions checkoutNotifications = new CheckoutNotificationOptions((path, flags) => { conflictPath = path; return false; }, CheckoutNotifyFlags.Conflict);
Assert.Throws<UserCancelledException>(() => repo.Checkout("master", CheckoutModifiers.None, null, checkoutNotifications));

CheckoutOptions options = new CheckoutOptions()
{
OnCheckoutNotify = (path, flags) => { conflictPath = path; return false; },
CheckoutNotifyFlags = CheckoutNotifyFlags.Conflict,
};

Assert.Throws<UserCancelledException>(() => repo.Checkout("master", options));
Assert.Equal(relativePath, conflictPath);
}
}
Expand Down Expand Up @@ -398,7 +404,7 @@ public void CheckingOutThroughBranchCallsCheckoutProgress()
bool wasCalled = false;

Branch branch = repo.Branches[otherBranchName];
branch.Checkout(CheckoutModifiers.None, (path, completed, total) => wasCalled = true, null);
branch.Checkout(new CheckoutOptions() { OnCheckoutProgress = (path, completed, total) => wasCalled = true});

Assert.True(wasCalled);
}
Expand All @@ -414,7 +420,7 @@ public void CheckingOutThroughRepositoryCallsCheckoutProgress()
PopulateBasicRepository(repo);
bool wasCalled = false;

repo.Checkout(otherBranchName, CheckoutModifiers.None, (path, completed, total) => wasCalled = true, null);
repo.Checkout(otherBranchName, new CheckoutOptions() { OnCheckoutProgress = (path, completed, total) => wasCalled = true});

Assert.True(wasCalled);
}
Expand Down Expand Up @@ -486,11 +492,13 @@ public void CheckingOutCallsCheckoutNotify(CheckoutNotifyFlags notifyFlags, stri
string actualNotificationPath = string.Empty;
CheckoutNotifyFlags actualNotifyFlags = CheckoutNotifyFlags.None;

CheckoutNotificationOptions checkoutNotifications = new CheckoutNotificationOptions(
(path, notificationType) => { wasCalled = true; actualNotificationPath = path; actualNotifyFlags = notificationType; return true; },
notifyFlags);
CheckoutOptions options = new CheckoutOptions()
{
OnCheckoutNotify = (path, notificationType) => { wasCalled = true; actualNotificationPath = path; actualNotifyFlags = notificationType; return true; },
CheckoutNotifyFlags = notifyFlags,
};

Assert.Throws<MergeConflictException>(() => repo.Checkout("master", CheckoutModifiers.None, null, checkoutNotifications));
Assert.Throws<MergeConflictException>(() => repo.Checkout("master", options));

Assert.True(wasCalled);
Assert.Equal(expectedNotificationPath, actualNotificationPath);
Expand Down Expand Up @@ -538,7 +546,7 @@ public void ForceCheckoutRetainsUntrackedChanges()
Assert.Equal(1, repo.Index.RetrieveStatus().Untracked.Count());
Assert.Equal(FileStatus.Untracked, repo.Index.RetrieveStatus(fullPathFileB));

repo.Checkout(otherBranchName, CheckoutModifiers.Force, null, null);
repo.Checkout(otherBranchName, new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force });

// Verify untracked entry still exists.
Assert.Equal(1, repo.Index.RetrieveStatus().Untracked.Count());
Expand Down Expand Up @@ -641,7 +649,7 @@ public void ForceCheckoutRetainsIgnoredChanges()

Assert.Equal(FileStatus.Ignored, repo.Index.RetrieveStatus(ignoredFilePath));

repo.Checkout(otherBranchName, CheckoutModifiers.Force, null, null);
repo.Checkout(otherBranchName, new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force });

// Verify that the ignored file still exists.
Assert.Equal(FileStatus.Ignored, repo.Index.RetrieveStatus(ignoredFilePath));
Expand Down Expand Up @@ -718,7 +726,7 @@ public void CheckingOutABranchDoesNotAlterBinaryFiles()
// The blob actually exists in the object database with the correct Sha
Assert.Equal(expectedSha, repo.Lookup<Blob>(expectedSha).Sha);

repo.Checkout("refs/heads/logo", CheckoutModifiers.Force, null, null);
repo.Checkout("refs/heads/logo", new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force });

// The Index has been updated as well with the blob
Assert.Equal(expectedSha, repo.Index["square-logo.png"].Id.Sha);
Expand Down
227 changes: 226 additions & 1 deletion LibGit2Sharp.Tests/MergeFixture.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System.Linq;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;
using Xunit.Extensions;
Expand Down Expand Up @@ -341,6 +344,122 @@ public void CanNonFastForwardMergeCommit(bool fromDetachedHead, FastForwardStrat
}
}

[Fact]
public void MergeReportsCheckoutProgress()
{
string repoPath = CloneMergeTestRepo();
using (var repo = new Repository(repoPath))
{
Commit commitToMerge = repo.Branches["normal_merge"].Tip;

bool wasCalled = false;

MergeOptions options = new MergeOptions()
{
OnCheckoutProgress = (path, completed, total) => wasCalled = true,
};

MergeResult result = repo.Merge(commitToMerge, Constants.Signature, options);

Assert.True(wasCalled);
}
}

[Fact]
public void MergeReportsCheckoutNotifications()
{
string repoPath = CloneMergeTestRepo();
using (var repo = new Repository(repoPath))
{
Commit commitToMerge = repo.Branches["normal_merge"].Tip;

bool wasCalled = false;
CheckoutNotifyFlags actualNotifyFlags = CheckoutNotifyFlags.None;

MergeOptions options = new MergeOptions()
{
OnCheckoutNotify = (path, notificationType) => { wasCalled = true; actualNotifyFlags = notificationType; return true; },
CheckoutNotifyFlags = CheckoutNotifyFlags.Updated,
};

MergeResult result = repo.Merge(commitToMerge, Constants.Signature, options);

Assert.True(wasCalled);
Assert.Equal(CheckoutNotifyFlags.Updated, actualNotifyFlags);
}
}

[Fact]
public void FastForwardMergeReportsCheckoutProgress()
{
string repoPath = CloneMergeTestRepo();
using (var repo = new Repository(repoPath))
{
Commit commitToMerge = repo.Branches["fast_forward"].Tip;

bool wasCalled = false;

MergeOptions options = new MergeOptions()
{
OnCheckoutProgress = (path, completed, total) => wasCalled = true,
};

MergeResult result = repo.Merge(commitToMerge, Constants.Signature, options);

Assert.True(wasCalled);
}
}

[Fact]
public void FastForwardMergeReportsCheckoutNotifications()
{
string repoPath = CloneMergeTestRepo();
using (var repo = new Repository(repoPath))
{
Commit commitToMerge = repo.Branches["fast_forward"].Tip;

bool wasCalled = false;
CheckoutNotifyFlags actualNotifyFlags = CheckoutNotifyFlags.None;

MergeOptions options = new MergeOptions()
{
OnCheckoutNotify = (path, notificationType) => { wasCalled = true; actualNotifyFlags = notificationType; return true; },
CheckoutNotifyFlags = CheckoutNotifyFlags.Updated,
};

MergeResult result = repo.Merge(commitToMerge, Constants.Signature, options);

Assert.True(wasCalled);
Assert.Equal(CheckoutNotifyFlags.Updated, actualNotifyFlags);
}
}

[Fact]
public void MergeCanDetectRenames()
{
// The environment is set up such that:
// file b.txt is edited in the "rename" branch and
// edited and renamed in the "rename_source" branch.
// The edits are automergable.
// We can rename "rename_source" into "rename"
// if rename detection is enabled,
// but the merge will fail with conflicts if this
// change is not detected as a rename.

string repoPath = CloneMergeTestRepo();
using (var repo = new Repository(repoPath))
{
Branch currentBranch = repo.Checkout("rename_source");
Assert.NotNull(currentBranch);

Branch branchToMerge = repo.Branches["rename"];

MergeResult result = repo.Merge(branchToMerge, Constants.Signature);

Assert.Equal(MergeStatus.NonFastForward, result.Status);
}
}

[Fact]
public void FastForwardNonFastForwardableMergeThrows()
{
Expand Down Expand Up @@ -422,6 +541,112 @@ public void CanMergeCommittish(string committish, FastForwardStrategy strategy,
}
}

[Theory]
[InlineData(CheckoutFileConflictStrategy.Ours)]
[InlineData(CheckoutFileConflictStrategy.Theirs)]
public void CanSpecifyConflictFileStrategy(CheckoutFileConflictStrategy conflictStrategy)
{
const string conflictFile = "a.txt";
const string conflictBranchName = "conflicts";

string path = CloneMergeTestRepo();
using (var repo = new Repository(path))
{
Branch branch = repo.Branches[conflictBranchName];
Assert.NotNull(branch);

MergeOptions mergeOptions = new MergeOptions()
{
FileConflictStrategy = conflictStrategy,
};

MergeResult result = repo.Merge(branch, Constants.Signature, mergeOptions);
Assert.Equal(MergeStatus.Conflicts, result.Status);

// Get the information on the conflict.
Conflict conflict = repo.Index.Conflicts[conflictFile];

Assert.NotNull(conflict);
Assert.NotNull(conflict.Theirs);
Assert.NotNull(conflict.Ours);

// Get the blob containing the expected content.
Blob expectedBlob = null;
switch(conflictStrategy)
{
case CheckoutFileConflictStrategy.Theirs:
expectedBlob = repo.Lookup<Blob>(conflict.Theirs.Id);
break;
case CheckoutFileConflictStrategy.Ours:
expectedBlob = repo.Lookup<Blob>(conflict.Ours.Id);
break;
default:
throw new Exception("Unexpected FileConflictStrategy");
}

Assert.NotNull(expectedBlob);

// Check the content of the file on disk matches what is expected.
string expectedContent = expectedBlob.GetContentText(new FilteringOptions(conflictFile));
Assert.Equal(expectedContent, File.ReadAllText(Path.Combine(repo.Info.WorkingDirectory, conflictFile)));
}
}

[Theory]
[InlineData(MergeFileFavor.Ours)]
[InlineData(MergeFileFavor.Theirs)]
public void MergeCanSpecifyMergeFileFavorOption(MergeFileFavor fileFavorFlag)
{
const string conflictFile = "a.txt";
const string conflictBranchName = "conflicts";

string path = CloneMergeTestRepo();
using (var repo = InitIsolatedRepository(path))
{
Branch branch = repo.Branches[conflictBranchName];
Assert.NotNull(branch);

var status = repo.Index.RetrieveStatus();
MergeOptions mergeOptions = new MergeOptions()
{
MergeFileFavor = fileFavorFlag,
};

MergeResult result = repo.Merge(branch, Constants.Signature, mergeOptions);

Assert.Equal(MergeStatus.NonFastForward, result.Status);

// Verify that the index and working directory are clean
Assert.True(repo.Index.IsFullyMerged);
Assert.False(repo.Index.RetrieveStatus().IsDirty);

// Get the blob containing the expected content.
Blob expectedBlob = null;
switch (fileFavorFlag)
{
case MergeFileFavor.Theirs:
expectedBlob = repo.Lookup<Blob>("3dd9738af654bbf1c363f6c3bbc323bacdefa179");
break;
case MergeFileFavor.Ours:
expectedBlob = repo.Lookup<Blob>("610b16886ca829cebd2767d9196f3c4378fe60b5");
break;
default:
throw new Exception("Unexpected MergeFileFavor");
}

Assert.NotNull(expectedBlob);

// Verify the index has the expected contents
IndexEntry entry = repo.Index[conflictFile];
Assert.NotNull(entry);
Assert.Equal(expectedBlob.Id, entry.Id);

// Verify the content of the file on disk matches what is expected.
string expectedContent = expectedBlob.GetContentText(new FilteringOptions(conflictFile));
Assert.Equal(expectedContent, File.ReadAllText(Path.Combine(repo.Info.WorkingDirectory, conflictFile)));
}
}

[Theory]
[InlineData("refs/heads/normal_merge", FastForwardStrategy.Default, MergeStatus.NonFastForward)]
[InlineData("fast_forward", FastForwardStrategy.Default, MergeStatus.FastForward)]
Expand Down
2 changes: 1 addition & 1 deletion LibGit2Sharp.Tests/RepositoryFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ public void QueryingTheRemoteForADetachedHeadBranchReturnsNull()
string path = CloneStandardTestRepo();
using (var repo = new Repository(path))
{
repo.Checkout(repo.Head.Tip.Sha, CheckoutModifiers.Force, null, null);
repo.Checkout(repo.Head.Tip.Sha, new CheckoutOptions() { CheckoutModifiers = CheckoutModifiers.Force });
Branch trackLocal = repo.Head;
Assert.Null(trackLocal.Remote);
}
Expand Down
Binary file modified LibGit2Sharp.Tests/Resources/merge_testrepo_wd/dot_git/index
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
4dfaa1500526214ae7b33f9b2c1144ca8b6b1f53 refs/heads/fast_forward
83cebf5389a4adbcb80bda6b68513caee4559802 refs/heads/master
625186280ed2a6ec9b65d250ed90cf2e4acef957 refs/heads/normal_merge
24434077dec097c1203ef9e1345c0545c190936a refs/heads/rename
2bc71d0e8acfbb9fd1cc2d9d48c23dbf8aea52c9 refs/heads/rename_source
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
0000000000000000000000000000000000000000 83cebf5389a4adbcb80bda6b68513caee4559802 Jameson Miller <[email protected]> 1398366152 -0400 branch: Created from HEAD
83cebf5389a4adbcb80bda6b68513caee4559802 9075c06ff9cd736610dea688bca7e912903ff2d1 Jameson Miller <[email protected]> 1398366254 -0400 commit: Add content to b.txt
9075c06ff9cd736610dea688bca7e912903ff2d1 24434077dec097c1203ef9e1345c0545c190936a Jameson Miller <[email protected]> 1398366641 -0400 commit: edit to b.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
0000000000000000000000000000000000000000 9075c06ff9cd736610dea688bca7e912903ff2d1 Jameson Miller <[email protected]> 1398366267 -0400 branch: Created from rename
9075c06ff9cd736610dea688bca7e912903ff2d1 2bc71d0e8acfbb9fd1cc2d9d48c23dbf8aea52c9 Jameson Miller <[email protected]> 1398366593 -0400 commit: rename and edit b.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
P pack-52e214e240728e3b0ce2fc2d5e6513772fed0523.pack
P pack-f9b2f231d5e59d4a265578d02283f848a5dc4694.pack

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
4dfaa1500526214ae7b33f9b2c1144ca8b6b1f53 refs/heads/fast_forward
83cebf5389a4adbcb80bda6b68513caee4559802 refs/heads/master
625186280ed2a6ec9b65d250ed90cf2e4acef957 refs/heads/normal_merge
24434077dec097c1203ef9e1345c0545c190936a refs/heads/rename
2bc71d0e8acfbb9fd1cc2d9d48c23dbf8aea52c9 refs/heads/rename_source
Loading