~ubuntu-branches/ubuntu/intrepid/git-core/intrepid-updates

« back to all changes in this revision

Viewing changes to reflog-walk.c

  • Committer: Package Import Robot
  • Author(s): Gerrit Pape
  • Date: 2007-04-22 13:31:05 UTC
  • mto: This revision was merged to the branch mainline in revision 20.
  • Revision ID: package-import@ubuntu.com-20070422133105-xg8fnm18r2cxcbg1
Tags: upstream-1.5.1.2
ImportĀ upstreamĀ versionĀ 1.5.1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "cache.h"
 
2
#include "commit.h"
 
3
#include "refs.h"
 
4
#include "diff.h"
 
5
#include "revision.h"
 
6
#include "path-list.h"
 
7
#include "reflog-walk.h"
 
8
 
 
9
struct complete_reflogs {
 
10
        char *ref;
 
11
        struct reflog_info {
 
12
                unsigned char osha1[20], nsha1[20];
 
13
                char *email;
 
14
                unsigned long timestamp;
 
15
                int tz;
 
16
                char *message;
 
17
        } *items;
 
18
        int nr, alloc;
 
19
};
 
20
 
 
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)
 
24
{
 
25
        struct complete_reflogs *array = cb_data;
 
26
        struct reflog_info *item;
 
27
 
 
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));
 
32
        }
 
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;
 
38
        item->tz = tz;
 
39
        item->message = xstrdup(message);
 
40
        array->nr++;
 
41
        return 0;
 
42
}
 
43
 
 
44
static struct complete_reflogs *read_complete_reflog(const char *ref)
 
45
{
 
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);
 
53
                if (name)
 
54
                        for_each_reflog_ent(name, read_one_reflog, reflogs);
 
55
        }
 
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);
 
64
                }
 
65
                free(refname);
 
66
        }
 
67
        return reflogs;
 
68
}
 
69
 
 
70
static int get_reflog_recno_by_time(struct complete_reflogs *array,
 
71
        unsigned long timestamp)
 
72
{
 
73
        int i;
 
74
        for (i = array->nr - 1; i >= 0; i--)
 
75
                if (timestamp >= array->items[i].timestamp)
 
76
                        return i;
 
77
        return -1;
 
78
}
 
79
 
 
80
struct commit_info_lifo {
 
81
        struct commit_info {
 
82
                struct commit *commit;
 
83
                void *util;
 
84
        } *items;
 
85
        int nr, alloc;
 
86
};
 
87
 
 
88
static struct commit_info *get_commit_info(struct commit *commit,
 
89
                struct commit_info_lifo *lifo, int pop)
 
90
{
 
91
        int i;
 
92
        for (i = 0; i < lifo->nr; i++)
 
93
                if (lifo->items[i].commit == commit) {
 
94
                        struct commit_info *result = &lifo->items[i];
 
95
                        if (pop) {
 
96
                                if (i + 1 < lifo->nr)
 
97
                                        memmove(lifo->items + i,
 
98
                                                lifo->items + i + 1,
 
99
                                                (lifo->nr - i) *
 
100
                                                sizeof(struct commit_info));
 
101
                                lifo->nr--;
 
102
                        }
 
103
                        return result;
 
104
                }
 
105
        return NULL;
 
106
}
 
107
 
 
108
static void add_commit_info(struct commit *commit, void *util,
 
109
                struct commit_info_lifo *lifo)
 
110
{
 
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));
 
116
        }
 
117
        info = lifo->items + lifo->nr;
 
118
        info->commit = commit;
 
119
        info->util = util;
 
120
        lifo->nr++;
 
121
}
 
122
 
 
123
struct commit_reflog {
 
124
        int flag, recno;
 
125
        struct complete_reflogs *reflogs;
 
126
};
 
127
 
 
128
struct reflog_walk_info {
 
129
        struct commit_info_lifo reflogs;
 
130
        struct path_list complete_reflogs;
 
131
        struct commit_reflog *last_commit_reflog;
 
132
};
 
133
 
 
134
void init_reflog_walk(struct reflog_walk_info** info)
 
135
{
 
136
        *info = xcalloc(sizeof(struct reflog_walk_info), 1);
 
137
}
 
138
 
 
139
void add_reflog_for_walk(struct reflog_walk_info *info,
 
140
                struct commit *commit, const char *name)
 
