7 #include "reflog-walk.h"
9 struct complete_reflogs
{
12 unsigned char osha1
[20], nsha1
[20];
14 unsigned long timestamp
;
21 static int read_one_reflog(unsigned char *osha1
, unsigned char *nsha1
,
22 const char *email
, unsigned long timestamp
, int tz
,
23 const char *message
, void *cb_data
)
25 struct complete_reflogs
*array
= cb_data
;
26 struct reflog_info
*item
;
28 if (array
->nr
>= array
->alloc
) {
29 array
->alloc
= alloc_nr(array
->nr
+ 1);
30 array
->items
= xrealloc(array
->items
, array
->alloc
*
31 sizeof(struct reflog_info
));
33 item
= array
->items
+ array
->nr
;
34 memcpy(item
->osha1
, osha1
, 20);
35 memcpy(item
->nsha1
, nsha1
, 20);
36 item
->email
= xstrdup(email
);
37 item
->timestamp
= timestamp
;
39 item
->message
= xstrdup(message
);
44 static struct complete_reflogs
*read_complete_reflog(const char *ref
)
46 struct complete_reflogs
*reflogs
=
47 xcalloc(sizeof(struct complete_reflogs
), 1);
48 reflogs
->ref
= xstrdup(ref
);
49 for_each_reflog_ent(ref
, read_one_reflog
, reflogs
);
50 if (reflogs
->nr
== 0) {
51 unsigned char sha1
[20];
52 const char *name
= resolve_ref(ref
, sha1
, 1, NULL
);
54 for_each_reflog_ent(name
, read_one_reflog
, reflogs
);
56 if (reflogs
->nr
== 0) {
57 int len
= strlen(ref
);
58 char *refname
= xmalloc(len
+ 12);
59 sprintf(refname
, "refs/%s", ref
);
60 for_each_reflog_ent(refname
, read_one_reflog
, reflogs
);
61 if (reflogs
->nr
== 0) {
62 sprintf(refname
, "refs/heads/%s", ref
);
63 for_each_reflog_ent(refname
, read_one_reflog
, reflogs
);
70 static int get_reflog_recno_by_time(struct complete_reflogs
*array
,
71 unsigned long timestamp
)
74 for (i
= array
->nr
- 1; i
>= 0; i
--)
75 if (timestamp
>= array
->items
[i
].timestamp
)
80 struct commit_info_lifo
{
82 struct commit
*commit
;
88 static struct commit_info
*get_commit_info(struct commit
*commit
,
89 struct commit_info_lifo
*lifo
, int pop
)
92 for (i
= 0; i
< lifo
->nr
; i
++)
93 if (lifo
->items
[i
].commit
== commit
) {
94 struct commit_info
*result
= &lifo
->items
[i
];
97 memmove(lifo
->items
+ i
,
100 sizeof(struct commit_info
));
108 static void add_commit_info(struct commit
*commit
, void *util
,
109 struct commit_info_lifo
*lifo
)
111 struct commit_info
*info
;
112 if (lifo
->nr
>= lifo
->alloc
) {
113 lifo
->alloc
= alloc_nr(lifo
->nr
+ 1);
114 lifo
->items
= xrealloc(lifo
->items
,
115 lifo
->alloc
* sizeof(struct commit_info
));
117 info
= lifo
->items
+ lifo
->nr
;
118 info
->commit
= commit
;
123 struct commit_reflog
{
125 struct complete_reflogs
*reflogs
;
128 struct reflog_walk_info
{
129 struct commit_info_lifo reflogs
;
130 struct path_list complete_reflogs
;
131 struct commit_reflog
*last_commit_reflog
;
134 void init_reflog_walk(struct reflog_walk_info
** info
)
136 *info
= xcalloc(sizeof(struct reflog_walk_info
), 1);
139 void add_reflog_for_walk(struct reflog_walk_info
*info
,
140 struct commit
*commit
, const char *name
)
142 unsigned long timestamp
= 0;
144 struct path_list_item
*item
;
145 struct complete_reflogs
*reflogs
;
146 char *branch
, *at
= strchr(name
, '@');
147 struct commit_reflog
*commit_reflog
;
149 if (commit
->object
.flags
& UNINTERESTING
)
150 die ("Cannot walk reflogs for %s", name
);
152 branch
= xstrdup(name
);
153 if (at
&& at
[1] == '{') {
155 branch
[at
- name
] = '\0';
156 recno
= strtoul(at
+ 2, &ep
, 10);
159 timestamp
= approxidate(at
+ 2);
164 item
= path_list_lookup(branch
, &info
->complete_reflogs
);
166 reflogs
= item
->util
;
168 if (*branch
== '\0') {
169 unsigned char sha1
[20];
170 const char *head
= resolve_ref("HEAD", sha1
, 0, NULL
);
172 die ("No current branch");
174 branch
= xstrdup(head
);
176 reflogs
= read_complete_reflog(branch
);
177 if (!reflogs
|| reflogs
->nr
== 0)
178 die("No reflogs found for '%s'", branch
);
179 path_list_insert(branch
, &info
->complete_reflogs
)->util
183 commit_reflog
= xcalloc(sizeof(struct commit_reflog
), 1);
185 commit_reflog
->flag
= 1;
186 commit_reflog
->recno
= get_reflog_recno_by_time(reflogs
, timestamp
);
187 if (commit_reflog
->recno
< 0) {
193 commit_reflog
->recno
= reflogs
->nr
- recno
- 1;
194 commit_reflog
->reflogs
= reflogs
;
196 add_commit_info(commit
, commit_reflog
, &info
->reflogs
);
199 void fake_reflog_parent(struct reflog_walk_info
*info
, struct commit
*commit
)
201 struct commit_info
*commit_info
=
202 get_commit_info(commit
, &info
->reflogs
, 0);
203 struct commit_reflog
*commit_reflog
;
204 struct reflog_info
*reflog
;
206 info
->last_commit_reflog
= NULL
;
210 commit_reflog
= commit_info
->util
;
211 if (commit_reflog
->recno
< 0) {
212 commit
->parents
= NULL
;
216 reflog
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
];
217 info
->last_commit_reflog
= commit_reflog
;
218 commit_reflog
->recno
--;
219 commit_info
->commit
= (struct commit
*)parse_object(reflog
->osha1
);
220 if (!commit_info
->commit
) {
221 commit
->parents
= NULL
;
225 commit
->parents
= xcalloc(sizeof(struct commit_list
), 1);
226 commit
->parents
->item
= commit_info
->commit
;
227 commit
->object
.flags
&= ~(ADDED
| SEEN
| SHOWN
);
230 void show_reflog_message(struct reflog_walk_info
* info
, int oneline
,
233 if (info
&& info
->last_commit_reflog
) {
234 struct commit_reflog
*commit_reflog
= info
->last_commit_reflog
;
235 struct reflog_info
*info
;
237 info
= &commit_reflog
->reflogs
->items
[commit_reflog
->recno
+1];
239 printf("%s@{", commit_reflog
->reflogs
->ref
);
240 if (commit_reflog
->flag
|| relative_date
)
241 printf("%s", show_date(info
->timestamp
, 0, 1));
243 printf("%d", commit_reflog
->reflogs
->nr
244 - 2 - commit_reflog
->recno
);
245 printf("}: %s", info
->message
);
248 printf("Reflog: %s@{", commit_reflog
->reflogs
->ref
);
249 if (commit_reflog
->flag
|| relative_date
)
250 printf("%s", show_date(info
->timestamp
,
254 printf("%d", commit_reflog
->reflogs
->nr
255 - 2 - commit_reflog
->recno
);
256 printf("} (%s)\nReflog message: %s",
257 info
->email
, info
->message
);