Skip to content
Browse files

* GitSharp.Tests.csproj:

* StashTests.cs: Add some stash tests.

* Stash.cs: Improve unstashing. Add support for reporting merge
  conflicts.
  • Loading branch information...
1 parent 8d21dca commit 0438e28bd6710c4f0275574d4a89e4d92f1c113e @slluis slluis committed with
Showing with 264 additions and 18 deletions.
  1. +7 −9 GitSharp.Tests/GitSharp.Tests.csproj
  2. +164 −0 GitSharp.Tests/GitSharp/StashTests.cs
  3. +93 −9 GitSharp/Stash.cs
View
16 GitSharp.Tests/GitSharp.Tests.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -19,7 +19,7 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
- <DebugType>Full</DebugType>
+ <DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE;NDESK_OPTIONS</DefineConstants>
@@ -46,21 +46,18 @@
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
- <Reference Include="nunit.framework, Version=2.5.2.9222, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
- <SpecificVersion>False</SpecificVersion>
- <HintPath>..\tools\nunit\nunit.framework.dll</HintPath>
- </Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
+ <Reference Include="nunit.framework, Version=2.5.2.9222, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\tools\nunit\nunit.framework.dll</HintPath>
+ </Reference>
</ItemGroup>
<ItemGroup>
- <Compile Include="..\SharedAssemblyInfo.cs">
- <Link>Properties\SharedAssemblyInfo.cs</Link>
- </Compile>
<Compile Include="GitSharp.Core\AbbreviatedObjectIdTest.cs" />
<Compile Include="GitSharp.Core\CanReadMsysgitIndexFixture.cs" />
<Compile Include="GitSharp.Core\DirectoryCache\DirCacheEntryTest.cs" />
@@ -236,6 +233,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<None Include="GitSharp.Core\sample\README" />
<None Include="GitSharp.Core\sample\unpacked" />
+ <Compile Include="GitSharp\StashTests.cs" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\all_packed_objects.txt">
View
164 GitSharp.Tests/GitSharp/StashTests.cs
@@ -0,0 +1,164 @@
+//
+// StashTests.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@novell.com>
+//
+// Copyright (c) 2010 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.IO;
+using System.Linq;
+using GitSharp.Core.Tests;
+using GitSharp.Commands;
+using GitSharp.Tests.GitSharp;
+using NUnit.Framework;
+using System.Collections.Generic;
+using System;
+using System.Collections;
+
+namespace GitSharp.API.Tests
+{
+ [TestFixture]
+ public class StashTests : ApiTestCase
+ {
+ void EnsureModified (FileInfo file)
+ {
+ file.Refresh ();
+ file.LastWriteTime = file.LastWriteTime.AddSeconds (1);
+ }
+
+ [Test]
+ public void CreateStash ()
+ {
+ db = createWorkRepository ();
+ using (var repo = GetTrashRepository ())
+ {
+ FileInfo testFile = writeTrashFile ("test", "111");
+ repo.Index.Add ("test");
+ repo.Commit ("test1");
+
+ writeTrashFile ("test", "222");
+ EnsureModified (testFile);
+
+ Stash s = repo.Stashes.Create ("s1");
+ Assert.AreEqual ("s1", s.Comment);
+
+ Assert.AreEqual (1, repo.Stashes.Count ());
+ s = repo.Stashes.First ();
+ Assert.AreEqual ("s1", s.Comment);
+
+ Assert.AreEqual ("111", File.ReadAllText (testFile.FullName));
+
+ s.Apply ();
+
+ Assert.AreEqual ("222", File.ReadAllText (testFile.FullName));
+
+ repo.Stashes.Clear ();
+ Assert.AreEqual (0, repo.Stashes.Count ());
+ }
+ }
+
+ [Test]
+ public void RestoreModificationStash ()
+ {
+ db = createWorkRepository ();
+ using (var repo = GetTrashRepository ())
+ {
+ // Commit initial files
+ FileInfo testFile1 = writeTrashFile ("test1", "t1-111");
+ repo.Index.Add ("test1");
+ FileInfo testFile2 = writeTrashFile ("test2", "t2-111");
+ repo.Index.Add ("test2");
+ FileInfo testFile3 = writeTrashFile ("test3", "t3-111");
+ repo.Index.Add ("test3");
+ repo.Commit ("Test commit");
+
+ // Modify test1, stage it and modify again
+ writeTrashFile ("test1", "t1-222");
+ EnsureModified (testFile1);
+ repo.Index.Add ("test1");
+ writeTrashFile ("test1", "t1-333");
+ EnsureModified (testFile1);
+
+ // Modify test2 without staging
+ writeTrashFile ("test2", "t2-222");
+ EnsureModified (testFile2);
+
+ // Modify test3 and stage
+ writeTrashFile ("test3", "t3-222");
+ EnsureModified (testFile3);
+ repo.Index.Add ("test3");
+
+ Stash s = repo.Stashes.Create ();
+ Assert.AreEqual (1, repo.Stashes.Count ());
+
+ Assert.AreEqual ("t1-111", File.ReadAllText (testFile1.FullName));
+ Assert.AreEqual ("t2-111", File.ReadAllText (testFile2.FullName));
+ Assert.AreEqual ("t3-111", File.ReadAllText (testFile3.FullName));
+
+ s.Apply ();
+
+ Assert.AreEqual ("t1-333", File.ReadAllText (testFile1.FullName));
+ Assert.AreEqual ("t2-222", File.ReadAllText (testFile2.FullName));
+ Assert.AreEqual ("t3-222", File.ReadAllText (testFile3.FullName));
+
+ var status = repo.Status;
+ AssertStatus (status, "test1", status.Staged);
+ AssertStatus (status, "test2", status.Staged);
+ AssertStatus (status, "test3", status.Staged);
+ }
+ }
+
+ void AssertStatus (RepositoryStatus results, string file, params HashSet<string>[] fileStatuses)
+ {
+ Assert.IsNotNull(results);
+
+ var allStatus = new HashSet<string> [] {
+ results.Added,
+ results.MergeConflict,
+ results.Missing,
+ results.Modified,
+ results.Removed,
+ results.Staged,
+ results.Untracked
+ };
+
+ var allStatusName = new string[] {
+ "Added",
+ "MergeConflict",
+ "Missing",
+ "Modified",
+ "Removed",
+ "Staged",
+ "Untracked"
+ };
+
+ for (int n=0; n<allStatus.Length; n++) {
+ var status = allStatus [n];
+ if (((IList)fileStatuses).Contains (status))
+ Assert.IsTrue (status.Contains (file), "File " + file + " not found in " + allStatusName[n] + " collection");
+ else
+ Assert.IsFalse (status.Contains (file), "File " + file + " should no be in " + allStatusName[n] + " collection");
+ }
+ }
+ }
+}
+
View
102 GitSharp/Stash.cs
@@ -31,6 +31,10 @@
using System.Collections;
using GitSharp.Core;
using System.Text;
+using GitSharp.Core.Merge;
+using GitSharp.Core.TreeWalk;
+using GitSharp.Core.Diff;
+using GitSharp.Core.DirectoryCache;
namespace GitSharp
{
@@ -65,9 +69,12 @@ internal Stash (string prevStashCommitId, string commitId, Author author, string
this.PrevStashCommitId = prevStashCommitId;
this.CommitId = commitId;
this.Author = author;
- this.Comment = comment;
this.DateTime = DateTimeOffset.Now;
+ // Skip "WIP on master: "
+ int i = comment.IndexOf (':');
+ this.Comment = comment.Substring (i + 2);
+
// Create the text line to be written in the stash log
int secs = (int) (this.DateTime - new DateTimeOffset (1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds;
@@ -112,6 +119,9 @@ internal static Stash Parse (string line)
string st = t.ToString ("yyyy-MM-ddTHH:mm:ss") + line.Substring (i + 1, 3) + ":" + line.Substring (i + 4, 2);
s.DateTime = DateTimeOffset.Parse (st);
s.Comment = line.Substring (i + 7);
+ i = s.Comment.IndexOf (':');
+ if (i != -1)
+ s.Comment = s.Comment.Substring (i + 2);
}
s.FullLine = line;
return s;
@@ -157,7 +167,7 @@ public Stash Create (string message)
var parent = _repo.CurrentBranch.CurrentCommit;
Author author = new Author(_repo.Config["user.name"] ?? "unknown", _repo.Config["user.email"] ?? "unknown@(none).");
- if (message == null) {
+ if (string.IsNullOrEmpty (message)) {
// Use the commit summary as message
message = parent.ShortHash + " " + parent.Message;
int i = message.IndexOfAny (new char[] { '\r', '\n' });
@@ -227,15 +237,89 @@ void WriteTree (ObjectWriter writer, Core.Tree headTree, GitIndex index, Core.Tr
internal void Apply (Stash stash)
{
- // Restore the working tree
Commit wip = _repo.Get<Commit> (stash.CommitId);
- wip.Checkout();
- _repo._internal_repo.Index.write();
-
- // Restore the index
Commit index = wip.Parents.Last ();
- _repo.Index.GitIndex.ReadTree (index.Tree.InternalTree);
- _repo.Index.GitIndex.write ();
+
+ Tree wipTree = wip.Tree;
+ Tree headTree = _repo.CurrentBranch.CurrentCommit.Tree;
+ GitIndex currentIndex = _repo.Index.GitIndex;
+ Tree currentIndexTree = new Tree (_repo, _repo._internal_repo.MapTree (currentIndex.writeTree ()));
+
+ WorkDirCheckout co = new WorkDirCheckout (_repo._internal_repo, _repo._internal_repo.WorkingDirectory, headTree.InternalTree, currentIndex, wip.Tree.InternalTree);
+ co.checkout ();
+
+ currentIndex.write ();
+
+ List<DirCacheEntry> toAdd = new List<DirCacheEntry> ();
+
+ DirCache dc = DirCache.Lock (_repo._internal_repo);
+ try {
+ var cacheEditor = dc.editor ();
+
+ // The WorkDirCheckout class doesn't check if there are conflicts in modified files,
+ // so we have to do it here.
+
+ foreach (var c in co.Updated) {
+
+ var baseEntry = wip.Parents.First ().Tree[c.Key] as Leaf;
+ var oursEntry = wipTree [c.Key] as Leaf;
+ var theirsEntry = headTree [c.Key] as Leaf;
+
+ if (baseEntry != null && oursEntry != null && currentIndexTree [c.Key] == null) {
+ // If a file was reported as updated but that file is not present in the stashed index,
+ // it means that the file was scheduled to be deleted.
+ cacheEditor.@add (new DirCacheEditor.DeletePath (c.Key));
+ File.Delete (_repo.FromGitPath (c.Key));
+ }
+ else if (baseEntry != null && oursEntry != null && theirsEntry != null) {
+ MergeResult res = MergeAlgorithm.merge (new RawText (baseEntry.RawData), new RawText (oursEntry.RawData), new RawText (theirsEntry.RawData));
+ MergeFormatter f = new MergeFormatter ();
+ using (BinaryWriter bw = new BinaryWriter (File.OpenWrite (_repo.FromGitPath (c.Key)))) {
+ f.formatMerge (bw, res, "Base", "Stash", "Head", Constants.CHARSET.WebName);
+ }
+ if (res.containsConflicts ()) {
+ // Remove the entry from the index. It will be added later on.
+ cacheEditor.@add (new DirCacheEditor.DeletePath (c.Key));
+
+ // Generate index entries for each merge stage
+ // Those entries can't be added right now to the index because a DirCacheEditor
+ // can't be used at the same time as a DirCacheBuilder.
+ var e = new DirCacheEntry(c.Key, DirCacheEntry.STAGE_1);
+ e.setObjectId (baseEntry.InternalEntry.Id);
+ e.setFileMode (baseEntry.InternalEntry.Mode);
+ toAdd.Add (e);
+
+ e = new DirCacheEntry(c.Key, DirCacheEntry.STAGE_2);
+ e.setObjectId (oursEntry.InternalEntry.Id);
+ e.setFileMode (oursEntry.InternalEntry.Mode);
+ toAdd.Add (e);
+
+ e = new DirCacheEntry(c.Key, DirCacheEntry.STAGE_3);
+ e.setObjectId (theirsEntry.InternalEntry.Id);
+ e.setFileMode (theirsEntry.InternalEntry.Mode);
+ toAdd.Add (e);
+ }
+ }
+ }
+
+ cacheEditor.finish ();
+
+ if (toAdd.Count > 0) {
+ // Add the index entries generated above
+ var cacheBuilder = dc.builder ();
+ for (int n=0; n<dc.getEntryCount (); n++)
+ cacheBuilder.@add (dc.getEntry (n));
+ foreach (var entry in toAdd)
+ cacheBuilder.@add (entry);
+ cacheBuilder.finish ();
+ }
+
+ dc.write ();
+ dc.commit ();
+ } catch {
+ dc.unlock ();
+ throw;
+ }
}
public void Remove (Stash s)

0 comments on commit 0438e28

Please sign in to comment.
Something went wrong with that request. Please try again.