Skip to content

Commit 95430a1

Browse files
committed
Teach UpdateTarget() to append to the reflog
1 parent 5960c38 commit 95430a1

File tree

6 files changed

+106
-25
lines changed

6 files changed

+106
-25
lines changed

LibGit2Sharp.Tests/BranchFixture.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ public void CanGetTrackingInformationFromBranchSharingNoHistoryWithItsTrackedBra
382382
using (var repo = new Repository(path))
383383
{
384384
Branch master = repo.Branches["master"];
385-
repo.Refs.UpdateTarget("refs/remotes/origin/master", "origin/test");
385+
const string logMessage = "update target message";
386+
repo.Refs.UpdateTarget("refs/remotes/origin/master", "origin/test", logMessage);
386387

387388
Assert.True(master.IsTracking);
388389
Assert.NotNull(master.TrackedBranch);
@@ -391,6 +392,11 @@ public void CanGetTrackingInformationFromBranchSharingNoHistoryWithItsTrackedBra
391392
Assert.Equal(9, master.TrackingDetails.AheadBy);
392393
Assert.Equal(2, master.TrackingDetails.BehindBy);
393394
Assert.Null(repo.Head.TrackingDetails.CommonAncestor);
395+
396+
// Assert reflog entry is created
397+
var reflogEntry = repo.Refs.Log("refs/remotes/origin/master").First();
398+
Assert.Equal(repo.Branches["origin/test"].Tip.Id, reflogEntry.To);
399+
Assert.Equal(logMessage, reflogEntry.Message);
394400
}
395401
}
396402

LibGit2Sharp.Tests/ReferenceFixture.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -456,15 +456,34 @@ public void CanUpdateHeadWithEitherAnObjectIdOrAReference()
456456
Reference head = repo.Refs.Head;
457457
Reference test = repo.Refs["refs/heads/test"];
458458

459-
Reference direct = repo.Refs.UpdateTarget(head, new ObjectId(test.TargetIdentifier));
459+
const string firstLogMessage = "first update target message";
460+
Reference direct = repo.Refs.UpdateTarget(head, new ObjectId(test.TargetIdentifier), firstLogMessage);
460461
Assert.True((direct is DirectReference));
461462
Assert.Equal(test.TargetIdentifier, direct.TargetIdentifier);
462463
Assert.Equal(repo.Refs.Head, direct);
463464

464-
Reference symref = repo.Refs.UpdateTarget(head, test);
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);
473+
474+
const string secondLogMessage = "second update target message";
475+
Reference symref = repo.Refs.UpdateTarget(head, test, secondLogMessage);
465476
Assert.True((symref is SymbolicReference));
466477
Assert.Equal(test.CanonicalName, symref.TargetIdentifier);
467478
Assert.Equal(repo.Refs.Head, symref);
479+
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);
468487
}
469488
}
470489

@@ -478,13 +497,19 @@ public void CanUpdateTargetOfADirectReferenceWithARevparseSpec()
478497

479498
var master = (DirectReference) repo.Refs[name];
480499

481-
var newRef = (DirectReference)repo.Refs.UpdateTarget(master, "master^1^2");
500+
const string logMessage = "update target message";
501+
var newRef = (DirectReference)repo.Refs.UpdateTarget(master, "master^1^2", logMessage);
482502
Assert.NotNull(newRef);
483503
Assert.Equal(name, newRef.CanonicalName);
484504
Assert.NotNull(newRef.Target);
485505
Assert.Equal("c47800c7266a2be04c571c04d5a6614691ea99bd", newRef.Target.Sha);
486506
Assert.Equal(newRef.Target.Sha, newRef.TargetIdentifier);
487507
Assert.NotNull(repo.Refs[name]);
508+
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);
488513
}
489514
}
490515

LibGit2Sharp/ReferenceCollection.cs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,29 +152,39 @@ internal T Resolve<T>(string name) where T : Reference
152152
/// </summary>
153153
/// <param name = "directRef">The direct reference which target should be updated.</param>
154154
/// <param name = "targetId">The new target.</param>
155+
/// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/> of the <paramref name="directRef"/> reference</param>
155156
/// <returns>A new <see cref = "Reference" />.</returns>
156-
public virtual Reference UpdateTarget(Reference directRef, ObjectId targetId)
157+
public virtual Reference UpdateTarget(Reference directRef, ObjectId targetId, string logMessage = null)
157158
{
158159
Ensure.ArgumentNotNull(directRef, "directRef");
159160
Ensure.ArgumentNotNull(targetId, "targetId");
160161

161-
return UpdateTarget(directRef, targetId,
162-
(h, id) => Proxy.git_reference_set_target(h, id));
162+
Reference newTarget = UpdateTarget(directRef, targetId,
163+
Proxy.git_reference_set_target);
164+
165+
LogUpdateTarget(directRef, targetId, logMessage);
166+
167+
return newTarget;
163168
}
164169

