]> git.proxmox.com Git - libgit2.git/blame - src/checkout.c
note: rename the id getter to git_note_id()
[libgit2.git] / src / checkout.c
CommitLineData
14741d62 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
14741d62
BS
3 *
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.
6 */
7
8#include <assert.h>
9
cf208031
RB
10#include "checkout.h"
11
14741d62
BS
12#include "git2/repository.h"
13#include "git2/refs.h"
14#include "git2/tree.h"
24b0d3d5 15#include "git2/blob.h"
8651c10f 16#include "git2/config.h"
3aa443a9 17#include "git2/diff.h"
e0548c0e 18#include "git2/submodule.h"
e1807113 19#include "git2/sys/index.h"
14741d62 20
14741d62 21#include "refs.h"
24b0d3d5 22#include "repository.h"
114f5a6c 23#include "index.h"
0e874b12 24#include "filter.h"
41ad70d0 25#include "blob.h"
32def5af 26#include "diff.h"
ad9a921b 27#include "pathspec.h"
3658e81e 28#include "buf_text.h"
7fa73de1 29#include "merge_file.h"
c929d6b7 30#include "path.h"
14741d62 31
77cffa31 32/* See docs/checkout-internals.md for more information */
cf208031 33
7fa73de1
ET
34enum {
35 CHECKOUT_ACTION__NONE = 0,
36 CHECKOUT_ACTION__REMOVE = 1,
37 CHECKOUT_ACTION__UPDATE_BLOB = 2,
38 CHECKOUT_ACTION__UPDATE_SUBMODULE = 4,
39 CHECKOUT_ACTION__CONFLICT = 8,
40 CHECKOUT_ACTION__UPDATE_CONFLICT = 16,
41 CHECKOUT_ACTION__MAX = 16,
42 CHECKOUT_ACTION__DEFER_REMOVE = 32,
43 CHECKOUT_ACTION__REMOVE_AND_UPDATE =
44 (CHECKOUT_ACTION__UPDATE_BLOB | CHECKOUT_ACTION__REMOVE),
45};
46
47typedef struct {
48 git_repository *repo;
3ff1d123 49 git_diff *diff;
7fa73de1
ET
50 git_checkout_opts opts;
51 bool opts_free_baseline;
52 char *pfx;
53 git_index *index;
54 git_pool pool;
55 git_vector removes;
56 git_vector conflicts;
57 git_buf path;
58 size_t workdir_len;
59 unsigned int strategy;
60 int can_symlink;
61 bool reload_submodules;
62 size_t total_steps;
63 size_t completed_steps;
64} checkout_data;
65
66typedef struct {
67 const git_index_entry *ancestor;
68 const git_index_entry *ours;
69 const git_index_entry *theirs;
70
71 int name_collision:1,
72 directoryfile:1,
6b92c99b 73 one_to_two:1,
0ef19fe1
ET
74 binary:1,
75 submodule:1;
7fa73de1
ET
76} checkout_conflictdata;
77
cf208031 78static int checkout_notify(
7e5c8a5b 79 checkout_data *data,
cf208031
RB
80 git_checkout_notify_t why,
81 const git_diff_delta *delta,
16a666d3 82 const git_index_entry *wditem)
cf208031 83{
16a666d3 84 git_diff_file wdfile;
7e5c8a5b 85 const git_diff_file *baseline = NULL, *target = NULL, *workdir = NULL;
56543a60 86 const char *path = NULL;
7e5c8a5b 87
25e0b157
RB
88 if (!data->opts.notify_cb ||
89 (why & data->opts.notify_flags) == 0)
7e5c8a5b
RB
90 return 0;
91
16a666d3
RB
92 if (wditem) {
93 memset(&wdfile, 0, sizeof(wdfile));
7e5c8a5b 94
16a666d3
RB
95 git_oid_cpy(&wdfile.oid, &wditem->oid);
96 wdfile.path = wditem->path;
97 wdfile.size = wditem->file_size;
71a3d27e 98 wdfile.flags = GIT_DIFF_FLAG_VALID_OID;
16a666d3 99 wdfile.mode = wditem->mode;
7e5c8a5b 100
16a666d3 101 workdir = &wdfile;
56543a60
RB
102
103 path = wditem->path;
7e5c8a5b
RB
104 }
105
16a666d3 106 if (delta) {
7e5c8a5b
RB
107 switch (delta->status) {
108 case GIT_DELTA_UNMODIFIED:
109 case GIT_DELTA_MODIFIED:
110 case GIT_DELTA_TYPECHANGE:
111 default:
16a666d3
RB
112 baseline = &delta->old_file;
113 target = &delta->new_file;
7e5c8a5b
RB
114 break;
115 case GIT_DELTA_ADDED:
116 case GIT_DELTA_IGNORED:
117 case GIT_DELTA_UNTRACKED:
16a666d3 118 target = &delta->new_file;
7e5c8a5b
RB
119 break;
120 case GIT_DELTA_DELETED:
16a666d3 121 baseline = &delta->old_file;
7e5c8a5b
RB
122 break;
123 }
56543a60
RB
124
125 path = delta->old_file.path;
7e5c8a5b
RB
126 }
127
26c1cb91
RB
128 {
129 int error = data->opts.notify_cb(
130 why, path, baseline, target, workdir, data->opts.notify_payload);
131
132 return giterr_set_after_callback_function(
133 error, "git_checkout notification");
134 }
cf208031
RB
135}
136
137static bool checkout_is_workdir_modified(
7e5c8a5b 138 checkout_data *data,
5cf9875a
RB
139 const git_diff_file *baseitem,
140 const git_index_entry *wditem)
cf208031
RB
141{
142 git_oid oid;
0da62c5c 143 const git_index_entry *ie;
cf208031 144
e0548c0e
RB
145 /* handle "modified" submodule */
146 if (wditem->mode == GIT_FILEMODE_COMMIT) {
147 git_submodule *sm;
148 unsigned int sm_status = 0;
149 const git_oid *sm_oid = NULL;
150
151 if (git_submodule_lookup(&sm, data->repo, wditem->path) < 0 ||
152 git_submodule_status(&sm_status, sm) < 0)
153 return true;
154
155 if (GIT_SUBMODULE_STATUS_IS_WD_DIRTY(sm_status))
156 return true;
157
158 sm_oid = git_submodule_wd_id(sm);
159 if (!sm_oid)
160 return false;
161
b7f167da 162 return (git_oid__cmp(&baseitem->oid, sm_oid) != 0);
e0548c0e
RB
163 }
164
0da62c5c
ET
165 /* Look at the cache to decide if the workdir is modified. If not,
166 * we can simply compare the oid in the cache to the baseitem instead
167 * of hashing the file.
168 */
169 if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) {
170 if (wditem->mtime.seconds == ie->mtime.seconds &&
171 wditem->mtime.nanoseconds == ie->mtime.nanoseconds &&
172 wditem->file_size == ie->file_size)
b7f167da 173 return (git_oid__cmp(&baseitem->oid, &ie->oid) != 0);
0da62c5c
ET
174 }
175
5cf9875a
RB
176 /* depending on where base is coming from, we may or may not know
177 * the actual size of the data, so we can't rely on this shortcut.
178 */
179 if (baseitem->size && wditem->file_size != baseitem->size)
cf208031
RB
180 return true;
181
182 if (git_diff__oid_for_file(
5cf9875a
RB
183 data->repo, wditem->path, wditem->mode,
184 wditem->file_size, &oid) < 0)
cf208031
RB
185 return false;
186
b7f167da 187 return (git_oid__cmp(&baseitem->oid, &oid) != 0);
7e5c8a5b
RB
188}
189
190#define CHECKOUT_ACTION_IF(FLAG,YES,NO) \
191 ((data->strategy & GIT_CHECKOUT_##FLAG) ? CHECKOUT_ACTION__##YES : CHECKOUT_ACTION__##NO)
192
7e5c8a5b 193static int checkout_action_common(
25e0b157 194 int *action,
7e5c8a5b 195 checkout_data *data,
cf208031 196 const git_diff_delta *delta,
7e5c8a5b
RB
197 const git_index_entry *wd)
198{
199 git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
200
7e5c8a5b 201 if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
25e0b157 202 *action = (*action & ~CHECKOUT_ACTION__REMOVE);
7e5c8a5b 203
25e0b157 204 if ((*action & CHECKOUT_ACTION__UPDATE_BLOB) != 0) {
7e5c8a5b 205 if (S_ISGITLINK(delta->new_file.mode))
25e0b157 206 *action = (*action & ~CHECKOUT_ACTION__UPDATE_BLOB) |
7e5c8a5b
RB
207 CHECKOUT_ACTION__UPDATE_SUBMODULE;
208
55d3a390
RB
209 /* to "update" a symlink, we must remove the old one first */
210 if (delta->new_file.mode == GIT_FILEMODE_LINK && wd != NULL)
25e0b157 211 *action |= CHECKOUT_ACTION__REMOVE;
55d3a390 212
7e5c8a5b
RB
213 notify = GIT_CHECKOUT_NOTIFY_UPDATED;
214 }
215
25e0b157 216 if ((*action & CHECKOUT_ACTION__CONFLICT) != 0)
7e5c8a5b
RB
217 notify = GIT_CHECKOUT_NOTIFY_CONFLICT;
218
25e0b157 219 return checkout_notify(data, notify, delta, wd);
7e5c8a5b
RB
220}
221
222static int checkout_action_no_wd(
25e0b157 223 int *action,
7e5c8a5b
RB
224 checkout_data *data,
225 const git_diff_delta *delta)
cf208031 226{
25e0b157
RB
227 int error = 0;
228
229 *action = CHECKOUT_ACTION__NONE;
cf208031 230
7e5c8a5b
RB
231 switch (delta->status) {
232 case GIT_DELTA_UNMODIFIED: /* case 12 */
25e0b157
RB
233 error = checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL);
234 if (error)
235 return error;
236 *action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE);
7e5c8a5b
RB
237 break;
238 case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */
25e0b157 239 *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
7e5c8a5b 240 break;
36fd9e30 241 case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */
25e0b157 242 *action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, CONFLICT);
36fd9e30 243 break;
7e5c8a5b
RB
244 case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/
245 if (delta->new_file.mode == GIT_FILEMODE_TREE)
25e0b157 246 *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
7e5c8a5b
RB
247 break;
248 case GIT_DELTA_DELETED: /* case 8 or 25 */
249 default: /* impossible */
250 break;
cf208031
RB
251 }
252
25e0b157 253 return checkout_action_common(action, data, delta, NULL);
7e5c8a5b
RB
254}
255
256static int checkout_action_wd_only(
257 checkout_data *data,
258 git_iterator *workdir,
259 const git_index_entry *wd,
260 git_vector *pathspec)
261{
25e0b157 262 int error = 0;
5cf9875a 263 bool remove = false;
7e5c8a5b
RB
264 git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
265
d2ce27dd 266 if (!git_pathspec__match(
40342bd2
RB
267 pathspec, wd->path,
268 (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
d2ce27dd 269 git_iterator_ignore_case(workdir), NULL, NULL))
7e5c8a5b
RB
270 return 0;
271
5cf9875a 272 /* check if item is tracked in the index but not in the checkout diff */
817d6251
RB
273 if (data->index != NULL) {
274 if (wd->mode != GIT_FILEMODE_TREE) {
25e0b157 275 if (!(error = git_index_find(NULL, data->index, wd->path))) {
817d6251
RB
276 notify = GIT_CHECKOUT_NOTIFY_DIRTY;
277 remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
54a1a042
ET
278 } else if (error != GIT_ENOTFOUND)
279 return error;
25e0b157
RB
280 else
281 giterr_clear();
817d6251
RB
282 } else {
283 /* for tree entries, we have to see if there are any index
284 * entries that are contained inside that tree
285 */
286 size_t pos = git_index__prefix_position(data->index, wd->path);
287 const git_index_entry *e = git_index_get_byindex(data->index, pos);
288
289 if (e != NULL && data->diff->pfxcomp(e->path, wd->path) == 0) {
290 notify = GIT_CHECKOUT_NOTIFY_DIRTY;
291 remove = ((data->strategy & GIT_CHECKOUT_FORCE) != 0);
292 }
293 }
5cf9875a 294 }
817d6251
RB
295
296 if (notify != GIT_CHECKOUT_NOTIFY_NONE)
297 /* found in index */;
5cf9875a 298 else if (git_iterator_current_is_ignored(workdir)) {
7e5c8a5b
RB
299 notify = GIT_CHECKOUT_NOTIFY_IGNORED;
300 remove = ((data->strategy & GIT_CHECKOUT_REMOVE_IGNORED) != 0);
5cf9875a
RB
301 }
302 else {
7e5c8a5b
RB
303 notify = GIT_CHECKOUT_NOTIFY_UNTRACKED;
304 remove = ((data->strategy & GIT_CHECKOUT_REMOVE_UNTRACKED) != 0);
cf208031
RB
305 }
306
25e0b157 307 error = checkout_notify(data, notify, NULL, wd);
cf208031 308
25e0b157 309 if (!error && remove) {
7e5c8a5b
RB
310 char *path = git_pool_strdup(&data->pool, wd->path);
311 GITERR_CHECK_ALLOC(path);
312
25e0b157 313 error = git_vector_insert(&data->removes, path);
7e5c8a5b
RB
314 }
315
25e0b157 316 return error;
7e5c8a5b
RB
317}
318
e0548c0e
RB
319static bool submodule_is_config_only(
320 checkout_data *data,
321 const char *path)
322{
323 git_submodule *sm = NULL;
324 unsigned int sm_loc = 0;
325
326 if (git_submodule_lookup(&sm, data->repo, path) < 0 ||
327 git_submodule_location(&sm_loc, sm) < 0 ||
328 sm_loc == GIT_SUBMODULE_STATUS_IN_CONFIG)
329 return true;
330
331 return false;
332}
333
7e5c8a5b 334static int checkout_action_with_wd(
25e0b157 335 int *action,
7e5c8a5b
RB
336 checkout_data *data,
337 const git_diff_delta *delta,
81a2012d 338 git_iterator *workdir,
7e5c8a5b
RB
339 const git_index_entry *wd)
340{
25e0b157 341 *action = CHECKOUT_ACTION__NONE;
7e5c8a5b
RB
342
343 switch (delta->status) {
344 case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */
e0548c0e 345 if (checkout_is_workdir_modified(data, &delta->old_file, wd)) {
25e0b157
RB
346 GITERR_CHECK_ERROR(
347 checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) );
348 *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE);
cf208031 349 }
7e5c8a5b
RB
350 break;
351 case GIT_DELTA_ADDED: /* case 3, 4 or 6 */
81a2012d
ET
352 if (git_iterator_current_is_ignored(workdir))
353 *action = CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED, CONFLICT, UPDATE_BLOB);
354 else
355 *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
7e5c8a5b
RB
356 break;
357 case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */
358 if (checkout_is_workdir_modified(data, &delta->old_file, wd))
25e0b157 359 *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
7e5c8a5b 360 else
25e0b157 361 *action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE);
7e5c8a5b
RB
362 break;
363 case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */
364 if (checkout_is_workdir_modified(data, &delta->old_file, wd))
25e0b157 365 *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT);
7e5c8a5b 366 else
25e0b157 367 *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
7e5c8a5b
RB
368 break;
369 case GIT_DELTA_TYPECHANGE: /* case 22, 23, 29, 30 */
e0548c0e
RB
370 if (delta->old_file.mode == GIT_FILEMODE_TREE) {
371 if (wd->mode == GIT_FILEMODE_TREE)
372 /* either deleting items in old tree will delete the wd dir,
373 * or we'll get a conflict when we attempt blob update...
374 */
25e0b157 375 *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
e0548c0e
RB
376 else if (wd->mode == GIT_FILEMODE_COMMIT) {
377 /* workdir is possibly a "phantom" submodule - treat as a
378 * tree if the only submodule info came from the config
379 */
380 if (submodule_is_config_only(data, wd->path))
25e0b157 381 *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
e0548c0e 382 else
25e0b157 383 *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
e0548c0e 384 } else
25e0b157 385 *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
e0548c0e 386 }
7e5c8a5b 387 else if (checkout_is_workdir_modified(data, &delta->old_file, wd))
25e0b157 388 *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
7e5c8a5b 389 else
25e0b157 390 *action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE);
e0548c0e
RB
391
392 /* don't update if the typechange is to a tree */
393 if (delta->new_file.mode == GIT_FILEMODE_TREE)
25e0b157 394 *action = (*action & ~CHECKOUT_ACTION__UPDATE_BLOB);
7e5c8a5b
RB
395 break;
396 default: /* impossible */
397 break;
cf208031
RB
398 }
399
25e0b157 400 return checkout_action_common(action, data, delta, wd);
7e5c8a5b 401}
cf208031 402
7e5c8a5b 403static int checkout_action_with_wd_blocker(
25e0b157 404 int *action,
7e5c8a5b
RB
405 checkout_data *data,
406 const git_diff_delta *delta,
407 const git_index_entry *wd)
408{
25e0b157 409 *action = CHECKOUT_ACTION__NONE;
cf208031 410
7e5c8a5b
RB
411 switch (delta->status) {
412 case GIT_DELTA_UNMODIFIED:
413 /* should show delta as dirty / deleted */
25e0b157
RB
414 GITERR_CHECK_ERROR(
415 checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) );
416 *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, NONE);
7e5c8a5b
RB
417 break;
418 case GIT_DELTA_ADDED:
419 case GIT_DELTA_MODIFIED:
25e0b157 420 *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
7e5c8a5b
RB
421 break;
422 case GIT_DELTA_DELETED:
25e0b157 423 *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT);
7e5c8a5b
RB
424 break;
425 case GIT_DELTA_TYPECHANGE:
426 /* not 100% certain about this... */
25e0b157 427 *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
7e5c8a5b
RB
428 break;
429 default: /* impossible */
430 break;
cf208031
RB
431 }
432
25e0b157 433 return checkout_action_common(action, data, delta, wd);
7e5c8a5b
RB
434}
435
436static int checkout_action_with_wd_dir(
25e0b157 437 int *action,
7e5c8a5b
RB
438 checkout_data *data,
439 const git_diff_delta *delta,
bf4a577c 440 git_iterator *workdir,
7e5c8a5b
RB
441 const git_index_entry *wd)
442{
25e0b157 443 *action = CHECKOUT_ACTION__NONE;
7e5c8a5b
RB
444
445 switch (delta->status) {
446 case GIT_DELTA_UNMODIFIED: /* case 19 or 24 (or 34 but not really) */
25e0b157
RB
447 GITERR_CHECK_ERROR(
448 checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, NULL));
449 GITERR_CHECK_ERROR(
450 checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd));
7e5c8a5b
RB
451 break;
452 case GIT_DELTA_ADDED:/* case 4 (and 7 for dir) */
453 case GIT_DELTA_MODIFIED: /* case 20 (or 37 but not really) */
e0548c0e
RB
454 if (delta->old_file.mode == GIT_FILEMODE_COMMIT)
455 /* expected submodule (and maybe found one) */;
456 else if (delta->new_file.mode != GIT_FILEMODE_TREE)
bf4a577c
ET
457 *action = git_iterator_current_is_ignored(workdir) ?
458 CHECKOUT_ACTION_IF(DONT_OVERWRITE_IGNORED, CONFLICT, REMOVE_AND_UPDATE) :
459 CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
7e5c8a5b
RB
460 break;
461 case GIT_DELTA_DELETED: /* case 11 (and 27 for dir) */
25e0b157
RB
462 if (delta->old_file.mode != GIT_FILEMODE_TREE)
463 GITERR_CHECK_ERROR(
464 checkout_notify(data, GIT_CHECKOUT_NOTIFY_UNTRACKED, NULL, wd));
7e5c8a5b
RB
465 break;
466 case GIT_DELTA_TYPECHANGE: /* case 24 or 31 */
7e5c8a5b 467 if (delta->old_file.mode == GIT_FILEMODE_TREE) {
e0548c0e
RB
468 /* For typechange from dir, remove dir and add blob, but it is
469 * not safe to remove dir if it contains modified files.
470 * However, safely removing child files will remove the parent
471 * directory if is it left empty, so we can defer removing the
472 * dir and it will succeed if no children are left.
473 */
25e0b157
RB
474 *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
475 if (*action != CHECKOUT_ACTION__NONE)
476 *action |= CHECKOUT_ACTION__DEFER_REMOVE;
7e5c8a5b 477 }
e0548c0e
RB
478 else if (delta->new_file.mode != GIT_FILEMODE_TREE)
479 /* For typechange to dir, dir is already created so no action */
25e0b157 480 *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT);
7e5c8a5b
RB
481 break;
482 default: /* impossible */
483 break;
cf208031
RB
484 }
485
25e0b157 486 return checkout_action_common(action, data, delta, wd);
cf208031
RB
487}
488
7e5c8a5b 489static int checkout_action(
25e0b157 490 int *action,
7e5c8a5b 491 checkout_data *data,
cf208031 492 git_diff_delta *delta,
7e5c8a5b 493 git_iterator *workdir,
25e0b157 494 const git_index_entry **wditem,
cf208031
RB
495 git_vector *pathspec)
496{
25e0b157 497 int cmp = -1, error;
7e5c8a5b
RB
498 int (*strcomp)(const char *, const char *) = data->diff->strcomp;
499 int (*pfxcomp)(const char *str, const char *pfx) = data->diff->pfxcomp;
25e0b157 500 int (*advance)(const git_index_entry **, git_iterator *) = NULL;
7e5c8a5b
RB
501
502 /* move workdir iterator to follow along with deltas */
503
504 while (1) {
25e0b157
RB
505 const git_index_entry *wd = *wditem;
506
7e5c8a5b 507 if (!wd)
25e0b157 508 return checkout_action_no_wd(action, data, delta);
169dc616 509
7e5c8a5b
RB
510 cmp = strcomp(wd->path, delta->old_file.path);
511
512 /* 1. wd before delta ("a/a" before "a/b")
513 * 2. wd prefixes delta & should expand ("a/" before "a/b")
514 * 3. wd prefixes delta & cannot expand ("a/b" before "a/b/c")
515 * 4. wd equals delta ("a/b" and "a/b")
516 * 5. wd after delta & delta prefixes wd ("a/b/c" after "a/b/" or "a/b")
517 * 6. wd after delta ("a/c" after "a/b")
518 */
519
520 if (cmp < 0) {
521 cmp = pfxcomp(delta->old_file.path, wd->path);
522
d8889d2b 523 if (cmp == 0) {
817d6251
RB
524 if (wd->mode == GIT_FILEMODE_TREE) {
525 /* case 2 - entry prefixed by workdir tree */
25e0b157
RB
526 error = git_iterator_advance_into_or_over(wditem, workdir);
527 if (error < 0 && error != GIT_ITEROVER)
528 goto done;
817d6251
RB
529 continue;
530 }
531
532 /* case 3 maybe - wd contains non-dir where dir expected */
533 if (delta->old_file.path[strlen(wd->path)] == '/') {
25e0b157
RB
534 error = checkout_action_with_wd_blocker(
535 action, data, delta, wd);
536 advance = git_iterator_advance;
537 goto done;
817d6251 538 }
7e5c8a5b 539 }
cf208031 540
7e5c8a5b 541 /* case 1 - handle wd item (if it matches pathspec) */
25e0b157
RB
542 error = checkout_action_wd_only(data, workdir, wd, pathspec);
543 if (error)
544 goto done;
545 if ((error = git_iterator_advance(wditem, workdir)) < 0 &&
cee695ae 546 error != GIT_ITEROVER)
25e0b157 547 goto done;
7e5c8a5b
RB
548 continue;
549 }
cf208031 550
7e5c8a5b
RB
551 if (cmp == 0) {
552 /* case 4 */
81a2012d 553 error = checkout_action_with_wd(action, data, delta, workdir, wd);
25e0b157
RB
554 advance = git_iterator_advance;
555 goto done;
7e5c8a5b 556 }
cf208031 557
7e5c8a5b 558 cmp = pfxcomp(wd->path, delta->old_file.path);
cf208031 559
7e5c8a5b 560 if (cmp == 0) { /* case 5 */
817d6251 561 if (wd->path[strlen(delta->old_file.path)] != '/')
25e0b157 562 return checkout_action_no_wd(action, data, delta);
e0548c0e
RB
563
564 if (delta->status == GIT_DELTA_TYPECHANGE) {
565 if (delta->old_file.mode == GIT_FILEMODE_TREE) {
81a2012d 566 error = checkout_action_with_wd(action, data, delta, workdir, wd);
25e0b157
RB
567 advance = git_iterator_advance_into;
568 goto done;
e0548c0e
RB
569 }
570
571 if (delta->new_file.mode == GIT_FILEMODE_TREE ||
572 delta->new_file.mode == GIT_FILEMODE_COMMIT ||
573 delta->old_file.mode == GIT_FILEMODE_COMMIT)
574 {
81a2012d 575 error = checkout_action_with_wd(action, data, delta, workdir, wd);
25e0b157
RB
576 advance = git_iterator_advance;
577 goto done;
e0548c0e 578 }
cf208031 579 }
cf208031 580
bf4a577c 581 return checkout_action_with_wd_dir(action, data, delta, workdir, wd);
7e5c8a5b 582 }
cf208031 583
7e5c8a5b 584 /* case 6 - wd is after delta */
25e0b157 585 return checkout_action_no_wd(action, data, delta);
cf208031
RB
586 }
587
25e0b157
RB
588done:
589 if (!error && advance != NULL &&
590 (error = advance(wditem, workdir)) < 0) {
591 *wditem = NULL;
592 if (error == GIT_ITEROVER)
593 error = 0;
594 }
595
596 return error;
cf208031
RB
597}
598
d8889d2b
RB
599static int checkout_remaining_wd_items(
600 checkout_data *data,
601 git_iterator *workdir,
602 const git_index_entry *wd,
603 git_vector *spec)
604{
605 int error = 0;
d8889d2b
RB
606
607 while (wd && !error) {
817d6251 608 if (!(error = checkout_action_wd_only(data, workdir, wd, spec)))
169dc616 609 error = git_iterator_advance(&wd, workdir);
d8889d2b
RB
610 }
611
cee695ae
RB
612 if (error == GIT_ITEROVER)
613 error = 0;
614
d8889d2b
RB
615 return error;
616}
617
7fa73de1
ET
618GIT_INLINE(int) checkout_idxentry_cmp(
619 const git_index_entry *a,
620 const git_index_entry *b)
621{
622 if (!a && !b)
623 return 0;
624 else if (!a && b)
625 return -1;
626 else if(a && !b)
627 return 1;
628 else
629 return strcmp(a->path, b->path);
630}
631
632static int checkout_conflictdata_cmp(const void *a, const void *b)
633{
634 const checkout_conflictdata *ca = a;
635 const checkout_conflictdata *cb = b;
636 int diff;
637
638 if ((diff = checkout_idxentry_cmp(ca->ancestor, cb->ancestor)) == 0 &&
639 (diff = checkout_idxentry_cmp(ca->ours, cb->theirs)) == 0)
640 diff = checkout_idxentry_cmp(ca->theirs, cb->theirs);
641
642 return diff;
643}
644
645int checkout_conflictdata_empty(const git_vector *conflicts, size_t idx)
646{
647 checkout_conflictdata *conflict;
648
649 if ((conflict = git_vector_get(conflicts, idx)) == NULL)
650 return -1;
651
652 if (conflict->ancestor || conflict->ours || conflict->theirs)
653 return 0;
654
655 git__free(conflict);
656 return 1;
657}
658
659GIT_INLINE(bool) conflict_pathspec_match(
660 checkout_data *data,
661 git_iterator *workdir,
662 git_vector *pathspec,
663 const git_index_entry *ancestor,
664 const git_index_entry *ours,
665 const git_index_entry *theirs)
666{
667 /* if the pathspec matches ours *or* theirs, proceed */
668 if (ours && git_pathspec__match(pathspec, ours->path,
669 (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
670 git_iterator_ignore_case(workdir), NULL, NULL))
671 return true;
672
673 if (theirs && git_pathspec__match(pathspec, theirs->path,
674 (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
675 git_iterator_ignore_case(workdir), NULL, NULL))
676 return true;
677
678 if (ancestor && git_pathspec__match(pathspec, ancestor->path,
679 (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
680 git_iterator_ignore_case(workdir), NULL, NULL))
681 return true;
682
683 return false;
684}
685
0ef19fe1
ET
686GIT_INLINE(int) checkout_conflict_detect_submodule(checkout_conflictdata *conflict)
687{
688 conflict->submodule = ((conflict->ancestor && S_ISGITLINK(conflict->ancestor->mode)) ||
689 (conflict->ours && S_ISGITLINK(conflict->ours->mode)) ||
690 (conflict->theirs && S_ISGITLINK(conflict->theirs->mode)));
691 return 0;
692}
693
6b92c99b
ET
694GIT_INLINE(int) checkout_conflict_detect_binary(git_repository *repo, checkout_conflictdata *conflict)
695{
696 git_blob *ancestor_blob = NULL, *our_blob = NULL, *their_blob = NULL;
697 int error = 0;
698
0ef19fe1
ET
699 if (conflict->submodule)
700 return 0;
701
6b92c99b
ET
702 if (conflict->ancestor) {
703 if ((error = git_blob_lookup(&ancestor_blob, repo, &conflict->ancestor->oid)) < 0)
704 goto done;
705
706 conflict->binary = git_blob_is_binary(ancestor_blob);
707 }
708
709 if (!conflict->binary && conflict->ours) {
710 if ((error = git_blob_lookup(&our_blob, repo, &conflict->ours->oid)) < 0)
711 goto done;
712
713 conflict->binary = git_blob_is_binary(our_blob);
714 }
715
716 if (!conflict->binary && conflict->theirs) {
717 if ((error = git_blob_lookup(&their_blob, repo, &conflict->theirs->oid)) < 0)
718 goto done;
719
720 conflict->binary = git_blob_is_binary(their_blob);
721 }
722
723done:
724 git_blob_free(ancestor_blob);
725 git_blob_free(our_blob);
726 git_blob_free(their_blob);
727
728 return error;
729}
730
7fa73de1
ET
731static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec)
732{
733 git_index_conflict_iterator *iterator = NULL;
734 const git_index_entry *ancestor, *ours, *theirs;
735 checkout_conflictdata *conflict;
736 int error = 0;
737
738 if ((error = git_index_conflict_iterator_new(&iterator, data->index)) < 0)
739 goto done;
740
741 data->conflicts._cmp = checkout_conflictdata_cmp;
742
743 /* Collect the conflicts */
744 while ((error = git_index_conflict_next(&ancestor, &ours, &theirs, iterator)) == 0) {
745 if (!conflict_pathspec_match(data, workdir, pathspec, ancestor, ours, theirs))
746 continue;
747
748 conflict = git__calloc(1, sizeof(checkout_conflictdata));
749 GITERR_CHECK_ALLOC(conflict);
750
751 conflict->ancestor = ancestor;
752 conflict->ours = ours;
753 conflict->theirs = theirs;
754
0ef19fe1 755 if ((error = checkout_conflict_detect_submodule(conflict)) < 0 ||
ab4bcc03
BS
756 (error = checkout_conflict_detect_binary(data->repo, conflict)) < 0)
757 {
758 git__free(conflict);
6b92c99b 759 goto done;
ab4bcc03 760 }
6b92c99b 761
7fa73de1
ET
762 git_vector_insert(&data->conflicts, conflict);
763 }
764
765 if (error == GIT_ITEROVER)
766 error = 0;
767
768done:
769 git_index_conflict_iterator_free(iterator);
770
771 return error;
772}
773
774GIT_INLINE(int) checkout_conflicts_cmp_entry(
775 const char *path,
776 const git_index_entry *entry)
777{
778 return strcmp((const char *)path, entry->path);
779}
780
781static int checkout_conflicts_cmp_ancestor(const void *p, const void *c)
782{
783 const char *path = p;
784 const checkout_conflictdata *conflict = c;
785
786 if (!conflict->ancestor)
787 return 1;
788
789 return checkout_conflicts_cmp_entry(path, conflict->ancestor);
790}
791
792static checkout_conflictdata *checkout_conflicts_search_ancestor(
793 checkout_data *data,
794 const char *path)
795{
796 size_t pos;
797
798 if (git_vector_bsearch2(&pos, &data->conflicts, checkout_conflicts_cmp_ancestor, path) < 0)
799 return NULL;
800
801 return git_vector_get(&data->conflicts, pos);
802}
803
804static checkout_conflictdata *checkout_conflicts_search_branch(
805 checkout_data *data,
806 const char *path)
807{
808 checkout_conflictdata *conflict;
809 size_t i;
810
811 git_vector_foreach(&data->conflicts, i, conflict) {
812 int cmp = -1;
813
814 if (conflict->ancestor)
815 break;
816
817 if (conflict->ours)
818 cmp = checkout_conflicts_cmp_entry(path, conflict->ours);
819 else if (conflict->theirs)
820 cmp = checkout_conflicts_cmp_entry(path, conflict->theirs);
821
822 if (cmp == 0)
823 return conflict;
824 }
825
826 return NULL;
827}
828
829static int checkout_conflicts_load_byname_entry(
830 checkout_conflictdata **ancestor_out,
831 checkout_conflictdata **ours_out,
832 checkout_conflictdata **theirs_out,
833 checkout_data *data,
834 const git_index_name_entry *name_entry)
835{
836 checkout_conflictdata *ancestor, *ours = NULL, *theirs = NULL;
837 int error = 0;
838
839 *ancestor_out = NULL;
840 *ours_out = NULL;
841 *theirs_out = NULL;
842
843 if (!name_entry->ancestor) {
844 giterr_set(GITERR_INDEX, "A NAME entry exists without an ancestor");
845 error = -1;
846 goto done;
847 }
848
849 if (!name_entry->ours && !name_entry->theirs) {
850 giterr_set(GITERR_INDEX, "A NAME entry exists without an ours or theirs");
851 error = -1;
852 goto done;
853 }
854
855 if ((ancestor = checkout_conflicts_search_ancestor(data,
856 name_entry->ancestor)) == NULL) {
857 giterr_set(GITERR_INDEX,
858 "A NAME entry referenced ancestor entry '%s' which does not exist in the main index",
859 name_entry->ancestor);
860 error = -1;
861 goto done;
862 }
863
864 if (name_entry->ours) {
865 if (strcmp(name_entry->ancestor, name_entry->ours) == 0)
866 ours = ancestor;
867 else if ((ours = checkout_conflicts_search_branch(data, name_entry->ours)) == NULL ||
868 ours->ours == NULL) {
869 giterr_set(GITERR_INDEX,
870 "A NAME entry referenced our entry '%s' which does not exist in the main index",
871 name_entry->ours);
872 error = -1;
873 goto done;
874 }
875 }
876
877 if (name_entry->theirs) {
878 if (strcmp(name_entry->ancestor, name_entry->theirs) == 0)
879 theirs = ancestor;
880 else if (name_entry->ours && strcmp(name_entry->ours, name_entry->theirs) == 0)
881 theirs = ours;
882 else if ((theirs = checkout_conflicts_search_branch(data, name_entry->theirs)) == NULL ||
883 theirs->theirs == NULL) {
884 giterr_set(GITERR_INDEX,
885 "A NAME entry referenced their entry '%s' which does not exist in the main index",
886 name_entry->theirs);
887 error = -1;
888 goto done;
889 }
890 }
891
892 *ancestor_out = ancestor;
893 *ours_out = ours;
894 *theirs_out = theirs;
895
896done:
897 return error;
898}
899
900static int checkout_conflicts_coalesce_renames(
901 checkout_data *data)
902{
903 const git_index_name_entry *name_entry;
904 checkout_conflictdata *ancestor_conflict, *our_conflict, *their_conflict;
905 size_t i, names;
906 int error = 0;
907
908 /* Juggle entries based on renames */
909 names = git_index_name_entrycount(data->index);
fcd324c6 910
7fa73de1
ET
911 for (i = 0; i < names; i++) {
912 name_entry = git_index_name_get_byindex(data->index, i);
913
914 if ((error = checkout_conflicts_load_byname_entry(
915 &ancestor_conflict, &our_conflict, &their_conflict,
916 data, name_entry)) < 0)
917 goto done;
918
919 if (our_conflict && our_conflict != ancestor_conflict) {
920 ancestor_conflict->ours = our_conflict->ours;
921 our_conflict->ours = NULL;
922
923 if (our_conflict->theirs)
924 our_conflict->name_collision = 1;
925
926 if (our_conflict->name_collision)
927 ancestor_conflict->name_collision = 1;
928 }
929
930 if (their_conflict && their_conflict != ancestor_conflict) {
931 ancestor_conflict->theirs = their_conflict->theirs;
932 their_conflict->theirs = NULL;
933
934 if (their_conflict->ours)
935 their_conflict->name_collision = 1;
936
937 if (their_conflict->name_collision)
938 ancestor_conflict->name_collision = 1;
939 }
940
941 if (our_conflict && our_conflict != ancestor_conflict &&
942 their_conflict && their_conflict != ancestor_conflict)
943 ancestor_conflict->one_to_two = 1;
944 }
945
946 git_vector_remove_matching(&data->conflicts, checkout_conflictdata_empty);
947
948done:
949 return error;
950}
951
7fa73de1
ET
952static int checkout_conflicts_mark_directoryfile(
953 checkout_data *data)
954{
955 checkout_conflictdata *conflict;
956 const git_index_entry *entry;
957 size_t i, j, len;
958 const char *path;
c929d6b7 959 int prefixed, error = 0;
7fa73de1
ET
960
961 len = git_index_entrycount(data->index);
962
963 /* Find d/f conflicts */
964 git_vector_foreach(&data->conflicts, i, conflict) {
965 if ((conflict->ours && conflict->theirs) ||
966 (!conflict->ours && !conflict->theirs))
967 continue;
968
969 path = conflict->ours ?
970 conflict->ours->path : conflict->theirs->path;
971
972 if ((error = git_index_find(&j, data->index, path)) < 0) {
973 if (error == GIT_ENOTFOUND)
974 giterr_set(GITERR_INDEX,
975 "Index inconsistency, could not find entry for expected conflict '%s'", path);
976
977 goto done;
978 }
979
980 for (; j < len; j++) {
981 if ((entry = git_index_get_byindex(data->index, j)) == NULL) {
982 giterr_set(GITERR_INDEX,
983 "Index inconsistency, truncated index while loading expected conflict '%s'", path);
984 error = -1;
985 goto done;
986 }
987
c929d6b7 988 prefixed = git_path_equal_or_prefixed(path, entry->path);
7fa73de1 989
c929d6b7 990 if (prefixed == GIT_PATH_EQUAL)
7fa73de1
ET
991 continue;
992
c929d6b7 993 if (prefixed == GIT_PATH_PREFIX)
7fa73de1
ET
994 conflict->directoryfile = 1;
995
996 break;
997 }
998 }
999
1000done:
1001 return error;
1002}
1003
1004static int checkout_get_conflicts(
1005 checkout_data *data,
1006 git_iterator *workdir,
1007 git_vector *pathspec)
1008{
1009 int error = 0;
1010
1011 if (data->strategy & GIT_CHECKOUT_SKIP_UNMERGED)
1012 return 0;
1013
1014 if ((error = checkout_conflicts_load(data, workdir, pathspec)) < 0 ||
1015 (error = checkout_conflicts_coalesce_renames(data)) < 0 ||
1016 (error = checkout_conflicts_mark_directoryfile(data)) < 0)
1017 goto done;
1018
1019done:
1020 return error;
1021}
1022
cf208031
RB
1023static int checkout_get_actions(
1024 uint32_t **actions_ptr,
1025 size_t **counts_ptr,
7e5c8a5b
RB
1026 checkout_data *data,
1027 git_iterator *workdir)
cf208031 1028{
25e0b157 1029 int error = 0, act;
cf208031
RB
1030 const git_index_entry *wditem;
1031 git_vector pathspec = GIT_VECTOR_INIT, *deltas;
1032 git_pool pathpool = GIT_POOL_INIT_STRINGPOOL;
1033 git_diff_delta *delta;
1034 size_t i, *counts = NULL;
1035 uint32_t *actions = NULL;
cf208031 1036
7e5c8a5b 1037 if (data->opts.paths.count > 0 &&
d2ce27dd 1038 git_pathspec__vinit(&pathspec, &data->opts.paths, &pathpool) < 0)
cf208031
RB
1039 return -1;
1040
cee695ae
RB
1041 if ((error = git_iterator_current(&wditem, workdir)) < 0 &&
1042 error != GIT_ITEROVER)
cf208031
RB
1043 goto fail;
1044
1045 deltas = &data->diff->deltas;
1046
1047 *counts_ptr = counts = git__calloc(CHECKOUT_ACTION__MAX+1, sizeof(size_t));
1048 *actions_ptr = actions = git__calloc(
1049 deltas->length ? deltas->length : 1, sizeof(uint32_t));
1050 if (!counts || !actions) {
1051 error = -1;
1052 goto fail;
1053 }
1054
1055 git_vector_foreach(deltas, i, delta) {
25e0b157 1056 error = checkout_action(&act, data, delta, workdir, &wditem, &pathspec);
cbd04896 1057 if (error != 0)
cf208031 1058 goto fail;
cf208031 1059
cf208031
RB
1060 actions[i] = act;
1061
1062 if (act & CHECKOUT_ACTION__REMOVE)
1063 counts[CHECKOUT_ACTION__REMOVE]++;
1064 if (act & CHECKOUT_ACTION__UPDATE_BLOB)
1065 counts[CHECKOUT_ACTION__UPDATE_BLOB]++;
1066 if (act & CHECKOUT_ACTION__UPDATE_SUBMODULE)
1067 counts[CHECKOUT_ACTION__UPDATE_SUBMODULE]++;
1068 if (act & CHECKOUT_ACTION__CONFLICT)
1069 counts[CHECKOUT_ACTION__CONFLICT]++;
1070 }
d85296ab 1071
d8889d2b 1072 error = checkout_remaining_wd_items(data, workdir, wditem, &pathspec);
25e0b157 1073 if (error)
d8889d2b 1074 goto fail;
16a666d3 1075
7e5c8a5b
RB
1076 counts[CHECKOUT_ACTION__REMOVE] += data->removes.length;
1077
1078 if (counts[CHECKOUT_ACTION__CONFLICT] > 0 &&
1079 (data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) == 0)
1080 {
81a2012d
ET
1081 giterr_set(GITERR_CHECKOUT, "%d %s checkout",
1082 (int)counts[CHECKOUT_ACTION__CONFLICT],
1083 counts[CHECKOUT_ACTION__CONFLICT] == 1 ?
1084 "conflict prevents" : "conflicts prevent");
4a0ac175 1085 error = GIT_EMERGECONFLICT;
cf208031
RB
1086 goto fail;
1087 }
1088
216f97e4 1089
7fa73de1 1090 if ((error = checkout_get_conflicts(data, workdir, &pathspec)) < 0)
216f97e4
ET
1091 goto fail;
1092
1093 counts[CHECKOUT_ACTION__UPDATE_CONFLICT] = git_vector_length(&data->conflicts);
1094
d2ce27dd 1095 git_pathspec__vfree(&pathspec);
cf208031
RB
1096 git_pool_clear(&pathpool);
1097
1098 return 0;
1099
1100fail:
1101 *counts_ptr = NULL;
1102 git__free(counts);
1103 *actions_ptr = NULL;
1104 git__free(actions);
1105
d2ce27dd 1106 git_pathspec__vfree(&pathspec);
cf208031
RB
1107 git_pool_clear(&pathpool);
1108
1109 return error;
1110}
1111
3aa443a9 1112static int buffer_to_file(
5cf9875a 1113 struct stat *st,
a9f51e43 1114 git_buf *buf,
3aa443a9 1115 const char *path,
28abf3db 1116 mode_t dir_mode,
3aa443a9 1117 int file_open_flags,
1118 mode_t file_mode)
1119{
4742148d 1120 int error;
ec532d5e 1121
0d64bef9
RB
1122 if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
1123 return error;
ec532d5e 1124
4742148d 1125 if ((error = git_futils_writebuffer(
a9f51e43 1126 buf, path, file_open_flags, file_mode)) < 0)
4742148d 1127 return error;
d828f118 1128
f240acce
RB
1129 if (st != NULL && (error = p_stat(path, st)) < 0)
1130 giterr_set(GITERR_OS, "Error statting '%s'", path);
0d64bef9 1131
a7fcc44d 1132 else if (GIT_PERMS_IS_EXEC(file_mode) &&
f240acce 1133 (error = p_chmod(path, file_mode)) < 0)
0d64bef9
RB
1134 giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
1135
f240acce 1136 return error;
1d68fcd0
BS
1137}
1138
3aa443a9 1139static int blob_content_to_file(
5cf9875a 1140 struct stat *st,
3aa443a9 1141 git_blob *blob,
1142 const char *path,
629b661c 1143 const char * hint_path,
28abf3db 1144 mode_t entry_filemode,
3aa443a9 1145 git_checkout_opts *opts)
dc1b0909 1146{
85d54812
RB
1147 int error = 0;
1148 mode_t file_mode = opts->file_mode ? opts->file_mode : entry_filemode;
a9f51e43 1149 git_buf out = GIT_BUF_INIT;
85d54812 1150 git_filter_list *fl = NULL;
6eb240b0 1151
629b661c
ET
1152 if (hint_path == NULL)
1153 hint_path = path;
1154
0e32635f 1155 if (!opts->disable_filters)
85d54812 1156 error = git_filter_list_load(
629b661c 1157 &fl, git_blob_owner(blob), blob, hint_path, GIT_FILTER_TO_WORKTREE);
5e4cb4f4 1158
2a7d224f
RB
1159 if (!error)
1160 error = git_filter_list_apply_to_blob(&out, fl, blob);
3aa443a9 1161
2a7d224f 1162 git_filter_list_free(fl);
5e4cb4f4 1163
2a7d224f
RB
1164 if (!error) {
1165 error = buffer_to_file(
1166 st, &out, path, opts->dir_mode, opts->file_open_flags, file_mode);
095ccc01 1167
5cf9875a 1168 st->st_mode = entry_filemode;
095ccc01 1169
a9f51e43 1170 git_buf_free(&out);
2a7d224f 1171 }
5e4cb4f4 1172
1173 return error;
3aa443a9 1174}
1175
ad9a921b 1176static int blob_content_to_link(
55d3a390
RB
1177 struct stat *st,
1178 git_blob *blob,
1179 const char *path,
1180 mode_t dir_mode,
1181 int can_symlink)
3aa443a9 1182{
1183 git_buf linktarget = GIT_BUF_INIT;
1184 int error;
6eb240b0 1185
fbcab44b 1186 if ((error = git_futils_mkpath2file(path, dir_mode)) < 0)
0cb16fe9 1187 return error;
55d3a390 1188
fade21db
RB
1189 if ((error = git_blob__getbuf(&linktarget, blob)) < 0)
1190 return error;
3aa443a9 1191
5cf9875a
RB
1192 if (can_symlink) {
1193 if ((error = p_symlink(git_buf_cstr(&linktarget), path)) < 0)
55d3a390 1194 giterr_set(GITERR_OS, "Could not create symlink %s\n", path);
5cf9875a 1195 } else {
3aa443a9 1196 error = git_futils_fake_symlink(git_buf_cstr(&linktarget), path);
5cf9875a
RB
1197 }
1198
1199 if (!error) {
1200 if ((error = p_lstat(path, st)) < 0)
1201 giterr_set(GITERR_CHECKOUT, "Could not stat symlink %s", path);
1202
1203 st->st_mode = GIT_FILEMODE_LINK;
1204 }
4a26ee4f 1205
3aa443a9 1206 git_buf_free(&linktarget);
1207
1208 return error;
24b0d3d5
BS
1209}
1210
5cf9875a
RB
1211static int checkout_update_index(
1212 checkout_data *data,
1213 const git_diff_file *file,
1214 struct stat *st)
1215{
1216 git_index_entry entry;
1217
1218 if (!data->index)
1219 return 0;
1220
1221 memset(&entry, 0, sizeof(entry));
1222 entry.path = (char *)file->path; /* cast to prevent warning */
e8b81c69 1223 git_index_entry__init_from_stat(&entry, st, true);
5cf9875a
RB
1224 git_oid_cpy(&entry.oid, &file->oid);
1225
1226 return git_index_add(data->index, &entry);
1227}
1228
dcb0f7c0
RB
1229static int checkout_submodule_update_index(
1230 checkout_data *data,
1231 const git_diff_file *file)
1232{
1233 struct stat st;
1234
1235 /* update the index unless prevented */
1236 if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) != 0)
1237 return 0;
1238
1239 git_buf_truncate(&data->path, data->workdir_len);
1240 if (git_buf_puts(&data->path, file->path) < 0)
1241 return -1;
1242
1243 if (p_stat(git_buf_cstr(&data->path), &st) < 0) {
1244 giterr_set(
1245 GITERR_CHECKOUT, "Could not stat submodule %s\n", file->path);
1246 return GIT_ENOTFOUND;
1247 }
1248
1249 st.st_mode = GIT_FILEMODE_COMMIT;
1250
1251 return checkout_update_index(data, file, &st);
1252}
1253
0d64bef9 1254static int checkout_submodule(
7e5c8a5b 1255 checkout_data *data,
0d64bef9
RB
1256 const git_diff_file *file)
1257{
5cf9875a 1258 int error = 0;
e0548c0e 1259 git_submodule *sm;
5cf9875a 1260
ad9a921b 1261 /* Until submodules are supported, UPDATE_ONLY means do nothing here */
7e5c8a5b 1262 if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0)
ad9a921b
RB
1263 return 0;
1264
5cf9875a 1265 if ((error = git_futils_mkdir(
9094ae5a 1266 file->path, data->opts.target_directory,
5cf9875a
RB
1267 data->opts.dir_mode, GIT_MKDIR_PATH)) < 0)
1268 return error;
0d64bef9 1269
dcb0f7c0
RB
1270 if ((error = git_submodule_lookup(&sm, data->repo, file->path)) < 0) {
1271 /* I've observed repos with submodules in the tree that do not
1272 * have a .gitmodules - core Git just makes an empty directory
1273 */
1274 if (error == GIT_ENOTFOUND) {
1275 giterr_clear();
1276 return checkout_submodule_update_index(data, file);
1277 }
1278
e0548c0e 1279 return error;
dcb0f7c0 1280 }
e0548c0e 1281
ad9a921b 1282 /* TODO: Support checkout_strategy options. Two circumstances:
0d64bef9
RB
1283 * 1 - submodule already checked out, but we need to move the HEAD
1284 * to the new OID, or
1285 * 2 - submodule not checked out and we should recursively check it out
1286 *
ad9a921b
RB
1287 * Checkout will not execute a pull on the submodule, but a clone
1288 * command should probably be able to. Do we need a submodule callback?
0d64bef9
RB
1289 */
1290
dcb0f7c0 1291 return checkout_submodule_update_index(data, file);
0d64bef9
RB
1292}
1293
c929d6b7 1294static void report_progress(
7e5c8a5b 1295 checkout_data *data,
32def5af 1296 const char *path)
45b60d7b 1297{
7e5c8a5b
RB
1298 if (data->opts.progress_cb)
1299 data->opts.progress_cb(
ad9a921b 1300 path, data->completed_steps, data->total_steps,
7e5c8a5b 1301 data->opts.progress_payload);
45b60d7b
BS
1302}
1303
c929d6b7 1304static int checkout_safe_for_update_only(const char *path, mode_t expected_mode)
0d70f650
RB
1305{
1306 struct stat st;
1307
1308 if (p_lstat(path, &st) < 0) {
1309 /* if doesn't exist, then no error and no update */
1310 if (errno == ENOENT || errno == ENOTDIR)
1311 return 0;
1312
1313 /* otherwise, stat error and no update */
1314 giterr_set(GITERR_OS, "Failed to stat file '%s'", path);
1315 return -1;
1316 }
1317
1318 /* only safe for update if this is the same type of file */
1319 if ((st.st_mode & ~0777) == (expected_mode & ~0777))
1320 return 1;
1321
1322 return 0;
1323}
1324
c929d6b7 1325static int checkout_write_content(
7e5c8a5b 1326 checkout_data *data,
629b661c
ET
1327 const git_oid *oid,
1328 const char *full_path,
1329 const char *hint_path,
1330 unsigned int mode,
1331 struct stat *st)
ec532d5e 1332{
32def5af 1333 int error = 0;
ad9a921b 1334 git_blob *blob;
0d70f650 1335
629b661c 1336 if ((error = git_blob_lookup(&blob, data->repo, oid)) < 0)
0d64bef9
RB
1337 return error;
1338
629b661c 1339 if (S_ISLNK(mode))
0d64bef9 1340 error = blob_content_to_link(
629b661c 1341 st, blob, full_path, data->opts.dir_mode, data->can_symlink);
3aa443a9 1342 else
0d64bef9 1343 error = blob_content_to_file(
629b661c 1344 st, blob, full_path, hint_path, mode, &data->opts);
3aa443a9 1345
1346 git_blob_free(blob);
1347
7e5c8a5b
RB
1348 /* if we try to create the blob and an existing directory blocks it from
1349 * being written, then there must have been a typechange conflict in a
1350 * parent directory - suppress the error and try to continue.
1351 */
1352 if ((data->strategy & GIT_CHECKOUT_ALLOW_CONFLICTS) != 0 &&
1353 (error == GIT_ENOTFOUND || error == GIT_EEXISTS))
1354 {
1355 giterr_clear();
1356 error = 0;
1357 }
1358
629b661c
ET
1359 return error;
1360}
1361
1362static int checkout_blob(
1363 checkout_data *data,
1364 const git_diff_file *file)
1365{
1366 int error = 0;
1367 struct stat st;
1368
1369 git_buf_truncate(&data->path, data->workdir_len);
1370 if (git_buf_puts(&data->path, file->path) < 0)
1371 return -1;
1372
1373 if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) {
c929d6b7 1374 int rval = checkout_safe_for_update_only(
629b661c
ET
1375 git_buf_cstr(&data->path), file->mode);
1376 if (rval <= 0)
1377 return rval;
1378 }
1379
c929d6b7 1380 error = checkout_write_content(
629b661c
ET
1381 data, &file->oid, git_buf_cstr(&data->path), NULL, file->mode, &st);
1382
5cf9875a
RB
1383 /* update the index unless prevented */
1384 if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
1385 error = checkout_update_index(data, file, &st);
1386
e0548c0e
RB
1387 /* update the submodule data if this was a new .gitmodules file */
1388 if (!error && strcmp(file->path, ".gitmodules") == 0)
1389 data->reload_submodules = true;
1390
3aa443a9 1391 return error;
1392}
1393
32def5af 1394static int checkout_remove_the_old(
32def5af 1395 unsigned int *actions,
7e5c8a5b 1396 checkout_data *data)
32def5af 1397{
cf208031 1398 int error = 0;
32def5af 1399 git_diff_delta *delta;
7e5c8a5b 1400 const char *str;
32def5af 1401 size_t i;
7e5c8a5b
RB
1402 const char *workdir = git_buf_cstr(&data->path);
1403 uint32_t flg = GIT_RMDIR_EMPTY_PARENTS |
1404 GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_REMOVE_BLOCKERS;
32def5af 1405
e09d18ee
ET
1406 if (data->opts.checkout_strategy & GIT_CHECKOUT_SKIP_LOCKED_DIRECTORIES)
1407 flg |= GIT_RMDIR_SKIP_NONEMPTY;
1408
7e5c8a5b 1409 git_buf_truncate(&data->path, data->workdir_len);
ad9a921b 1410
cf208031 1411 git_vector_foreach(&data->diff->deltas, i, delta) {
32def5af 1412 if (actions[i] & CHECKOUT_ACTION__REMOVE) {
cf208031 1413 error = git_futils_rmdir_r(delta->old_file.path, workdir, flg);
7e5c8a5b 1414 if (error < 0)
32def5af
RB
1415 return error;
1416
1417 data->completed_steps++;
7fa73de1 1418 report_progress(data, delta->old_file.path);
5cf9875a
RB
1419
1420 if ((actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) == 0 &&
1421 (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
1422 data->index != NULL)
1423 {
1424 (void)git_index_remove(data->index, delta->old_file.path, 0);
1425 }
32def5af
RB
1426 }
1427 }
1428
7e5c8a5b
RB
1429 git_vector_foreach(&data->removes, i, str) {
1430 error = git_futils_rmdir_r(str, workdir, flg);
1431 if (error < 0)
1432 return error;
1433
1434 data->completed_steps++;
7fa73de1 1435 report_progress(data, str);
5cf9875a
RB
1436
1437 if ((data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0 &&
1438 data->index != NULL)
1439 {
817d6251
RB
1440 if (str[strlen(str) - 1] == '/')
1441 (void)git_index_remove_directory(data->index, str, 0);
1442 else
1443 (void)git_index_remove(data->index, str, 0);
5cf9875a 1444 }
7e5c8a5b
RB
1445 }
1446
1447 return 0;
1448}
1449
1450static int checkout_deferred_remove(git_repository *repo, const char *path)
1451{
1452#if 0
1453 int error = git_futils_rmdir_r(
9094ae5a 1454 path, data->opts.target_directory, GIT_RMDIR_EMPTY_PARENTS);
7e5c8a5b
RB
1455
1456 if (error == GIT_ENOTFOUND) {
1457 error = 0;
1458 giterr_clear();
1459 }
1460
1461 return error;
1462#else
1463 GIT_UNUSED(repo);
1464 GIT_UNUSED(path);
5cf9875a 1465 assert(false);
32def5af 1466 return 0;
7e5c8a5b 1467#endif
32def5af
RB
1468}
1469
1470static int checkout_create_the_new(
32def5af 1471 unsigned int *actions,
7e5c8a5b 1472 checkout_data *data)
32def5af 1473{
7e5c8a5b 1474 int error = 0;
32def5af
RB
1475 git_diff_delta *delta;
1476 size_t i;
1477
cf208031 1478 git_vector_foreach(&data->diff->deltas, i, delta) {
7e5c8a5b
RB
1479 if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
1480 /* this had a blocker directory that should only be removed iff
1481 * all of the contents of the directory were safely removed
1482 */
1483 if ((error = checkout_deferred_remove(
1484 data->repo, delta->old_file.path)) < 0)
1485 return error;
1486 }
1487
ad9a921b 1488 if (actions[i] & CHECKOUT_ACTION__UPDATE_BLOB) {
7e5c8a5b 1489 error = checkout_blob(data, &delta->new_file);
ad9a921b 1490 if (error < 0)
32def5af
RB
1491 return error;
1492
1493 data->completed_steps++;
7fa73de1 1494 report_progress(data, delta->new_file.path);
32def5af 1495 }
32def5af
RB
1496 }
1497
1498 return 0;
1499}
1500
1501static int checkout_create_submodules(
32def5af 1502 unsigned int *actions,
7e5c8a5b 1503 checkout_data *data)
32def5af 1504{
7e5c8a5b 1505 int error = 0;
32def5af
RB
1506 git_diff_delta *delta;
1507 size_t i;
1508
e0548c0e
RB
1509 /* initial reload of submodules if .gitmodules was changed */
1510 if (data->reload_submodules &&
1511 (error = git_submodule_reload_all(data->repo)) < 0)
1512 return error;
1513
cf208031 1514 git_vector_foreach(&data->diff->deltas, i, delta) {
7e5c8a5b
RB
1515 if (actions[i] & CHECKOUT_ACTION__DEFER_REMOVE) {
1516 /* this has a blocker directory that should only be removed iff
1517 * all of the contents of the directory were safely removed
1518 */
1519 if ((error = checkout_deferred_remove(
1520 data->repo, delta->old_file.path)) < 0)
1521 return error;
1522 }
1523
ad9a921b 1524 if (actions[i] & CHECKOUT_ACTION__UPDATE_SUBMODULE) {
cf208031 1525 int error = checkout_submodule(data, &delta->new_file);
32def5af
RB
1526 if (error < 0)
1527 return error;
1528
1529 data->completed_steps++;
7fa73de1 1530 report_progress(data, delta->new_file.path);
32def5af
RB
1531 }
1532 }
1533
e0548c0e
RB
1534 /* final reload once submodules have been updated */
1535 return git_submodule_reload_all(data->repo);
32def5af
RB
1536}
1537
7e5c8a5b
RB
1538static int checkout_lookup_head_tree(git_tree **out, git_repository *repo)
1539{
1540 int error = 0;
1541 git_reference *ref = NULL;
1542 git_object *head;
1543
1544 if (!(error = git_repository_head(&ref, repo)) &&
1545 !(error = git_reference_peel(&head, ref, GIT_OBJ_TREE)))
1546 *out = (git_tree *)head;
1547
1548 git_reference_free(ref);
1549
1550 return error;
1551}
1552
7fa73de1
ET
1553
1554static int conflict_entry_name(
1555 git_buf *out,
1556 const char *side_name,
1557 const char *filename)
1558{
1559 if (git_buf_puts(out, side_name) < 0 ||
1560 git_buf_putc(out, ':') < 0 ||
1561 git_buf_puts(out, filename) < 0)
1562 return -1;
1563
1564 return 0;
1565}
1566
1567static int checkout_path_suffixed(git_buf *path, const char *suffix)
1568{
1569 size_t path_len;
1570 int i = 0, error = 0;
1571
1572 if ((error = git_buf_putc(path, '~')) < 0 || (error = git_buf_puts(path, suffix)) < 0)
1573 return -1;
1574
1575 path_len = git_buf_len(path);
1576
1577 while (git_path_exists(git_buf_cstr(path)) && i < INT_MAX) {
1578 git_buf_truncate(path, path_len);
1579
1580 if ((error = git_buf_putc(path, '_')) < 0 ||
1581 (error = git_buf_printf(path, "%d", i)) < 0)
1582 return error;
1583
1584 i++;
1585 }
1586
1587 if (i == INT_MAX) {
1588 git_buf_truncate(path, path_len);
1589
1590 giterr_set(GITERR_CHECKOUT, "Could not write '%s': working directory file exists", path);
1591 return GIT_EEXISTS;
1592 }
1593
1594 return 0;
1595}
1596
1597static int checkout_write_entry(
1598 checkout_data *data,
1599 checkout_conflictdata *conflict,
1600 const git_index_entry *side)
1601{
1602 const char *hint_path = NULL, *suffix;
1603 struct stat st;
1604 int error;
1605
1606 assert (side == conflict->ours || side == conflict->theirs);
1607
1608 git_buf_truncate(&data->path, data->workdir_len);
1609 if (git_buf_puts(&data->path, side->path) < 0)
1610 return -1;
1611
1612 if ((conflict->name_collision || conflict->directoryfile) &&
1613 (data->strategy & GIT_CHECKOUT_USE_OURS) == 0 &&
1614 (data->strategy & GIT_CHECKOUT_USE_THEIRS) == 0) {
1615
1616 if (side == conflict->ours)
1617 suffix = data->opts.our_label ? data->opts.our_label :
1618 "ours";
1619 else
1620 suffix = data->opts.their_label ? data->opts.their_label :
1621 "theirs";
1622
1623 if (checkout_path_suffixed(&data->path, suffix) < 0)
1624 return -1;
1625
1626 hint_path = side->path;
1627 }
1628
1629 if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
c929d6b7 1630 (error = checkout_safe_for_update_only(git_buf_cstr(&data->path), side->mode)) <= 0)
7fa73de1
ET
1631 return error;
1632
c929d6b7 1633 return checkout_write_content(data,
7fa73de1
ET
1634 &side->oid, git_buf_cstr(&data->path), hint_path, side->mode, &st);
1635}
1636
1637static int checkout_write_entries(
1638 checkout_data *data,
1639 checkout_conflictdata *conflict)
1640{
1641 int error = 0;
1642
1643 if ((error = checkout_write_entry(data, conflict, conflict->ours)) >= 0)
1644 error = checkout_write_entry(data, conflict, conflict->theirs);
1645
1646 return error;
1647}
1648
1649static int checkout_merge_path(
1650 git_buf *out,
1651 checkout_data *data,
1652 checkout_conflictdata *conflict,
1653 git_merge_file_result *result)
1654{
1655 const char *our_label_raw, *their_label_raw, *suffix;
1656 int error = 0;
1657
1658 if ((error = git_buf_joinpath(out, git_repository_workdir(data->repo), result->path)) < 0)
1659 return error;
1660
1661 /* Most conflicts simply use the filename in the index */
1662 if (!conflict->name_collision)
1663 return 0;
1664
1665 /* Rename 2->1 conflicts need the branch name appended */
1666 our_label_raw = data->opts.our_label ? data->opts.our_label : "ours";
1667 their_label_raw = data->opts.their_label ? data->opts.their_label : "theirs";
1668 suffix = strcmp(result->path, conflict->ours->path) == 0 ? our_label_raw : their_label_raw;
1669
1670 if ((error = checkout_path_suffixed(out, suffix)) < 0)
1671 return error;
1672
1673 return 0;
1674}
1675
1676static int checkout_write_merge(
1677 checkout_data *data,
1678 checkout_conflictdata *conflict)
1679{
1680 git_buf our_label = GIT_BUF_INIT, their_label = GIT_BUF_INIT,
1681 path_suffixed = GIT_BUF_INIT, path_workdir = GIT_BUF_INIT;
c1d648c5 1682 git_merge_file_options merge_file_opts = GIT_MERGE_FILE_OPTIONS_INIT;
7fa73de1
ET
1683 git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT,
1684 ours = GIT_MERGE_FILE_INPUT_INIT,
1685 theirs = GIT_MERGE_FILE_INPUT_INIT;
1686 git_merge_file_result result = GIT_MERGE_FILE_RESULT_INIT;
1687 git_filebuf output = GIT_FILEBUF_INIT;
1688 int error = 0;
1689
e651e8e2
ET
1690 if (data->opts.checkout_strategy & GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)
1691 merge_file_opts.style = GIT_MERGE_FILE_STYLE_DIFF3;
1692
7fa73de1
ET
1693 if ((conflict->ancestor &&
1694 (error = git_merge_file_input_from_index_entry(
1695 &ancestor, data->repo, conflict->ancestor)) < 0) ||
1696 (error = git_merge_file_input_from_index_entry(
1697 &ours, data->repo, conflict->ours)) < 0 ||
1698 (error = git_merge_file_input_from_index_entry(
1699 &theirs, data->repo, conflict->theirs)) < 0)
1700 goto done;
1701
e651e8e2 1702 ancestor.label = data->opts.ancestor_label ? data->opts.ancestor_label : "ancestor";
7fa73de1
ET
1703 ours.label = data->opts.our_label ? data->opts.our_label : "ours";
1704 theirs.label = data->opts.their_label ? data->opts.their_label : "theirs";
1705
1706 /* If all the paths are identical, decorate the diff3 file with the branch
1707 * names. Otherwise, append branch_name:path.
1708 */
1709 if (conflict->ours && conflict->theirs &&
1710 strcmp(conflict->ours->path, conflict->theirs->path) != 0) {
1711
1712 if ((error = conflict_entry_name(
1713 &our_label, ours.label, conflict->ours->path)) < 0 ||
1714 (error = conflict_entry_name(
1715 &their_label, theirs.label, conflict->theirs->path)) < 0)
1716 goto done;
1717
1718 ours.label = git_buf_cstr(&our_label);
1719 theirs.label = git_buf_cstr(&their_label);
1720 }
1721
c1d648c5 1722 if ((error = git_merge_files(&result, &ancestor, &ours, &theirs, &merge_file_opts)) < 0)
7fa73de1
ET
1723 goto done;
1724
1725 if (result.path == NULL || result.mode == 0) {
1726 giterr_set(GITERR_CHECKOUT, "Could not merge contents of file");
1727 error = GIT_EMERGECONFLICT;
1728 goto done;
1729 }
1730
1731 if ((error = checkout_merge_path(&path_workdir, data, conflict, &result)) < 0)
1732 goto done;
1733
1734 if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0 &&
c929d6b7 1735 (error = checkout_safe_for_update_only(git_buf_cstr(&path_workdir), result.mode)) <= 0)
7fa73de1
ET
1736 goto done;
1737
1738 if ((error = git_futils_mkpath2file(path_workdir.ptr, 0755)) < 0 ||
1d3a8aeb 1739 (error = git_filebuf_open(&output, path_workdir.ptr, GIT_FILEBUF_DO_NOT_BUFFER, result.mode)) < 0 ||
7fa73de1 1740 (error = git_filebuf_write(&output, result.data, result.len)) < 0 ||
1d3a8aeb 1741 (error = git_filebuf_commit(&output)) < 0)
7fa73de1
ET
1742 goto done;
1743
1744done:
1745 git_buf_free(&our_label);
1746 git_buf_free(&their_label);
1747
1748 git_merge_file_input_free(&ancestor);
1749 git_merge_file_input_free(&ours);
1750 git_merge_file_input_free(&theirs);
1751 git_merge_file_result_free(&result);
1752 git_buf_free(&path_workdir);
1753 git_buf_free(&path_suffixed);
1754
1755 return error;
1756}
1757
1758static int checkout_create_conflicts(checkout_data *data)
1759{
7fa73de1
ET
1760 checkout_conflictdata *conflict;
1761 size_t i;
1762 int error = 0;
1763
1764 git_vector_foreach(&data->conflicts, i, conflict) {
6b92c99b 1765
7fa73de1
ET
1766 /* Both deleted: nothing to do */
1767 if (conflict->ours == NULL && conflict->theirs == NULL)
1768 error = 0;
1769
1770 else if ((data->strategy & GIT_CHECKOUT_USE_OURS) &&
1771 conflict->ours)
1772 error = checkout_write_entry(data, conflict, conflict->ours);
1773 else if ((data->strategy & GIT_CHECKOUT_USE_THEIRS) &&
1774 conflict->theirs)
1775 error = checkout_write_entry(data, conflict, conflict->theirs);
1776
1777 /* Ignore the other side of name collisions. */
1778 else if ((data->strategy & GIT_CHECKOUT_USE_OURS) &&
1779 !conflict->ours && conflict->name_collision)
1780 error = 0;
1781 else if ((data->strategy & GIT_CHECKOUT_USE_THEIRS) &&
1782 !conflict->theirs && conflict->name_collision)
1783 error = 0;
1784
1785 /* For modify/delete, name collisions and d/f conflicts, write
1786 * the file (potentially with the name mangled.
1787 */
1788 else if (conflict->ours != NULL && conflict->theirs == NULL)
1789 error = checkout_write_entry(data, conflict, conflict->ours);
1790 else if (conflict->ours == NULL && conflict->theirs != NULL)
1791 error = checkout_write_entry(data, conflict, conflict->theirs);
1792
1793 /* Add/add conflicts and rename 1->2 conflicts, write the
1794 * ours/theirs sides (potentially name mangled).
1795 */
1796 else if (conflict->one_to_two)
1797 error = checkout_write_entries(data, conflict);
1798
1799 /* If all sides are links, write the ours side */
1800 else if (S_ISLNK(conflict->ours->mode) &&
1801 S_ISLNK(conflict->theirs->mode))
1802 error = checkout_write_entry(data, conflict, conflict->ours);
1803 /* Link/file conflicts, write the file side */
1804 else if (S_ISLNK(conflict->ours->mode))
1805 error = checkout_write_entry(data, conflict, conflict->theirs);
1806 else if (S_ISLNK(conflict->theirs->mode))
1807 error = checkout_write_entry(data, conflict, conflict->ours);
1808
0ef19fe1
ET
1809 /* If any side is a gitlink, do nothing. */
1810 else if (conflict->submodule)
1811 error = 0;
1812
6b92c99b
ET
1813 /* If any side is binary, write the ours side */
1814 else if (conflict->binary)
1815 error = checkout_write_entry(data, conflict, conflict->ours);
1816
1817 else if (!error)
7fa73de1
ET
1818 error = checkout_write_merge(data, conflict);
1819
1820 if (error)
1821 break;
1822
1823 data->completed_steps++;
1824 report_progress(data,
1825 conflict->ours ? conflict->ours->path :
1826 (conflict->theirs ? conflict->theirs->path : conflict->ancestor->path));
1827 }
1828
1829 return error;
1830}
1831
1832
7e5c8a5b
RB
1833static void checkout_data_clear(checkout_data *data)
1834{
1835 if (data->opts_free_baseline) {
1836 git_tree_free(data->opts.baseline);
1837 data->opts.baseline = NULL;
1838 }
1839
1840 git_vector_free(&data->removes);
1841 git_pool_clear(&data->pool);
1842
9cfce273 1843 git_vector_free_deep(&data->conflicts);
216f97e4 1844
7e5c8a5b
RB
1845 git__free(data->pfx);
1846 data->pfx = NULL;
1847
1848 git_buf_free(&data->path);
5cf9875a
RB
1849
1850 git_index_free(data->index);
1851 data->index = NULL;
7e5c8a5b
RB
1852}
1853
1854static int checkout_data_init(
1855 checkout_data *data,
5cf9875a 1856 git_iterator *target,
eec1c1fe 1857 const git_checkout_opts *proposed)
3aa443a9 1858{
7e5c8a5b 1859 int error = 0;
5cf9875a 1860 git_repository *repo = git_iterator_owner(target);
cf208031 1861
7e5c8a5b
RB
1862 memset(data, 0, sizeof(*data));
1863
1864 if (!repo) {
1865 giterr_set(GITERR_CHECKOUT, "Cannot checkout nothing");
cf208031 1866 return -1;
7e5c8a5b 1867 }
cf208031 1868
9094ae5a
RB
1869 if ((!proposed || !proposed->target_directory) &&
1870 (error = git_repository__ensure_not_bare(repo, "checkout")) < 0)
7e5c8a5b 1871 return error;
cf208031 1872
7e5c8a5b
RB
1873 data->repo = repo;
1874
1875 GITERR_CHECK_VERSION(
1876 proposed, GIT_CHECKOUT_OPTS_VERSION, "git_checkout_opts");
1877
1878 if (!proposed)
1879 GIT_INIT_STRUCTURE(&data->opts, GIT_CHECKOUT_OPTS_VERSION);
1880 else
1881 memmove(&data->opts, proposed, sizeof(git_checkout_opts));
1882
9094ae5a
RB
1883 if (!data->opts.target_directory)
1884 data->opts.target_directory = git_repository_workdir(repo);
1885 else if (!git_path_isdir(data->opts.target_directory) &&
1886 (error = git_futils_mkdir(data->opts.target_directory, NULL,
1887 GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0)
1888 goto cleanup;
1889
5cf9875a
RB
1890 /* refresh config and index content unless NO_REFRESH is given */
1891 if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) {
eac76c23
RB
1892 git_config *cfg;
1893
1894 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
1895 (error = git_config_refresh(cfg)) < 0)
5cf9875a
RB
1896 goto cleanup;
1897
169dc616
RB
1898 /* if we are checking out the index, don't reload,
1899 * otherwise get index and force reload
1900 */
1901 if ((data->index = git_iterator_get_index(target)) != NULL) {
5cf9875a
RB
1902 GIT_REFCOUNT_INC(data->index);
1903 } else {
1904 /* otherwise, grab and reload the index */
1905 if ((error = git_repository_index(&data->index, data->repo)) < 0 ||
8e5a8ef8 1906 (error = git_index_read(data->index, true)) < 0)
5cf9875a 1907 goto cleanup;
169dc616 1908
629b661c
ET
1909 /* cannot checkout if unresolved conflicts exist */
1910 if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) == 0 &&
1911 git_index_has_conflicts(data->index)) {
1912 error = GIT_EMERGECONFLICT;
1913 giterr_set(GITERR_CHECKOUT,
1914 "unresolved conflicts exist in the index");
1915 goto cleanup;
1916 }
1917
1918 /* clean conflict data when doing a tree or commit checkout */
1919 git_index_name_clear(data->index);
5bddabcc 1920 git_index_reuc_clear(data->index);
5cf9875a
RB
1921 }
1922 }
7e5c8a5b 1923
5cf9875a 1924 /* if you are forcing, definitely allow safe updates */
7e5c8a5b
RB
1925 if ((data->opts.checkout_strategy & GIT_CHECKOUT_FORCE) != 0)
1926 data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE_CREATE;
1927 if ((data->opts.checkout_strategy & GIT_CHECKOUT_SAFE_CREATE) != 0)
1928 data->opts.checkout_strategy |= GIT_CHECKOUT_SAFE;
1929
1930 data->strategy = data->opts.checkout_strategy;
1931
1932 /* opts->disable_filters is false by default */
1933
1934 if (!data->opts.dir_mode)
1935 data->opts.dir_mode = GIT_DIR_MODE;
1936
1937 if (!data->opts.file_open_flags)
1938 data->opts.file_open_flags = O_CREAT | O_TRUNC | O_WRONLY;
1939
1940 data->pfx = git_pathspec_prefix(&data->opts.paths);
1941
eac76c23
RB
1942 if ((error = git_repository__cvar(
1943 &data->can_symlink, repo, GIT_CVAR_SYMLINKS)) < 0)
1944 goto cleanup;
cf208031 1945
7e5c8a5b
RB
1946 if (!data->opts.baseline) {
1947 data->opts_free_baseline = true;
eac76c23 1948
2a3b3e03 1949 error = checkout_lookup_head_tree(&data->opts.baseline, repo);
1950
605da51a 1951 if (error == GIT_EUNBORNBRANCH) {
2a3b3e03 1952 error = 0;
1953 giterr_clear();
1954 }
1955
1956 if (error < 0)
7e5c8a5b
RB
1957 goto cleanup;
1958 }
1959
6891a862
ET
1960 if ((data->opts.checkout_strategy &
1961 (GIT_CHECKOUT_CONFLICT_STYLE_MERGE | GIT_CHECKOUT_CONFLICT_STYLE_DIFF3)) == 0) {
1962 const char *conflict_style;
1963 git_config *cfg = NULL;
1964
1965 if ((error = git_repository_config__weakptr(&cfg, repo)) < 0 ||
1966 (error = git_config_get_string(&conflict_style, cfg, "merge.conflictstyle")) < 0 ||
1967 error == GIT_ENOTFOUND)
1968 ;
1969 else if (error)
1970 goto cleanup;
1971 else if (strcmp(conflict_style, "merge") == 0)
1972 data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_MERGE;
1973 else if (strcmp(conflict_style, "diff3") == 0)
1974 data->opts.checkout_strategy |= GIT_CHECKOUT_CONFLICT_STYLE_DIFF3;
1975 else {
1976 giterr_set(GITERR_CHECKOUT, "unknown style '%s' given for 'merge.conflictstyle'",
1977 conflict_style);
1978 error = -1;
1979 goto cleanup;
1980 }
1981 }
1982
7e5c8a5b 1983 if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 ||
216f97e4 1984 (error = git_vector_init(&data->conflicts, 0, NULL)) < 0 ||
7e5c8a5b 1985 (error = git_pool_init(&data->pool, 1, 0)) < 0 ||
9094ae5a
RB
1986 (error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 ||
1987 (error = git_path_to_dir(&data->path)) < 0)
7e5c8a5b
RB
1988 goto cleanup;
1989
1990 data->workdir_len = git_buf_len(&data->path);
1991
1992cleanup:
1993 if (error < 0)
1994 checkout_data_clear(data);
cf208031
RB
1995
1996 return error;
1997}
1998
7e5c8a5b
RB
1999int git_checkout_iterator(
2000 git_iterator *target,
eec1c1fe 2001 const git_checkout_opts *opts)
cf208031
RB
2002{
2003 int error = 0;
7e5c8a5b
RB
2004 git_iterator *baseline = NULL, *workdir = NULL;
2005 checkout_data data = {0};
cf208031 2006 git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
32def5af
RB
2007 uint32_t *actions = NULL;
2008 size_t *counts = NULL;
134d8c91 2009 git_iterator_flag_t iterflags = 0;
3aa443a9 2010
7e5c8a5b 2011 /* initialize structures and options */
5cf9875a 2012 error = checkout_data_init(&data, target, opts);
7e5c8a5b
RB
2013 if (error < 0)
2014 return error;
c7231c45 2015
7e5c8a5b
RB
2016 diff_opts.flags =
2017 GIT_DIFF_INCLUDE_UNMODIFIED |
2018 GIT_DIFF_INCLUDE_UNTRACKED |
2019 GIT_DIFF_RECURSE_UNTRACKED_DIRS | /* needed to match baseline */
2020 GIT_DIFF_INCLUDE_IGNORED |
2021 GIT_DIFF_INCLUDE_TYPECHANGE |
2022 GIT_DIFF_INCLUDE_TYPECHANGE_TREES |
2023 GIT_DIFF_SKIP_BINARY_CHECK;
40342bd2
RB
2024 if (data.opts.checkout_strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH)
2025 diff_opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
7e5c8a5b
RB
2026 if (data.opts.paths.count > 0)
2027 diff_opts.pathspec = data.opts.paths;
2028
2029 /* set up iterators */
134d8c91
RB
2030
2031 iterflags = git_iterator_ignore_case(target) ?
2032 GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
2033
7e5c8a5b 2034 if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 ||
9094ae5a
RB
2035 (error = git_iterator_for_workdir_ext(
2036 &workdir, data.repo, data.opts.target_directory,
2037 iterflags | GIT_ITERATOR_DONT_AUTOEXPAND,
9bea03ce 2038 data.pfx, data.pfx)) < 0 ||
169dc616 2039 (error = git_iterator_for_tree(
9094ae5a
RB
2040 &baseline, data.opts.baseline,
2041 iterflags, data.pfx, data.pfx)) < 0)
7e5c8a5b
RB
2042 goto cleanup;
2043
cc216a01
RB
2044 /* Should not have case insensitivity mismatch */
2045 assert(git_iterator_ignore_case(workdir) == git_iterator_ignore_case(baseline));
3aa443a9 2046
77cffa31
RB
2047 /* Generate baseline-to-target diff which will include an entry for
2048 * every possible update that might need to be made.
cf208031
RB
2049 */
2050 if ((error = git_diff__from_iterators(
7e5c8a5b 2051 &data.diff, data.repo, baseline, target, &diff_opts)) < 0)
3aa443a9 2052 goto cleanup;
2053
77cffa31 2054 /* Loop through diff (and working directory iterator) building a list of
216f97e4
ET
2055 * actions to be taken, plus look for conflicts and send notifications,
2056 * then loop through conflicts.
32def5af 2057 */
cbd04896 2058 if ((error = checkout_get_actions(&actions, &counts, &data, workdir)) != 0)
ad9a921b
RB
2059 goto cleanup;
2060
32def5af 2061 data.total_steps = counts[CHECKOUT_ACTION__REMOVE] +
ad9a921b 2062 counts[CHECKOUT_ACTION__UPDATE_BLOB] +
216f97e4
ET
2063 counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] +
2064 counts[CHECKOUT_ACTION__UPDATE_CONFLICT];
3aa443a9 2065
7fa73de1 2066 report_progress(&data, NULL); /* establish 0 baseline */
45b60d7b 2067
77cffa31
RB
2068 /* To deal with some order dependencies, perform remaining checkout
2069 * in three passes: removes, then update blobs, then update submodules.
2070 */
32def5af 2071 if (counts[CHECKOUT_ACTION__REMOVE] > 0 &&
cf208031 2072 (error = checkout_remove_the_old(actions, &data)) < 0)
32def5af
RB
2073 goto cleanup;
2074
ad9a921b 2075 if (counts[CHECKOUT_ACTION__UPDATE_BLOB] > 0 &&
cf208031 2076 (error = checkout_create_the_new(actions, &data)) < 0)
32def5af
RB
2077 goto cleanup;
2078
ad9a921b 2079 if (counts[CHECKOUT_ACTION__UPDATE_SUBMODULE] > 0 &&
cf208031 2080 (error = checkout_create_submodules(actions, &data)) < 0)
32def5af
RB
2081 goto cleanup;
2082
216f97e4 2083 if (counts[CHECKOUT_ACTION__UPDATE_CONFLICT] > 0 &&
7fa73de1 2084 (error = checkout_create_conflicts(&data)) < 0)
216f97e4 2085 goto cleanup;
3aa443a9 2086
216f97e4 2087 assert(data.completed_steps == data.total_steps);
629b661c 2088
0d64bef9 2089cleanup:
5cf9875a
RB
2090 if (!error && data.index != NULL &&
2091 (data.strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0)
2092 error = git_index_write(data.index);
2093
3ff1d123 2094 git_diff_free(data.diff);
7e5c8a5b 2095 git_iterator_free(workdir);
dde7602a 2096 git_iterator_free(baseline);
32def5af
RB
2097 git__free(actions);
2098 git__free(counts);
7e5c8a5b 2099 checkout_data_clear(&data);
cf208031
RB
2100
2101 return error;
2102}
2103
cf208031
RB
2104int git_checkout_index(
2105 git_repository *repo,
2106 git_index *index,
10749f6c 2107 const git_checkout_opts *opts)
cf208031
RB
2108{
2109 int error;
7e5c8a5b 2110 git_iterator *index_i;
cf208031 2111
6a15e8d2
RB
2112 if (!index && !repo) {
2113 giterr_set(GITERR_CHECKOUT,
2114 "Must provide either repository or index to checkout");
2115 return -1;
2116 }
2117 if (index && repo && git_index_owner(index) != repo) {
2118 giterr_set(GITERR_CHECKOUT,
2119 "Index to checkout does not match repository");
2120 return -1;
2121 }
2122
2123 if (!repo)
2124 repo = git_index_owner(index);
cf208031
RB
2125
2126 if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0)
2127 return error;
7e5c8a5b 2128 GIT_REFCOUNT_INC(index);
cf208031 2129
169dc616 2130 if (!(error = git_iterator_for_index(&index_i, index, 0, NULL, NULL)))
7e5c8a5b 2131 error = git_checkout_iterator(index_i, opts);
cf208031 2132
cf208031 2133 git_iterator_free(index_i);
7e5c8a5b 2134 git_index_free(index);
0d64bef9 2135
e93af304 2136 return error;
2137}
2138
2139int git_checkout_tree(
2140 git_repository *repo,
cfbe4be3 2141 const git_object *treeish,
10749f6c 2142 const git_checkout_opts *opts)
e93af304 2143{
cf208031 2144 int error;
7e5c8a5b
RB
2145 git_tree *tree = NULL;
2146 git_iterator *tree_i = NULL;
cf208031 2147
6a15e8d2
RB
2148 if (!treeish && !repo) {
2149 giterr_set(GITERR_CHECKOUT,
2150 "Must provide either repository or tree to checkout");
2151 return -1;
2152 }
2153 if (treeish && repo && git_object_owner(treeish) != repo) {
2154 giterr_set(GITERR_CHECKOUT,
2155 "Object to checkout does not match repository");
2156 return -1;
2157 }
2158
2159 if (!repo)
2160 repo = git_object_owner(treeish);
e93af304 2161
35221441
SC
2162 if (treeish) {
2163 if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) {
2164 giterr_set(
2165 GITERR_CHECKOUT, "Provided object cannot be peeled to a tree");
2166 return -1;
2167 }
2168 }
2169 else {
2170 if ((error = checkout_lookup_head_tree(&tree, repo)) < 0) {
2171 if (error != GIT_EUNBORNBRANCH)
2172 giterr_set(
2173 GITERR_CHECKOUT,
2174 "HEAD could not be peeled to a tree and no treeish given");
2175 return error;
2176 }
e93af304 2177 }
2178
169dc616 2179 if (!(error = git_iterator_for_tree(&tree_i, tree, 0, NULL, NULL)))
7e5c8a5b 2180 error = git_checkout_iterator(tree_i, opts);
e93af304 2181
cf208031 2182 git_iterator_free(tree_i);
3aa443a9 2183 git_tree_free(tree);
ad9a921b 2184
3aa443a9 2185 return error;
14741d62
BS
2186}
2187
3aa443a9 2188int git_checkout_head(
2189 git_repository *repo,
eec1c1fe 2190 const git_checkout_opts *opts)
3aa443a9 2191{
6a15e8d2 2192 assert(repo);
7b3959b2 2193 return git_checkout_tree(repo, NULL, opts);
3aa443a9 2194}