]>
Commit | Line | Data |
---|---|---|
3315782c | 1 | /* |
5e0de328 | 2 | * Copyright (C) 2009-2012 the libgit2 contributors |
3315782c | 3 | * |
bb742ede VM |
4 | * This file is part of libgit2, distributed under the GNU GPL v2 with |
5 | * a Linking Exception. For full terms see the included COPYING file. | |
3315782c | 6 | */ |
e802d8cc | 7 | #include <stdarg.h> |
7784bcbb | 8 | #include <ctype.h> |
3315782c | 9 | |
44908fe7 | 10 | #include "git2/object.h" |
d12299fe | 11 | |
3315782c VM |
12 | #include "common.h" |
13 | #include "repository.h" | |
14 | #include "commit.h" | |
15 | #include "tag.h" | |
237da401 | 16 | #include "blob.h" |
6fd195d7 | 17 | #include "fileops.h" |
b22d1479 | 18 | #include "config.h" |
9282e921 | 19 | #include "refs.h" |
47bfa0be RB |
20 | #include "filter.h" |
21 | #include "odb.h" | |
096d9e94 | 22 | #include "remote.h" |
632d8b23 | 23 | #include "merge.h" |
9282e921 | 24 | |
7784bcbb | 25 | #define GIT_FILE_CONTENT_PREFIX "gitdir:" |
6a01b6bd | 26 | |
28990938 | 27 | #define GIT_BRANCH_MASTER "master" |
28 | ||
29e948de | 29 | #define GIT_REPO_VERSION 0 |
691aa968 | 30 | |
ca1b6e54 RB |
31 | #define GIT_TEMPLATE_DIR "/usr/share/git-core/templates" |
32 | ||
9462c471 VM |
33 | static void drop_odb(git_repository *repo) |
34 | { | |
35 | if (repo->_odb != NULL) { | |
36 | GIT_REFCOUNT_OWN(repo->_odb, NULL); | |
37 | git_odb_free(repo->_odb); | |
38 | repo->_odb = NULL; | |
eb2f3b47 | 39 | } |
9462c471 | 40 | } |
691aa968 | 41 | |
9462c471 VM |
42 | static void drop_config(git_repository *repo) |
43 | { | |
44 | if (repo->_config != NULL) { | |
45 | GIT_REFCOUNT_OWN(repo->_config, NULL); | |
46 | git_config_free(repo->_config); | |
47 | repo->_config = NULL; | |
eb2f3b47 | 48 | } |
f2c25d18 VM |
49 | |
50 | git_repository__cvar_cache_clear(repo); | |
691aa968 VM |
51 | } |
52 | ||
9462c471 | 53 | static void drop_index(git_repository *repo) |
6fd195d7 | 54 | { |
9462c471 VM |
55 | if (repo->_index != NULL) { |
56 | GIT_REFCOUNT_OWN(repo->_index, NULL); | |
57 | git_index_free(repo->_index); | |
58 | repo->_index = NULL; | |
59 | } | |
e0011be3 VM |
60 | } |
61 | ||
9462c471 | 62 | void git_repository_free(git_repository *repo) |
e0011be3 | 63 | { |
9462c471 VM |
64 | if (repo == NULL) |
65 | return; | |
6fd195d7 | 66 | |
9462c471 VM |
67 | git_cache_free(&repo->objects); |
68 | git_repository__refcache_free(&repo->references); | |
73b51450 | 69 | git_attr_cache_flush(repo); |
bfc9ca59 | 70 | git_submodule_config_free(repo); |
6fd195d7 | 71 | |
9462c471 VM |
72 | git__free(repo->path_repository); |
73 | git__free(repo->workdir); | |
6fd195d7 | 74 | |
9462c471 VM |
75 | drop_config(repo); |
76 | drop_index(repo); | |
77 | drop_odb(repo); | |
78 | ||
79 | git__free(repo); | |
6fd195d7 VM |
80 | } |
81 | ||
9462c471 VM |
82 | /* |
83 | * Git repository open methods | |
84 | * | |
85 | * Open a repository object from its path | |
86 | */ | |
cb8a7961 | 87 | static bool valid_repository_path(git_buf *repository_path) |
5ad739e8 | 88 | { |
97769280 | 89 | /* Check OBJECTS_DIR first, since it will generate the longest path name */ |
1a481123 | 90 | if (git_path_contains_dir(repository_path, GIT_OBJECTS_DIR) == false) |
cb8a7961 | 91 | return false; |
5ad739e8 | 92 | |
97769280 | 93 | /* Ensure HEAD file exists */ |
1a481123 | 94 | if (git_path_contains_file(repository_path, GIT_HEAD_FILE) == false) |
cb8a7961 | 95 | return false; |
5ad739e8 | 96 | |
1a481123 | 97 | if (git_path_contains_dir(repository_path, GIT_REFS_DIR) == false) |
cb8a7961 | 98 | return false; |
5ad739e8 | 99 | |
cb8a7961 | 100 | return true; |
5ad739e8 VM |
101 | } |
102 | ||
51d00446 | 103 | static git_repository *repository_alloc(void) |
3315782c VM |
104 | { |
105 | git_repository *repo = git__malloc(sizeof(git_repository)); | |
106 | if (!repo) | |
107 | return NULL; | |
108 | ||
109 | memset(repo, 0x0, sizeof(git_repository)); | |
110 | ||
cb8a7961 | 111 | if (git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free) < 0) { |
3286c408 | 112 | git__free(repo); |
81201a4c | 113 | return NULL; |
114 | } | |
3315782c | 115 | |
f2c25d18 VM |
116 | /* set all the entries in the cvar cache to `unset` */ |
117 | git_repository__cvar_cache_clear(repo); | |
118 | ||
6fd195d7 VM |
119 | return repo; |
120 | } | |
121 | ||
9462c471 | 122 | static int load_config_data(git_repository *repo) |
ec3c7a16 | 123 | { |
cb8a7961 | 124 | int is_bare; |
9462c471 | 125 | git_config *config; |
ec3c7a16 | 126 | |
cb8a7961 VM |
127 | if (git_repository_config__weakptr(&config, repo) < 0) |
128 | return -1; | |
ec3c7a16 | 129 | |
d3e9c4a5 | 130 | /* Try to figure out if it's bare, default to non-bare if it's not set */ |
29e948de | 131 | if (git_config_get_bool(&is_bare, config, "core.bare") < 0) |
d3e9c4a5 CMN |
132 | repo->is_bare = 0; |
133 | else | |
134 | repo->is_bare = is_bare; | |
c94785a9 | 135 | |
cb8a7961 | 136 | return 0; |
9462c471 | 137 | } |
ec3c7a16 | 138 | |
7784bcbb | 139 | static int load_workdir(git_repository *repo, git_buf *parent_path) |
9462c471 | 140 | { |
7784bcbb RB |
141 | int error; |
142 | git_config *config; | |
143 | const char *worktree; | |
144 | git_buf worktree_buf = GIT_BUF_INIT; | |
ec3c7a16 | 145 | |
97769280 | 146 | if (repo->is_bare) |
cb8a7961 | 147 | return 0; |
ec3c7a16 | 148 | |
7784bcbb | 149 | if (git_repository_config__weakptr(&config, repo) < 0) |
cb8a7961 | 150 | return -1; |
ec3c7a16 | 151 | |
29e948de | 152 | error = git_config_get_string(&worktree, config, "core.worktree"); |
5f4a61ae RB |
153 | if (!error && worktree != NULL) { |
154 | error = git_path_prettify_dir( | |
155 | &worktree_buf, worktree, repo->path_repository); | |
156 | if (error < 0) | |
157 | return error; | |
158 | repo->workdir = git_buf_detach(&worktree_buf); | |
159 | } | |
904b67e6 | 160 | else if (error != GIT_ENOTFOUND) |
7784bcbb RB |
161 | return error; |
162 | else { | |
163 | giterr_clear(); | |
164 | ||
165 | if (parent_path && git_path_isdir(parent_path->ptr)) | |
166 | repo->workdir = git_buf_detach(parent_path); | |
167 | else { | |
168 | git_path_dirname_r(&worktree_buf, repo->path_repository); | |
169 | git_path_to_dir(&worktree_buf); | |
170 | repo->workdir = git_buf_detach(&worktree_buf); | |
171 | } | |
172 | } | |
173 | ||
174 | GITERR_CHECK_ALLOC(repo->workdir); | |
97769280 | 175 | |
cb8a7961 | 176 | return 0; |
ec3c7a16 VM |
177 | } |
178 | ||
7784bcbb RB |
179 | /* |
180 | * This function returns furthest offset into path where a ceiling dir | |
181 | * is found, so we can stop processing the path at that point. | |
182 | * | |
183 | * Note: converting this to use git_bufs instead of GIT_PATH_MAX buffers on | |
184 | * the stack could remove directories name limits, but at the cost of doing | |
185 | * repeated malloc/frees inside the loop below, so let's not do it now. | |
186 | */ | |
187 | static int find_ceiling_dir_offset( | |
188 | const char *path, | |
189 | const char *ceiling_directories) | |
190 | { | |
191 | char buf[GIT_PATH_MAX + 1]; | |
192 | char buf2[GIT_PATH_MAX + 1]; | |
193 | const char *ceil, *sep; | |
44ef8b1b | 194 | size_t len, max_len = 0, min_len; |
7784bcbb RB |
195 | |
196 | assert(path); | |
197 | ||
44ef8b1b | 198 | min_len = (size_t)(git_path_root(path) + 1); |
7784bcbb RB |
199 | |
200 | if (ceiling_directories == NULL || min_len == 0) | |
44ef8b1b | 201 | return (int)min_len; |
7784bcbb RB |
202 | |
203 | for (sep = ceil = ceiling_directories; *sep; ceil = sep + 1) { | |
204 | for (sep = ceil; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++); | |
205 | len = sep - ceil; | |
206 | ||
44ef8b1b | 207 | if (len == 0 || len >= sizeof(buf) || git_path_root(ceil) == -1) |
7784bcbb RB |
208 | continue; |
209 | ||
210 | strncpy(buf, ceil, len); | |
211 | buf[len] = '\0'; | |
212 | ||
213 | if (p_realpath(buf, buf2) == NULL) | |
214 | continue; | |
215 | ||
216 | len = strlen(buf2); | |
217 | if (len > 0 && buf2[len-1] == '/') | |
218 | buf[--len] = '\0'; | |
219 | ||
220 | if (!strncmp(path, buf2, len) && | |
221 | path[len] == '/' && | |
222 | len > max_len) | |
223 | { | |
224 | max_len = len; | |
225 | } | |
226 | } | |
227 | ||
44ef8b1b | 228 | return (int)(max_len <= min_len ? min_len : max_len); |
7784bcbb RB |
229 | } |
230 | ||
231 | /* | |
232 | * Read the contents of `file_path` and set `path_out` to the repo dir that | |
233 | * it points to. Before calling, set `path_out` to the base directory that | |
234 | * should be used if the contents of `file_path` are a relative path. | |
235 | */ | |
236 | static int read_gitfile(git_buf *path_out, const char *file_path) | |
237 | { | |
238 | int error = 0; | |
239 | git_buf file = GIT_BUF_INIT; | |
240 | size_t prefix_len = strlen(GIT_FILE_CONTENT_PREFIX); | |
241 | ||
242 | assert(path_out && file_path); | |
243 | ||
244 | if (git_futils_readbuffer(&file, file_path) < 0) | |
245 | return -1; | |
246 | ||
247 | git_buf_rtrim(&file); | |
248 | ||
662880ca RB |
249 | if (git_buf_len(&file) <= prefix_len || |
250 | memcmp(git_buf_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0) | |
7784bcbb RB |
251 | { |
252 | giterr_set(GITERR_REPOSITORY, "The `.git` file at '%s' is malformed", file_path); | |
253 | error = -1; | |
254 | } | |
255 | else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) { | |
662880ca | 256 | const char *gitlink = git_buf_cstr(&file) + prefix_len; |
0f49200c | 257 | while (*gitlink && git__isspace(*gitlink)) gitlink++; |
662880ca RB |
258 | error = git_path_prettify_dir( |
259 | path_out, gitlink, git_buf_cstr(path_out)); | |
7784bcbb RB |
260 | } |
261 | ||
262 | git_buf_free(&file); | |
263 | return error; | |
264 | } | |
265 | ||
266 | static int find_repo( | |
267 | git_buf *repo_path, | |
268 | git_buf *parent_path, | |
269 | const char *start_path, | |
270 | uint32_t flags, | |
271 | const char *ceiling_dirs) | |
691aa968 | 272 | { |
7784bcbb RB |
273 | int error; |
274 | git_buf path = GIT_BUF_INIT; | |
275 | struct stat st; | |
276 | dev_t initial_device = 0; | |
277 | bool try_with_dot_git = false; | |
278 | int ceiling_offset; | |
279 | ||
280 | git_buf_free(repo_path); | |
281 | ||
282 | if ((error = git_path_prettify_dir(&path, start_path, NULL)) < 0) | |
283 | return error; | |
284 | ||
285 | ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs); | |
286 | ||
287 | if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0) | |
288 | return error; | |
289 | ||
fa6420f7 | 290 | while (!error && !git_buf_len(repo_path)) { |
7784bcbb RB |
291 | if (p_stat(path.ptr, &st) == 0) { |
292 | /* check that we have not crossed device boundaries */ | |
293 | if (initial_device == 0) | |
294 | initial_device = st.st_dev; | |
295 | else if (st.st_dev != initial_device && | |
296 | (flags & GIT_REPOSITORY_OPEN_CROSS_FS) == 0) | |
297 | break; | |
298 | ||
299 | if (S_ISDIR(st.st_mode)) { | |
300 | if (valid_repository_path(&path)) { | |
301 | git_path_to_dir(&path); | |
302 | git_buf_set(repo_path, path.ptr, path.size); | |
303 | break; | |
304 | } | |
305 | } | |
306 | else if (S_ISREG(st.st_mode)) { | |
307 | git_buf repo_link = GIT_BUF_INIT; | |
308 | ||
309 | if (!(error = read_gitfile(&repo_link, path.ptr))) { | |
310 | if (valid_repository_path(&repo_link)) | |
311 | git_buf_swap(repo_path, &repo_link); | |
146f5c75 CMN |
312 | |
313 | git_buf_free(&repo_link); | |
7784bcbb RB |
314 | break; |
315 | } | |
316 | git_buf_free(&repo_link); | |
317 | } | |
318 | } | |
319 | ||
320 | /* move up one directory level */ | |
321 | if (git_path_dirname_r(&path, path.ptr) < 0) { | |
322 | error = -1; | |
323 | break; | |
324 | } | |
325 | ||
326 | if (try_with_dot_git) { | |
327 | /* if we tried original dir with and without .git AND either hit | |
328 | * directory ceiling or NO_SEARCH was requested, then be done. | |
329 | */ | |
330 | if (path.ptr[ceiling_offset] == '\0' || | |
331 | (flags & GIT_REPOSITORY_OPEN_NO_SEARCH) != 0) | |
332 | break; | |
333 | /* otherwise look first for .git item */ | |
334 | error = git_buf_joinpath(&path, path.ptr, DOT_GIT); | |
335 | } | |
336 | try_with_dot_git = !try_with_dot_git; | |
337 | } | |
338 | ||
339 | if (!error && parent_path != NULL) { | |
fa6420f7 | 340 | if (!git_buf_len(repo_path)) |
7784bcbb RB |
341 | git_buf_clear(parent_path); |
342 | else { | |
343 | git_path_dirname_r(parent_path, path.ptr); | |
344 | git_path_to_dir(parent_path); | |
345 | } | |
346 | if (git_buf_oom(parent_path)) | |
347 | return -1; | |
348 | } | |
349 | ||
350 | git_buf_free(&path); | |
351 | ||
fa6420f7 | 352 | if (!git_buf_len(repo_path) && !error) { |
cb8a7961 | 353 | giterr_set(GITERR_REPOSITORY, |
7784bcbb | 354 | "Could not find repository from '%s'", start_path); |
904b67e6 | 355 | error = GIT_ENOTFOUND; |
97769280 | 356 | } |
691aa968 | 357 | |
7784bcbb RB |
358 | return error; |
359 | } | |
360 | ||
361 | int git_repository_open_ext( | |
362 | git_repository **repo_ptr, | |
363 | const char *start_path, | |
364 | uint32_t flags, | |
365 | const char *ceiling_dirs) | |
366 | { | |
367 | int error; | |
368 | git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT; | |
369 | git_repository *repo; | |
370 | ||
662880ca RB |
371 | if (repo_ptr) |
372 | *repo_ptr = NULL; | |
7784bcbb | 373 | |
662880ca RB |
374 | error = find_repo(&path, &parent, start_path, flags, ceiling_dirs); |
375 | if (error < 0 || !repo_ptr) | |
7784bcbb RB |
376 | return error; |
377 | ||
e52ed7a5 | 378 | repo = repository_alloc(); |
cb8a7961 | 379 | GITERR_CHECK_ALLOC(repo); |
691aa968 | 380 | |
7784bcbb | 381 | repo->path_repository = git_buf_detach(&path); |
cb8a7961 | 382 | GITERR_CHECK_ALLOC(repo->path_repository); |
691aa968 | 383 | |
7784bcbb RB |
384 | if ((error = load_config_data(repo)) < 0 || |
385 | (error = load_workdir(repo, &parent)) < 0) | |
386 | { | |
387 | git_repository_free(repo); | |
388 | return error; | |
389 | } | |
691aa968 | 390 | |
146f5c75 | 391 | git_buf_free(&parent); |
7784bcbb | 392 | *repo_ptr = repo; |
cb8a7961 | 393 | return 0; |
7784bcbb | 394 | } |
97769280 | 395 | |
7784bcbb RB |
396 | int git_repository_open(git_repository **repo_out, const char *path) |
397 | { | |
398 | return git_repository_open_ext( | |
399 | repo_out, path, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL); | |
400 | } | |
401 | ||
6782245e CMN |
402 | int git_repository_wrap_odb(git_repository **repo_out, git_odb *odb) |
403 | { | |
404 | git_repository *repo; | |
405 | ||
406 | repo = repository_alloc(); | |
407 | GITERR_CHECK_ALLOC(repo); | |
408 | ||
409 | git_repository_set_odb(repo, odb); | |
410 | *repo_out = repo; | |
411 | ||
412 | return 0; | |
413 | } | |
414 | ||
7784bcbb RB |
415 | int git_repository_discover( |
416 | char *repository_path, | |
417 | size_t size, | |
418 | const char *start_path, | |
419 | int across_fs, | |
420 | const char *ceiling_dirs) | |
421 | { | |
422 | git_buf path = GIT_BUF_INIT; | |
423 | uint32_t flags = across_fs ? GIT_REPOSITORY_OPEN_CROSS_FS : 0; | |
464cf248 | 424 | int error; |
7784bcbb RB |
425 | |
426 | assert(start_path && repository_path && size > 0); | |
427 | ||
428 | *repository_path = '\0'; | |
429 | ||
464cf248 | 430 | if ((error = find_repo(&path, NULL, start_path, flags, ceiling_dirs)) < 0) |
904b67e6 | 431 | return error != GIT_ENOTFOUND ? -1 : error; |
7784bcbb RB |
432 | |
433 | if (size < (size_t)(path.size + 1)) { | |
434 | giterr_set(GITERR_REPOSITORY, | |
13b554e3 | 435 | "The given buffer is too small to store the discovered path"); |
7784bcbb RB |
436 | git_buf_free(&path); |
437 | return -1; | |
438 | } | |
439 | ||
440 | /* success: we discovered a repository */ | |
441 | git_buf_copy_cstr(repository_path, size, &path); | |
442 | git_buf_free(&path); | |
443 | return 0; | |
691aa968 VM |
444 | } |
445 | ||
9462c471 | 446 | static int load_config( |
7784bcbb RB |
447 | git_config **out, |
448 | git_repository *repo, | |
449 | const char *global_config_path, | |
4258d483 | 450 | const char *xdg_config_path, |
7784bcbb | 451 | const char *system_config_path) |
b22d1479 | 452 | { |
97769280 | 453 | git_buf config_path = GIT_BUF_INIT; |
9462c471 | 454 | git_config *cfg = NULL; |
b22d1479 | 455 | |
9462c471 | 456 | assert(repo && out); |
07ff8817 | 457 | |
cb8a7961 VM |
458 | if (git_config_new(&cfg) < 0) |
459 | return -1; | |
b22d1479 | 460 | |
cb8a7961 VM |
461 | if (git_buf_joinpath( |
462 | &config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO) < 0) | |
463 | goto on_error; | |
97769280 | 464 | |
a1abe66a | 465 | if (git_config_add_file_ondisk(cfg, config_path.ptr, GIT_CONFIG_LEVEL_LOCAL, 0) < 0) |
cb8a7961 VM |
466 | goto on_error; |
467 | ||
468 | git_buf_free(&config_path); | |
b22d1479 | 469 | |
40fe5fbe | 470 | if (global_config_path != NULL) { |
a1abe66a | 471 | if (git_config_add_file_ondisk(cfg, global_config_path, GIT_CONFIG_LEVEL_GLOBAL, 0) < 0) |
8b4f9b17 SS |
472 | goto on_error; |
473 | } | |
474 | ||
4258d483 | 475 | if (xdg_config_path != NULL) { |
a1abe66a | 476 | if (git_config_add_file_ondisk(cfg, xdg_config_path, GIT_CONFIG_LEVEL_XDG, 0) < 0) |
cb8a7961 | 477 | goto on_error; |
b22d1479 CMN |
478 | } |
479 | ||
07ff8817 | 480 | if (system_config_path != NULL) { |
a1abe66a | 481 | if (git_config_add_file_ondisk(cfg, system_config_path, GIT_CONFIG_LEVEL_SYSTEM, 0) < 0) |
cb8a7961 | 482 | goto on_error; |
9ba9e513 CMN |
483 | } |
484 | ||
9462c471 | 485 | *out = cfg; |
cb8a7961 | 486 | return 0; |
b22d1479 | 487 | |
cb8a7961 VM |
488 | on_error: |
489 | git_buf_free(&config_path); | |
9462c471 VM |
490 | git_config_free(cfg); |
491 | *out = NULL; | |
cb8a7961 | 492 | return -1; |
b22d1479 CMN |
493 | } |
494 | ||
9462c471 | 495 | int git_repository_config__weakptr(git_config **out, git_repository *repo) |
40fe5fbe | 496 | { |
9462c471 | 497 | if (repo->_config == NULL) { |
4258d483 | 498 | git_buf global_buf = GIT_BUF_INIT, xdg_buf = GIT_BUF_INIT, system_buf = GIT_BUF_INIT; |
cb8a7961 | 499 | int res; |
9462c471 VM |
500 | |
501 | const char *global_config_path = NULL; | |
4258d483 | 502 | const char *xdg_config_path = NULL; |
9462c471 | 503 | const char *system_config_path = NULL; |
40fe5fbe | 504 | |
cb8a7961 | 505 | if (git_config_find_global_r(&global_buf) == 0) |
97769280 | 506 | global_config_path = global_buf.ptr; |
40fe5fbe | 507 | |
4258d483 SS |
508 | if (git_config_find_xdg_r(&xdg_buf) == 0) |
509 | xdg_config_path = xdg_buf.ptr; | |
8b4f9b17 | 510 | |
cb8a7961 | 511 | if (git_config_find_system_r(&system_buf) == 0) |
97769280 | 512 | system_config_path = system_buf.ptr; |
40fe5fbe | 513 | |
4258d483 | 514 | res = load_config(&repo->_config, repo, global_config_path, xdg_config_path, system_config_path); |
97769280 RB |
515 | |
516 | git_buf_free(&global_buf); | |
a8918418 | 517 | git_buf_free(&xdg_buf); |
97769280 RB |
518 | git_buf_free(&system_buf); |
519 | ||
cb8a7961 VM |
520 | if (res < 0) |
521 | return -1; | |
9462c471 VM |
522 | |
523 | GIT_REFCOUNT_OWN(repo->_config, repo); | |
524 | } | |
40fe5fbe | 525 | |
9462c471 | 526 | *out = repo->_config; |
cb8a7961 | 527 | return 0; |
40fe5fbe CMN |
528 | } |
529 | ||
9462c471 | 530 | int git_repository_config(git_config **out, git_repository *repo) |
fd0574e5 | 531 | { |
cb8a7961 VM |
532 | if (git_repository_config__weakptr(out, repo) < 0) |
533 | return -1; | |
fd0574e5 | 534 | |
cb8a7961 VM |
535 | GIT_REFCOUNT_INC(*out); |
536 | return 0; | |
9462c471 VM |
537 | } |
538 | ||
539 | void git_repository_set_config(git_repository *repo, git_config *config) | |
540 | { | |
541 | assert(repo && config); | |
542 | ||
543 | drop_config(repo); | |
544 | ||
545 | repo->_config = config; | |
546 | GIT_REFCOUNT_OWN(repo->_config, repo); | |
547 | } | |
548 | ||
549 | int git_repository_odb__weakptr(git_odb **out, git_repository *repo) | |
550 | { | |
551 | assert(repo && out); | |
552 | ||
553 | if (repo->_odb == NULL) { | |
97769280 | 554 | git_buf odb_path = GIT_BUF_INIT; |
cb8a7961 | 555 | int res; |
9462c471 | 556 | |
cb8a7961 VM |
557 | if (git_buf_joinpath(&odb_path, repo->path_repository, GIT_OBJECTS_DIR) < 0) |
558 | return -1; | |
9462c471 | 559 | |
cb8a7961 | 560 | res = git_odb_open(&repo->_odb, odb_path.ptr); |
97769280 | 561 | git_buf_free(&odb_path); /* done with path */ |
cb8a7961 VM |
562 | |
563 | if (res < 0) | |
564 | return -1; | |
9462c471 VM |
565 | |
566 | GIT_REFCOUNT_OWN(repo->_odb, repo); | |
567 | } | |
fd0574e5 | 568 | |
9462c471 | 569 | *out = repo->_odb; |
cb8a7961 | 570 | return 0; |
fd0574e5 RG |
571 | } |
572 | ||
9462c471 | 573 | int git_repository_odb(git_odb **out, git_repository *repo) |
6fd195d7 | 574 | { |
cb8a7961 VM |
575 | if (git_repository_odb__weakptr(out, repo) < 0) |
576 | return -1; | |
1795f879 | 577 | |
cb8a7961 VM |
578 | GIT_REFCOUNT_INC(*out); |
579 | return 0; | |
9462c471 | 580 | } |
6fd195d7 | 581 | |
9462c471 VM |
582 | void git_repository_set_odb(git_repository *repo, git_odb *odb) |
583 | { | |
584 | assert(repo && odb); | |
3315782c | 585 | |
9462c471 | 586 | drop_odb(repo); |
1795f879 | 587 | |
9462c471 VM |
588 | repo->_odb = odb; |
589 | GIT_REFCOUNT_OWN(repo->_odb, repo); | |
baf861a5 | 590 | GIT_REFCOUNT_INC(odb); |
9462c471 VM |
591 | } |
592 | ||
593 | int git_repository_index__weakptr(git_index **out, git_repository *repo) | |
594 | { | |
595 | assert(out && repo); | |
596 | ||
9462c471 | 597 | if (repo->_index == NULL) { |
cb8a7961 | 598 | int res; |
97769280 | 599 | git_buf index_path = GIT_BUF_INIT; |
9462c471 | 600 | |
cb8a7961 VM |
601 | if (git_buf_joinpath(&index_path, repo->path_repository, GIT_INDEX_FILE) < 0) |
602 | return -1; | |
9462c471 | 603 | |
cb8a7961 | 604 | res = git_index_open(&repo->_index, index_path.ptr); |
97769280 | 605 | git_buf_free(&index_path); /* done with path */ |
cb8a7961 VM |
606 | |
607 | if (res < 0) | |
608 | return -1; | |
9462c471 VM |
609 | |
610 | GIT_REFCOUNT_OWN(repo->_index, repo); | |
da825c92 RB |
611 | |
612 | if (git_index_set_caps(repo->_index, GIT_INDEXCAP_FROM_OWNER) < 0) | |
613 | return -1; | |
9462c471 VM |
614 | } |
615 | ||
9462c471 | 616 | *out = repo->_index; |
cb8a7961 | 617 | return 0; |
9462c471 | 618 | } |
1795f879 | 619 | |
9462c471 VM |
620 | int git_repository_index(git_index **out, git_repository *repo) |
621 | { | |
cb8a7961 VM |
622 | if (git_repository_index__weakptr(out, repo) < 0) |
623 | return -1; | |
9462c471 | 624 | |
cb8a7961 VM |
625 | GIT_REFCOUNT_INC(*out); |
626 | return 0; | |
3315782c VM |
627 | } |
628 | ||
9462c471 VM |
629 | void git_repository_set_index(git_repository *repo, git_index *index) |
630 | { | |
631 | assert(repo && index); | |
632 | ||
633 | drop_index(repo); | |
634 | ||
635 | repo->_index = index; | |
636 | GIT_REFCOUNT_OWN(repo->_index, repo); | |
c1aefb35 | 637 | GIT_REFCOUNT_INC(index); |
9462c471 VM |
638 | } |
639 | ||
2c227b8b | 640 | static int check_repositoryformatversion(git_config *config) |
40c44d2f | 641 | { |
cb8a7961 | 642 | int version; |
5663e61a | 643 | |
29e948de | 644 | if (git_config_get_int32(&version, config, "core.repositoryformatversion") < 0) |
cb8a7961 | 645 | return -1; |
5663e61a | 646 | |
29e948de | 647 | if (GIT_REPO_VERSION < version) { |
cb8a7961 VM |
648 | giterr_set(GITERR_REPOSITORY, |
649 | "Unsupported repository version %d. Only versions up to %d are supported.", | |
29e948de | 650 | version, GIT_REPO_VERSION); |
cb8a7961 VM |
651 | return -1; |
652 | } | |
5663e61a | 653 | |
cb8a7961 | 654 | return 0; |
5663e61a | 655 | } |
656 | ||
662880ca | 657 | static int repo_init_create_head(const char *git_dir, const char *ref_name) |
e1f8cad0 | 658 | { |
97769280 | 659 | git_buf ref_path = GIT_BUF_INIT; |
9462c471 | 660 | git_filebuf ref = GIT_FILEBUF_INIT; |
662880ca | 661 | const char *fmt; |
9462c471 | 662 | |
cb8a7961 | 663 | if (git_buf_joinpath(&ref_path, git_dir, GIT_HEAD_FILE) < 0 || |
662880ca RB |
664 | git_filebuf_open(&ref, ref_path.ptr, 0) < 0) |
665 | goto fail; | |
666 | ||
667 | if (!ref_name) | |
668 | ref_name = GIT_BRANCH_MASTER; | |
669 | ||
74a24005 | 670 | if (git__prefixcmp(ref_name, GIT_REFS_DIR) == 0) |
662880ca RB |
671 | fmt = "ref: %s\n"; |
672 | else | |
74a24005 | 673 | fmt = "ref: " GIT_REFS_HEADS_DIR "%s\n"; |
662880ca RB |
674 | |
675 | if (git_filebuf_printf(&ref, fmt, ref_name) < 0 || | |
cb8a7961 | 676 | git_filebuf_commit(&ref, GIT_REFS_FILE_MODE) < 0) |
662880ca | 677 | goto fail; |
9462c471 | 678 | |
97769280 | 679 | git_buf_free(&ref_path); |
cb8a7961 | 680 | return 0; |
662880ca RB |
681 | |
682 | fail: | |
683 | git_buf_free(&ref_path); | |
684 | git_filebuf_cleanup(&ref); | |
685 | return -1; | |
9462c471 VM |
686 | } |
687 | ||
fac66990 | 688 | static bool is_chmod_supported(const char *file_path) |
689 | { | |
690 | struct stat st1, st2; | |
691 | static int _is_supported = -1; | |
692 | ||
693 | if (_is_supported > -1) | |
694 | return _is_supported; | |
695 | ||
696 | if (p_stat(file_path, &st1) < 0) | |
697 | return false; | |
698 | ||
699 | if (p_chmod(file_path, st1.st_mode ^ S_IXUSR) < 0) | |
700 | return false; | |
701 | ||
702 | if (p_stat(file_path, &st2) < 0) | |
703 | return false; | |
704 | ||
705 | _is_supported = (st1.st_mode != st2.st_mode); | |
ca1b6e54 | 706 | |
fac66990 | 707 | return _is_supported; |
708 | } | |
709 | ||
693b23c0 | 710 | static bool is_filesystem_case_insensitive(const char *gitdir_path) |
711 | { | |
712 | git_buf path = GIT_BUF_INIT; | |
713 | static int _is_insensitive = -1; | |
714 | ||
715 | if (_is_insensitive > -1) | |
716 | return _is_insensitive; | |
717 | ||
718 | if (git_buf_joinpath(&path, gitdir_path, "CoNfIg") < 0) | |
719 | goto cleanup; | |
720 | ||
721 | _is_insensitive = git_path_exists(git_buf_cstr(&path)); | |
722 | ||
723 | cleanup: | |
724 | git_buf_free(&path); | |
725 | return _is_insensitive; | |
726 | } | |
727 | ||
ca1b6e54 RB |
728 | static bool are_symlinks_supported(const char *wd_path) |
729 | { | |
730 | git_buf path = GIT_BUF_INIT; | |
731 | int fd; | |
732 | struct stat st; | |
733 | static int _symlinks_supported = -1; | |
734 | ||
735 | if (_symlinks_supported > -1) | |
736 | return _symlinks_supported; | |
737 | ||
738 | if ((fd = git_futils_mktmp(&path, wd_path)) < 0 || | |
739 | p_close(fd) < 0 || | |
740 | p_unlink(path.ptr) < 0 || | |
741 | p_symlink("testing", path.ptr) < 0 || | |
742 | p_lstat(path.ptr, &st) < 0) | |
743 | _symlinks_supported = false; | |
744 | else | |
745 | _symlinks_supported = (S_ISLNK(st.st_mode) != 0); | |
746 | ||
747 | (void)p_unlink(path.ptr); | |
748 | git_buf_free(&path); | |
749 | ||
750 | return _symlinks_supported; | |
751 | } | |
752 | ||
662880ca | 753 | static int repo_init_config( |
ca1b6e54 RB |
754 | const char *repo_dir, |
755 | const char *work_dir, | |
756 | git_repository_init_options *opts) | |
9462c471 | 757 | { |
ca1b6e54 | 758 | int error = 0; |
97769280 RB |
759 | git_buf cfg_path = GIT_BUF_INIT; |
760 | git_config *config = NULL; | |
9462c471 | 761 | |
ca1b6e54 RB |
762 | #define SET_REPO_CONFIG(TYPE, NAME, VAL) do {\ |
763 | if ((error = git_config_set_##TYPE(config, NAME, VAL)) < 0) \ | |
764 | goto cleanup; } while (0) | |
9462c471 | 765 | |
ca1b6e54 | 766 | if (git_buf_joinpath(&cfg_path, repo_dir, GIT_CONFIG_FILENAME_INREPO) < 0) |
cb8a7961 | 767 | return -1; |
9462c471 | 768 | |
fac66990 | 769 | if (git_config_open_ondisk(&config, git_buf_cstr(&cfg_path)) < 0) { |
cb8a7961 VM |
770 | git_buf_free(&cfg_path); |
771 | return -1; | |
772 | } | |
9462c471 | 773 | |
662880ca | 774 | if ((opts->flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0 && |
ca1b6e54 RB |
775 | (error = check_repositoryformatversion(config)) < 0) |
776 | goto cleanup; | |
2c227b8b | 777 | |
662880ca RB |
778 | SET_REPO_CONFIG( |
779 | bool, "core.bare", (opts->flags & GIT_REPOSITORY_INIT_BARE) != 0); | |
780 | SET_REPO_CONFIG( | |
781 | int32, "core.repositoryformatversion", GIT_REPO_VERSION); | |
782 | SET_REPO_CONFIG( | |
783 | bool, "core.filemode", is_chmod_supported(git_buf_cstr(&cfg_path))); | |
784 | ||
ca1b6e54 | 785 | if (!(opts->flags & GIT_REPOSITORY_INIT_BARE)) { |
7623b1b6 | 786 | SET_REPO_CONFIG(bool, "core.logallrefupdates", true); |
787 | ||
ca1b6e54 RB |
788 | if (!are_symlinks_supported(work_dir)) |
789 | SET_REPO_CONFIG(bool, "core.symlinks", false); | |
790 | ||
791 | if (!(opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD)) { | |
792 | SET_REPO_CONFIG(string, "core.worktree", work_dir); | |
793 | } | |
794 | else if ((opts->flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0) { | |
89cd5708 | 795 | if (git_config_delete(config, "core.worktree") < 0) |
796 | giterr_clear(); | |
ca1b6e54 RB |
797 | } |
798 | } else { | |
799 | if (!are_symlinks_supported(repo_dir)) | |
800 | SET_REPO_CONFIG(bool, "core.symlinks", false); | |
801 | } | |
802 | ||
662880ca | 803 | if (!(opts->flags & GIT_REPOSITORY_INIT__IS_REINIT) && |
ca1b6e54 | 804 | is_filesystem_case_insensitive(repo_dir)) |
693b23c0 | 805 | SET_REPO_CONFIG(bool, "core.ignorecase", true); |
662880ca | 806 | |
ca1b6e54 | 807 | if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP) { |
662880ca RB |
808 | SET_REPO_CONFIG(int32, "core.sharedrepository", 1); |
809 | SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true); | |
ca1b6e54 RB |
810 | } |
811 | else if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL) { | |
662880ca RB |
812 | SET_REPO_CONFIG(int32, "core.sharedrepository", 2); |
813 | SET_REPO_CONFIG(bool, "receive.denyNonFastforwards", true); | |
814 | } | |
9462c471 | 815 | |
ca1b6e54 | 816 | cleanup: |
97769280 | 817 | git_buf_free(&cfg_path); |
9462c471 | 818 | git_config_free(config); |
662880ca | 819 | |
ca1b6e54 | 820 | return error; |
d2d6912e | 821 | } |
e1f8cad0 | 822 | |
dc34da6e | 823 | static int repo_write_template( |
991a56c7 RB |
824 | const char *git_dir, |
825 | bool allow_overwrite, | |
826 | const char *file, | |
827 | mode_t mode, | |
662880ca | 828 | bool hidden, |
991a56c7 | 829 | const char *content) |
dc34da6e RB |
830 | { |
831 | git_buf path = GIT_BUF_INIT; | |
991a56c7 | 832 | int fd, error = 0, flags; |
dc34da6e RB |
833 | |
834 | if (git_buf_joinpath(&path, git_dir, file) < 0) | |
835 | return -1; | |
836 | ||
991a56c7 RB |
837 | if (allow_overwrite) |
838 | flags = O_WRONLY | O_CREAT | O_TRUNC; | |
839 | else | |
840 | flags = O_WRONLY | O_CREAT | O_EXCL; | |
841 | ||
842 | fd = p_open(git_buf_cstr(&path), flags, mode); | |
dc34da6e | 843 | |
db628072 RB |
844 | if (fd >= 0) { |
845 | error = p_write(fd, content, strlen(content)); | |
dc34da6e | 846 | |
db628072 RB |
847 | p_close(fd); |
848 | } | |
849 | else if (errno != EEXIST) | |
850 | error = fd; | |
dc34da6e | 851 | |
662880ca RB |
852 | #ifdef GIT_WIN32 |
853 | if (!error && hidden) { | |
854 | if (p_hide_directory__w32(path.ptr) < 0) | |
855 | error = -1; | |
856 | } | |
857 | #else | |
858 | GIT_UNUSED(hidden); | |
859 | #endif | |
860 | ||
dc34da6e | 861 | git_buf_free(&path); |
db628072 RB |
862 | |
863 | if (error) | |
864 | giterr_set(GITERR_OS, | |
865 | "Failed to initialize repository with template '%s'", file); | |
866 | ||
867 | return error; | |
dc34da6e RB |
868 | } |
869 | ||
662880ca RB |
870 | static int repo_write_gitlink( |
871 | const char *in_dir, const char *to_repo) | |
4b8e27c8 | 872 | { |
662880ca RB |
873 | int error; |
874 | git_buf buf = GIT_BUF_INIT; | |
875 | struct stat st; | |
876 | ||
877 | git_path_dirname_r(&buf, to_repo); | |
878 | git_path_to_dir(&buf); | |
879 | if (git_buf_oom(&buf)) | |
cb8a7961 | 880 | return -1; |
a67a096a | 881 | |
662880ca RB |
882 | /* don't write gitlink to natural workdir */ |
883 | if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 && | |
884 | strcmp(in_dir, buf.ptr) == 0) | |
885 | { | |
886 | error = GIT_PASSTHROUGH; | |
887 | goto cleanup; | |
888 | } | |
889 | ||
890 | if ((error = git_buf_joinpath(&buf, in_dir, DOT_GIT)) < 0) | |
891 | goto cleanup; | |
892 | ||
893 | if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) { | |
894 | giterr_set(GITERR_REPOSITORY, | |
895 | "Cannot overwrite gitlink file into path '%s'", in_dir); | |
896 | error = GIT_EEXISTS; | |
897 | goto cleanup; | |
898 | } | |
899 | ||
900 | git_buf_clear(&buf); | |
901 | ||
902 | error = git_buf_printf(&buf, "%s %s", GIT_FILE_CONTENT_PREFIX, to_repo); | |
903 | ||
904 | if (!error) | |
905 | error = repo_write_template(in_dir, true, DOT_GIT, 0644, true, buf.ptr); | |
906 | ||
907 | cleanup: | |
908 | git_buf_free(&buf); | |
909 | return error; | |
910 | } | |
911 | ||
ca1b6e54 RB |
912 | static mode_t pick_dir_mode(git_repository_init_options *opts) |
913 | { | |
914 | if (opts->mode == GIT_REPOSITORY_INIT_SHARED_UMASK) | |
915 | return 0755; | |
916 | if (opts->mode == GIT_REPOSITORY_INIT_SHARED_GROUP) | |
917 | return (0775 | S_ISGID); | |
918 | if (opts->mode == GIT_REPOSITORY_INIT_SHARED_ALL) | |
919 | return (0777 | S_ISGID); | |
920 | return opts->mode; | |
921 | } | |
922 | ||
662880ca RB |
923 | #include "repo_template.h" |
924 | ||
925 | static int repo_init_structure( | |
926 | const char *repo_dir, | |
927 | const char *work_dir, | |
928 | git_repository_init_options *opts) | |
929 | { | |
ca1b6e54 | 930 | int error = 0; |
662880ca | 931 | repo_template_item *tpl; |
ca1b6e54 RB |
932 | bool external_tpl = |
933 | ((opts->flags & GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE) != 0); | |
934 | mode_t dmode = pick_dir_mode(opts); | |
662880ca RB |
935 | |
936 | /* Hide the ".git" directory */ | |
17837602 | 937 | #ifdef GIT_WIN32 |
2eb4edf5 | 938 | if ((opts->flags & GIT_REPOSITORY_INIT__HAS_DOTGIT) != 0) { |
662880ca | 939 | if (p_hide_directory__w32(repo_dir) < 0) { |
cb8a7961 VM |
940 | giterr_set(GITERR_REPOSITORY, |
941 | "Failed to mark Git repository folder as hidden"); | |
942 | return -1; | |
943 | } | |
17837602 | 944 | } |
2eb4edf5 RB |
945 | #endif |
946 | ||
947 | /* Create the .git gitlink if appropriate */ | |
948 | if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 && | |
949 | (opts->flags & GIT_REPOSITORY_INIT__NATURAL_WD) == 0) | |
950 | { | |
662880ca | 951 | if (repo_write_gitlink(work_dir, repo_dir) < 0) |
cb8a7961 | 952 | return -1; |
97769280 | 953 | } |
1c2c7c0d | 954 | |
ca1b6e54 RB |
955 | /* Copy external template if requested */ |
956 | if (external_tpl) { | |
957 | git_config *cfg; | |
958 | const char *tdir; | |
662880ca | 959 | |
ca1b6e54 RB |
960 | if (opts->template_path) |
961 | tdir = opts->template_path; | |
85bd1746 | 962 | else if ((error = git_config_open_default(&cfg)) < 0) |
ca1b6e54 RB |
963 | return error; |
964 | else { | |
965 | error = git_config_get_string(&tdir, cfg, "init.templatedir"); | |
662880ca | 966 | |
ca1b6e54 | 967 | git_config_free(cfg); |
662880ca | 968 | |
ca1b6e54 RB |
969 | if (error && error != GIT_ENOTFOUND) |
970 | return error; | |
971 | ||
972 | giterr_clear(); | |
973 | tdir = GIT_TEMPLATE_DIR; | |
662880ca | 974 | } |
ca1b6e54 RB |
975 | |
976 | error = git_futils_cp_r(tdir, repo_dir, | |
977 | GIT_CPDIR_COPY_SYMLINKS | GIT_CPDIR_CHMOD, dmode); | |
978 | ||
979 | if (error < 0) { | |
980 | if (strcmp(tdir, GIT_TEMPLATE_DIR) != 0) | |
981 | return error; | |
982 | ||
983 | /* if template was default, ignore error and use internal */ | |
984 | giterr_clear(); | |
985 | external_tpl = false; | |
986 | } | |
987 | } | |
988 | ||
989 | /* Copy internal template | |
990 | * - always ensure existence of dirs | |
991 | * - only create files if no external template was specified | |
992 | */ | |
993 | for (tpl = repo_template; !error && tpl->path; ++tpl) { | |
994 | if (!tpl->content) | |
995 | error = git_futils_mkdir( | |
996 | tpl->path, repo_dir, dmode, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD); | |
997 | else if (!external_tpl) { | |
662880ca RB |
998 | const char *content = tpl->content; |
999 | ||
1000 | if (opts->description && strcmp(tpl->path, GIT_DESC_FILE) == 0) | |
1001 | content = opts->description; | |
1002 | ||
ca1b6e54 RB |
1003 | error = repo_write_template( |
1004 | repo_dir, false, tpl->path, tpl->mode, false, content); | |
662880ca | 1005 | } |
dc34da6e RB |
1006 | } |
1007 | ||
ca1b6e54 | 1008 | return error; |
4b8e27c8 | 1009 | } |
1010 | ||
662880ca RB |
1011 | static int repo_init_directories( |
1012 | git_buf *repo_path, | |
1013 | git_buf *wd_path, | |
1014 | const char *given_repo, | |
1015 | git_repository_init_options *opts) | |
4b8e27c8 | 1016 | { |
662880ca RB |
1017 | int error = 0; |
1018 | bool add_dotgit, has_dotgit, natural_wd; | |
ca1b6e54 | 1019 | mode_t dirmode; |
932d1baf | 1020 | |
662880ca | 1021 | /* set up repo path */ |
4b8e27c8 | 1022 | |
662880ca RB |
1023 | add_dotgit = |
1024 | (opts->flags & GIT_REPOSITORY_INIT_NO_DOTGIT_DIR) == 0 && | |
1025 | (opts->flags & GIT_REPOSITORY_INIT_BARE) == 0 && | |
1026 | git__suffixcmp(given_repo, "/" DOT_GIT) != 0 && | |
1027 | git__suffixcmp(given_repo, "/" GIT_DIR) != 0; | |
4b8e27c8 | 1028 | |
662880ca RB |
1029 | if (git_buf_joinpath(repo_path, given_repo, add_dotgit ? GIT_DIR : "") < 0) |
1030 | return -1; | |
693b23c0 | 1031 | |
662880ca RB |
1032 | has_dotgit = (git__suffixcmp(repo_path->ptr, "/" GIT_DIR) == 0); |
1033 | if (has_dotgit) | |
1034 | opts->flags |= GIT_REPOSITORY_INIT__HAS_DOTGIT; | |
1035 | ||
1036 | /* set up workdir path */ | |
1037 | ||
1038 | if ((opts->flags & GIT_REPOSITORY_INIT_BARE) == 0) { | |
1039 | if (opts->workdir_path) { | |
ca1b6e54 RB |
1040 | if (git_path_join_unrooted( |
1041 | wd_path, opts->workdir_path, repo_path->ptr, NULL) < 0) | |
1042 | return -1; | |
662880ca RB |
1043 | } else if (has_dotgit) { |
1044 | if (git_path_dirname_r(wd_path, repo_path->ptr) < 0) | |
1045 | return -1; | |
1046 | } else { | |
1047 | giterr_set(GITERR_REPOSITORY, "Cannot pick working directory" | |
1048 | " for non-bare repository that isn't a '.git' directory"); | |
1049 | return -1; | |
1050 | } | |
693b23c0 | 1051 | |
662880ca RB |
1052 | if (git_path_to_dir(wd_path) < 0) |
1053 | return -1; | |
1054 | } else { | |
1055 | git_buf_clear(wd_path); | |
1056 | } | |
1057 | ||
1058 | natural_wd = | |
1059 | has_dotgit && | |
1060 | wd_path->size > 0 && | |
1061 | wd_path->size + strlen(GIT_DIR) == repo_path->size && | |
1062 | memcmp(repo_path->ptr, wd_path->ptr, wd_path->size) == 0; | |
1063 | if (natural_wd) | |
1064 | opts->flags |= GIT_REPOSITORY_INIT__NATURAL_WD; | |
1065 | ||
662880ca RB |
1066 | /* create directories as needed / requested */ |
1067 | ||
ca1b6e54 | 1068 | dirmode = pick_dir_mode(opts); |
662880ca | 1069 | |
ca1b6e54 RB |
1070 | if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 && has_dotgit) { |
1071 | git_buf p = GIT_BUF_INIT; | |
1072 | if ((error = git_path_dirname_r(&p, repo_path->ptr)) >= 0) | |
1073 | error = git_futils_mkdir(p.ptr, NULL, dirmode, 0); | |
1074 | git_buf_free(&p); | |
662880ca | 1075 | } |
662880ca | 1076 | |
ca1b6e54 RB |
1077 | if ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 || |
1078 | (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0 || | |
1079 | has_dotgit) | |
1080 | { | |
1081 | uint32_t mkflag = GIT_MKDIR_CHMOD; | |
1082 | if ((opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0) | |
1083 | mkflag |= GIT_MKDIR_PATH; | |
1084 | error = git_futils_mkdir(repo_path->ptr, NULL, dirmode, mkflag); | |
662880ca | 1085 | } |
ca1b6e54 RB |
1086 | |
1087 | if (wd_path->size > 0 && | |
1088 | !natural_wd && | |
1089 | ((opts->flags & GIT_REPOSITORY_INIT_MKDIR) != 0 || | |
1090 | (opts->flags & GIT_REPOSITORY_INIT_MKPATH) != 0)) | |
1091 | error = git_futils_mkdir(wd_path->ptr, NULL, dirmode & ~S_ISGID, | |
1092 | (opts->flags & GIT_REPOSITORY_INIT_MKPATH) ? GIT_MKDIR_PATH : 0); | |
662880ca RB |
1093 | |
1094 | /* prettify both directories now that they are created */ | |
1095 | ||
1096 | if (!error) { | |
1097 | error = git_path_prettify_dir(repo_path, repo_path->ptr, NULL); | |
1098 | ||
1099 | if (!error && wd_path->size > 0) | |
1100 | error = git_path_prettify_dir(wd_path, wd_path->ptr, NULL); | |
1101 | } | |
1102 | ||
1103 | return error; | |
1104 | } | |
1105 | ||
1106 | static int repo_init_create_origin(git_repository *repo, const char *url) | |
1107 | { | |
1108 | int error; | |
1109 | git_remote *remote; | |
1110 | ||
096d9e94 | 1111 | if (!(error = git_remote_add(&remote, repo, GIT_REMOTE_ORIGIN, url))) { |
662880ca RB |
1112 | error = git_remote_save(remote); |
1113 | git_remote_free(remote); | |
1114 | } | |
1115 | ||
1116 | return error; | |
1117 | } | |
1118 | ||
1119 | int git_repository_init( | |
1120 | git_repository **repo_out, const char *path, unsigned is_bare) | |
1121 | { | |
1122 | git_repository_init_options opts; | |
1123 | ||
1124 | memset(&opts, 0, sizeof(opts)); | |
1125 | opts.flags = GIT_REPOSITORY_INIT_MKPATH; /* don't love this default */ | |
1126 | if (is_bare) | |
1127 | opts.flags |= GIT_REPOSITORY_INIT_BARE; | |
1128 | ||
1129 | return git_repository_init_ext(repo_out, path, &opts); | |
1130 | } | |
1131 | ||
1132 | int git_repository_init_ext( | |
1133 | git_repository **repo_out, | |
1134 | const char *given_repo, | |
1135 | git_repository_init_options *opts) | |
1136 | { | |
1137 | int error; | |
1138 | git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT; | |
1139 | ||
1140 | assert(repo_out && given_repo && opts); | |
1141 | ||
1142 | error = repo_init_directories(&repo_path, &wd_path, given_repo, opts); | |
1143 | if (error < 0) | |
693b23c0 | 1144 | goto cleanup; |
662880ca RB |
1145 | |
1146 | if (valid_repository_path(&repo_path)) { | |
1147 | ||
1148 | if ((opts->flags & GIT_REPOSITORY_INIT_NO_REINIT) != 0) { | |
1149 | giterr_set(GITERR_REPOSITORY, | |
1150 | "Attempt to reinitialize '%s'", given_repo); | |
1151 | error = GIT_EEXISTS; | |
1152 | goto cleanup; | |
1153 | } | |
1154 | ||
1155 | opts->flags |= GIT_REPOSITORY_INIT__IS_REINIT; | |
1156 | ||
ca1b6e54 RB |
1157 | error = repo_init_config( |
1158 | git_buf_cstr(&repo_path), git_buf_cstr(&wd_path), opts); | |
662880ca RB |
1159 | |
1160 | /* TODO: reinitialize the templates */ | |
1161 | } | |
1162 | else { | |
1163 | if (!(error = repo_init_structure( | |
1164 | git_buf_cstr(&repo_path), git_buf_cstr(&wd_path), opts)) && | |
ca1b6e54 RB |
1165 | !(error = repo_init_config( |
1166 | git_buf_cstr(&repo_path), git_buf_cstr(&wd_path), opts))) | |
662880ca RB |
1167 | error = repo_init_create_head( |
1168 | git_buf_cstr(&repo_path), opts->initial_head); | |
cb8a7961 | 1169 | } |
662880ca RB |
1170 | if (error < 0) |
1171 | goto cleanup; | |
1172 | ||
1173 | error = git_repository_open(repo_out, git_buf_cstr(&repo_path)); | |
d2d6912e | 1174 | |
662880ca RB |
1175 | if (!error && opts->origin_url) |
1176 | error = repo_init_create_origin(*repo_out, opts->origin_url); | |
693b23c0 | 1177 | |
1178 | cleanup: | |
662880ca RB |
1179 | git_buf_free(&repo_path); |
1180 | git_buf_free(&wd_path); | |
1181 | ||
1182 | return error; | |
40c44d2f | 1183 | } |
35502d2e | 1184 | |
c682886e | 1185 | int git_repository_head_detached(git_repository *repo) |
35502d2e CMN |
1186 | { |
1187 | git_reference *ref; | |
9462c471 | 1188 | git_odb *odb = NULL; |
cb8a7961 | 1189 | int exists; |
9462c471 | 1190 | |
cb8a7961 VM |
1191 | if (git_repository_odb__weakptr(&odb, repo) < 0) |
1192 | return -1; | |
35502d2e | 1193 | |
cb8a7961 VM |
1194 | if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0) |
1195 | return -1; | |
35502d2e | 1196 | |
75abd2b9 MS |
1197 | if (git_reference_type(ref) == GIT_REF_SYMBOLIC) { |
1198 | git_reference_free(ref); | |
35502d2e | 1199 | return 0; |
75abd2b9 | 1200 | } |
35502d2e | 1201 | |
cb8a7961 | 1202 | exists = git_odb_exists(odb, git_reference_oid(ref)); |
75abd2b9 MS |
1203 | |
1204 | git_reference_free(ref); | |
cb8a7961 | 1205 | return exists; |
35502d2e CMN |
1206 | } |
1207 | ||
3601c4bf | 1208 | int git_repository_head(git_reference **head_out, git_repository *repo) |
35502d2e | 1209 | { |
b1a3a70e | 1210 | git_reference *head; |
8b05bea8 | 1211 | int error; |
1212 | ||
b1a3a70e | 1213 | if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0) |
1214 | return error; | |
1215 | ||
1216 | if (git_reference_type(head) == GIT_REF_OID) { | |
1217 | *head_out = head; | |
1218 | return 0; | |
1219 | } | |
1220 | ||
1221 | error = git_reference_lookup_resolved(head_out, repo, git_reference_target(head), -1); | |
1222 | git_reference_free(head); | |
8b05bea8 | 1223 | |
1224 | return error == GIT_ENOTFOUND ? GIT_EORPHANEDHEAD : error; | |
3601c4bf | 1225 | } |
1226 | ||
1227 | int git_repository_head_orphan(git_repository *repo) | |
1228 | { | |
cb8a7961 | 1229 | git_reference *ref = NULL; |
3601c4bf | 1230 | int error; |
1231 | ||
1232 | error = git_repository_head(&ref, repo); | |
cb8a7961 | 1233 | git_reference_free(ref); |
35502d2e | 1234 | |
8b05bea8 | 1235 | if (error == GIT_EORPHANEDHEAD) |
cb8a7961 | 1236 | return 1; |
75abd2b9 | 1237 | |
cb8a7961 VM |
1238 | if (error < 0) |
1239 | return -1; | |
1240 | ||
1241 | return 0; | |
35502d2e | 1242 | } |
e0011be3 | 1243 | |
41233c40 VM |
1244 | int git_repository_is_empty(git_repository *repo) |
1245 | { | |
d4a0b124 | 1246 | git_reference *head = NULL, *branch = NULL; |
41233c40 VM |
1247 | int error; |
1248 | ||
74a24005 | 1249 | if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0) |
cb8a7961 | 1250 | return -1; |
41233c40 | 1251 | |
75abd2b9 MS |
1252 | if (git_reference_type(head) != GIT_REF_SYMBOLIC) { |
1253 | git_reference_free(head); | |
0f489fb2 | 1254 | return 0; |
75abd2b9 | 1255 | } |
0f489fb2 | 1256 | |
74a24005 | 1257 | if (strcmp(git_reference_target(head), GIT_REFS_HEADS_DIR "master") != 0) { |
75abd2b9 | 1258 | git_reference_free(head); |
0f489fb2 | 1259 | return 0; |
75abd2b9 | 1260 | } |
41233c40 | 1261 | |
0f489fb2 | 1262 | error = git_reference_resolve(&branch, head); |
75abd2b9 MS |
1263 | |
1264 | git_reference_free(head); | |
1265 | git_reference_free(branch); | |
1266 | ||
904b67e6 | 1267 | if (error == GIT_ENOTFOUND) |
cb8a7961 VM |
1268 | return 1; |
1269 | ||
1270 | if (error < 0) | |
1271 | return -1; | |
1272 | ||
1273 | return 0; | |
41233c40 VM |
1274 | } |
1275 | ||
9462c471 | 1276 | const char *git_repository_path(git_repository *repo) |
4a34b3a9 | 1277 | { |
1278 | assert(repo); | |
9462c471 VM |
1279 | return repo->path_repository; |
1280 | } | |
4a34b3a9 | 1281 | |
9462c471 VM |
1282 | const char *git_repository_workdir(git_repository *repo) |
1283 | { | |
1284 | assert(repo); | |
602ee38b | 1285 | |
9462c471 VM |
1286 | if (repo->is_bare) |
1287 | return NULL; | |
602ee38b | 1288 | |
9462c471 VM |
1289 | return repo->workdir; |
1290 | } | |
602ee38b | 1291 | |
991a56c7 RB |
1292 | int git_repository_set_workdir( |
1293 | git_repository *repo, const char *workdir, int update_gitlink) | |
9462c471 | 1294 | { |
991a56c7 | 1295 | int error = 0; |
b78fb64d | 1296 | git_buf path = GIT_BUF_INIT; |
1297 | ||
9462c471 | 1298 | assert(repo && workdir); |
602ee38b | 1299 | |
b78fb64d | 1300 | if (git_path_prettify_dir(&path, workdir, NULL) < 0) |
1301 | return -1; | |
9462c471 | 1302 | |
991a56c7 RB |
1303 | if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0) |
1304 | return 0; | |
9462c471 | 1305 | |
991a56c7 RB |
1306 | if (update_gitlink) { |
1307 | git_config *config; | |
1308 | ||
1309 | if (git_repository_config__weakptr(&config, repo) < 0) | |
1310 | return -1; | |
1311 | ||
662880ca | 1312 | error = repo_write_gitlink(path.ptr, git_repository_path(repo)); |
991a56c7 RB |
1313 | |
1314 | /* passthrough error means gitlink is unnecessary */ | |
1315 | if (error == GIT_PASSTHROUGH) | |
1316 | error = git_config_delete(config, "core.worktree"); | |
1317 | else if (!error) | |
1318 | error = git_config_set_string(config, "core.worktree", path.ptr); | |
1319 | ||
1320 | if (!error) | |
1321 | error = git_config_set_bool(config, "core.bare", false); | |
1322 | } | |
1323 | ||
1324 | if (!error) { | |
1325 | char *old_workdir = repo->workdir; | |
1326 | ||
1327 | repo->workdir = git_buf_detach(&path); | |
1328 | repo->is_bare = 0; | |
1329 | ||
1330 | git__free(old_workdir); | |
1331 | } | |
1332 | ||
1333 | return error; | |
4a34b3a9 | 1334 | } |
fa9bcd81 | 1335 | |
1336 | int git_repository_is_bare(git_repository *repo) | |
1337 | { | |
1338 | assert(repo); | |
1339 | return repo->is_bare; | |
1340 | } | |
f917481e RB |
1341 | |
1342 | int git_repository_head_tree(git_tree **tree, git_repository *repo) | |
1343 | { | |
1344 | git_oid head_oid; | |
1345 | git_object *obj = NULL; | |
1346 | ||
1347 | if (git_reference_name_to_oid(&head_oid, repo, GIT_HEAD_FILE) < 0) { | |
1348 | /* cannot resolve HEAD - probably brand new repo */ | |
1349 | giterr_clear(); | |
1350 | *tree = NULL; | |
1351 | return 0; | |
1352 | } | |
1353 | ||
1354 | if (git_object_lookup(&obj, repo, &head_oid, GIT_OBJ_ANY) < 0 || | |
1355 | git_object__resolve_to_type(&obj, GIT_OBJ_TREE) < 0) | |
1356 | return -1; | |
1357 | ||
1358 | *tree = (git_tree *)obj; | |
1359 | return 0; | |
1360 | } | |
074841ec | 1361 | |
074841ec CMN |
1362 | int git_repository_message(char *buffer, size_t len, git_repository *repo) |
1363 | { | |
0ac349a9 VM |
1364 | git_buf buf = GIT_BUF_INIT, path = GIT_BUF_INIT; |
1365 | struct stat st; | |
0ac349a9 | 1366 | int error; |
074841ec | 1367 | |
632d8b23 | 1368 | if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0) |
0ac349a9 | 1369 | return -1; |
074841ec | 1370 | |
e9ca852e | 1371 | if ((error = p_stat(git_buf_cstr(&path), &st)) < 0) { |
074841ec CMN |
1372 | if (errno == ENOENT) |
1373 | error = GIT_ENOTFOUND; | |
0ac349a9 | 1374 | } |
e9ca852e RB |
1375 | else if (buffer != NULL) { |
1376 | error = git_futils_readbuffer(&buf, git_buf_cstr(&path)); | |
1377 | git_buf_copy_cstr(buffer, len, &buf); | |
0ac349a9 | 1378 | } |
074841ec | 1379 | |
0ac349a9 VM |
1380 | git_buf_free(&path); |
1381 | git_buf_free(&buf); | |
074841ec | 1382 | |
e9ca852e RB |
1383 | if (!error) |
1384 | error = (int)st.st_size + 1; /* add 1 for NUL byte */ | |
1385 | ||
1386 | return error; | |
074841ec CMN |
1387 | } |
1388 | ||
1389 | int git_repository_message_remove(git_repository *repo) | |
1390 | { | |
0ac349a9 VM |
1391 | git_buf path = GIT_BUF_INIT; |
1392 | int error; | |
074841ec | 1393 | |
632d8b23 | 1394 | if (git_buf_joinpath(&path, repo->path_repository, GIT_MERGE_MSG_FILE) < 0) |
0ac349a9 | 1395 | return -1; |
074841ec CMN |
1396 | |
1397 | error = p_unlink(git_buf_cstr(&path)); | |
1398 | git_buf_free(&path); | |
1399 | ||
1400 | return error; | |
1401 | } | |
47bfa0be RB |
1402 | |
1403 | int git_repository_hashfile( | |
1404 | git_oid *out, | |
1405 | git_repository *repo, | |
1406 | const char *path, | |
1407 | git_otype type, | |
1408 | const char *as_path) | |
1409 | { | |
1410 | int error; | |
1411 | git_vector filters = GIT_VECTOR_INIT; | |
b1127a30 | 1412 | git_file fd = -1; |
47bfa0be RB |
1413 | git_off_t len; |
1414 | git_buf full_path = GIT_BUF_INIT; | |
1415 | ||
a13fb55a RB |
1416 | assert(out && path && repo); /* as_path can be NULL */ |
1417 | ||
1418 | /* At some point, it would be nice if repo could be NULL to just | |
1419 | * apply filter rules defined in system and global files, but for | |
1420 | * now that is not possible because git_filters_load() needs it. | |
1421 | */ | |
47bfa0be RB |
1422 | |
1423 | error = git_path_join_unrooted( | |
1424 | &full_path, path, repo ? git_repository_workdir(repo) : NULL, NULL); | |
1425 | if (error < 0) | |
1426 | return error; | |
1427 | ||
1428 | if (!as_path) | |
1429 | as_path = path; | |
1430 | ||
1431 | /* passing empty string for "as_path" indicated --no-filters */ | |
1432 | if (strlen(as_path) > 0) { | |
1433 | error = git_filters_load(&filters, repo, as_path, GIT_FILTER_TO_ODB); | |
1434 | if (error < 0) | |
1435 | return error; | |
1436 | } else { | |
1437 | error = 0; | |
1438 | } | |
1439 | ||
1440 | /* at this point, error is a count of the number of loaded filters */ | |
1441 | ||
1442 | fd = git_futils_open_ro(full_path.ptr); | |
1443 | if (fd < 0) { | |
1444 | error = fd; | |
1445 | goto cleanup; | |
1446 | } | |
1447 | ||
1448 | len = git_futils_filesize(fd); | |
1449 | if (len < 0) { | |
75050223 | 1450 | error = (int)len; |
47bfa0be RB |
1451 | goto cleanup; |
1452 | } | |
1453 | ||
1454 | if (!git__is_sizet(len)) { | |
1455 | giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); | |
1456 | error = -1; | |
1457 | goto cleanup; | |
1458 | } | |
1459 | ||
75050223 | 1460 | error = git_odb__hashfd_filtered(out, fd, (size_t)len, type, &filters); |
47bfa0be RB |
1461 | |
1462 | cleanup: | |
b1127a30 SS |
1463 | if (fd >= 0) |
1464 | p_close(fd); | |
47bfa0be RB |
1465 | git_filters_free(&filters); |
1466 | git_buf_free(&full_path); | |
1467 | ||
1468 | return error; | |
1469 | } | |
1470 | ||
44af67a8 | 1471 | static bool looks_like_a_branch(const char *refname) |
1472 | { | |
1473 | return git__prefixcmp(refname, GIT_REFS_HEADS_DIR) == 0; | |
1474 | } | |
1475 | ||
1476 | int git_repository_set_head( | |
1477 | git_repository* repo, | |
1478 | const char* refname) | |
1479 | { | |
1480 | git_reference *ref, | |
1481 | *new_head = NULL; | |
1482 | int error; | |
1483 | ||
1484 | assert(repo && refname); | |
1485 | ||
1486 | error = git_reference_lookup(&ref, repo, refname); | |
1487 | if (error < 0 && error != GIT_ENOTFOUND) | |
1488 | return error; | |
1489 | ||
1490 | if (!error) { | |
1491 | if (git_reference_is_branch(ref)) | |
1492 | error = git_reference_create_symbolic(&new_head, repo, GIT_HEAD_FILE, git_reference_name(ref), 1); | |
1493 | else | |
1494 | error = git_repository_set_head_detached(repo, git_reference_oid(ref)); | |
1495 | } else if (looks_like_a_branch(refname)) | |
1496 | error = git_reference_create_symbolic(&new_head, repo, GIT_HEAD_FILE, refname, 1); | |
1497 | ||
1498 | git_reference_free(ref); | |
1499 | git_reference_free(new_head); | |
1500 | return error; | |
1501 | } | |
1502 | ||
4ebe38bd | 1503 | int git_repository_set_head_detached( |
1504 | git_repository* repo, | |
1505 | const git_oid* commitish) | |
1506 | { | |
1507 | int error; | |
1508 | git_object *object, | |
1509 | *peeled = NULL; | |
1510 | git_reference *new_head = NULL; | |
1511 | ||
1512 | assert(repo && commitish); | |
1513 | ||
1514 | if ((error = git_object_lookup(&object, repo, commitish, GIT_OBJ_ANY)) < 0) | |
1515 | return error; | |
1516 | ||
1517 | if ((error = git_object_peel(&peeled, object, GIT_OBJ_COMMIT)) < 0) | |
1518 | goto cleanup; | |
1519 | ||
1520 | error = git_reference_create_oid(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), 1); | |
1521 | ||
1522 | cleanup: | |
1523 | git_object_free(object); | |
1524 | git_object_free(peeled); | |
1525 | git_reference_free(new_head); | |
1526 | return error; | |
1527 | } | |
1528 | ||
3f4c3072 | 1529 | int git_repository_detach_head( |
1530 | git_repository* repo) | |
1531 | { | |
1532 | git_reference *old_head = NULL, | |
1533 | *new_head = NULL; | |
1534 | git_object *object = NULL; | |
8b05bea8 | 1535 | int error; |
3f4c3072 | 1536 | |
1537 | assert(repo); | |
1538 | ||
8b05bea8 | 1539 | if ((error = git_repository_head(&old_head, repo)) < 0) |
1540 | return error; | |
3f4c3072 | 1541 | |
8b05bea8 | 1542 | if ((error = git_object_lookup(&object, repo, git_reference_oid(old_head), GIT_OBJ_COMMIT)) < 0) |
3f4c3072 | 1543 | goto cleanup; |
1544 | ||
1545 | error = git_reference_create_oid(&new_head, repo, GIT_HEAD_FILE, git_reference_oid(old_head), 1); | |
1546 | ||
1547 | cleanup: | |
1548 | git_object_free(object); | |
1549 | git_reference_free(old_head); | |
1550 | git_reference_free(new_head); | |
1551 | return error; | |
1552 | } | |
632d8b23 | 1553 | |
31966d20 | 1554 | /** |
1555 | * Loosely ported from git.git | |
1556 | * https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh#L198-289 | |
1557 | */ | |
632d8b23 ET |
1558 | int git_repository_state(git_repository *repo) |
1559 | { | |
1560 | git_buf repo_path = GIT_BUF_INIT; | |
1561 | int state = GIT_REPOSITORY_STATE_NONE; | |
1562 | ||
1563 | assert(repo); | |
1564 | ||
1565 | if (git_buf_puts(&repo_path, repo->path_repository) < 0) | |
1566 | return -1; | |
1567 | ||
31966d20 | 1568 | if (git_path_contains_file(&repo_path, GIT_REBASE_MERGE_INTERACTIVE_FILE)) |
1569 | state = GIT_REPOSITORY_STATE_REBASE_INTERACTIVE; | |
1570 | else if (git_path_contains_dir(&repo_path, GIT_REBASE_MERGE_DIR)) | |
1571 | state = GIT_REPOSITORY_STATE_REBASE_MERGE; | |
1572 | else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_REBASING_FILE)) | |
1573 | state = GIT_REPOSITORY_STATE_REBASE; | |
1574 | else if (git_path_contains_file(&repo_path, GIT_REBASE_APPLY_APPLYING_FILE)) | |
1575 | state = GIT_REPOSITORY_STATE_APPLY_MAILBOX; | |
1576 | else if (git_path_contains_dir(&repo_path, GIT_REBASE_APPLY_DIR)) | |
1577 | state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE; | |
1578 | else if (git_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE)) | |
632d8b23 ET |
1579 | state = GIT_REPOSITORY_STATE_MERGE; |
1580 | else if(git_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE)) | |
1581 | state = GIT_REPOSITORY_STATE_REVERT; | |
1582 | else if(git_path_contains_file(&repo_path, GIT_CHERRY_PICK_HEAD_FILE)) | |
1583 | state = GIT_REPOSITORY_STATE_CHERRY_PICK; | |
31966d20 | 1584 | else if(git_path_contains_file(&repo_path, GIT_BISECT_LOG_FILE)) |
1585 | state = GIT_REPOSITORY_STATE_BISECT; | |
632d8b23 ET |
1586 | |
1587 | git_buf_free(&repo_path); | |
1588 | return state; | |
1589 | } |