Skip to content

Commit 7df508d

Browse files
committed
Teach Refs.Add() to append to the reflog
1 parent ba6e5c9 commit 7df508d

File tree

3 files changed

+89
-35
lines changed

3 files changed

+89
-35
lines changed

LibGit2Sharp.Tests/ReferenceFixture.cs

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,24 @@ public void CanAddADirectReference()
3838
public void CanAddADirectReferenceFromRevParseSpec()
3939
{
4040
const string name = "refs/heads/extendedShaSyntaxRulz";
41+
const string logMessage = "Create new ref";
4142

4243
string path = CloneBareTestRepo();
4344
using (var repo = new Repository(path))
4445
{
45-
var newRef = (DirectReference)repo.Refs.Add(name, "master^1^2");
46+
var newRef = (DirectReference)repo.Refs.Add(name, "master^1^2", logMessage: logMessage);
4647
Assert.NotNull(newRef);
4748
Assert.Equal(name, newRef.CanonicalName);
4849
Assert.NotNull(newRef.Target);
4950
Assert.Equal("c47800c7266a2be04c571c04d5a6614691ea99bd", newRef.Target.Sha);
5051
Assert.Equal(newRef.Target.Sha, newRef.TargetIdentifier);
5152
Assert.NotNull(repo.Refs[name]);
53+
54+
AssertReflogEntryIsCreated(
55+
repo.Refs.Log(newRef),
56+
newRef.ResolveToDirectReference().Target.Sha,
57+
logMessage,
58+
ObjectId.Zero.Sha);
5259
}
5360
}
5461

@@ -84,15 +91,22 @@ public void CanAddASymbolicReferenceFromTheTargetReference()
8491
{
8592
const string name = "refs/heads/unit_test";
8693
const string target = "refs/heads/master";
94+
const string logMessage = "unit_test reference init";
8795

8896
string path = CloneBareTestRepo();
8997
using (var repo = new Repository(path))
9098
{
9199
var targetRef = repo.Refs[target];
92100

93-
var newRef = repo.Refs.Add(name, targetRef);
101+
var newRef = repo.Refs.Add(name, targetRef, logMessage: logMessage);
94102

95103
AssertSymbolicRef(newRef, repo, target, name);
104+
105+
AssertReflogEntryIsCreated(
106+
repo.Refs.Log(newRef),
107+
newRef.ResolveToDirectReference().Target.Sha,
108+
logMessage,
109+
ObjectId.Zero.Sha);
96110
}
97111
}
98112

@@ -131,16 +145,23 @@ public void CanAddAndOverwriteADirectReference()
131145
{
132146
const string name = "refs/heads/br2";
133147
const string target = "4c062a6361ae6959e06292c1fa5e2822d9c96345";
148+
const string logMessage = "Create new ref";
134149

135150
string path = CloneBareTestRepo();
136151
using (var repo = new Repository(path))
137152
{
138-
var newRef = (DirectReference)repo.Refs.Add(name, target, true);
153+
var newRef = (DirectReference)repo.Refs.Add(name, target, true, logMessage);
139154
Assert.NotNull(newRef);
140155
Assert.Equal(name, newRef.CanonicalName);
141156
Assert.NotNull(newRef.Target);
142157
Assert.Equal(target, newRef.Target.Sha);
143158
Assert.Equal(target, ((DirectReference)repo.Refs[name]).Target.Sha);
159+
160+
AssertReflogEntryIsCreated(
161+
repo.Refs.Log(newRef),
162+
newRef.ResolveToDirectReference().Target.Sha,
163+
logMessage,
164+
ObjectId.Zero.Sha);
144165
}
145166
}
146167