165170
/// <summary>
166171
/// Updates the target of a symbolic reference.
167172
/// </summary>
168173
/// <param name = "symbolicRef">The symbolic reference which target should be updated.</param>
169174
/// <param name = "targetRef">The new target.</param>
175+
/// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/> of the <paramref name="symbolicRef"/> reference.</param>
170176
/// <returns>A new <see cref = "Reference" />.</returns>
171-
public virtual Reference UpdateTarget(Reference symbolicRef, Reference targetRef)
177+
public virtual Reference UpdateTarget(Reference symbolicRef, Reference targetRef, string logMessage = null)
172178
{
173179
Ensure.ArgumentNotNull(symbolicRef, "symbolicRef");
174180
Ensure.ArgumentNotNull(targetRef, "targetRef");
175181

176-
return UpdateTarget(symbolicRef, targetRef,
182+
Reference newTarget = UpdateTarget(symbolicRef, targetRef,
177183
(h, r) => Proxy.git_reference_symbolic_set_target(h, r.CanonicalName));
184+
185+
LogUpdateTarget(symbolicRef, targetRef, logMessage);
186+
187+
return newTarget;
178188
}
179189

180190
private Reference UpdateTarget<T>(Reference reference, T target, Func<ReferenceSafeHandle, T, ReferenceSafeHandle> setter)
@@ -209,6 +219,28 @@ private Reference UpdateTarget<T>(Reference reference, T target, Func<ReferenceS
209219
}
210220
}
211221

