2 * "git mv" builtin command
4 * Copyright (C) 2006 Johannes Schindelin
6 #define USE_THE_INDEX_VARIABLE
11 #include "environment.h"
16 #include "cache-tree.h"
17 #include "string-list.h"
18 #include "parse-options.h"
20 #include "submodule.h"
23 static const char * const builtin_mv_usage
[] = {
24 N_("git mv [<options>] <source>... <destination>"),
29 WORKING_DIRECTORY
= (1 << 1),
32 SKIP_WORKTREE_DIR
= (1 << 4),
35 #define DUP_BASENAME 1
36 #define KEEP_TRAILING_SLASH 2
38 static const char **internal_prefix_pathspec(const char *prefix
,
39 const char **pathspec
,
40 int count
, unsigned flags
)
44 int prefixlen
= prefix
? strlen(prefix
) : 0;
45 ALLOC_ARRAY(result
, count
+ 1);
47 /* Create an intermediate copy of the pathspec based on the flags */
48 for (i
= 0; i
< count
; i
++) {
49 int length
= strlen(pathspec
[i
]);
52 while (!(flags
& KEEP_TRAILING_SLASH
) &&
53 to_copy
> 0 && is_dir_sep(pathspec
[i
][to_copy
- 1]))
56 it
= xmemdupz(pathspec
[i
], to_copy
);
57 if (flags
& DUP_BASENAME
) {
58 result
[i
] = xstrdup(basename(it
));
66 /* Prefix the pathspec and free the old intermediate strings */
67 for (i
= 0; i
< count
; i
++) {
68 const char *match
= prefix_path(prefix
, prefixlen
, result
[i
]);
69 free((char *) result
[i
]);
76 static const char *add_slash(const char *path
)
78 size_t len
= strlen(path
);
79 if (len
&& path
[len
- 1] != '/') {
80 char *with_slash
= xmalloc(st_add(len
, 2));
81 memcpy(with_slash
, path
, len
);
82 with_slash
[len
++] = '/';
89 #define SUBMODULE_WITH_GITDIR ((const char *)1)
91 static void prepare_move_submodule(const char *src
, int first
,
92 const char **submodule_gitfile
)
94 struct strbuf submodule_dotgit
= STRBUF_INIT
;
95 if (!S_ISGITLINK(the_index
.cache
[first
]->ce_mode
))
96 die(_("Directory %s is in index and no submodule?"), src
);
97 if (!is_staging_gitmodules_ok(&the_index
))
98 die(_("Please stage your changes to .gitmodules or stash them to proceed"));
99 strbuf_addf(&submodule_dotgit
, "%s/.git", src
);
100 *submodule_gitfile
= read_gitfile(submodule_dotgit
.buf
);
101 if (*submodule_gitfile
)
102 *submodule_gitfile
= xstrdup(*submodule_gitfile
);
104 *submodule_gitfile
= SUBMODULE_WITH_GITDIR
;
105 strbuf_release(&submodule_dotgit
);
108 static int index_range_of_same_dir(const char *src
, int length
,
109 int *first_p
, int *last_p
)
111 const char *src_w_slash
= add_slash(src
);
112 int first
, last
, len_w_slash
= length
+ 1;
114 first
= index_name_pos(&the_index
, src_w_slash
, len_w_slash
);
116 die(_("%.*s is in index"), len_w_slash
, src_w_slash
);
119 for (last
= first
; last
< the_index
.cache_nr
; last
++) {
120 const char *path
= the_index
.cache
[last
]->name
;
121 if (strncmp(path
, src_w_slash
, len_w_slash
))
124 if (src_w_slash
!= src
)
125 free((char *)src_w_slash
);
132 * Given the path of a directory that does not exist on-disk, check whether the
133 * directory contains any entries in the index with the SKIP_WORKTREE flag
135 * Return 1 if such index entries exist.
136 * Return 0 otherwise.
138 static int empty_dir_has_sparse_contents(const char *name
)
141 const char *with_slash
= add_slash(name
);
142 int length
= strlen(with_slash
);
144 int pos
= index_name_pos(&the_index
, with_slash
, length
);
145 const struct cache_entry
*ce
;
149 if (pos
>= the_index
.cache_nr
)
151 ce
= the_index
.cache
[pos
];
152 if (strncmp(with_slash
, ce
->name
, length
))
154 if (ce_skip_worktree(ce
))
159 if (with_slash
!= name
)
160 free((char *)with_slash
);
164 int cmd_mv(int argc
, const char **argv
, const char *prefix
)
166 int i
, flags
, gitmodules_modified
= 0;
167 int verbose
= 0, show_only
= 0, force
= 0, ignore_errors
= 0, ignore_sparse
= 0;
168 struct option builtin_mv_options
[] = {
169 OPT__VERBOSE(&verbose
, N_("be verbose")),
170 OPT__DRY_RUN(&show_only
, N_("dry run")),
171 OPT__FORCE(&force
, N_("force move/rename even if target exists"),
172 PARSE_OPT_NOCOMPLETE
),
173 OPT_BOOL('k', NULL
, &ignore_errors
, N_("skip move/rename errors")),
174 OPT_BOOL(0, "sparse", &ignore_sparse
, N_("allow updating entries outside of the sparse-checkout cone")),
177 const char **source
, **destination
, **dest_path
, **submodule_gitfile
;
178 const char *dst_w_slash
;
179 const char **src_dir
= NULL
;
180 int src_dir_nr
= 0, src_dir_alloc
= 0;
181 struct strbuf a_src_dir
= STRBUF_INIT
;
182 enum update_mode
*modes
, dst_mode
= 0;
184 struct string_list src_for_dst
= STRING_LIST_INIT_NODUP
;
185 struct lock_file lock_file
= LOCK_INIT
;
186 struct cache_entry
*ce
;
187 struct string_list only_match_skip_worktree
= STRING_LIST_INIT_NODUP
;
188 struct string_list dirty_paths
= STRING_LIST_INIT_NODUP
;
190 git_config(git_default_config
, NULL
);
192 argc
= parse_options(argc
, argv
, prefix
, builtin_mv_options
,
193 builtin_mv_usage
, 0);
195 usage_with_options(builtin_mv_usage
, builtin_mv_options
);
197 repo_hold_locked_index(the_repository
, &lock_file
, LOCK_DIE_ON_ERROR
);
198 if (repo_read_index(the_repository
) < 0)
199 die(_("index file corrupt"));
201 source
= internal_prefix_pathspec(prefix
, argv
, argc
, 0);
202 CALLOC_ARRAY(modes
, argc
);
205 * Keep trailing slash, needed to let
206 * "git mv file no-such-dir/" error out, except in the case
207 * "git mv directory no-such-dir/".
209 flags
= KEEP_TRAILING_SLASH
;
210 if (argc
== 1 && is_directory(argv
[0]) && !is_directory(argv
[1]))
212 dest_path
= internal_prefix_pathspec(prefix
, argv
+ argc
, 1, flags
);
213 dst_w_slash
= add_slash(dest_path
[0]);
214 submodule_gitfile
= xcalloc(argc
, sizeof(char *));
216 if (dest_path
[0][0] == '\0')
217 /* special case: "." was normalized to "" */
218 destination
= internal_prefix_pathspec(dest_path
[0], argv
, argc
, DUP_BASENAME
);
219 else if (!lstat(dest_path
[0], &st
) &&
220 S_ISDIR(st
.st_mode
)) {
221 destination
= internal_prefix_pathspec(dst_w_slash
, argv
, argc
, DUP_BASENAME
);
223 if (!path_in_sparse_checkout(dst_w_slash
, &the_index
) &&
224 empty_dir_has_sparse_contents(dst_w_slash
)) {
225 destination
= internal_prefix_pathspec(dst_w_slash
, argv
, argc
, DUP_BASENAME
);
226 dst_mode
= SKIP_WORKTREE_DIR
;
227 } else if (argc
!= 1) {
228 die(_("destination '%s' is not a directory"), dest_path
[0]);
230 destination
= dest_path
;
232 * <destination> is a file outside of sparse-checkout
233 * cone. Insist on cone mode here for backward
234 * compatibility. We don't want dst_mode to be assigned
235 * for a file when the repo is using no-cone mode (which
236 * is deprecated at this point) sparse-checkout. As
237 * SPARSE here is only considering cone-mode situation.
239 if (!path_in_cone_mode_sparse_checkout(destination
[0], &the_index
))
243 if (dst_w_slash
!= dest_path
[0]) {
244 free((char *)dst_w_slash
);
249 for (i
= 0; i
< argc
; i
++) {
250 const char *src
= source
[i
], *dst
= destination
[i
];
252 const char *bad
= NULL
;
256 printf(_("Checking rename of '%s' to '%s'\n"), src
, dst
);
258 length
= strlen(src
);
259 if (lstat(src
, &st
) < 0) {
261 const struct cache_entry
*ce
;
263 pos
= index_name_pos(&the_index
, src
, length
);
265 const char *src_w_slash
= add_slash(src
);
266 if (!path_in_sparse_checkout(src_w_slash
, &the_index
) &&
267 empty_dir_has_sparse_contents(src
)) {
268 modes
[i
] |= SKIP_WORKTREE_DIR
;
271 /* only error if existence is expected. */
272 if (!(modes
[i
] & SPARSE
))
273 bad
= _("bad source");
276 ce
= the_index
.cache
[pos
];
277 if (!ce_skip_worktree(ce
)) {
278 bad
= _("bad source");
281 if (!ignore_sparse
) {
282 string_list_append(&only_match_skip_worktree
, src
);
285 /* Check if dst exists in index */
286 if (index_name_pos(&the_index
, dst
, strlen(dst
)) < 0) {
291 bad
= _("destination exists");
297 if (!strncmp(src
, dst
, length
) &&
298 (dst
[length
] == 0 || dst
[length
] == '/')) {
299 bad
= _("can not move directory into itself");
302 if (S_ISDIR(st
.st_mode
)
303 && lstat(dst
, &st
) == 0) {
304 bad
= _("cannot move directory over file");
309 if (S_ISDIR(st
.st_mode
)) {
311 int first
= index_name_pos(&the_index
, src
, length
), last
;
314 prepare_move_submodule(src
, first
,
315 submodule_gitfile
+ i
);
317 } else if (index_range_of_same_dir(src
, length
,
318 &first
, &last
) < 1) {
319 bad
= _("source directory is empty");
323 /* last - first >= 1 */
324 modes
[i
] |= WORKING_DIRECTORY
;
326 ALLOC_GROW(src_dir
, src_dir_nr
+ 1, src_dir_alloc
);
327 src_dir
[src_dir_nr
++] = src
;
329 n
= argc
+ last
- first
;
330 REALLOC_ARRAY(source
, n
);
331 REALLOC_ARRAY(destination
, n
);
332 REALLOC_ARRAY(modes
, n
);
333 REALLOC_ARRAY(submodule_gitfile
, n
);
335 dst
= add_slash(dst
);
336 dst_len
= strlen(dst
);
338 for (j
= 0; j
< last
- first
; j
++) {
339 const struct cache_entry
*ce
= the_index
.cache
[first
+ j
];
340 const char *path
= ce
->name
;
341 source
[argc
+ j
] = path
;
342 destination
[argc
+ j
] =
343 prefix_path(dst
, dst_len
, path
+ length
+ 1);
344 memset(modes
+ argc
+ j
, 0, sizeof(enum update_mode
));
345 modes
[argc
+ j
] |= ce_skip_worktree(ce
) ? SPARSE
: INDEX
;
346 submodule_gitfile
[argc
+ j
] = NULL
;
348 argc
+= last
- first
;
351 if (!(ce
= index_file_exists(&the_index
, src
, length
, 0))) {
352 bad
= _("not under version control");
356 bad
= _("conflicted");
359 if (lstat(dst
, &st
) == 0 &&
360 (!ignore_case
|| strcasecmp(src
, dst
))) {
361 bad
= _("destination exists");
364 * only files can overwrite each other:
365 * check both source and destination
367 if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
369 warning(_("overwriting '%s'"), dst
);
372 bad
= _("Cannot overwrite");
376 if (string_list_has_string(&src_for_dst
, dst
)) {
377 bad
= _("multiple sources for the same target");
380 if (is_dir_sep(dst
[strlen(dst
) - 1])) {
381 bad
= _("destination directory does not exist");
386 (dst_mode
& (SKIP_WORKTREE_DIR
| SPARSE
)) &&
387 index_entry_exists(&the_index
, dst
, strlen(dst
))) {
388 bad
= _("destination exists in the index");
391 warning(_("overwriting '%s'"), dst
);
398 * We check if the paths are in the sparse-checkout
399 * definition as a very final check, since that
400 * allows us to point the user to the --sparse
401 * option as a way to have a successful run.
403 if (!ignore_sparse
&&
404 !path_in_sparse_checkout(src
, &the_index
)) {
405 string_list_append(&only_match_skip_worktree
, src
);
408 if (!ignore_sparse
&&
409 !path_in_sparse_checkout(dst
, &the_index
)) {
410 string_list_append(&only_match_skip_worktree
, dst
);
417 string_list_insert(&src_for_dst
, dst
);
423 die(_("%s, source=%s, destination=%s"),
428 MOVE_ARRAY(source
+ i
, source
+ i
+ 1, n
);
429 MOVE_ARRAY(destination
+ i
, destination
+ i
+ 1, n
);
430 MOVE_ARRAY(modes
+ i
, modes
+ i
+ 1, n
);
431 MOVE_ARRAY(submodule_gitfile
+ i
,
432 submodule_gitfile
+ i
+ 1, n
);
437 if (only_match_skip_worktree
.nr
) {
438 advise_on_updating_sparse_paths(&only_match_skip_worktree
);
443 for (i
= 0; i
< argc
; i
++) {
444 const char *src
= source
[i
], *dst
= destination
[i
];
445 enum update_mode mode
= modes
[i
];
447 int sparse_and_dirty
= 0;
448 struct checkout state
= CHECKOUT_INIT
;
449 state
.istate
= &the_index
;
453 if (show_only
|| verbose
)
454 printf(_("Renaming %s to %s\n"), src
, dst
);
457 if (!(mode
& (INDEX
| SPARSE
| SKIP_WORKTREE_DIR
)) &&
458 !(dst_mode
& (SKIP_WORKTREE_DIR
| SPARSE
)) &&
459 rename(src
, dst
) < 0) {
462 die_errno(_("renaming '%s' failed"), src
);
464 if (submodule_gitfile
[i
]) {
465 if (!update_path_in_gitmodules(src
, dst
))
466 gitmodules_modified
= 1;
467 if (submodule_gitfile
[i
] != SUBMODULE_WITH_GITDIR
)
468 connect_work_tree_and_git_dir(dst
,
469 submodule_gitfile
[i
],
473 if (mode
& (WORKING_DIRECTORY
| SKIP_WORKTREE_DIR
))
476 pos
= index_name_pos(&the_index
, src
, strlen(src
));
478 if (!(mode
& SPARSE
) && !lstat(src
, &st
))
479 sparse_and_dirty
= ie_modified(&the_index
,
480 the_index
.cache
[pos
],
483 rename_index_entry_at(&the_index
, pos
, dst
);
486 core_apply_sparse_checkout
&&
487 core_sparse_checkout_cone
) {
489 * NEEDSWORK: we are *not* paying attention to
490 * "out-to-out" move (<source> is out-of-cone and
491 * <destination> is out-of-cone) at this point. It
492 * should be added in a future patch.
494 if ((mode
& SPARSE
) &&
495 path_in_sparse_checkout(dst
, &the_index
)) {
496 /* from out-of-cone to in-cone */
497 int dst_pos
= index_name_pos(&the_index
, dst
,
499 struct cache_entry
*dst_ce
= the_index
.cache
[dst_pos
];
501 dst_ce
->ce_flags
&= ~CE_SKIP_WORKTREE
;
503 if (checkout_entry(dst_ce
, &state
, NULL
, NULL
))
504 die(_("cannot checkout %s"), dst_ce
->name
);
505 } else if ((dst_mode
& (SKIP_WORKTREE_DIR
| SPARSE
)) &&
507 !path_in_sparse_checkout(dst
, &the_index
)) {
508 /* from in-cone to out-of-cone */
509 int dst_pos
= index_name_pos(&the_index
, dst
,
511 struct cache_entry
*dst_ce
= the_index
.cache
[dst_pos
];
514 * if src is clean, it will suffice to remove it
516 if (!sparse_and_dirty
) {
517 dst_ce
->ce_flags
|= CE_SKIP_WORKTREE
;
521 * if src is dirty, move it to the
522 * destination and create leading
525 char *dst_dup
= xstrdup(dst
);
526 string_list_append(&dirty_paths
, dst
);
527 safe_create_leading_directories(dst_dup
);
528 FREE_AND_NULL(dst_dup
);
536 * cleanup the empty src_dirs
538 for (i
= 0; i
< src_dir_nr
; i
++) {
540 strbuf_addstr(&a_src_dir
, src_dir
[i
]);
542 * if entries under a_src_dir are all moved away,
543 * recursively remove a_src_dir to cleanup
545 if (index_range_of_same_dir(a_src_dir
.buf
, a_src_dir
.len
,
546 &dummy
, &dummy
) < 1) {
547 remove_dir_recursively(&a_src_dir
, 0);
549 strbuf_reset(&a_src_dir
);
552 strbuf_release(&a_src_dir
);
556 advise_on_moving_dirty_path(&dirty_paths
);
558 if (gitmodules_modified
)
559 stage_updated_gitmodules(&the_index
);
561 if (write_locked_index(&the_index
, &lock_file
,
562 COMMIT_LOCK
| SKIP_IF_UNCHANGED
))
563 die(_("Unable to write new index file"));
565 string_list_clear(&src_for_dst
, 0);
566 string_list_clear(&dirty_paths
, 0);
569 free(submodule_gitfile
);