@@ -149,16 +170,23 @@ public void CanAddAndOverwriteASymbolicReference()
149170
{
150171
const string name = "HEAD";
151172
const string target = "refs/heads/br2";
173+
const string logMessage = "Create new ref";
152174

153175
string path = CloneBareTestRepo();
154176
using (var repo = new Repository(path))
155177
{
156-
var newRef = (SymbolicReference)repo.Refs.Add(name, target, true);
178+
var newRef = (SymbolicReference)repo.Refs.Add(name, target, true, logMessage);
157179
Assert.NotNull(newRef);
158180
Assert.Equal(name, newRef.CanonicalName);
159181
Assert.NotNull(newRef.Target);
160182
Assert.Equal("a4a7dce85cf63874e984719f4fdd239f5145052f", newRef.ResolveToDirectReference().Target.Sha);
161183
Assert.Equal(target, ((SymbolicReference)repo.Refs.Head).Target.CanonicalName);
184+
185+
AssertReflogEntryIsCreated(
186+
repo.Refs.Log(newRef),
187+
newRef.ResolveToDirectReference().Target.Sha,
188+
logMessage,
189+
ObjectId.Zero.Sha);
162190
}
163191
}
164192

@@ -462,28 +490,23 @@ public void CanUpdateHeadWithEitherAnObjectIdOrAReference()
462490
Assert.Equal(test.TargetIdentifier, direct.TargetIdentifier);
463491
Assert.Equal(repo.Refs.Head, direct);
464492

465-
// Assert reflog entry is created
466-
var reflogEntry = repo.Refs.Log(repo.Refs.Head).First();
467-
ObjectId testTargetId = test.ResolveToDirectReference().Target.Id;
468-
469-
Assert.Equal(testTargetId, reflogEntry.To);
470-
Assert.NotNull(reflogEntry.Commiter.Email);
471-
Assert.NotNull(reflogEntry.Commiter.Name);
472-
Assert.Equal(firstLogMessage, reflogEntry.Message);
493+
String testTargetSha = test.ResolveToDirectReference().Target.Sha;
494+
AssertReflogEntryIsCreated(
495+
repo.Refs.Log(repo.Refs.Head),
496+
testTargetSha,
497+
firstLogMessage);
473498

474499
const string secondLogMessage = "second update target message";
475500
Reference symref = repo.Refs.UpdateTarget(head, test, secondLogMessage);
476501
Assert.True((symref is SymbolicReference));
477502
Assert.Equal(test.CanonicalName, symref.TargetIdentifier);
478503
Assert.Equal(repo.Refs.Head, symref);
479504

480-
// Assert reflog entry is created
481-
reflogEntry = repo.Refs.Log(repo.Refs.Head).First();
482-
Assert.Equal(testTargetId, reflogEntry.From);
483-
Assert.Equal(testTargetId, reflogEntry.To);
484-
Assert.NotNull(reflogEntry.Commiter.Email);
485-
Assert.NotNull(reflogEntry.Commiter.Name);
486-
Assert.Equal(secondLogMessage, reflogEntry.Message);
505+
AssertReflogEntryIsCreated(
506+
repo.Refs.Log(repo.Refs.Head),
507+
testTargetSha,
508+
secondLogMessage,
509+
testTargetSha);
487510
}
488511
}
489512

@@ -506,10 +529,10 @@ public void CanUpdateTargetOfADirectReferenceWithARevparseSpec()
506529
Assert.Equal(newRef.Target.Sha, newRef.TargetIdentifier);
507530
Assert.NotNull(repo.Refs[name]);
508531

509-
// Assert reflog entry is created
510-
var reflogEntry = repo.Refs.Log(master).First();
511-
Assert.Equal(newRef.Target.Id, reflogEntry.To);
512-
Assert.Equal(logMessage, reflogEntry.Message);
532+
AssertReflogEntryIsCreated(
533+
repo.Refs.Log(master),
534+
newRef.Target.Sha,
535+
logMessage);
513536
}
514537
}
515538

