@@ -66,6 +66,106 @@ IEnumerator IEnumerable.GetEnumerator()
66
66
67
67
#endregion
68
68
69
+ /// <summary>
70
+ /// Creates a direct or symbolic reference with the specified name and target
71
+ /// </summary>
72
+ /// <param name="name">The name of the reference to create.</param>
73
+ /// <param name="canonicalRefNameOrObjectish">The target which can be either the canonical name of a reference or a revparse spec.</param>
74
+ /// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/> when adding the <see cref="Reference"/></param>
75
+ /// <returns>A new <see cref="Reference"/>.</returns>
76
+ public virtual Reference Add ( string name , string canonicalRefNameOrObjectish ,
77
+ string logMessage )
78
+ {
79
+ return Add ( name , canonicalRefNameOrObjectish , logMessage , false ) ;
80
+ }
81
+
82
+ private enum RefState
83
+ {
84
+ Exists ,
85
+ DoesNotExistButLooksValid ,
86
+ DoesNotLookValid ,
87
+ }
88
+
89
+ private static RefState TryResolveReference ( out Reference reference , ReferenceCollection refsColl , string canonicalName )
90
+ {
91
+ if ( ! Reference . IsValidName ( canonicalName ) )
92
+ {
93
+ reference = null ;
94
+ return RefState . DoesNotLookValid ;
95
+ }
96
+
97
+ reference = refsColl [ canonicalName ] ;
98
+
99
+ return reference != null ? RefState . Exists : RefState . DoesNotExistButLooksValid ;
100
+ }
101
+
102
+ /// <summary>
103
+ /// Creates a direct or symbolic reference with the specified name and target
104
+ /// </summary>
105
+ /// <param name="name">The name of the reference to create.</param>
106
+ /// <param name="canonicalRefNameOrObjectish">The target which can be either the canonical name of a reference or a revparse spec.</param>
107
+ /// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/> when adding the <see cref="Reference"/></param>
108
+ /// <param name="allowOverwrite">True to allow silent overwriting a potentially existing reference, false otherwise.</param>
109
+ /// <returns>A new <see cref="Reference"/>.</returns>
110
+ public virtual Reference Add ( string name , string canonicalRefNameOrObjectish , string logMessage , bool allowOverwrite )
111
+ {
112
+ Ensure . ArgumentNotNullOrEmptyString ( name , "name" ) ;
113
+ Ensure . ArgumentNotNullOrEmptyString ( canonicalRefNameOrObjectish , "canonicalRefNameOrObjectish" ) ;
114
+
115
+ Reference reference ;
116
+ RefState refState = TryResolveReference ( out reference , this , canonicalRefNameOrObjectish ) ;
117
+
118
+ var gitObject = repo . Lookup ( canonicalRefNameOrObjectish , GitObjectType . Any , LookUpOptions . None ) ;
119
+
120
+ if ( refState == RefState . Exists )
121
+ {
122
+ return Add ( name , reference , logMessage , allowOverwrite ) ;
123
+ }
124
+
125
+ if ( refState == RefState . DoesNotExistButLooksValid && gitObject == null )
126
+ {
127
+ using ( ReferenceSafeHandle handle = Proxy . git_reference_symbolic_create ( repo . Handle , name , canonicalRefNameOrObjectish , allowOverwrite ,
128
+ logMessage ) )
129
+ {
130
+ return Reference . BuildFromPtr < Reference > ( handle , repo ) ;
131
+ }
132
+ }
133
+
134
+ Ensure . GitObjectIsNotNull ( gitObject , canonicalRefNameOrObjectish ) ;
135
+
136
+ if ( logMessage == null )
137
+ {
138
+ logMessage = string . Format ( CultureInfo . InvariantCulture , "{0}: Created from {1}" ,
139
+ name . LooksLikeLocalBranch ( ) ? "branch" : "reference" , canonicalRefNameOrObjectish ) ;
140
+ }
141
+
142
+ EnsureHasLog ( name ) ;
143
+ return Add ( name , gitObject . Id , logMessage , allowOverwrite ) ;
144
+ }
145
+
146
+
147
+ /// <summary>
148
+ /// Creates a direct or symbolic reference with the specified name and target
149
+ /// </summary>
150
+ /// <param name="name">The name of the reference to create.</param>
151
+ /// <param name="canonicalRefNameOrObjectish">The target which can be either the canonical name of a reference or a revparse spec.</param>
152
+ /// <returns>A new <see cref="Reference"/>.</returns>
153
+ public virtual Reference Add ( string name , string canonicalRefNameOrObjectish )
154
+ {
155
+ return Add ( name , canonicalRefNameOrObjectish , null , false ) ;
156
+ }
157
+
158
+ /// <summary>
159
+ /// Creates a direct or symbolic reference with the specified name and target
160
+ /// </summary>
161
+ /// <param name="name">The name of the reference to create.</param>
162
+ /// <param name="canonicalRefNameOrObjectish">The target which can be either the canonical name of a reference or a revparse spec.</param>
163
+ /// <param name="allowOverwrite">True to allow silent overwriting a potentially existing reference, false otherwise.</param>
164
+ /// <returns>A new <see cref="Reference"/>.</returns>
165
+ public virtual Reference Add ( string name , string canonicalRefNameOrObjectish , bool allowOverwrite )
166
+ {
167
+ return Add ( name , canonicalRefNameOrObjectish , null , allowOverwrite ) ;
168
+ }
69
169
/// <summary>
70
170
/// Creates a direct reference with the specified name and target
71
171
/// </summary>
@@ -175,6 +275,24 @@ public virtual SymbolicReference Add(string name, Reference targetRef, bool allo
175
275
return Add ( name , targetRef , null , allowOverwrite ) ;
176
276
}
177
277
278
+ /// <summary>
279
+ /// Remove a reference with the specified name
280
+ /// </summary>
281
+ /// <param name="name">The canonical name of the reference to delete.</param>
282
+ public virtual void Remove ( string name )
283
+ {
284
+ Ensure . ArgumentNotNullOrEmptyString ( name , "name" ) ;
285
+
286
+ Reference reference = this [ name ] ;
287
+
288
+ if ( reference == null )
289
+ {
290
+ return ;
291
+ }
292
+
293
+ Remove ( reference ) ;
294
+ }
295
+
178
296
/// <summary>
179
297
/// Remove a reference from the repository
180
298
/// </summary>
@@ -224,6 +342,68 @@ public virtual Reference Rename(Reference reference, string newName, string logM
224
342
}
225
343
}
226
344
345
+ /// <summary>
346
+ /// Rename an existing reference with a new name
347
+ /// </summary>
348
+ /// <param name="currentName">The canonical name of the reference to rename.</param>
349
+ /// <param name="newName">The new canonical name.</param>
350
+ /// <returns>A new <see cref="Reference"/>.</returns>
351
+ public virtual Reference Rename ( string currentName , string newName )
352
+ {
353
+ return Rename ( currentName , newName , null , false ) ;
354
+ }
355
+
356
+ /// <summary>
357
+ /// Rename an existing reference with a new name
358
+ /// </summary>
359
+ /// <param name="currentName">The canonical name of the reference to rename.</param>
360
+ /// <param name="newName">The new canonical name.</param>
361
+ /// <param name="allowOverwrite">True to allow silent overwriting a potentially existing reference, false otherwise.</param>
362
+ /// <returns>A new <see cref="Reference"/>.</returns>
363
+ public virtual Reference Rename ( string currentName , string newName ,
364
+ bool allowOverwrite )
365
+ {
366
+ return Rename ( currentName , newName , null , allowOverwrite ) ;
367
+ }
368
+
369
+ /// <summary>
370
+ /// Rename an existing reference with a new name
371
+ /// </summary>
372
+ /// <param name="currentName">The canonical name of the reference to rename.</param>
373
+ /// <param name="newName">The new canonical name.</param>
374
+ /// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/></param>
375
+ /// <returns>A new <see cref="Reference"/>.</returns>
376
+ public virtual Reference Rename ( string currentName , string newName ,
377
+ string logMessage )
378
+ {
379
+ return Rename ( currentName , newName , logMessage , false ) ;
380
+ }
381
+
382
+ /// <summary>
383
+ /// Rename an existing reference with a new name
384
+ /// </summary>
385
+ /// <param name="currentName">The canonical name of the reference to rename.</param>
386
+ /// <param name="newName">The new canonical name.</param>
387
+ /// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/></param>
388
+ /// <param name="allowOverwrite">True to allow silent overwriting a potentially existing reference, false otherwise.</param>
389
+ /// <returns>A new <see cref="Reference"/>.</returns>
390
+ public virtual Reference Rename ( string currentName , string newName ,
391
+ string logMessage , bool allowOverwrite )
392
+ {
393
+ Ensure . ArgumentNotNullOrEmptyString ( currentName , "currentName" ) ;
394
+
395
+ Reference reference = this [ currentName ] ;
396
+
397
+ if ( reference == null )
398
+ {
399
+ throw new LibGit2SharpException (
400
+ string . Format ( CultureInfo . InvariantCulture ,
401
+ "Reference '{0}' doesn't exist. One cannot move a non existing reference." , currentName ) ) ;
402
+ }
403
+
404
+ return Rename ( reference , newName , logMessage , allowOverwrite ) ;
405
+ }
406
+
227
407
/// <summary>
228
408
/// Rename an existing reference with a new name
229
409
/// </summary>
@@ -286,6 +466,93 @@ private Reference UpdateDirectReferenceTarget(Reference directRef, ObjectId targ
286
466
}
287
467
}
288
468
469
+ /// <summary>
470
+ /// Updates the target of a direct reference.
471
+ /// </summary>
472
+ /// <param name="directRef">The direct reference which target should be updated.</param>
473
+ /// <param name="objectish">The revparse spec of the target.</param>
474
+ /// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/></param>
475
+ /// <returns>A new <see cref="Reference"/>.</returns>
476
+ public virtual Reference UpdateTarget ( Reference directRef , string objectish , string logMessage )
477
+ {
478
+ Ensure . ArgumentNotNull ( directRef , "directRef" ) ;
479
+ Ensure . ArgumentNotNull ( objectish , "objectish" ) ;
480
+
481
+ GitObject target = repo . Lookup ( objectish ) ;
482
+
483
+ Ensure . GitObjectIsNotNull ( target , objectish ) ;
484
+
485
+ return UpdateTarget ( directRef , target . Id , logMessage ) ;
486
+ }
487
+
488
+ /// <summary>
489
+ /// Updates the target of a direct reference
490
+ /// </summary>
491
+ /// <param name="directRef">The direct reference which target should be updated.</param>
492
+ /// <param name="objectish">The revparse spec of the target.</param>
493
+ /// <returns>A new <see cref="Reference"/>.</returns>
494
+ public virtual Reference UpdateTarget ( Reference directRef , string objectish )
495
+ {
496
+ return UpdateTarget ( directRef , objectish , null ) ;
497
<
10000
code class="diff-text syntax-highlighted-line addition">+ }
498
+
499
+ /// <summary>
500
+ /// Updates the target of a reference
501
+ /// </summary>
502
+ /// <param name="name">The canonical name of the reference.</param>
503
+ /// <param name="canonicalRefNameOrObjectish">The target which can be either the canonical name of a reference or a revparse spec.</param>
504
+ /// <param name="logMessage">The optional message to log in the <see cref="ReflogCollection"/> of the <paramref name="name"/> reference.</param>
505
+ /// <returns>A new <see cref="Reference"/>.</returns>
506
+ public virtual Reference UpdateTarget ( string name , string canonicalRefNameOrObjectish , string logMessage )
507
+ {
508
+ Ensure . ArgumentNotNullOrEmptyString ( name , "name" ) ;
509
+ Ensure . ArgumentNotNullOrEmptyString ( canonicalRefNameOrObjectish , "canonicalRefNameOrObjectish" ) ;
510
+
511
+ if ( name == "HEAD" )
512
+ {
513
+ return UpdateHeadTarget ( canonicalRefNameOrObjectish , logMessage ) ;
514
+ }
515
+
516
+ Reference reference = this [ name ] ;
517
+
518
+ var directReference = reference as DirectReference ;
519
+ if ( directReference != null )
520
+ {
521
+ return UpdateTarget ( directReference , canonicalRefNameOrObjectish , logMessage ) ;
522
+ }
523
+
524
+ var symbolicReference = reference as SymbolicReference ;
525
+ if ( symbolicReference != null )
526
+ {
527
+ Reference targetRef ;
528
+
529
+ RefState refState = TryResolveReference ( out targetRef , this , canonicalRefNameOrObjectish ) ;
530
+
531
+ if ( refState == RefState . DoesNotLookValid )
532
+ {
533
+ 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" ) ;
534
+ }
535
+
536
+ return UpdateTarget ( symbolicReference , targetRef , logMessage ) ;
537
+ }
538
+
539
+ throw new LibGit2SharpException ( CultureInfo . InvariantCulture ,
540
+ "Reference '{0}' has an unexpected type ('{1}')." ,
541
+ name ,
542
+ reference . GetType ( ) ) ;
543
+ }
544
+
545
+ /// <summary>
546
+ /// Updates the target of a reference
547
+ /// </summary>
548
+ /// <param name="name">The canonical name of the reference.</param>
549
+ /// <param name="canonicalRefNameOrObjectish">The target which can be either the canonical name of a reference or a revparse spec.</param>
550
+ /// <returns>A new <see cref="Reference"/>.</returns>
551
+ public virtual Reference UpdateTarget ( string name , string canonicalRefNameOrObjectish )
552
+ {
553
+ return UpdateTarget ( name , canonicalRefNameOrObjectish , null ) ;
554
+ }
555
+
289
556
/// <summary>
290
557
/// Updates the target of a direct reference
291
558
/// </summary>
@@ -427,6 +694,79 @@ public virtual Reference Head
427
694
get { return this [ "HEAD" ] ; }
428
695
}
429
696
697
+
698
+ /// <summary>
699
+ /// Find the <see cref="Reference"/>s among <paramref name="refSubset"/>
700
+ /// that can reach at least one <see cref="Commit"/> in the specified <paramref name="targets"/>.
701
+ /// </summary>
702
+ /// <param name="refSubset">The set of <see cref="Reference"/>s to examine.</param>
703
+ /// <param name="targets">The set of <see cref="Commit"/>s that are interesting.</param>
704
+ /// <returns>A subset of <paramref name="refSubset"/> that can reach at least one <see cref="Commit"/> within <paramref name="targets"/>.</returns>
705
+ public virtual IEnumerable < Reference > ReachableFrom (
706
+ IEnumerable < Reference > refSubset ,
707
+ IEnumerable < Commit > targets )
708
+ {
709
+ Ensure . ArgumentNotNull ( refSubset , "refSubset" ) ;
710
+ Ensure . ArgumentNotNull ( targets , "targets" ) ;
711
+
712
+ var refs = new List < Reference > ( refSubset ) ;
713
+ if ( refs . Count == 0 )
714
+ {
715
+ return Enumerable . Empty < Reference > ( ) ;
716
+ }
10000
td>717
+
718
+ List < ObjectId > targetsSet = targets . Select ( c => c . Id ) . Distinct ( ) . ToList ( ) ;
719
+ if ( targetsSet . Count == 0 )
720
+ {
721
+ return Enumerable . Empty < Reference > ( ) ;
722
+ }
723
+
724
+ var result = new List < Reference > ( ) ;
725
+
726
+ foreach ( var reference in refs )
727
+ {
728
+ var peeledTargetCommit = reference
729
+ . ResolveToDirectReference ( )
730
+ . Target . DereferenceToCommit ( false ) ;
731
+
732
+ if ( peeledTargetCommit == null )
733
+ {
734
+ continue ;
735
+ }
736
+
737
+ var commitId = peeledTargetCommit . Id ;
738
+
739
+ foreach ( var potentialAncestorId in targetsSet )
740
+ {
741
+ if ( potentialAncestorId == commitId )
742
+ {
743
+ result . Add ( reference ) ;
744
+ break ;
745
+ }
746
+
747
+ if ( Proxy . git_graph_descendant_of ( repo . Handle , commitId , potentialAncestorId ) )
748
+ {
749
+ result . Add ( reference ) ;
750
+ break ;
751
+ }
752
+ }
753
+ }
754
+
755
+ return result ;
756
+ }
757
+
758
+ /// <summary>
759
+ /// Find the <see cref="Reference"/>s
760
+ /// that can reach at least one <see cref="Commit"/> in the specified <paramref name="targets"/>.
761
+ /// </summary>
762
+ /// <param name="targets">The set of <see cref="Commit"/>s that are interesting.</param>
763
+ /// <returns>The list of <see cref="Reference"/> that can reach at least one <see cref="Commit"/> within <paramref name="targets"/>.</returns>
764
+ public virtual IEnumerable < Reference > ReachableFrom (
765
+ IEnumerable < Commit > targets )
766
+ {
767
+ return ReachableFrom ( this , targets ) ;
768
+ }
769
+
430
770
private string DebuggerDisplay
431
771
{
432
772
get
0 commit comments