6 #include "string-list.h"
7 #include "reflog-walk.h"
9 struct complete_reflogs
{
11 const char *short_ref
;
13 unsigned char osha1
[20], nsha1
[20];
15 unsigned long timestamp
;
22 static int read_one_reflog(unsigned char *osha1
, unsigned char *nsha1
,
23 const char *email
, unsigned long timestamp
, int tz
,
24 const char *message
, void *cb_data
)
26 struct complete_reflogs
*array
= cb_data
;
27 struct reflog_info
*item
;
29 if (array
->nr
>= array
->alloc
) {
30 array
->alloc
= alloc_nr(array
->nr
+ 1);
31 array
->items
= xrealloc(array
->items
, array
->alloc
*
32 sizeof(struct reflog_info
));
34 item
= array
->items
+ array
->nr
;
35 memcpy(item
->osha1
, osha1
, 20);
36 memcpy(item
->nsha1
, nsha1
, 20);
37 item
->email
= xstrdup(email
);
38 item
->timestamp
= timestamp
;
40 item
->message
= xstrdup(message
);
45 static struct complete_reflogs
*read_complete_reflog(const char *ref
)
47 struct complete_reflogs
*reflogs
=
48 xcalloc(sizeof(struct complete_reflogs
), 1);
49 reflogs
->ref
= xstrdup(ref
);
50 for_each_reflog_ent(ref
, read_one_reflog
, reflogs
);
51 if (reflogs
->nr
== 0) {
52 unsigned char sha1
[20];
53 const char *name
= resolve_ref(ref
, sha1
, 1, NULL
);
55 for_each_reflog_ent(name
, read_one_reflog
, reflogs
);
57 if (reflogs
->nr
== 0) {
58 int len
= strlen(ref
);
59 char *refname
= xmalloc(len
+ 12);
60 sprintf(refname
, "refs/%s", ref
);
61 for_each_reflog_ent(refname
, read_one_reflog
, reflogs
);
62 if (reflogs
->nr
== 0) {
63 sprintf(refname
, "refs/heads/%s", ref
);
64 for_each_reflog_ent(refname
, read_one_reflog
, reflogs
);
71 static int get_reflog_recno_by_time(struct complete_reflogs
*array
,
72 unsigned long timestamp
)
75 for (i
= array
->nr
- 1; i
>= 0; i
--)
76 if (timestamp
>= array
->items
[i
].timestamp
)
81 struct commit_info_lifo
{
83 struct commit
*commit
;
89 static struct commit_info
*get_commit_info(struct commit
*commit
,
90 struct commit_info_lifo
*lifo
, int pop
)
93 for (i
= 0; i
< lifo
->nr
; i
++)
94 if (lifo
->items
[i
].commit
== commit
) {
95 struct commit_info
*result
= &lifo
->items
[i
];
98 memmove(lifo
->items
+ i
,
101 sizeof(struct commit_info
));
109 static void add_commit_info(struct commit
*commit
, void *util
,
110 struct commit_info_lifo
*lifo
)
112 struct commit_info
*info
;
113 if (lifo
->nr
>= lifo
->alloc
) {
114 lifo
->alloc
= alloc_nr(lifo
->nr
+ 1);
115 lifo
->items
= xrealloc(lifo
->items
,
116 lifo
->alloc
* sizeof(struct commit_info
));
118 info
= lifo
->items
+ lifo
->nr
;
119 info
->commit
= commit
;
124 struct commit_reflog
{
126 struct complete_reflogs
*reflogs
;
129 struct reflog_walk_info
{
130 struct commit_info_lifo reflogs
;
131 struct string_list complete_reflogs
;
132 struct commit_reflog
*last_commit_reflog
;
135 void init_reflog_walk(struct reflog_walk_info
** info
)
137 *info
= xcalloc(sizeof(struct reflog_walk_info
), 1);
140 int add_reflog_for_walk(struct reflog_walk_info
*info
,
141 struct commit
*commit
, const char *name
)
143 unsigned long timestamp
= 0;
145 struct string_list_item
*item
;
146 struct complete_reflogs
*reflogs
;
147 char *branch
, *at
= strchr(name
, '@');
148 struct commit_reflog
*commit_reflog
;
150 if (commit
->object
.flags
& UNINTERESTING
)
151 die ("Cannot walk reflogs for %s", name
);
153 branch
= xstrdup(name
);
154 if (at
&& at
[1] == '{') {
156 branch
[at
- name
] = '\0';
157 recno
= strtoul(at
+ 2, &ep
, 10);
160 timestamp
= approxidate(at
+ 2);
165 item
= string_list_lookup(&info
->complete_reflogs
, branch
);
167 reflogs
= item
->util
;
169 if (*branch
== '\0') {
170 unsigned char sha1
[20];
171 const char *head
= resolve_ref("HEAD", sha1
, 0, NULL
);
173 die ("No current branch");
175 branch
= xstrdup(head
);
177 reflogs
= read_complete_reflog(branch
);
178 if (!reflogs
|| reflogs
->nr
== 0) {
179 unsigned char sha1
[20];
181 if (dwim_log(branch
, strlen(branch
), sha1
, &b
) == 1) {
188 reflogs
= read_complete_reflog(branch
);
191 if (!reflogs
|| reflogs
->nr
== 0)
193 string_list_insert(&info
->complete_reflogs
, branch
)->util
197 commit_reflog
= xcalloc(sizeof(struct commit_reflog
), 1);
199 commit_reflog
->flag
= 1;
200 commit_reflog
->recno
= get_reflog_recno_by_time(reflogs
, timestamp
);
201 if (commit_reflog
->recno
< 0) {
207 commit_reflog
->recno
= reflogs
->nr
- recno
- 1;
208 commit_reflog
->reflogs
= reflogs
;
210 add_commit_info(commit
, commit_reflog
, &info
->reflogs
);
214 void fake_reflog_parent(struct reflog_walk_info
*info
, struct commit
*commit
)
216 struct commit_info
*commit_info
=
217 get_commit_info(commit
, &info
->reflogs
, 0);
218 struct commit_reflog
*commit_reflog
;
219 struct reflog_info
*reflog
;
221 info
->last_commit_reflog
= NULL
;
225 commit_reflog
= commit_info
->util
;
226 if (commit_reflog
->recno
< 0) {
227 commit
->parents
= NULL
;
231 reflog
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
];
232 info
->last_commit_reflog
= commit_reflog
;
233 commit_reflog
->recno
--;
234 commit_info
->commit
= (struct commit
*)parse_object(reflog
->osha1
);
235 if (!commit_info
->commit
) {
236 commit
->parents
= NULL
;
240 commit
->parents
= xcalloc(sizeof(struct commit_list
), 1);
241 commit
->parents
->item
= commit_info
->commit
;
242 commit
->object
.flags
&= ~(ADDED
| SEEN
| SHOWN
);
245 void get_reflog_selector(struct strbuf
*sb
,
246 struct reflog_walk_info
*reflog_info
,
247 enum date_mode dmode
,
250 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
251 struct reflog_info
*info
;
252 const char *printed_ref
;
258 if (!commit_reflog
->reflogs
->short_ref
)
259 commit_reflog
->reflogs
->short_ref
260 = shorten_unambiguous_ref(commit_reflog
->reflogs
->ref
, 0);
261 printed_ref
= commit_reflog
->reflogs
->short_ref
;
263 printed_ref
= commit_reflog
->reflogs
->ref
;
266 strbuf_addf(sb
, "%s@{", printed_ref
);
267 if (commit_reflog
->flag
|| dmode
) {
268 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
269 strbuf_addstr(sb
, show_date(info
->timestamp
, info
->tz
, dmode
));
271 strbuf_addf(sb
, "%d", commit_reflog
->reflogs
->nr
272 - 2 - commit_reflog
->recno
);
275 strbuf_addch(sb
, '}');
278 void get_reflog_message(struct strbuf
*sb
,
279 struct reflog_walk_info
*reflog_info
)
281 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
282 struct reflog_info
*info
;
288 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
289 len
= strlen(info
->message
);
291 len
--; /* strip away trailing newline */
292 strbuf_add(sb
, info
->message
, len
);
295 void show_reflog_message(struct reflog_walk_info
*reflog_info
, int oneline
,
296 enum date_mode dmode
)
298 if (reflog_info
&& reflog_info
->last_commit_reflog
) {
299 struct commit_reflog
*commit_reflog
= reflog_info
->last_commit_reflog
;
300 struct reflog_info
*info
;
301 struct strbuf selector
= STRBUF_INIT
;
303 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
304 get_reflog_selector(&selector
, reflog_info
, dmode
, 0);
306 printf("%s: %s", selector
.buf
, info
->message
);
309 printf("Reflog: %s (%s)\nReflog message: %s",
310 selector
.buf
, info
->email
, info
->message
);
313 strbuf_release(&selector
);