Skip to content

Commit 1d4d35a

Browse files
committed
Make Stash expose Base, Index and Untracked commits
1 parent b0086f3 commit 1d4d35a

File tree

2 files changed

+73
-18
lines changed

2 files changed

+73
-18
lines changed

LibGit2Sharp.Tests/StashFixture.cs

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,22 @@ public void CanAddAndRemoveStash()
3434
Stash stash = repo.Stashes.Add(stasher, "My very first stash", StashModifiers.IncludeUntracked);
3535

3636
// Check that untracked files are deleted from working directory
37-
Assert.False(File.Exists(Path.Combine(repo.Info.WorkingDirectory, "new_untracked_file.txt")));
37+
string untrackedFilename = "new_untracked_file.txt";
38+
Assert.False(File.Exists(Path.Combine(repo.Info.WorkingDirectory, untrackedFilename)));
39+
Assert.NotNull(stash.Untracked[untrackedFilename]);
3840

3941
Assert.NotNull(stash);
4042
Assert.Equal("stash@{0}", stash.CanonicalName);
4143
Assert.Contains("My very first stash", stash.Message);
4244

4345
var stashRef = repo.Refs["refs/stash"];
44-
Assert.Equal(stash.Target.Sha, stashRef.TargetIdentifier);
46+
Assert.Equal(stash.WorkTree.Sha, stashRef.TargetIdentifier);
4547

4648
Assert.False(repo.Index.RetrieveStatus().IsDirty);
4749

4850
// Create extra file
49-
Touch(repo.Info.WorkingDirectory, "stash_candidate.txt", "Oh, I'm going to be stashed!\n");
51+
untrackedFilename = "stash_candidate.txt";
52+
Touch(repo.Info.WorkingDirectory, untrackedFilename, "Oh, I'm going to be stashed!\n");
5053

5154
Stash secondStash = repo.Stashes.Add(stasher, "My second stash", StashModifiers.IncludeUntracked);
5255

@@ -58,20 +61,22 @@ public void CanAddAndRemoveStash()
5861
Assert.Equal("stash@{0}", repo.Stashes.First().CanonicalName);
5962
Assert.Equal("stash@{1}", repo.Stashes.Last().CanonicalName);
6063

64+
Assert.NotNull(secondStash.Untracked[untrackedFilename]);
65+
6166
// Stash history has been shifted
62-
Assert.Equal(repo.Lookup<Commit>("stash@{0}").Sha, secondStash.Target.Sha);
63-
Assert.Equal(repo.Lookup<Commit>("stash@{1}").Sha, stash.Target.Sha);
67+
Assert.Equal(repo.Lookup<Commit>("stash@{0}").Sha, secondStash.WorkTree.Sha);
68+
Assert.Equal(repo.Lookup<Commit>("stash@{1}").Sha, stash.WorkTree.Sha);
6469

6570
//Remove one stash
6671
repo.Stashes.Remove(0);
6772
Assert.Equal(1, repo.Stashes.Count());
6873
Stash newTopStash = repo.Stashes.First();
6974
Assert.Equal("stash@{0}", newTopStash.CanonicalName);
70-
Assert.Equal(stash.Target.Sha, newTopStash.Target.Sha);
75+
Assert.Equal(stash.WorkTree.Sha, newTopStash.WorkTree.Sha);
7176

7277
// Stash history has been shifted
73-
Assert.Equal(stash.Target.Sha, repo.Lookup<Commit>("stash").Sha);
74-
Assert.Equal(stash.Target.Sha, repo.Lookup<Commit>("stash@{0}").Sha);
78+
Assert.Equal(stash.WorkTree.Sha, repo.Lookup<Commit>("stash").Sha);
79+
Assert.Equal(stash.WorkTree.Sha, repo.Lookup<Commit>("stash@{0}").Sha);
7580
}
7681
}
7782

@@ -87,10 +92,10 @@ public void AddingAStashWithNoMessageGeneratesADefaultOne()
8792

8893
Assert.NotNull(stash);
8994
Assert.Equal("stash@{0}", stash.CanonicalName);
90-
Assert.NotEmpty(stash.Target.Message);
95+
Assert.NotEmpty(stash.WorkTree.Message);
9196

9297
var stashRef = repo.Refs["refs/stash"];
93-
Assert.Equal(stash.Target.Sha, stashRef.TargetIdentifier);
98+
Assert.Equal(stash.WorkTree.Sha, stashRef.TargetIdentifier);
9499
}
95100
}
96101

@@ -142,9 +147,11 @@ public void CanStashWithoutOptions()
142147

143148
//It should not keep staged files
144149
Assert.Equal(FileStatus.Nonexistent, repo.Index.RetrieveStatus(staged));
150+
Assert.NotNull(stash.Index[staged]);
145151

146152
//It should leave untracked files untracked
147153
Assert.Equal(FileStatus.Untracked, repo.Index.RetrieveStatus(untracked));
154+
Assert.Null(stash.Untracked);
148155
}
149156
}
150157

@@ -160,10 +167,12 @@ public void CanStashAndKeepIndex()
160167
Touch(repo.Info.WorkingDirectory, filename, "I'm staged\n");
161168
repo.Index.Stage(filename);
162169