@@ -755,5 +778,20 @@ public void CanIdentifyReferenceKind()
755778
Assert.True(repo.Refs["refs/notes/commits"].IsNote());
756779
}
757780
}
781+
782+
private static void AssertReflogEntryIsCreated(IEnumerable<ReflogEntry> reflog, string targetSha, string logMessage, string fromSha = null)
783+
{
784+
var reflogEntry = reflog.First();
785+
786+
if (!string.IsNullOrEmpty(fromSha))
787+
{
788+
Assert.Equal(fromSha, reflogEntry.From.Sha);
789+
}
790+
791+
Assert.Equal(targetSha, reflogEntry.To.Sha);
792+
Assert.NotNull(reflogEntry.Commiter.Email);
793+
Assert.NotNull(reflogEntry.Commiter.Name);
794+
Assert.Equal(logMessage, reflogEntry.Message);
795+
}
758796
}
759797
}

LibGit2Sharp/ReferenceCollection.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,20 @@ IEnumerator IEnumerable.GetEnumerator()
7272
/// <param name = "name">The canonical name of the reference to create.</param>
7373
/// <param name = "targetId">Id of the target object.</param>
7474
/// <param name = "allowOverwrite">True to allow silent overwriting a potentially existing reference, false otherwise.</param>
75+
/// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/> when adding the <see cref="DirectReference"/></param>
7576
/// <returns>A new <see cref = "Reference" />.</returns>
76-
public virtual DirectReference Add(string name, ObjectId targetId, bool allowOverwrite = false)
77+
public virtual DirectReference Add(string name, ObjectId targetId, bool allowOverwrite = false, string logMessage = null)
7778
{
7879
Ensure.ArgumentNotNullOrEmptyString(name, "name");
7980
Ensure.ArgumentNotNull(targetId, "targetId");
8081

8182
using (ReferenceSafeHandle handle = Proxy.git_reference_create(repo.Handle, name, targetId, allowOverwrite))
8283
{
83-
return (DirectReference)Reference.BuildFromPtr<Reference>(handle, repo);
84+
var newTarget = (DirectReference)Reference.BuildFromPtr<Reference>(handle, repo);
85+
86+
LogReference(newTarget, targetId, logMessage);
87+
88+
return newTarget;
8489
}
8590
}
8691

@@ -90,15 +95,20 @@ public virtual DirectReference Add(string name, ObjectId targetId, bool allowOve
9095
/// <param name = "name">The canonical name of the reference to create.</param>
9196
/// <param name = "targetRef">The target reference.</param>
9297
/// <param name = "allowOverwrite">True to allow silent overwriting a potentially existing reference, false otherwise.</param>
98+
/// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/> when adding the <see cref="SymbolicReference"/></param>
9399
/// <returns>A new <see cref = "Reference" />.</returns>
94-
public virtual SymbolicReference Add(string name, Reference targetRef, bool allowOverwrite = false)
100+
public virtual SymbolicReference Add(string name, Reference targetRef, bool allowOverwrite = false, string logMessage = null)
95101
{
96102
Ensure.ArgumentNotNullOrEmptyString(name, "name");
97103
Ensure.ArgumentNotNull(targetRef, "targetRef");
98104

99105
using (ReferenceSafeHandle handle = Proxy.git_reference_symbolic_create(repo.Handle, name, targetRef.CanonicalName, allowOverwrite))
100106
{
101-
return (SymbolicReference)Reference.BuildFromPtr<Reference>(handle, repo);
107+
var newTarget = (SymbolicReference)Reference.BuildFromPtr<Reference>(handle, repo);
108+
109+
LogReference(newTarget, targetRef, logMessage);
110+
111+
return newTarget;
102112
}
103113
}
104114

@@ -162,7 +172,7 @@ public virtual Reference UpdateTarget(Reference directRef, ObjectId targetId, st
162172
Reference newTarget = UpdateTarget(directRef, targetId,
163173
Proxy.git_reference_set_target);
164174

165-
LogUpdateTarget(directRef, targetId, logMessage);
175+
LogReference(directRef, targetId, logMessage);
166176

167177
return newTarget;
168178
}
@@ -182,7 +192,7 @@ public virtual Reference UpdateTarget(Reference symbolicRef, Reference targetRef
182192
Reference newTarget = UpdateTarget(symbolicRef, targetRef,
183193
(h, r) => Proxy.git_reference_symbolic_set_target(h, r.CanonicalName));
184194

185-
LogUpdateTarget(symbolicRef, targetRef, logMessage);
195+
LogReference(symbolicRef, targetRef, logMessage);
186196

187197
return newTarget;
188198
}
@@ -219,7 +229,7 @@ private Reference UpdateTarget<T>(Reference reference, T target, Func<ReferenceS
219229
}
220230
}
221231

