Skip to content

Commit 4f492d3

Browse files
angusbjonesjamill
authored andcommitted
Introduce basic merging
1 parent 7089f63 commit 4f492d3

12 files changed

+342
-0
lines changed

LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,33 @@
4242
<WarningLevel>4</WarningLevel>
4343
<DocumentationFile />
4444
</PropertyGroup>
45+
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
46+
<DebugSymbols>true</DebugSymbols>
47+
<OutputPath>bin\x86\Debug\</OutputPath>
48+
<DefineConstants>TRACE;DEBUG;NET35</DefineConstants>
49+
<DebugType>full</DebugType>
50+
<PlatformTarget>x86</PlatformTarget>
51+
<ErrorReport>prompt</ErrorReport>
52+
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
53+
</PropertyGroup>
54+
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
55+
<OutputPath>bin\x86\Release\</OutputPath>
56+
<DefineConstants>TRACE</DefineConstants>
57+
<Optimize>true</Optimize>
58+
<DebugType>pdbonly</DebugType>
59+
<PlatformTarget>x86</PlatformTarget>
60+
<ErrorReport>prompt</ErrorReport>
61+
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
62+
</PropertyGroup>
63+
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Leaks|x86'">
64+
<DebugSymbols>true</DebugSymbols>
65+
<OutputPath>bin\x86\Leaks\</OutputPath>
66+
<DefineConstants>TRACE;DEBUG;NET35;LEAKS</DefineConstants>
67+
<DebugType>full</DebugType>
68+
<PlatformTarget>x86</PlatformTarget>
69+
<ErrorReport>prompt</ErrorReport>
70+
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
71+
</PropertyGroup>
4572
<ItemGroup>
4673
<Reference Include="Moq, Version=4.0.10827.0, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
4774
<SpecificVersion>False</SpecificVersion>
@@ -131,6 +158,9 @@
131158
<Name>LibGit2Sharp</Name>
132159
</ProjectReference>
133160
</ItemGroup>
161+
<ItemGroup>
162+
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
163+
</ItemGroup>
134164
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
135165
<PropertyGroup>
136166
<NativeBinariesDirectory>$(MSBuildProjectDirectory)\..\Lib\NativeBinaries</NativeBinariesDirectory>

LibGit2Sharp.Tests/MergeFixture.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Linq;
22
using LibGit2Sharp.Tests.TestHelpers;
33
using Xunit;
4+
using System;
45

56
namespace LibGit2Sharp.Tests
67
{
@@ -80,5 +81,48 @@ public void CanRetrieveTheBranchBeingMerged()
8081
Assert.Null(mergedHeads[1].Tip);
8182
}
8283
}
84+
85+
[Fact]
86+
public void CanMergeRepos()
87+
{
88+
string path = CloneStandardTestRepo();
89+
using (var repo = new Repository(path))
90+
{
91+
var firstBranch = repo.CreateBranch("FirstBranch");
92+
firstBranch.Checkout();
93+
AddFileCommitToRepo(repo, "first+second branch file");
94+
95+
var secondBranch = repo.CreateBranch("SecondBranch");
96+
AddFileCommitToRepo(repo, "first branch file");
97+
secondBranch.Checkout();
98+
AddFileCommitToRepo(repo, "second branch file");
99+
100+
repo.MergeOnto(repo.Branches["FirstBranch"].Tip);
101+
102+
repo.Commit("Merge First+Second");
103+
}
104+
}
105+
106+
private Commit AddCommitToRepo(IRepository repository)
107+
{
108+
string random = Guid.NewGuid().ToString();
109+
string filename = random + ".txt";
110+
111+
Touch(repository.Info.WorkingDirectory, filename, random);
112+
113+
repository.Index.Stage(filename);
114+
115+
return repository.Commit("New commit", Constants.Signature, Constants.Signature);
116+
}
117+
118+
private Commit AddFileCommitToRepo(IRepository repository, string filename, string content = null)
119+
{
120+
filename = filename + ".txt";
121+
Touch(repository.Info.WorkingDirectory, filename, content);
122+
123+
repository.Index.Stage(filename);
124+
125+
return repository.Commit("New commit", Constants.Signature, Constants.Signature);
126+
}
83127
}
84128
}

LibGit2Sharp/Core/GitMergeHead.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using LibGit2Sharp.Core.Handles;
2+
using System;
3+
using System.Runtime.InteropServices;
4+
5+
namespace LibGit2Sharp.Core
6+
{
7+
[StructLayout(LayoutKind.Sequential)]
8+
internal struct GitMergeHead
9+
{
10+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string RefName;
11+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string RemoteUrl;
12+
13+
GitOid Oid;
14+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string OidStr;
15+
GitObjectSafeHandle Commit;
16+
}
17+
}