222+
private void LogUpdateTarget(Reference reference, Reference target, string logMessage)
223+
{
224+
var directReference = target.ResolveToDirectReference();
225+
226+
if (directReference == null)
227+
{
228+
return;
229+
}
230+
231+
LogUpdateTarget(reference, directReference.Target.Id, logMessage);
232+
}
233+
234+
private void LogUpdateTarget(Reference reference, ObjectId target, string logMessage)
235+
{
236+
if (string.IsNullOrEmpty(logMessage))
237+
{
238+
return;
239+
}
240+
241+
repo.Refs.Log(reference).Append(target, logMessage);
242+
}
243+
212244
internal ReferenceSafeHandle RetrieveReferencePtr(string referenceName, bool shouldThrowIfNotFound = true)
213245
{
214246
ReferenceSafeHandle reference = Proxy.git_reference_lookup(repo.Handle, referenceName, shouldThrowIfNotFound);

LibGit2Sharp/ReferenceCollectionExtensions.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ public static Reference Add(this ReferenceCollection refsColl, string name, stri
6666
/// <param name = "directRef">The direct reference which target should be updated.</param>
6767
/// <param name = "objectish">The revparse spec of the target.</param>
6868
/// <param name = "refsColl">The <see cref="ReferenceCollection"/> being worked with.</param>
69-
public static Reference UpdateTarget(this ReferenceCollection refsColl, Reference directRef, string objectish)
69+
/// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/> of the <paramref name="directRef"/> reference.</param>
70+
/// <returns>A new <see cref = "Reference" />.</returns>
71+
public static Reference UpdateTarget(this ReferenceCollection refsColl, Reference directRef, string objectish, string logMessage = null)
7072
{
7173
Ensure.ArgumentNotNull(directRef, "directRef");
7274
Ensure.ArgumentNotNull(objectish, "objectish");
@@ -75,7 +77,7 @@ public static Reference UpdateTarget(this ReferenceCollection refsColl, Referenc
7577

7678
Ensure.GitObjectIsNotNull(target, objectish);
7779

78-
return refsColl.UpdateTarget(directRef, target.Id);
80+
return refsColl.UpdateTarget(directRef, target.Id, logMessage);
7981
}
8082

8183
/// <summary>
@@ -108,8 +110,9 @@ public static Reference Move(this ReferenceCollection refsColl, string currentNa
108110
/// <param name = "name">The canonical name of the reference.</param>
109111
/// <param name = "canonicalRefNameOrObjectish">The target which can be either the canonical name of a reference or a revparse spec.</param>
110112
/// <param name = "refsColl">The <see cref="ReferenceCollection"/> being worked with.</param>
113+
/// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/> of the <paramref name="name"/> reference.</param>
111114
/// <returns>A new <see cref = "Reference" />.</returns>
112-
public static Reference UpdateTarget(this ReferenceCollection refsColl, string name, string canonicalRefNameOrObjectish)
115+
public static Reference UpdateTarget(this ReferenceCollection refsColl, string name, string canonicalRefNameOrObjectish, string logMessage = null)
113116
{
114117
Ensure.ArgumentNotNullOrEmptyString(name, "name");
115118
Ensure.ArgumentNotNullOrEmptyString(canonicalRefNameOrObjectish, "canonicalRefNameOrObjectish");
@@ -124,7 +127,7 @@ public static Reference UpdateTarget(this ReferenceCollection refsColl, string n
124127
var directReference = reference as DirectReference;
125128
if (directReference != null)
126129
{
127-
return refsColl.UpdateTarget(directReference, canonicalRefNameOrObjectish);
130+
return refsColl.UpdateTarget(directReference, canonicalRefNameOrObjectish, logMessage);
128131
}
129132

130133
var symbolicReference = reference as SymbolicReference;
@@ -139,7 +142,7 @@ public static Reference UpdateTarget(this ReferenceCollection refsColl, string n
139142
throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The reference specified by {0} is a Symbolic reference, you must provide a reference canonical name as the target.", name), "canonicalRefNameOrObjectish");
140143
}
141144

142-
return refsColl.UpdateTarget(symbolicReference, targetRef);
145+
return refsColl.UpdateTarget(symbolicReference, targetRef, logMessage);
143146
}
144147

145148
throw new LibGit2SharpException(string.Format(CultureInfo.InvariantCulture, "Reference '{0}' has an unexpected type ('{1}').", name, reference.GetType()));

LibGit2Sharp/ReflogCollection.cs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections;
1+
using System;
2+
using System.Collections;
23
using System.Collections.Generic;
34
using System.Diagnostics;
45
using System.Globalization;
@@ -91,17 +92,32 @@ private string DebuggerDisplay
9192
/// Add a new <see cref="ReflogEntry"/> to the current <see cref="ReflogCollection"/>. It will be created as first item of the collection
9293
/// The native reflog object will be saved right after inserting the entry.
9394
/// </summary>
94-
/// <param name="objectId">the <see cref="ObjectId"/> of the new commit the <see cref="Reference"/> will point out.</param>
95-
/// <param name="committer"><see cref="Signature"/> of the author of the new commit.</param>
96-
/// <param name="message">the message associated with the new <see cref="ReflogEntry"/>.</param>
97-
internal virtual void Append(ObjectId objectId, Signature committer, string message)
95+
/// <param name="target">the <see cref="ObjectId"/> of the new target the <see cref="Reference"/> will point out to.</param>
96+
/// <param name="reflogMessage">the message associated with the new <see cref="ReflogEntry"/>.</param>
97+
/// <param name="committer"><see cref="Signature"/> of the comitter.</param>
98+
internal virtual void Append(ObjectId target, string reflogMessage, Signature committer)
9899
{
99100
using (ReferenceSafeHandle reference = Proxy.git_reference_lookup(repo.Handle, canonicalName, true))
100101
using (ReflogSafeHandle reflog = Proxy.git_reflog_read(reference))
101102
{
102-
string prettifiedMessage = Proxy.git_message_prettify(message);
103-
Proxy.git_reflog_append(reflog, objectId, committer, prettifiedMessage);
103+
string prettifiedMessage = Proxy.git_message_prettify(reflogMessage);
104+
Proxy.git_reflog_append(reflog, target, committer, prettifiedMessage);
104105
}
105106
}
107+
108+
/// <summary>
109+
/// Add a new <see cref="ReflogEntry"/> to the current <see cref="ReflogCollection"/>. It will be created as first item of the collection
110+
/// The native reflog object will be saved right after inserting the entry.
111+
/// <para>
112+
/// The <see cref="Signature"/> will be built from the current Git configuration.
113+
/// </para>
114+
/// </summary>
115+
/// <param name="target">the <see cref="ObjectId"/> of the new target the <see cref="Reference"/> will point out to.</param>
116+
/// <param name="reflogMessage">the message associated with the new <see cref="ReflogEntry"/>.</param>
117+
internal void Append(ObjectId target, string reflogMessage)
118+
{
119+
Signature author = repo.Config.BuildSignatureFromGlobalConfiguration(DateTimeOffset.Now, false);
120+
Append(target, reflogMessage, author);
121+
}
106122
}
107123
}

LibGit2Sharp/Repository.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -675,8 +675,7 @@ private void LogCheckout(string previousHeadName, ObjectId newHeadTip, string ne
675675
string reflogMessage = string.Format("checkout: moving from {0} to {1}", previousHeadName, newHeadSpec);
676676

677677
// Log checkout
678-
Signature author = Config.BuildSignatureFromGlobalConfiguration(DateTimeOffset.Now, false);
679-
Refs.Log(Refs.Head).Append(newHeadTip, author, reflogMessage);
678+
Refs.Log(Refs.Head).Append(newHeadTip, reflogMessage);
680679
}
681680

682681
/// <summary>
@@ -796,11 +795,11 @@ private void LogCommit(Commit commit, bool amendPreviousCommit, bool isHeadOrpha
796795
// in case HEAD targets a symbolic reference, log commit on the targeted direct reference
797796
if (headRef is SymbolicReference)
798797
{
799-
Refs.Log(headRef.ResolveToDirectReference()).Append(commit.Id, commit.Committer, reflogMessage);
798+
Refs.Log(headRef.ResolveToDirectReference()).Append(commit.Id, reflogMessage, commit.Committer);
800799
}
801800

802801
// Log commit on HEAD
803-
Refs.Log(headRef).Append(commit.Id, commit.Committer, reflogMessage);
802+
Refs.Log(headRef).Append(commit.Id, reflogMessage, commit.Committer);
804803
}
805804

806805
private IEnumerable<Commit> RetrieveParentsOfTheCommitBeingCreated(bool amendPreviousCommit)

0 commit comments

Comments
 (0)