163-
Stash stash = repo.Stashes.Add(stasher, "This stash wil keep index", StashModifiers.KeepIndex);
170+
Stash stash = repo.Stashes.Add(stasher, "This stash will keep index", StashModifiers.KeepIndex);
164171

165172
Assert.NotNull(stash);
173+
Assert.NotNull(stash.Index[filename]);
166174
Assert.Equal(FileStatus.Added, repo.Index.RetrieveStatus(filename));
175+
Assert.Null(stash.Untracked);
167176
}
168177
}
169178

@@ -180,18 +189,19 @@ public void CanStashIgnoredFiles()
180189
repo.Index.Stage(gitIgnore);
181190
repo.Commit("Modify gitignore", Constants.Signature, Constants.Signature);
182191

183-
string ignoredFilePath = Touch(repo.Info.WorkingDirectory, ignoredFilename, "I'm ignored\n");
192+
Touch(repo.Info.WorkingDirectory, ignoredFilename, "I'm ignored\n");
184193

185194
Assert.True(repo.Ignore.IsPathIgnored(ignoredFilename));
186195

187196
var stasher = Constants.Signature;
188-
repo.Stashes.Add(stasher, "This stash includes ignore files", StashModifiers.IncludeIgnored);
197+
var stash = repo.Stashes.Add(stasher, "This stash includes ignore files", StashModifiers.IncludeIgnored);
189198

190199
//TODO : below assertion doesn't pass. Bug?
191200
//Assert.False(File.Exists(ignoredFilePath));
192201

193202
var blob = repo.Lookup<Blob>("stash^3:ignored_file.txt");
194203
Assert.NotNull(blob);
204+
Assert.NotNull(stash.Untracked[ignoredFilename]);
195205
}
196206
}
197207

@@ -239,13 +249,13 @@ public void CanGetStashByIndexer()
239249
Assert.Equal(3, repo.Stashes.Count());
240250
Assert.Equal("stash@{0}", repo.Stashes[0].CanonicalName);
241251
Assert.Contains(thirdStashMessage, repo.Stashes[0].Message);
242-
Assert.Equal(thirdStash.Target, repo.Stashes[0].Target);
252+
Assert.Equal(thirdStash.WorkTree, repo.Stashes[0].WorkTree);
243253
Assert.Equal("stash@{1}", repo.Stashes[1].CanonicalName);
244254
Assert.Contains(secondStashMessage, repo.Stashes[1].Message);
245-
Assert.Equal(secondStash.Target, repo.Stashes[1].Target);
255+
Assert.Equal(secondStash.WorkTree, repo.Stashes[1].WorkTree);
246256
Assert.Equal("stash@{2}", repo.Stashes[2].CanonicalName);
247257
Assert.Contains(firstStashMessage, repo.Stashes[2].Message);
248-
Assert.Equal(firstStash.Target, repo.Stashes[2].Target);
258+
Assert.Equal(firstStash.WorkTree, repo.Stashes[2].WorkTree);
249259
}
250260
}
251261

LibGit2Sharp/Stash.cs

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
namespace LibGit2Sharp
1+
using System;
2+
using System.Linq;
3+
4+
namespace LibGit2Sharp
25
{
36
///<summary>
47
/// A Stash
@@ -19,17 +22,59 @@ internal Stash(Repository repo, ObjectId targetId, int index)
1922
/// <summary>
2023
/// Gets the <see cref="Commit"/> that this stash points to.
2124
/// </summary>
25+
[Obsolete("This property will be removed in the next release. Please use Stash.WorkTree instead.")]
2226
public virtual Commit Target
27+
{
28+
get { return WorkTree; }
29+
}
30+
31+
/// <summary>
32+
/// Gets the <see cref="Commit"/> that contains to the captured content of the worktree when the
33+
/// stash was created.
34+
/// </summary>
35+
public virtual Commit WorkTree
2336
{
2437
get { return TargetObject; }
2538
}
2639

40+
/// <summary>
41+
/// Gets the base <see cref="Commit"/> (i.e. the HEAD when the stash was
42+
/// created).
43+
/// </summary>
44+
public virtual Commit Base
45+
{
46+
get { return TargetObject.Parents.First(); }
47+
}
48+
49+
/// <summary>
50+
/// Gets the <see cref="Commit"/> that contains the captured content of the index when the stash was
51+
/// created.
52+
/// </summary>
53+
public virtual Commit Index
54+
{
55+
get { return GetParentAtOrDefault(1); }
56+
}
57+
58+
/// <summary>
59+
/// Gets the <see cref="Commit"/> that contains the list of either the untracked files, the ignored files, or both,
60+
/// depending on the <see cref="StashModifiers"/> options passed when the stash was created.
61+
/// </summary>
62+
public virtual Commit Untracked
63+
{
64+
get { return GetParentAtOrDefault(2); }
65+
}
66+
67+
private Commit GetParentAtOrDefault(int parentIndex)
68+
{
69+
return TargetObject.Parents.ElementAtOrDefault(parentIndex);
70+
}
71+
2772
/// <summary>
2873
/// Gets the message associated to this <see cref="Stash"/>.
2974
/// </summary>
3075
public virtual string Message
3176
{
32-
get { return Target.Message; }
77+
get { return WorkTree.Message; }
3378
}
3479

3580
/// <summary>

0 commit comments

Comments
 (0)