]> git.ipfire.org Git - thirdparty/git.git/blame - builtin/mv.c
alloc.h: move ALLOC_GROW() functions from cache.h
[thirdparty/git.git] / builtin / mv.c
CommitLineData
11be42a4
JS
1/*
2 * "git mv" builtin command
3 *
4 * Copyright (C) 2006 Johannes Schindelin
5 */
babed893 6#define USE_THE_INDEX_VARIABLE
11be42a4 7#include "builtin.h"
36bf1958 8#include "alloc.h"
b2141fc1 9#include "config.h"
2ec87741 10#include "pathspec.h"
697cc8ef 11#include "lockfile.h"
11be42a4
JS
12#include "dir.h"
13#include "cache-tree.h"
c455c87c 14#include "string-list.h"
c7a20c11 15#include "parse-options.h"
a88c915d 16#include "submodule.h"
707fa2f7 17#include "entry.h"
11be42a4 18
c7a20c11 19static const char * const builtin_mv_usage[] = {
9c9b4f2f 20 N_("git mv [<options>] <source>... <destination>"),
c7a20c11
PH
21 NULL
22};
11be42a4 23
24ea81d9 24enum update_mode {
24ea81d9
SY
25 WORKING_DIRECTORY = (1 << 1),
26 INDEX = (1 << 2),
27 SPARSE = (1 << 3),
b91a2b65 28 SKIP_WORKTREE_DIR = (1 << 4),
24ea81d9
SY
29};
30
c57f6281
MM
31#define DUP_BASENAME 1
32#define KEEP_TRAILING_SLASH 2
33
2ec87741
BW
34static const char **internal_prefix_pathspec(const char *prefix,
35 const char **pathspec,
36 int count, unsigned flags)
11be42a4 37{
d78b0f3d 38 int i;
b32fa95f 39 const char **result;
2ec87741 40 int prefixlen = prefix ? strlen(prefix) : 0;
b32fa95f 41 ALLOC_ARRAY(result, count + 1);
2ec87741
BW
42
43 /* Create an intermediate copy of the pathspec based on the flags */
d78b0f3d 44 for (i = 0; i < count; i++) {
2ec87741 45 int length = strlen(pathspec[i]);
af82559b 46 int to_copy = length;
2ec87741 47 char *it;
c57f6281 48 while (!(flags & KEEP_TRAILING_SLASH) &&
2ec87741 49 to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
af82559b 50 to_copy--;
2ec87741
BW
51
52 it = xmemdupz(pathspec[i], to_copy);
53 if (flags & DUP_BASENAME) {
54 result[i] = xstrdup(basename(it));
55 free(it);
56 } else {
57 result[i] = it;
af82559b 58 }
11be42a4 59 }
2ec87741
BW
60 result[count] = NULL;
61
62 /* Prefix the pathspec and free the old intermediate strings */
63 for (i = 0; i < count; i++) {
64 const char *match = prefix_path(prefix, prefixlen, result[i]);
65 free((char *) result[i]);
66 result[i] = match;
67 }
68
69 return result;
11be42a4
JS
70}
71
ac64a722
JS
72static const char *add_slash(const char *path)
73{
50a6c8ef 74 size_t len = strlen(path);
7ead4681 75 if (len && path[len - 1] != '/') {
50a6c8ef 76 char *with_slash = xmalloc(st_add(len, 2));
ac64a722 77 memcpy(with_slash, path, len);
329a3047
JH
78 with_slash[len++] = '/';
79 with_slash[len] = 0;
ac64a722
JS
80 return with_slash;
81 }
82 return path;
83}
84
04c1ee57 85#define SUBMODULE_WITH_GITDIR ((const char *)1)
11be42a4 86
3af05a6d
NTND
87static void prepare_move_submodule(const char *src, int first,
88 const char **submodule_gitfile)
89{
90 struct strbuf submodule_dotgit = STRBUF_INIT;
dc594180 91 if (!S_ISGITLINK(the_index.cache[first]->ce_mode))
3af05a6d 92 die(_("Directory %s is in index and no submodule?"), src);
91b83480 93 if (!is_staging_gitmodules_ok(&the_index))
3af05a6d
NTND
94 die(_("Please stage your changes to .gitmodules or stash them to proceed"));
95 strbuf_addf(&submodule_dotgit, "%s/.git", src);
96 *submodule_gitfile = read_gitfile(submodule_dotgit.buf);
97 if (*submodule_gitfile)
98 *submodule_gitfile = xstrdup(*submodule_gitfile);
99 else
100 *submodule_gitfile = SUBMODULE_WITH_GITDIR;
101 strbuf_release(&submodule_dotgit);
102}
103
e2b6cfa0
NTND
104static int index_range_of_same_dir(const char *src, int length,
105 int *first_p, int *last_p)
106{
107 const char *src_w_slash = add_slash(src);
108 int first, last, len_w_slash = length + 1;
109
07047d68 110 first = index_name_pos(&the_index, src_w_slash, len_w_slash);
e2b6cfa0
NTND
111 if (first >= 0)
112 die(_("%.*s is in index"), len_w_slash, src_w_slash);
113
114 first = -1 - first;
dc594180
ÆAB
115 for (last = first; last < the_index.cache_nr; last++) {
116 const char *path = the_index.cache[last]->name;
e2b6cfa0
NTND
117 if (strncmp(path, src_w_slash, len_w_slash))
118 break;
119 }
120 if (src_w_slash != src)
121 free((char *)src_w_slash);
122 *first_p = first;
123 *last_p = last;
124 return last - first;
125}
126
b91a2b65 127/*
72e59ba1
SY
128 * Given the path of a directory that does not exist on-disk, check whether the
129 * directory contains any entries in the index with the SKIP_WORKTREE flag
130 * enabled.
131 * Return 1 if such index entries exist.
132 * Return 0 otherwise.
b91a2b65 133 */
72e59ba1 134static int empty_dir_has_sparse_contents(const char *name)
b91a2b65 135{
d57690a9 136 int ret = 0;
b91a2b65
SY
137 const char *with_slash = add_slash(name);
138 int length = strlen(with_slash);
139
07047d68 140 int pos = index_name_pos(&the_index, with_slash, length);
b91a2b65
SY
141 const struct cache_entry *ce;
142
143 if (pos < 0) {
144 pos = -pos - 1;
145 if (pos >= the_index.cache_nr)
d57690a9 146 goto free_return;
dc594180 147 ce = the_index.cache[pos];
b91a2b65 148 if (strncmp(with_slash, ce->name, length))
d57690a9 149 goto free_return;
b91a2b65 150 if (ce_skip_worktree(ce))
d57690a9 151 ret = 1;
b91a2b65 152 }
d57690a9
SY
153
154free_return:
155 if (with_slash != name)
156 free((char *)with_slash);
157 return ret;
b91a2b65
SY
158}
159
7061cf0f 160int cmd_mv(int argc, const char **argv, const char *prefix)
11be42a4 161{
189d035e 162 int i, flags, gitmodules_modified = 0;
93d2c160 163 int verbose = 0, show_only = 0, force = 0, ignore_errors = 0, ignore_sparse = 0;
c7a20c11 164 struct option builtin_mv_options[] = {
6c54dc46
NTND
165 OPT__VERBOSE(&verbose, N_("be verbose")),
166 OPT__DRY_RUN(&show_only, N_("dry run")),
61d15cd6
NTND
167 OPT__FORCE(&force, N_("force move/rename even if target exists"),
168 PARSE_OPT_NOCOMPLETE),
d5d09d47 169 OPT_BOOL('k', NULL, &ignore_errors, N_("skip move/rename errors")),
93d2c160 170 OPT_BOOL(0, "sparse", &ignore_sparse, N_("allow updating entries outside of the sparse-checkout cone")),
c7a20c11
PH
171 OPT_END(),
172 };
a88c915d 173 const char **source, **destination, **dest_path, **submodule_gitfile;
c08830de 174 const char *dst_w_slash;
b6f51e3d
SY
175 const char **src_dir = NULL;
176 int src_dir_nr = 0, src_dir_alloc = 0;
177 struct strbuf a_src_dir = STRBUF_INIT;
5784db1b 178 enum update_mode *modes, dst_mode = 0;
11be42a4 179 struct stat st;
183113a5 180 struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
0fa5a2ed 181 struct lock_file lock_file = LOCK_INIT;
9b906af6 182 struct cache_entry *ce;
93d2c160 183 struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
5784db1b 184 struct string_list dirty_paths = STRING_LIST_INIT_NODUP;
11be42a4 185
ef90d6d4 186 git_config(git_default_config, NULL);
11be42a4 187
37782920
SB
188 argc = parse_options(argc, argv, prefix, builtin_mv_options,
189 builtin_mv_usage, 0);
c7a20c11
PH
190 if (--argc < 1)
191 usage_with_options(builtin_mv_usage, builtin_mv_options);
11be42a4 192
07047d68
ÆAB
193 repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
194 if (repo_read_index(the_repository) < 0)
431b049e 195 die(_("index file corrupt"));
99caeed0 196
2ec87741 197 source = internal_prefix_pathspec(prefix, argv, argc, 0);
eee227ad
JH
198 CALLOC_ARRAY(modes, argc);
199
c57f6281
MM
200 /*
201 * Keep trailing slash, needed to let
189d035e
JS
202 * "git mv file no-such-dir/" error out, except in the case
203 * "git mv directory no-such-dir/".
c57f6281 204 */
189d035e
JS
205 flags = KEEP_TRAILING_SLASH;
206 if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
207 flags = 0;
2ec87741 208 dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
c08830de 209 dst_w_slash = add_slash(dest_path[0]);
a88c915d 210 submodule_gitfile = xcalloc(argc, sizeof(char *));
11be42a4 211
c5203bdf
JS
212 if (dest_path[0][0] == '\0')
213 /* special case: "." was normalized to "" */
2ec87741 214 destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
c5203bdf 215 else if (!lstat(dest_path[0], &st) &&
ac64a722 216 S_ISDIR(st.st_mode)) {
c08830de 217 destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
ac64a722 218 } else {
c08830de
SY
219 if (!path_in_sparse_checkout(dst_w_slash, &the_index) &&
220 empty_dir_has_sparse_contents(dst_w_slash)) {
221 destination = internal_prefix_pathspec(dst_w_slash, argv, argc, DUP_BASENAME);
5784db1b 222 dst_mode = SKIP_WORKTREE_DIR;
c08830de 223 } else if (argc != 1) {
eac0ccc2 224 die(_("destination '%s' is not a directory"), dest_path[0]);
c08830de
SY
225 } else {
226 destination = dest_path;
5784db1b
SY
227 /*
228 * <destination> is a file outside of sparse-checkout
229 * cone. Insist on cone mode here for backward
230 * compatibility. We don't want dst_mode to be assigned
231 * for a file when the repo is using no-cone mode (which
232 * is deprecated at this point) sparse-checkout. As
233 * SPARSE here is only considering cone-mode situation.
234 */
235 if (!path_in_cone_mode_sparse_checkout(destination[0], &the_index))
236 dst_mode = SPARSE;
c08830de
SY
237 }
238 }
239 if (dst_w_slash != dest_path[0]) {
240 free((char *)dst_w_slash);
241 dst_w_slash = NULL;
11be42a4
JS
242 }
243
244 /* Checking */
c7a20c11 245 for (i = 0; i < argc; i++) {
60a6bf5f 246 const char *src = source[i], *dst = destination[i];
b91a2b65 247 int length;
11be42a4 248 const char *bad = NULL;
93d2c160 249 int skip_sparse = 0;
11be42a4
JS
250
251 if (show_only)
431b049e 252 printf(_("Checking rename of '%s' to '%s'\n"), src, dst);
11be42a4 253
60a6bf5f 254 length = strlen(src);
93d2c160 255 if (lstat(src, &st) < 0) {
6645b03c
SY
256 int pos;
257 const struct cache_entry *ce;
258
07047d68 259 pos = index_name_pos(&the_index, src, length);
6645b03c 260 if (pos < 0) {
b91a2b65
SY
261 const char *src_w_slash = add_slash(src);
262 if (!path_in_sparse_checkout(src_w_slash, &the_index) &&
72e59ba1 263 empty_dir_has_sparse_contents(src)) {
b91a2b65
SY
264 modes[i] |= SKIP_WORKTREE_DIR;
265 goto dir_check;
266 }
6645b03c 267 /* only error if existence is expected. */
24ea81d9 268 if (!(modes[i] & SPARSE))
6645b03c
SY
269 bad = _("bad source");
270 goto act_on_entry;
271 }
dc594180 272 ce = the_index.cache[pos];
6645b03c 273 if (!ce_skip_worktree(ce)) {
93d2c160 274 bad = _("bad source");
7889755b
SY
275 goto act_on_entry;
276 }
8a26a391 277 if (!ignore_sparse) {
6645b03c 278 string_list_append(&only_match_skip_worktree, src);
8a26a391
SY
279 goto act_on_entry;
280 }
281 /* Check if dst exists in index */
07047d68 282 if (index_name_pos(&the_index, dst, strlen(dst)) < 0) {
24ea81d9 283 modes[i] |= SPARSE;
8a26a391
SY
284 goto act_on_entry;
285 }
286 if (!force) {
287 bad = _("destination exists");
288 goto act_on_entry;
289 }
24ea81d9 290 modes[i] |= SPARSE;
6645b03c 291 goto act_on_entry;
7889755b
SY
292 }
293 if (!strncmp(src, dst, length) &&
294 (dst[length] == 0 || dst[length] == '/')) {
a7d5629f 295 bad = _("can not move directory into itself");
7889755b
SY
296 goto act_on_entry;
297 }
b91a2b65 298 if (S_ISDIR(st.st_mode)
7889755b 299 && lstat(dst, &st) == 0) {
a7d5629f 300 bad = _("cannot move directory over file");
7889755b
SY
301 goto act_on_entry;
302 }
b91a2b65
SY
303
304dir_check:
305 if (S_ISDIR(st.st_mode)) {
7889755b 306 int j, dst_len, n;
07047d68 307 int first = index_name_pos(&the_index, src, length), last;
3af05a6d 308
7889755b 309 if (first >= 0) {
3af05a6d
NTND
310 prepare_move_submodule(src, first,
311 submodule_gitfile + i);
7889755b
SY
312 goto act_on_entry;
313 } else if (index_range_of_same_dir(src, length,
314 &first, &last) < 1) {
b46b15de 315 bad = _("source directory is empty");
7889755b
SY
316 goto act_on_entry;
317 }
11502468 318
7889755b 319 /* last - first >= 1 */
24ea81d9 320 modes[i] |= WORKING_DIRECTORY;
b6f51e3d
SY
321
322 ALLOC_GROW(src_dir, src_dir_nr + 1, src_dir_alloc);
323 src_dir[src_dir_nr++] = src;
324
7889755b
SY
325 n = argc + last - first;
326 REALLOC_ARRAY(source, n);
327 REALLOC_ARRAY(destination, n);
328 REALLOC_ARRAY(modes, n);
329 REALLOC_ARRAY(submodule_gitfile, n);
b46b15de 330
7889755b
SY
331 dst = add_slash(dst);
332 dst_len = strlen(dst);
b46b15de 333
7889755b 334 for (j = 0; j < last - first; j++) {
dc594180 335 const struct cache_entry *ce = the_index.cache[first + j];
7889755b
SY
336 const char *path = ce->name;
337 source[argc + j] = path;
338 destination[argc + j] =
339 prefix_path(dst, dst_len, path + length + 1);
24ea81d9
SY
340 memset(modes + argc + j, 0, sizeof(enum update_mode));
341 modes[argc + j] |= ce_skip_worktree(ce) ? SPARSE : INDEX;
7889755b 342 submodule_gitfile[argc + j] = NULL;
ac64a722 343 }
7889755b
SY
344 argc += last - first;
345 goto act_on_entry;
346 }
fbc1ed62 347 if (!(ce = index_file_exists(&the_index, src, length, 0))) {
a7d5629f 348 bad = _("not under version control");
7889755b
SY
349 goto act_on_entry;
350 }
351 if (ce_stage(ce)) {
9b906af6 352 bad = _("conflicted");
7889755b
SY
353 goto act_on_entry;
354 }
355 if (lstat(dst, &st) == 0 &&
356 (!ignore_case || strcasecmp(src, dst))) {
a7d5629f 357 bad = _("destination exists");
11be42a4
JS
358 if (force) {
359 /*
360 * only files can overwrite each other:
361 * check both source and destination
362 */
81dc2307 363 if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
534376ca
JK
364 if (verbose)
365 warning(_("overwriting '%s'"), dst);
11be42a4 366 bad = NULL;
11be42a4 367 } else
a7d5629f 368 bad = _("Cannot overwrite");
11be42a4 369 }
7889755b
SY
370 goto act_on_entry;
371 }
372 if (string_list_has_string(&src_for_dst, dst)) {
a7d5629f 373 bad = _("multiple sources for the same target");
7889755b
SY
374 goto act_on_entry;
375 }
376 if (is_dir_sep(dst[strlen(dst) - 1])) {
a8933469 377 bad = _("destination directory does not exist");
7889755b
SY
378 goto act_on_entry;
379 }
93d2c160 380
da6fe05b
SY
381 if (ignore_sparse &&
382 (dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
383 index_entry_exists(&the_index, dst, strlen(dst))) {
384 bad = _("destination exists in the index");
385 if (force) {
386 if (verbose)
387 warning(_("overwriting '%s'"), dst);
388 bad = NULL;
389 } else {
390 goto act_on_entry;
391 }
392 }
7889755b
SY
393 /*
394 * We check if the paths are in the sparse-checkout
395 * definition as a very final check, since that
396 * allows us to point the user to the --sparse
397 * option as a way to have a successful run.
398 */
399 if (!ignore_sparse &&
400 !path_in_sparse_checkout(src, &the_index)) {
401 string_list_append(&only_match_skip_worktree, src);
402 skip_sparse = 1;
403 }
404 if (!ignore_sparse &&
405 !path_in_sparse_checkout(dst, &the_index)) {
406 string_list_append(&only_match_skip_worktree, dst);
407 skip_sparse = 1;
93d2c160 408 }
11be42a4 409
7889755b
SY
410 if (skip_sparse)
411 goto remove_entry;
412
413 string_list_insert(&src_for_dst, dst);
414
415act_on_entry:
ad1a19d0
NTND
416 if (!bad)
417 continue;
418 if (!ignore_errors)
4f1bbd23 419 die(_("%s, source=%s, destination=%s"),
ad1a19d0 420 bad, src, dst);
93d2c160 421remove_entry:
ad1a19d0
NTND
422 if (--argc > 0) {
423 int n = argc - i;
eee227ad
JH
424 MOVE_ARRAY(source + i, source + i + 1, n);
425 MOVE_ARRAY(destination + i, destination + i + 1, n);
426 MOVE_ARRAY(modes + i, modes + i + 1, n);
427 MOVE_ARRAY(submodule_gitfile + i,
428 submodule_gitfile + i + 1, n);
ad1a19d0 429 i--;
11be42a4
JS
430 }
431 }
432
93d2c160
DS
433 if (only_match_skip_worktree.nr) {
434 advise_on_updating_sparse_paths(&only_match_skip_worktree);
435 if (!ignore_errors)
436 return 1;
437 }
438
c7a20c11 439 for (i = 0; i < argc; i++) {
60a6bf5f
JS
440 const char *src = source[i], *dst = destination[i];
441 enum update_mode mode = modes[i];
81dc2307 442 int pos;
5784db1b 443 int sparse_and_dirty = 0;
707fa2f7
SY
444 struct checkout state = CHECKOUT_INIT;
445 state.istate = &the_index;
446
447 if (force)
448 state.force = 1;
11be42a4 449 if (show_only || verbose)
431b049e 450 printf(_("Renaming %s to %s\n"), src, dst);
a127331c
SB
451 if (show_only)
452 continue;
b91a2b65 453 if (!(mode & (INDEX | SPARSE | SKIP_WORKTREE_DIR)) &&
5784db1b 454 !(dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
24ea81d9 455 rename(src, dst) < 0) {
a127331c
SB
456 if (ignore_errors)
457 continue;
458 die_errno(_("renaming '%s' failed"), src);
459 }
460 if (submodule_gitfile[i]) {
a127331c
SB
461 if (!update_path_in_gitmodules(src, dst))
462 gitmodules_modified = 1;
da62f786
SB
463 if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
464 connect_work_tree_and_git_dir(dst,
465 submodule_gitfile[i],
466 1);
a88c915d 467 }
60a6bf5f 468
b91a2b65 469 if (mode & (WORKING_DIRECTORY | SKIP_WORKTREE_DIR))
ac64a722
JS
470 continue;
471
07047d68 472 pos = index_name_pos(&the_index, src, strlen(src));
81dc2307 473 assert(pos >= 0);
5784db1b 474 if (!(mode & SPARSE) && !lstat(src, &st))
031b2033 475 sparse_and_dirty = ie_modified(&the_index,
dc594180
ÆAB
476 the_index.cache[pos],
477 &st,
031b2033 478 0);
fbc1ed62 479 rename_index_entry_at(&the_index, pos, dst);
707fa2f7 480
5784db1b
SY
481 if (ignore_sparse &&
482 core_apply_sparse_checkout &&
483 core_sparse_checkout_cone) {
484 /*
485 * NEEDSWORK: we are *not* paying attention to
486 * "out-to-out" move (<source> is out-of-cone and
487 * <destination> is out-of-cone) at this point. It
488 * should be added in a future patch.
489 */
490 if ((mode & SPARSE) &&
491 path_in_sparse_checkout(dst, &the_index)) {
492 /* from out-of-cone to in-cone */
babed893
ÆAB
493 int dst_pos = index_name_pos(&the_index, dst,
494 strlen(dst));
dc594180 495 struct cache_entry *dst_ce = the_index.cache[dst_pos];
5784db1b
SY
496
497 dst_ce->ce_flags &= ~CE_SKIP_WORKTREE;
498
499 if (checkout_entry(dst_ce, &state, NULL, NULL))
500 die(_("cannot checkout %s"), dst_ce->name);
501 } else if ((dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
502 !(mode & SPARSE) &&
503 !path_in_sparse_checkout(dst, &the_index)) {
504 /* from in-cone to out-of-cone */
babed893
ÆAB
505 int dst_pos = index_name_pos(&the_index, dst,
506 strlen(dst));
dc594180 507 struct cache_entry *dst_ce = the_index.cache[dst_pos];
707fa2f7 508
5784db1b
SY
509 /*
510 * if src is clean, it will suffice to remove it
511 */
512 if (!sparse_and_dirty) {
513 dst_ce->ce_flags |= CE_SKIP_WORKTREE;
514 unlink_or_warn(src);
515 } else {
516 /*
517 * if src is dirty, move it to the
518 * destination and create leading
519 * dirs if necessary
520 */
521 char *dst_dup = xstrdup(dst);
522 string_list_append(&dirty_paths, dst);
523 safe_create_leading_directories(dst_dup);
524 FREE_AND_NULL(dst_dup);
525 rename(src, dst);
526 }
527 }
707fa2f7 528 }
11be42a4 529 }
707fa2f7 530
b6f51e3d
SY
531 /*
532 * cleanup the empty src_dirs
533 */
534 for (i = 0; i < src_dir_nr; i++) {
535 int dummy;
536 strbuf_addstr(&a_src_dir, src_dir[i]);
537 /*
538 * if entries under a_src_dir are all moved away,
539 * recursively remove a_src_dir to cleanup
540 */
541 if (index_range_of_same_dir(a_src_dir.buf, a_src_dir.len,
542 &dummy, &dummy) < 1) {
543 remove_dir_recursively(&a_src_dir, 0);
707fa2f7 544 }
b6f51e3d 545 strbuf_reset(&a_src_dir);
11be42a4
JS
546 }
547
b6f51e3d
SY
548 strbuf_release(&a_src_dir);
549 free(src_dir);
550
5efd533e
SY
551 if (dirty_paths.nr)
552 advise_on_moving_dirty_path(&dirty_paths);
553
0656781f 554 if (gitmodules_modified)
3b8317a9 555 stage_updated_gitmodules(&the_index);
0656781f 556
61000814
557 if (write_locked_index(&the_index, &lock_file,
558 COMMIT_LOCK | SKIP_IF_UNCHANGED))
dcadc8b8 559 die(_("Unable to write new index file"));
11be42a4 560
ed3c566d 561 string_list_clear(&src_for_dst, 0);
5784db1b 562 string_list_clear(&dirty_paths, 0);
ed3c566d
AH
563 UNLEAK(source);
564 UNLEAK(dest_path);
565 free(submodule_gitfile);
566 free(modes);
11be42a4
JS
567 return 0;
568}