1515#include "string-list.h"
1616#include "line-log.h"
1717#include "mailmap.h"
18+ #include "commit-slab.h"
1819
1920volatile show_early_output_fn_t show_early_output ;
2021
@@ -2763,7 +2764,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
27632764 return retval ;
27642765}
27652766
2766- static inline int want_ancestry (struct rev_info * revs )
2767+ static inline int want_ancestry (const struct rev_info * revs )
27672768{
27682769 return (revs -> rewrite_parents || revs -> children .name );
27692770}
@@ -2820,6 +2821,14 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
28202821 if (action == commit_show &&
28212822 !revs -> show_all &&
28222823 revs -> prune && revs -> dense && want_ancestry (revs )) {
2824+ /*
2825+ * --full-diff on simplified parents is no good: it
2826+ * will show spurious changes from the commits that
2827+ * were elided. So we save the parents on the side
2828+ * when --full-diff is in effect.
2829+ */
2830+ if (revs -> full_diff )
2831+ save_parents (revs , commit );
28232832 if (rewrite_parents (revs , commit , rewrite_one ) < 0 )
28242833 return commit_error ;
28252834 }
@@ -2839,6 +2848,7 @@ static struct commit *get_revision_1(struct rev_info *revs)
28392848 free (entry );
28402849
28412850 if (revs -> reflog_info ) {
2851+ save_parents (revs , commit );
28422852 fake_reflog_parent (revs -> reflog_info , commit );
28432853 commit -> object .flags &= ~(ADDED | SEEN | SHOWN );
28442854 }
@@ -3038,6 +3048,8 @@ struct commit *get_revision(struct rev_info *revs)
30383048 c = get_revision_internal (revs );
30393049 if (c && revs -> graph )
30403050 graph_update (revs -> graph , c );
3051+ if (!c )
3052+ free_saved_parents (revs );
30413053 return c ;
30423054}
30433055
@@ -3069,3 +3081,54 @@ void put_revision_mark(const struct rev_info *revs, const struct commit *commit)
30693081 fputs (mark , stdout );
30703082 putchar (' ' );
30713083}
3084+
3085+ define_commit_slab (saved_parents , struct commit_list * );
3086+
3087+ #define EMPTY_PARENT_LIST ((struct commit_list *)-1)
3088+
3089+ void save_parents (struct rev_info * revs , struct commit * commit )
3090+ {
3091+ struct commit_list * * pp ;
3092+
3093+ if (!revs -> saved_parents_slab ) {
3094+ revs -> saved_parents_slab = xmalloc (sizeof (struct saved_parents ));
3095+ init_saved_parents (revs -> saved_parents_slab );
3096+ }
3097+
3098+ pp = saved_parents_at (revs -> saved_parents_slab , commit );
3099+
3100+ /*
3101+ * When walking with reflogs, we may visit the same commit
3102+ * several times: once for each appearance in the reflog.
3103+ *
3104+ * In this case, save_parents() will be called multiple times.
3105+ * We want to keep only the first set of parents. We need to
3106+ * store a sentinel value for an empty (i.e., NULL) parent
3107+ * list to distinguish it from a not-yet-saved list, however.
3108+ */
3109+ if (* pp )
3110+ return ;
3111+ if (commit -> parents )
3112+ * pp = copy_commit_list (commit -> parents );
3113+ else
3114+ * pp = EMPTY_PARENT_LIST ;
3115+ }
3116+
3117+ struct commit_list * get_saved_parents (struct rev_info * revs , const struct commit * commit )
3118+ {
3119+ struct commit_list * parents ;
3120+
3121+ if (!revs -> saved_parents_slab )
3122+ return commit -> parents ;
3123+
3124+ parents = * saved_parents_at (revs -> saved_parents_slab , commit );
3125+ if (parents == EMPTY_PARENT_LIST )
3126+ return NULL ;
3127+ return parents ;
3128+ }
3129+
3130+ void free_saved_parents (struct rev_info * revs )
3131+ {
3132+ if (revs -> saved_parents_slab )
3133+ clear_saved_parents (revs -> saved_parents_slab );
3134+ }
0 commit comments