141
{
 
142
        unsigned long timestamp = 0;
 
143
        int recno = -1;
 
144
        struct path_list_item *item;
 
145
        struct complete_reflogs *reflogs;
 
146
        char *branch, *at = strchr(name, '@');
 
147
        struct commit_reflog *commit_reflog;
 
148
 
 
149
        if (commit->object.flags & UNINTERESTING)
 
150
                die ("Cannot walk reflogs for %s", name);
 
151
 
 
152
        branch = xstrdup(name);
 
153
        if (at && at[1] == '{') {
 
154
                char *ep;
 
155
                branch[at - name] = '\0';
 
156
                recno = strtoul(at + 2, &ep, 10);
 
157
                if (*ep != '}') {
 
158
                        recno = -1;
 
159
                        timestamp = approxidate(at + 2);
 
160
                }
 
161
        } else
 
162
                recno = 0;
 
163
 
 
164
        item = path_list_lookup(branch, &info->complete_reflogs);
 
165
        if (item)
 
166
                reflogs = item->util;
 
167
        else {
 
168
                if (*branch == '\0') {
 
169
                        unsigned char sha1[20];
 
170
                        const char *head = resolve_ref("HEAD", sha1, 0, NULL);
 
171
                        if (!head)
 
172
                                die ("No current branch");
 
173
                        free(branch);
 
174
                        branch = xstrdup(head);
 
175
                }
 
176
                reflogs = read_complete_reflog(branch);
 
177
                if (!reflogs || reflogs->nr == 0) {
 
178
                        unsigned char sha1[20];
 
179
                        char *b;
 
180
                        if (dwim_log(branch, strlen(branch), sha1, &b) == 1) {
 
181
                                if (reflogs) {
 
182
                                        free(reflogs->ref);
 
183
                                        free(reflogs);
 
184
                                }
 
185
                                free(branch);
 
186
                                branch = b;
 
187
                                reflogs = read_complete_reflog(branch);
 
188
                        }
 
189
                }
 
190
                if (!reflogs || reflogs->nr == 0)
 
191
                        die("No reflogs found for '%s'", branch);
 
192
                path_list_insert(branch, &info->complete_reflogs)->util
 
193
                        = reflogs;
 
194
        }
 
195
 
 
196
        commit_reflog = xcalloc(sizeof(struct commit_reflog), 1);
 
197
        if (recno < 0) {
 
198
                commit_reflog->flag = 1;
 
199
                commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp);
 
200
                if (commit_reflog->recno < 0) {
 
201
                        free(branch);
 
202
                        free(commit_reflog);
 
203
                        return;
 
204
                }
 
205
        } else
 
206
                commit_reflog->recno = reflogs->nr - recno - 1;
 
207
        commit_reflog->reflogs = reflogs;
 
208
 
 
209
        add_commit_info(commit, commit_reflog, &info->reflogs);
 
210
}
 
211
 
 
212
void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
 
213
{
 
214
        struct commit_info *commit_info =
 
215
                get_commit_info(commit, &info->reflogs, 0);
 
216
        struct commit_reflog *commit_reflog;
 
217
        struct reflog_info *reflog;
 
218
 
 
219
        info->last_commit_reflog = NULL;
 
220
        if (!commit_info)
 
221
                return;
 
222
 
 
223
        commit_reflog = commit_info->util;
 
224
        if (commit_reflog->recno < 0) {
 
225
                commit->parents = NULL;
 
226
                return;
 
227
        }
 
228
 
 
229
        reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
 
230
        info->last_commit_reflog = commit_reflog;
 
231
        commit_reflog->recno--;
 
232
        commit_info->commit = (struct commit *)parse_object(reflog->osha1);
 
233
        if (!commit_info->commit) {
 
234
                commit->parents = NULL;
 
235
                return;
 
236
        }
 
237
 
 
238
        commit->parents = xcalloc(sizeof(struct commit_list), 1);
 
239
        commit->parents->item = commit_info->commit;
 
240
        commit->object.flags &= ~(ADDED | SEEN | SHOWN);
 
241
}
 
242
 
 
243
void show_reflog_message(struct reflog_walk_info* info, int oneline,
 
244
        int relative_date)
 
245
{
 
246
        if (info && info->last_commit_reflog) {
 
247
                struct commit_reflog *commit_reflog = info->last_commit_reflog;
 
248
                struct reflog_info *info;
 
249
 
 
250
                info = &commit_reflog->reflogs->items[commit_reflog->recno+1];
 
251
                if (oneline) {
 
252
                        printf("%s@{", commit_reflog->reflogs->ref);
 
253
                        if (commit_reflog->flag || relative_date)
 
254
                                printf("%s", show_date(info->timestamp, 0, 1));
 
255
                        else
 
256
                                printf("%d", commit_reflog->reflogs->nr
 
257
                                       - 2 - commit_reflog->recno);
 
258
                        printf("}: %s", info->message);
 
259
                }
 
260
                else {
 
261
                        printf("Reflog: %s@{", commit_reflog->reflogs->ref);
 
262
                        if (commit_reflog->flag || relative_date)
 
263
                                printf("%s", show_date(info->timestamp,
 
264
                                                        info->tz,
 
265
                                                        relative_date));
 
266
                        else
 
267
                                printf("%d", commit_reflog->reflogs->nr
 
268
                                       - 2 - commit_reflog->recno);
 
269
                        printf("} (%s)\nReflog message: %s",
 
270
                               info->email, info->message);
 
271
                }
 
272
        }
 
273
}