222-
private void LogUpdateTarget(Reference reference, Reference target, string logMessage)
232+
private void LogReference(Reference reference, Reference target, string logMessage)
223233
{
224234
var directReference = target.ResolveToDirectReference();
225235

@@ -228,10 +238,10 @@ private void LogUpdateTarget(Reference reference, Reference target, string logMe
228238
return;
229239
}
230240

231-
LogUpdateTarget(reference, directReference.Target.Id, logMessage);
241+
LogReference(reference, directReference.Target.Id, logMessage);
232242
}
233243

234-
private void LogUpdateTarget(Reference reference, ObjectId target, string logMessage)
244+
private void LogReference(Reference reference, ObjectId target, string logMessage)
235245
{
236246
if (string.IsNullOrEmpty(logMessage))
237247
{

LibGit2Sharp/ReferenceCollectionExtensions.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ private static RefState TryResolveReference(out Reference reference, ReferenceCo
3737
/// <param name = "canonicalRefNameOrObjectish">The target which can be either the canonical name of a reference or a revparse spec.</param>
3838
/// <param name = "allowOverwrite">True to allow silent overwriting a potentially existing reference, false otherwise.</param>
3939
/// <param name = "refsColl">The <see cref="ReferenceCollection"/> being worked with.</param>
40+
/// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/> when adding the <see cref="Reference"/></param>
4041
/// <returns>A new <see cref = "Reference" />.</returns>
41-
public static Reference Add(this ReferenceCollection refsColl, string name, string canonicalRefNameOrObjectish, bool allowOverwrite = false)
42+
public static Reference Add(this ReferenceCollection refsColl, string name, string canonicalRefNameOrObjectish, bool allowOverwrite = false, string logMessage = null)
4243
{
4344
Ensure.ArgumentNotNullOrEmptyString(name, "name");
4445
Ensure.ArgumentNotNullOrEmptyString(canonicalRefNameOrObjectish, "canonicalRefNameOrObjectish");
@@ -48,7 +49,12 @@ public static Reference Add(this ReferenceCollection refsColl, string name, stri
4849

4950
var gitObject = refsColl.repo.Lookup(canonicalRefNameOrObjectish, GitObjectType.Any, LookUpOptions.None);
5051

51-
if (refState == RefState.Exists || (refState == RefState.DoesNotExistButLooksValid && gitObject == null))
52+
if (refState == RefState.Exists)
53+
{
54+
return refsColl.Add(name, reference, allowOverwrite, logMessage);
55+
}
56+
57+
if (refState == RefState.DoesNotExistButLooksValid && gitObject == null)
5258
{
5359
using (ReferenceSafeHandle handle = Proxy.git_reference_symbolic_create(refsColl.repo.Handle, name, canonicalRefNameOrObjectish, allowOverwrite))
5460
{
@@ -58,7 +64,7 @@ public static Reference Add(this ReferenceCollection refsColl, string name, stri
5864

5965
Ensure.GitObjectIsNotNull(gitObject, canonicalRefNameOrObjectish);
6066

61-
return refsColl.Add(name, gitObject.Id, allowOverwrite);
67+
return refsColl.Add(name, gitObject.Id, allowOverwrite, logMessage);
6268
}
6369
/// <summary>
6470
/// Updates the target of a direct reference.

0 commit comments

Comments
 (0)