LibGit2Sharp/Core/GitMergeOpts.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
4+
namespace LibGit2Sharp.Core
5+
{
6+
[Flags]
7+
internal enum MergeFlags
8+
{
9+
GIT_MERGE_NO_FASTFORWARD = 1,
10+
GIT_MERGE_FASTFORWARD_ONLY = 2,
11+
}
12+
13+
[StructLayout(LayoutKind.Sequential)]
14+
internal struct GitMergeOpts
15+
{
16+
public uint Version;
17+
18+
public MergeFlags MergeFlags;
19+
public GitMergeTreeOpts MergeTreeOpts;
20+
public GitCheckoutOpts CheckoutOpts;
21+
}
22+
}

LibGit2Sharp/Core/GitMergeTreeOpts.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using LibGit2Sharp.Core.Handles;
2+
using System;
3+
using System.Runtime.InteropServices;
4+
5+
namespace LibGit2Sharp.Core
6+
{
7+
[Flags]
8+
internal enum MergeTreeFlags
9+
{
10+
GIT_MERGE_TREE_FIND_RENAMES = (1 << 0),
11+
}
12+
[Flags]
13+
internal enum MergeAutomergeFlags
14+
{
15+
GIT_MERGE_AUTOMERGE_NORMAL = 0,
16+
GIT_MERGE_AUTOMERGE_NONE = 1,
17+
GIT_MERGE_AUTOMERGE_FAVOR_OURS = 2,
18+
GIT_MERGE_AUTOMERGE_FAVOR_THEIRS = 3,
19+
}
20+
21+
[StructLayout(LayoutKind.Sequential)]
22+
internal struct GitMergeTreeOpts
23+
{
24+
public uint Version;
25+
26+
public MergeTreeFlags MergeTreeFlags;
27+
public uint RenameThreshold;
28+
public uint TargetLimit;
29+
30+
public UIntPtr Metric;
31+
32+
public MergeAutomergeFlags MergeAutomergeFlags;
33+
}
34+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Runtime.InteropServices;
2+
3+
namespace LibGit2Sharp.Core.Handles
4+
{
5+
internal class GitMergeHeadHandle : SafeHandleBase
6+
{
7+
protected override bool ReleaseHandleImpl()
8+
{
9+
Proxy.git_merge_head_free(handle);
10+
return true;
11+
}
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Runtime.InteropServices;
2+
3+
namespace LibGit2Sharp.Core.Handles
4+
{
5+
internal class GitMergeResultHandle : SafeHandleBase
6+
{
7+
protected override bool ReleaseHandleImpl()
8+
{
9+
Proxy.git_merge_result_free(handle);
10+
return true;
11+
}
12+
}
13+
}

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,41 @@ internal static extern int git_merge_base(
570570
GitObjectSafeHandle one,
571571
GitObjectSafeHandle two);
572572

573+
[DllImport(libgit2)]
574+
internal static extern int git_merge_head_from_oid(
575+
out GitMergeHeadHandle their_heads,
576+
RepositorySafeHandle repo,
577+
ref GitOid mergeBase);
578+
579+
[DllImport(libgit2)]
580+
internal static extern int git_merge(
581+
out GitMergeResultHandle mergeResult,
582+
RepositorySafeHandle repo,
583+
ref GitMergeHeadHandle their_heads,
584+
UIntPtr their_heads_len,
585+
ref GitMergeOpts given_opts);
586+
587+
[DllImport(libgit2)]
588+
internal static extern int git_merge_result_is_uptodate(
589+
GitMergeResultHandle merge_result);
590+
591+
[DllImport(libgit2)]
592+
internal static extern int git_merge_result_is_fastforward(
593+
GitMergeResultHandle merge_result);
594+
595+
[DllImport(libgit2)]
596+
internal static extern int git_merge_result_fastforward_oid(
597+
out GitOid oid,
598+
GitMergeResultHandle merge_result);
599+
600+
[DllImport(libgit2)]
601+
internal static extern void git_merge_result_free(
602+
IntPtr merge_result);
603+
604+
[DllImport(libgit2)]
605+
internal static extern void git_merge_head_free(
606+
IntPtr merge_head);
607+
573608
[DllImport(libgit2)]
574609
internal static extern int git_message_prettify(
575610
byte[] message_out, // NB: This is more properly a StringBuilder, but it's UTF8

LibGit2Sharp/Core/Proxy.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,77 @@ public static ObjectId git_merge_base(RepositorySafeHandle repo, Commit first, C
948948
}
949949
}
950950

951+
public static GitMergeResult git_merge(RepositorySafeHandle repo, GitMergeOpts opts, GitOid oid)
952+
{
953+
using (ThreadAffinity())
954+
{
955+
GitMergeHeadHandle their_heads;
956+
957+
int res1 = NativeMethods.git_merge_head_from_oid(out their_heads, repo, ref oid);
958+
if (res1 == (int)GitErrorCode.NotFound)
959+
return null;
960+
961+
Ensure.ZeroResult(res1);
962+
963+
GitMergeResultHandle ret;
964+
965+
int res2 = NativeMethods.git_merge(out ret, repo, ref their_heads, (UIntPtr)1, ref opts);
966+
967+
if (res2 == (int)GitErrorCode.NotFound)
968+
{
969+
return null;
970+
}
971+
972+
Ensure.ZeroResult(res2);
973+
974+
return new GitMergeResult(ret);
975+
}
976+
}
977+
978+
public static bool git_merge_result_is_uptodate(GitMergeResultHandle handle)
979+
{
980+
using (ThreadAffinity())
981+
{
982+
int res = NativeMethods.git_merge_result_is_uptodate(handle);
983+
Ensure.ZeroResult(res);
984+
985+
return (res == 1);
986+
}
987+
}
988+
989+
public static bool git_merge_result_is_fastforward(GitMergeResultHandle handle)
990+
{
991+
using (ThreadAffinity())
992+
{
993+
int res = NativeMethods.git_merge_result_is_fastforward(handle);
994+
Ensure.ZeroResult(res);
995+
996+
return (res == 1);
997+
}
998+
}
999+
1000+
public static GitOid git_merge_result_fastforward_oid(GitMergeResultHandle handle)
1001+
{
1002+
using (ThreadAffinity())
1003+
{
1004+
GitOid oid;
1005+
int res = NativeMethods.git_merge_result_fastforward_oid(out oid, handle);
1006+
Ensure.ZeroResult(res);
1007+
1008+
return oid;
1009+
}
1010+
}
1011+
1012+
public static void git_merge_result_free(IntPtr handle)
1013+
{
1014+
NativeMethods.git_merge_result_free(handle);
1015+
}
1016+
1017+
public static void git_merge_head_free(IntPtr handle)
1018+
{
1019+
NativeMethods.git_merge_head_free(handle);
1020+
}
1021+
9511022
#endregion
9521023

9531024
#region git_message_

LibGit2Sharp/GitMergeResult.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Globalization;
5+
using System.IO;
6+
using System.Linq;
7+
using System.Reflection;
8+
using System.Text.RegularExpressions;
9+
using LibGit2Sharp.Core;
10+
using LibGit2Sharp.Core.Compat;
11+
using LibGit2Sharp.Core.Handles;
12+
using LibGit2Sharp.Handlers;
13+
14+
namespace LibGit2Sharp
15+
{
16+
[DebuggerDisplay("{DebuggerDisplay,nq}")]
17+
public class GitMergeResult
18+
{
19+
public GitMergeResult(){}
20+
internal GitMergeResult(GitMergeResultHandle handle)
21+
{
22+
_handle = handle;
23+
}
24+
25+
private readonly GitMergeResultHandle _handle;
26+
27+
internal GitMergeResultHandle Handle
28+
{
29+
get { return _handle; }
30+
}
31+
32+
public virtual bool IsUpToDate
33+
{
34+
get { return Proxy.git_merge_result_is_uptodate(_handle); }
35+
}
36+
37+
public virtual bool IsFastForward
38+
{
39+
get { return Proxy.git_merge_result_is_fastforward(_handle); }
40+
}
41+
}
42+
}

LibGit2Sharp/LibGit2Sharp.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,22 @@
7979
<Compile Include="RefSpec.cs" />
8080
<Compile Include="RefSpecCollection.cs" />
8181
<Compile Include="Core\EncodingMarshaler.cs" />
82+
<Compile Include="Core\GitMergeHead.cs" />
83+
<Compile Include="Core\GitMergeOpts.cs" />
84+
<Compile Include="Core\GitMergeTreeOpts.cs" />
8285
<Compile Include="Core\Handles\BranchIteratorSafeHandle.cs" />
8386
<Compile Include="Core\Handles\ConfigurationIteratorSafeHandle.cs" />
8487
<Compile Include="Core\GitBlame.cs" />
8588
<Compile Include="Core\Handles\BlameSafeHandle.cs" />
89+
<Compile Include="Core\Handles\GitMergeHeadHandle.cs" />
90+
<Compile Include="Core\Handles\GitMergeResultHandle.cs" />
8691
<Compile Include="Core\PushTransferProgressCallbacks.cs" />
8792
<Compile Include="Core\PackbuilderCallbacks.cs" />
8893
<Compile Include="HistoryDivergence.cs" />
8994
<Compile Include="PushOptions.cs" />
9095
<Compile Include="Core\GitBuf.cs" />
9196
<Compile Include="FilteringOptions.cs" />
97+
<Compile Include="GitMergeResult.cs" />
9298
<Compile Include="ResetMode.cs" />
9399
<Compile Include="NoteCollectionExtensions.cs" />
94100
<Compile Include="RefSpecDirection.cs" />

0 commit comments

Comments
 (0)