9
9
#include "tag.h"
10
10
#include "quote.h"
11
11
#include "ref-filter.h"
12
+ #include "revision.h"
12
13
13
14
typedef enum { FIELD_STR , FIELD_ULONG , FIELD_TIME } cmp_type ;
14
15
@@ -898,6 +899,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
898
899
struct ref_filter_cbdata * ref_cbdata = cb_data ;
899
900
struct ref_filter * filter = ref_cbdata -> filter ;
900
901
struct ref_array_item * ref ;
902
+ struct commit * commit = NULL ;
901
903
902
904
if (flag & REF_BAD_NAME ) {
903
905
warning ("ignoring ref with broken name %s" , refname );
@@ -910,12 +912,24 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
910
912
if (filter -> points_at .nr && !match_points_at (& filter -> points_at , oid -> hash , refname ))
911
913
return 0 ;
912
914
915
+ /*
916
+ * A merge filter is applied on refs pointing to commits. Hence
917
+ * obtain the commit using the 'oid' available and discard all
918
+ * non-commits early. The actual filtering is done later.
919
+ */
920
+ if (filter -> merge_commit ) {
921
+ commit = lookup_commit_reference_gently (oid -> hash , 1 );
922
+ if (!commit )
923
+ return 0 ;
924
+ }
925
+
913
926
/*
914
927
* We do not open the object yet; sort may only need refname
915
928
* to do its job and the resulting list may yet to be pruned
916
929
* by maxcount logic.
917
930
*/
918
931
ref = new_ref_array_item (refname , oid -> hash , flag );
932
+ ref -> commit = commit ;
919
933
920
934
REALLOC_ARRAY (ref_cbdata -> array -> items , ref_cbdata -> array -> nr + 1 );
921
935
ref_cbdata -> array -> items [ref_cbdata -> array -> nr ++ ] = ref ;
@@ -941,6 +955,50 @@ void ref_array_clear(struct ref_array *array)
941
955
array -> nr = array -> alloc = 0 ;
942
956
}
943
957
958
+ static void do_merge_filter (struct ref_filter_cbdata * ref_cbdata )
959
+ {
960
+ struct rev_info revs ;
961
+ int i , old_nr ;
962
+ struct ref_filter * filter = ref_cbdata -> filter ;
963
+ struct ref_array * array = ref_cbdata -> array ;
964
+ struct commit * * to_clear = xcalloc (sizeof (struct commit * ), array -> nr );
965
+
966
+ init_revisions (& revs , NULL );
967
+
968
+ for (i = 0 ; i < array -> nr ; i ++ ) {
969
+ struct ref_array_item * item = array -> items [i ];
970
+ add_pending_object (& revs , & item -> commit -> object , item -> refname );
971
+ to_clear [i ] = item -> commit ;
972
+ }
973
+
974
+ filter -> merge_commit -> object .flags |= UNINTERESTING ;
975
+ add_pending_object (& revs , & filter -> merge_commit -> object , "" );
976
+
977
+ revs .limited = 1 ;
978
+ if (prepare_revision_walk (& revs ))
979
+ die (_ ("revision walk setup failed" ));
980
+
981
+ old_nr = array -> nr ;
982
+ array -> nr = 0 ;
983
+
984
+ for (i = 0 ; i < old_nr ; i ++ ) {
985
+ struct ref_array_item * item = array -> items [i ];
986
+ struct commit * commit = item -> commit ;
987
+
988
+ int is_merged = !!(commit -> object .flags & UNINTERESTING );
989
+
990
+ if (is_merged == (filter -> merge == REF_FILTER_MERGED_INCLUDE ))
991
+ array -> items [array -> nr ++ ] = array -> items [i ];
992
+ else
993
+ free_array_item (item );
994
+ }
995
+
996
+ for (i = 0 ; i < old_nr ; i ++ )
997
+ clear_commit_marks (to_clear [i ], ALL_REV_FLAGS );
998
+ clear_commit_marks (filter -> merge_commit , ALL_REV_FLAGS );
999
+ free (to_clear );
1000
+ }
1001
+
944
1002
/*
945
1003
* API for filtering a set of refs. Based on the type of refs the user
946
1004
* has requested, we iterate through those refs and apply filters
@@ -950,17 +1008,24 @@ void ref_array_clear(struct ref_array *array)
950
1008
int filter_refs (struct ref_array * array , struct ref_filter * filter , unsigned int type )
951
1009
{
952
1010
struct ref_filter_cbdata ref_cbdata ;
1011
+ int ret = 0 ;
953
1012
954
1013
ref_cbdata .array = array ;
955
1014
ref_cbdata .filter = filter ;
956
1015
1016
+ /* Simple per-ref filtering */
957
1017
if (type & (FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN ))
958
- return for_each_rawref (ref_filter_handler , & ref_cbdata );
1018
+ ret = for_each_rawref (ref_filter_handler , & ref_cbdata );
959
1019
else if (type & FILTER_REFS_ALL )
960
- return for_each_ref (ref_filter_handler , & ref_cbdata );
961
- else
1020
+ ret = for_each_ref (ref_filter_handler , & ref_cbdata );
1021
+ else if ( type )
962
1022
die ("filter_refs: invalid type" );
963
- return 0 ;
1023
+
1024
+ /* Filters that need revision walking */
1025
+ if (filter -> merge_commit )
1026
+ do_merge_filter (& ref_cbdata );
1027
+
1028
+ return ret ;
964
1029
}
965
1030
966
1031
static int cmp_ref_sorting (struct ref_sorting * s , struct ref_array_item * a , struct ref_array_item * b )
0 commit comments