Merge branch 'rr/diffcore-pickaxe-doc' into maint
[git] / shallow.c
1 #include "cache.h"
2 #include "commit.h"
3 #include "tag.h"
4
5 static int is_shallow = -1;
6 static struct stat shallow_stat;
7 static char *alternate_shallow_file;
8
9 void set_alternate_shallow_file(const char *path)
10 {
11         if (is_shallow != -1)
12                 die("BUG: is_repository_shallow must not be called before set_alternate_shallow_file");
13         free(alternate_shallow_file);
14         alternate_shallow_file = path ? xstrdup(path) : NULL;
15 }
16
17 int register_shallow(const unsigned char *sha1)
18 {
19         struct commit_graft *graft =
20                 xmalloc(sizeof(struct commit_graft));
21         struct commit *commit = lookup_commit(sha1);
22
23         hashcpy(graft->sha1, sha1);
24         graft->nr_parent = -1;
25         if (commit && commit->object.parsed)
26                 commit->parents = NULL;
27         return register_commit_graft(graft, 0);
28 }
29
30 int is_repository_shallow(void)
31 {
32         FILE *fp;
33         char buf[1024];
34         const char *path = alternate_shallow_file;
35
36         if (is_shallow >= 0)
37                 return is_shallow;
38
39         if (!path)
40                 path = git_path("shallow");
41         /*
42          * fetch-pack sets '--shallow-file ""' as an indicator that no
43          * shallow file should be used. We could just open it and it
44          * will likely fail. But let's do an explicit check instead.
45          */
46         if (!*path ||
47             stat(path, &shallow_stat) ||
48             (fp = fopen(path, "r")) == NULL) {
49                 is_shallow = 0;
50                 return is_shallow;
51         }
52         is_shallow = 1;
53
54         while (fgets(buf, sizeof(buf), fp)) {
55                 unsigned char sha1[20];
56                 if (get_sha1_hex(buf, sha1))
57                         die("bad shallow line: %s", buf);
58                 register_shallow(sha1);
59         }
60         fclose(fp);
61         return is_shallow;
62 }
63
64 struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
65                 int shallow_flag, int not_shallow_flag)
66 {
67         int i = 0, cur_depth = 0;
68         struct commit_list *result = NULL;
69         struct object_array stack = OBJECT_ARRAY_INIT;
70         struct commit *commit = NULL;
71
72         while (commit || i < heads->nr || stack.nr) {
73                 struct commit_list *p;
74                 if (!commit) {
75                         if (i < heads->nr) {
76                                 commit = (struct commit *)
77                                         deref_tag(heads->objects[i++].item, NULL, 0);
78                                 if (!commit || commit->object.type != OBJ_COMMIT) {
79                                         commit = NULL;
80                                         continue;
81                                 }
82                                 if (!commit->util)
83                                         commit->util = xmalloc(sizeof(int));
84                                 *(int *)commit->util = 0;
85                                 cur_depth = 0;
86                         } else {
87                                 commit = (struct commit *)
88                                         stack.objects[--stack.nr].item;
89                                 cur_depth = *(int *)commit->util;
90                         }
91                 }
92                 if (parse_commit(commit))
93                         die("invalid commit");
94                 cur_depth++;
95                 if (cur_depth >= depth) {
96                         commit_list_insert(commit, &result);
97                         commit->object.flags |= shallow_flag;
98                         commit = NULL;
99                         continue;
100                 }
101                 commit->object.flags |= not_shallow_flag;
102                 for (p = commit->parents, commit = NULL; p; p = p->next) {
103                         if (!p->item->util) {
104                                 int *pointer = xmalloc(sizeof(int));
105                                 p->item->util = pointer;
106                                 *pointer =  cur_depth;
107                         } else {
108                                 int *pointer = p->item->util;
109                                 if (cur_depth >= *pointer)
110                                         continue;
111                                 *pointer = cur_depth;
112                         }
113                         if (cur_depth < depth) {
114                                 if (p->next)
115                                         add_object_array(&p->item->object,
116                                                         NULL, &stack);
117                                 else {
118                                         commit = p->item;
119                                         cur_depth = *(int *)commit->util;
120                                 }
121                         } else {
122                                 commit_list_insert(p->item, &result);
123                                 p->item->object.flags |= shallow_flag;
124                         }
125                 }
126         }
127
128         return result;
129 }
130
131 void check_shallow_file_for_update(void)
132 {
133         struct stat st;
134
135         if (!is_shallow)
136                 return;
137         else if (is_shallow == -1)
138                 die("BUG: shallow must be initialized by now");
139
140         if (stat(git_path("shallow"), &st))
141                 die("shallow file was removed during fetch");
142         else if (st.st_mtime != shallow_stat.st_mtime
143 #ifdef USE_NSEC
144                  || ST_MTIME_NSEC(st) != ST_MTIME_NSEC(shallow_stat)
145 #endif
146                    )
147                 die("shallow file was changed during fetch");
148 }