1 #define USE_THE_REPOSITORY_VARIABLE
3 #include "git-compat-util.h"
7 #include "repository.h"
9 #include "string-list.h"
10 #include "reflog-walk.h"
12 struct complete_reflogs
{
16 struct object_id ooid
, noid
;
18 timestamp_t timestamp
;
25 static int read_one_reflog(struct object_id
*ooid
, struct object_id
*noid
,
26 const char *email
, timestamp_t timestamp
, int tz
,
27 const char *message
, void *cb_data
)
29 struct complete_reflogs
*array
= cb_data
;
30 struct reflog_info
*item
;
32 ALLOC_GROW(array
->items
, array
->nr
+ 1, array
->alloc
);
33 item
= array
->items
+ array
->nr
;
34 oidcpy(&item
->ooid
, ooid
);
35 oidcpy(&item
->noid
, noid
);
36 item
->email
= xstrdup(email
);
37 item
->timestamp
= timestamp
;
39 item
->message
= xstrdup(message
);
44 static void free_complete_reflog(struct complete_reflogs
*array
)
51 for (i
= 0; i
< array
->nr
; i
++) {
52 free(array
->items
[i
].email
);
53 free(array
->items
[i
].message
);
57 free(array
->short_ref
);
61 static void complete_reflogs_clear(void *util
, const char *str UNUSED
)
63 struct complete_reflogs
*array
= util
;
64 free_complete_reflog(array
);
67 static struct complete_reflogs
*read_complete_reflog(const char *ref
)
69 struct complete_reflogs
*reflogs
=
70 xcalloc(1, sizeof(struct complete_reflogs
));
71 reflogs
->ref
= xstrdup(ref
);
72 refs_for_each_reflog_ent(get_main_ref_store(the_repository
), ref
,
73 read_one_reflog
, reflogs
);
74 if (reflogs
->nr
== 0) {
77 name
= name_to_free
= refs_resolve_refdup(get_main_ref_store(the_repository
),
82 refs_for_each_reflog_ent(get_main_ref_store(the_repository
),
83 name
, read_one_reflog
,
88 if (reflogs
->nr
== 0) {
89 char *refname
= xstrfmt("refs/%s", ref
);
90 refs_for_each_reflog_ent(get_main_ref_store(the_repository
),
91 refname
, read_one_reflog
, reflogs
);
92 if (reflogs
->nr
== 0) {
94 refname
= xstrfmt("refs/heads/%s", ref
);
95 refs_for_each_reflog_ent(get_main_ref_store(the_repository
),
96 refname
, read_one_reflog
,
104 static int get_reflog_recno_by_time(struct complete_reflogs
*array
,
105 timestamp_t timestamp
)
108 for (i
= array
->nr
- 1; i
>= 0; i
--)
109 if (timestamp
>= array
->items
[i
].timestamp
)
114 struct commit_reflog
{
121 struct complete_reflogs
*reflogs
;
124 struct reflog_walk_info
{
125 struct commit_reflog
**logs
;
127 struct string_list complete_reflogs
;
128 struct commit_reflog
*last_commit_reflog
;
131 void init_reflog_walk(struct reflog_walk_info
**info
)
133 CALLOC_ARRAY(*info
, 1);
134 (*info
)->complete_reflogs
.strdup_strings
= 1;
137 void reflog_walk_info_release(struct reflog_walk_info
*info
)
144 for (i
= 0; i
< info
->nr
; i
++)
146 string_list_clear_func(&info
->complete_reflogs
,
147 complete_reflogs_clear
);
152 int add_reflog_for_walk(struct reflog_walk_info
*info
,
153 struct commit
*commit
, const char *name
)
155 timestamp_t timestamp
= 0;
157 struct string_list_item
*item
;
158 struct complete_reflogs
*reflogs
;
159 char *branch
, *at
= strchr(name
, '@');
160 struct commit_reflog
*commit_reflog
;
161 enum selector_type selector
= SELECTOR_NONE
;
163 if (commit
->object
.flags
& UNINTERESTING
)
164 die("cannot walk reflogs for %s", name
);
166 branch
= xstrdup(name
);
167 if (at
&& at
[1] == '{') {
169 branch
[at
- name
] = '\0';
170 recno
= strtoul(at
+ 2, &ep
, 10);
173 timestamp
= approxidate(at
+ 2);
174 selector
= SELECTOR_DATE
;
177 selector
= SELECTOR_INDEX
;
181 item
= string_list_lookup(&info
->complete_reflogs
, branch
);
183 reflogs
= item
->util
;
185 if (*branch
== '\0') {
187 branch
= refs_resolve_refdup(get_main_ref_store(the_repository
),
188 "HEAD", 0, NULL
, NULL
);
190 die("no current branch");
193 reflogs
= read_complete_reflog(branch
);
194 if (!reflogs
|| reflogs
->nr
== 0) {
196 int ret
= repo_dwim_log(the_repository
, branch
, strlen(branch
),
201 free_complete_reflog(reflogs
);
204 reflogs
= read_complete_reflog(branch
);
207 if (!reflogs
|| reflogs
->nr
== 0) {
208 free_complete_reflog(reflogs
);
212 string_list_insert(&info
->complete_reflogs
, branch
)->util
217 CALLOC_ARRAY(commit_reflog
, 1);
219 commit_reflog
->recno
= get_reflog_recno_by_time(reflogs
, timestamp
);
220 if (commit_reflog
->recno
< 0) {
225 commit_reflog
->recno
= reflogs
->nr
- recno
- 1;
226 commit_reflog
->selector
= selector
;
227 commit_reflog
->reflogs
= reflogs
;
229 ALLOC_GROW(info
->logs
, info
->nr
+ 1, info
->alloc
);
230 info
->logs
[info
->nr
++] = commit_reflog
;
235 void get_reflog_selector(struct strbuf
*sb
,
236 struct reflog_walk_info
*reflog_info
,
237 struct date_mode dmode
, int force_date
,
240 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
241 struct reflog_info
*info
;
242 const char *printed_ref
;
248 if (!commit_reflog
->reflogs
->short_ref
)
249 commit_reflog
->reflogs
->short_ref
250 = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository
),
251 commit_reflog
->reflogs
->ref
,
253 printed_ref
= commit_reflog
->reflogs
->short_ref
;
255 printed_ref
= commit_reflog
->reflogs
->ref
;
258 strbuf_addf(sb
, "%s@{", printed_ref
);
259 if (commit_reflog
->selector
== SELECTOR_DATE
||
260 (commit_reflog
->selector
== SELECTOR_NONE
&& force_date
)) {
261 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
262 strbuf_addstr(sb
, show_date(info
->timestamp
, info
->tz
, dmode
));
264 strbuf_addf(sb
, "%d", commit_reflog
->reflogs
->nr
265 - 2 - commit_reflog
->recno
);
268 strbuf_addch(sb
, '}');
271 void get_reflog_message(struct strbuf
*sb
,
272 struct reflog_walk_info
*reflog_info
)
274 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
275 struct reflog_info
*info
;
281 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
282 len
= strlen(info
->message
);
284 len
--; /* strip away trailing newline */
285 strbuf_add(sb
, info
->message
, len
);
288 const char *get_reflog_ident(struct reflog_walk_info
*reflog_info
)
290 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
291 struct reflog_info
*info
;
296 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
300 timestamp_t
get_reflog_timestamp(struct reflog_walk_info
*reflog_info
)
302 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
303 struct reflog_info
*info
;
308 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
309 return info
->timestamp
;
312 void show_reflog_message(struct reflog_walk_info
*reflog_info
, int oneline
,
313 struct date_mode dmode
, int force_date
)
315 if (reflog_info
&& reflog_info
->last_commit_reflog
) {
316 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
317 struct reflog_info
*info
;
318 struct strbuf selector
= STRBUF_INIT
;
320 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
321 get_reflog_selector(&selector
, reflog_info
, dmode
, force_date
, 0);
323 printf("%s: %s", selector
.buf
, info
->message
);
326 printf("Reflog: %s (%s)\nReflog message: %s",
327 selector
.buf
, info
->email
, info
->message
);
330 strbuf_release(&selector
);
334 int reflog_walk_empty(struct reflog_walk_info
*info
)
336 return !info
|| !info
->nr
;
339 static struct commit
*next_reflog_commit(struct commit_reflog
*log
)
341 for (; log
->recno
>= 0; log
->recno
--) {
342 struct reflog_info
*entry
= &log
->reflogs
->items
[log
->recno
];
343 struct object
*obj
= parse_object(the_repository
,
346 if (obj
&& obj
->type
== OBJ_COMMIT
)
347 return (struct commit
*)obj
;
352 static timestamp_t
log_timestamp(struct commit_reflog
*log
)
354 return log
->reflogs
->items
[log
->recno
].timestamp
;
357 struct commit
*next_reflog_entry(struct reflog_walk_info
*walk
)
359 struct commit_reflog
*best
= NULL
;
360 struct commit
*best_commit
= NULL
;
363 for (i
= 0; i
< walk
->nr
; i
++) {
364 struct commit_reflog
*log
= walk
->logs
[i
];
365 struct commit
*commit
= next_reflog_commit(log
);
370 if (!best
|| log_timestamp(log
) > log_timestamp(best
)) {
372 best_commit
= commit
;
378 walk
->last_commit_reflog
= best
;