6 #include "string-list.h"
7 #include "reflog-walk.h"
9 struct complete_reflogs
{
11 const char *short_ref
;
13 struct object_id ooid
, noid
;
15 timestamp_t timestamp
;
22 static int read_one_reflog(struct object_id
*ooid
, struct object_id
*noid
,
23 const char *email
, timestamp_t timestamp
, int tz
,
24 const char *message
, void *cb_data
)
26 struct complete_reflogs
*array
= cb_data
;
27 struct reflog_info
*item
;
29 ALLOC_GROW(array
->items
, array
->nr
+ 1, array
->alloc
);
30 item
= array
->items
+ array
->nr
;
31 oidcpy(&item
->ooid
, ooid
);
32 oidcpy(&item
->noid
, noid
);
33 item
->email
= xstrdup(email
);
34 item
->timestamp
= timestamp
;
36 item
->message
= xstrdup(message
);
41 static void free_complete_reflog(struct complete_reflogs
*array
)
48 for (i
= 0; i
< array
->nr
; i
++) {
49 free(array
->items
[i
].email
);
50 free(array
->items
[i
].message
);
57 static struct complete_reflogs
*read_complete_reflog(const char *ref
)
59 struct complete_reflogs
*reflogs
=
60 xcalloc(1, sizeof(struct complete_reflogs
));
61 reflogs
->ref
= xstrdup(ref
);
62 for_each_reflog_ent(ref
, read_one_reflog
, reflogs
);
63 if (reflogs
->nr
== 0) {
66 name
= name_to_free
= resolve_refdup(ref
, RESOLVE_REF_READING
,
69 for_each_reflog_ent(name
, read_one_reflog
, reflogs
);
73 if (reflogs
->nr
== 0) {
74 char *refname
= xstrfmt("refs/%s", ref
);
75 for_each_reflog_ent(refname
, read_one_reflog
, reflogs
);
76 if (reflogs
->nr
== 0) {
78 refname
= xstrfmt("refs/heads/%s", ref
);
79 for_each_reflog_ent(refname
, read_one_reflog
, reflogs
);
86 static int get_reflog_recno_by_time(struct complete_reflogs
*array
,
87 timestamp_t timestamp
)
90 for (i
= array
->nr
- 1; i
>= 0; i
--)
91 if (timestamp
>= array
->items
[i
].timestamp
)
96 struct commit_reflog
{
103 struct complete_reflogs
*reflogs
;
106 struct reflog_walk_info
{
107 struct commit_reflog
**logs
;
109 struct string_list complete_reflogs
;
110 struct commit_reflog
*last_commit_reflog
;
113 void init_reflog_walk(struct reflog_walk_info
**info
)
115 *info
= xcalloc(1, sizeof(struct reflog_walk_info
));
116 (*info
)->complete_reflogs
.strdup_strings
= 1;
119 int add_reflog_for_walk(struct reflog_walk_info
*info
,
120 struct commit
*commit
, const char *name
)
122 timestamp_t timestamp
= 0;
124 struct string_list_item
*item
;
125 struct complete_reflogs
*reflogs
;
126 char *branch
, *at
= strchr(name
, '@');
127 struct commit_reflog
*commit_reflog
;
128 enum selector_type selector
= SELECTOR_NONE
;
130 if (commit
->object
.flags
& UNINTERESTING
)
131 die ("Cannot walk reflogs for %s", name
);
133 branch
= xstrdup(name
);
134 if (at
&& at
[1] == '{') {
136 branch
[at
- name
] = '\0';
137 recno
= strtoul(at
+ 2, &ep
, 10);
140 timestamp
= approxidate(at
+ 2);
141 selector
= SELECTOR_DATE
;
144 selector
= SELECTOR_INDEX
;
148 item
= string_list_lookup(&info
->complete_reflogs
, branch
);
150 reflogs
= item
->util
;
152 if (*branch
== '\0') {
154 branch
= resolve_refdup("HEAD", 0, NULL
, NULL
);
156 die ("No current branch");
159 reflogs
= read_complete_reflog(branch
);
160 if (!reflogs
|| reflogs
->nr
== 0) {
161 struct object_id oid
;
163 int ret
= dwim_log(branch
, strlen(branch
),
168 free_complete_reflog(reflogs
);
171 reflogs
= read_complete_reflog(branch
);
174 if (!reflogs
|| reflogs
->nr
== 0) {
175 free_complete_reflog(reflogs
);
179 string_list_insert(&info
->complete_reflogs
, branch
)->util
184 commit_reflog
= xcalloc(1, sizeof(struct commit_reflog
));
186 commit_reflog
->recno
= get_reflog_recno_by_time(reflogs
, timestamp
);
187 if (commit_reflog
->recno
< 0) {
192 commit_reflog
->recno
= reflogs
->nr
- recno
- 1;
193 commit_reflog
->selector
= selector
;
194 commit_reflog
->reflogs
= reflogs
;
196 ALLOC_GROW(info
->logs
, info
->nr
+ 1, info
->alloc
);
197 info
->logs
[info
->nr
++] = commit_reflog
;
202 void get_reflog_selector(struct strbuf
*sb
,
203 struct reflog_walk_info
*reflog_info
,
204 const struct date_mode
*dmode
, int force_date
,
207 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
208 struct reflog_info
*info
;
209 const char *printed_ref
;
215 if (!commit_reflog
->reflogs
->short_ref
)
216 commit_reflog
->reflogs
->short_ref
217 = shorten_unambiguous_ref(commit_reflog
->reflogs
->ref
, 0);
218 printed_ref
= commit_reflog
->reflogs
->short_ref
;
220 printed_ref
= commit_reflog
->reflogs
->ref
;
223 strbuf_addf(sb
, "%s@{", printed_ref
);
224 if (commit_reflog
->selector
== SELECTOR_DATE
||
225 (commit_reflog
->selector
== SELECTOR_NONE
&& force_date
)) {
226 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
227 strbuf_addstr(sb
, show_date(info
->timestamp
, info
->tz
, dmode
));
229 strbuf_addf(sb
, "%d", commit_reflog
->reflogs
->nr
230 - 2 - commit_reflog
->recno
);
233 strbuf_addch(sb
, '}');
236 void get_reflog_message(struct strbuf
*sb
,
237 struct reflog_walk_info
*reflog_info
)
239 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
240 struct reflog_info
*info
;
246 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
247 len
= strlen(info
->message
);
249 len
--; /* strip away trailing newline */
250 strbuf_add(sb
, info
->message
, len
);
253 const char *get_reflog_ident(struct reflog_walk_info
*reflog_info
)
255 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
256 struct reflog_info
*info
;
261 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
265 timestamp_t
get_reflog_timestamp(struct reflog_walk_info
*reflog_info
)
267 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
268 struct reflog_info
*info
;
273 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
274 return info
->timestamp
;
277 void show_reflog_message(struct reflog_walk_info
*reflog_info
, int oneline
,
278 const struct date_mode
*dmode
, int force_date
)
280 if (reflog_info
&& reflog_info
->last_commit_reflog
) {
281 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
282 struct reflog_info
*info
;
283 struct strbuf selector
= STRBUF_INIT
;
285 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
286 get_reflog_selector(&selector
, reflog_info
, dmode
, force_date
, 0);
288 printf("%s: %s", selector
.buf
, info
->message
);
291 printf("Reflog: %s (%s)\nReflog message: %s",
292 selector
.buf
, info
->email
, info
->message
);
295 strbuf_release(&selector
);
299 int reflog_walk_empty(struct reflog_walk_info
*info
)
301 return !info
|| !info
->nr
;
304 static struct commit
*next_reflog_commit(struct commit_reflog
*log
)
306 for (; log
->recno
>= 0; log
->recno
--) {
307 struct reflog_info
*entry
= &log
->reflogs
->items
[log
->recno
];
308 struct object
*obj
= parse_object(&entry
->noid
);
310 if (obj
&& obj
->type
== OBJ_COMMIT
)
311 return (struct commit
*)obj
;
316 static timestamp_t
log_timestamp(struct commit_reflog
*log
)
318 return log
->reflogs
->items
[log
->recno
].timestamp
;
321 struct commit
*next_reflog_entry(struct reflog_walk_info
*walk
)
323 struct commit_reflog
*best
= NULL
;
324 struct commit
*best_commit
= NULL
;
327 for (i
= 0; i
< walk
->nr
; i
++) {
328 struct commit_reflog
*log
= walk
->logs
[i
];
329 struct commit
*commit
= next_reflog_commit(log
);
334 if (!best
|| log_timestamp(log
) > log_timestamp(best
)) {
336 best_commit
= commit
;
342 walk
->last_commit_reflog
= best
;