13
13
#include "string-list.h"
14
14
#include "parse-options.h"
15
15
#include "submodule.h"
16
+ #include "entry.h"
16
17
17
18
static const char * const builtin_mv_usage [] = {
18
19
N_ ("git mv [<options>] <source>... <destination>" ),
19
20
NULL
20
21
};
21
22
23
+ enum update_mode {
24
+ BOTH = 0 ,
25
+ WORKING_DIRECTORY = (1 << 1 ),
26
+ INDEX = (1 << 2 ),
27
+ SPARSE = (1 << 3 ),
28
+ SKIP_WORKTREE_DIR = (1 << 4 ),
29
+ };
30
+
22
31
#define DUP_BASENAME 1
23
32
#define KEEP_TRAILING_SLASH 2
24
33
@@ -115,6 +124,36 @@ static int index_range_of_same_dir(const char *src, int length,
115
124
return last - first ;
116
125
}
117
126
127
+ /*
128
+ * Check if an out-of-cone directory should be in the index. Imagine this case
129
+ * that all the files under a directory are marked with 'CE_SKIP_WORKTREE' bit
130
+ * and thus the directory is sparsified.
131
+ *
132
+ * Return 0 if such directory exist (i.e. with any of its contained files not
133
+ * marked with CE_SKIP_WORKTREE, the directory would be present in working tree).
134
+ * Return 1 otherwise.
135
+ */
136
+ static int check_dir_in_index (const char * name )
137
+ {
138
+ const char * with_slash = add_slash (name );
139
+ int length = strlen (with_slash );
140
+
141
+ int pos = cache_name_pos (with_slash , length );
142
+ const struct cache_entry * ce ;
143
+
144
+ if (pos < 0 ) {
145
+ pos = - pos - 1 ;
146
+ if (pos >= the_index .cache_nr )
147
+ return 1 ;
148
+ ce = active_cache [pos ];
149
+ if (strncmp (with_slash , ce -> name , length ))
150
+ return 1 ;
151
+ if (ce_skip_worktree (ce ))
152
+ return 0 ;
153
+ }
154
+ return 1 ;
155
+ }
156
+
118
157
int cmd_mv (int argc , const char * * argv , const char * prefix )
119
158
{
120
159
int i , flags , gitmodules_modified = 0 ;
@@ -129,7 +168,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
129
168
OPT_END (),
130
169
};
131
170
const char * * source , * * destination , * * dest_path , * * submodule_gitfile ;
132
- enum update_mode { BOTH = 0 , WORKING_DIRECTORY , INDEX , SPARSE } * modes ;
171
+ enum update_mode * modes ;
133
172
struct stat st ;
134
173
struct string_list src_for_dst = STRING_LIST_INIT_NODUP ;
135
174
struct lock_file lock_file = LOCK_INIT ;
@@ -176,7 +215,7 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
176
215
/* Checking */
177
216
for (i = 0 ; i < argc ; i ++ ) {
178
217
const char * src = source [i ], * dst = destination [i ];
179
- int length , src_is_dir ;
218
+ int length ;
180
219
const char * bad = NULL ;
181
220
int skip_sparse = 0 ;
182
221
@@ -185,54 +224,103 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
185
224
186
225
length = strlen (src );
187
226
if (lstat (src , & st ) < 0 ) {
188
- /* only error if existence is expected. */
189
- if (modes [i ] != SPARSE )
227
+ int pos ;
228
+ const struct cache_entry * ce ;
229
+
230
+ pos = cache_name_pos (src , length );
231
+ if (pos < 0 ) {
232
+ const char * src_w_slash = add_slash (src );
233
+ if (!path_in_sparse_checkout (src_w_slash , & the_index ) &&
234
+ !check_dir_in_index (src )) {
235
+ modes [i ] |= SKIP_WORKTREE_DIR ;
236
+ goto dir_check ;
237
+ }
238
+ /* only error if existence is expected. */
239
+ if (!(modes [i ] & SPARSE ))
240
+ bad = _ ("bad source" );
241
+ goto act_on_entry ;
242
+ }
243
+ ce = active_cache [pos ];
244
+ if (!ce_skip_worktree (ce )) {
190
245
bad = _ ("bad source" );
191
- } else if (!strncmp (src , dst , length ) &&
192
- (dst [length ] == 0 || dst [length ] == '/' )) {
246
+ goto act_on_entry ;
247
+ }
248
+ if (!ignore_sparse ) {
249
+ string_list_append (& only_match_skip_worktree , src );
250
+ goto act_on_entry ;
251
+ }
252
+ /* Check if dst exists in index */
253
+ if (cache_name_pos (dst , strlen (dst )) < 0 ) {
254
+ modes [i ] |= SPARSE ;
255
+ goto act_on_entry ;
256
+ }
257
+ if (!force ) {
258
+ bad = _ ("destination exists" );
259
+ goto act_on_entry ;
260
+ }
261
+ modes [i ] |= SPARSE ;
262
+ goto act_on_entry ;
263
+ }
264
+ if (!strncmp (src , dst , length ) &&
265
+ (dst [length ] == 0 || dst [length ] == '/' )) {
193
266
bad = _ ("can not move directory into itself" );
194
- } else if ((src_is_dir = S_ISDIR (st .st_mode ))
195
- && lstat (dst , & st ) == 0 )
267
+ goto act_on_entry ;
268
+ }
269
+ if (S_ISDIR (st .st_mode )
270
+ && lstat (dst , & st ) == 0 ) {
196
271
bad = _ ("cannot move directory over file" );
197
- else if (src_is_dir ) {
272
+ goto act_on_entry ;
273
+ }
274
+
275
+ dir_check :
276
+ if (S_ISDIR (st .st_mode )) {
277
+ int j , dst_len , n ;
198
278
int first = cache_name_pos (src , length ), last ;
199
279
200
- if (first >= 0 )
280
+ if (first >= 0 ) {
201
281
prepare_move_submodule (src , first ,
202
282
submodule_gitfile + i );
203
- else if (index_range_of_same_dir (src , length ,
204
- & first , & last ) < 1 )
283
+ goto act_on_entry ;
284
+ } else if (index_range_of_same_dir (src , length ,
285
+ & first , & last ) < 1 ) {
205
286
bad = _ ("source directory is empty" );
206
- else { /* last - first >= 1 */
207
- int j , dst_len , n ;
208
-
209
- modes [ i ] = WORKING_DIRECTORY ;
210
- n = argc + last - first ;
211
- REALLOC_ARRAY ( source , n ) ;
212
- REALLOC_ARRAY (destination , n );
213
- REALLOC_ARRAY (modes , n );
214
- REALLOC_ARRAY (submodule_gitfile , n );
215
-
216
- dst = add_slash ( dst );
217
- dst_len = strlen (dst );
218
-
219
- for ( j = 0 ; j < last - first ; j ++ ) {
220
- const struct cache_entry * ce = active_cache [ first + j ];
221
- const char * path = ce -> name ;
222
- source [ argc + j ] = path ;
223
- destination [argc + j ] =
224
- prefix_path ( dst , dst_len , path + length + 1 );
225
- modes [ argc + j ] = ce_skip_worktree ( ce ) ? SPARSE : INDEX ;
226
- submodule_gitfile [ argc + j ] = NULL ;
227
- }
228
- argc += last - first ;
287
+ goto act_on_entry ;
288
+ }
289
+
290
+ /* last - first >= 1 */
291
+ modes [ i ] |= WORKING_DIRECTORY ;
292
+ n = argc + last - first ;
293
+ REALLOC_ARRAY (source , n );
294
+ REALLOC_ARRAY (destination , n );
295
+ REALLOC_ARRAY (modes , n );
296
+ REALLOC_ARRAY ( submodule_gitfile , n );
297
+
298
+ dst = add_slash (dst );
299
+ dst_len = strlen ( dst );
300
+
301
+ for ( j = 0 ; j < last - first ; j ++ ) {
302
+ const struct cache_entry * ce = active_cache [ first + j ] ;
303
+ const char * path = ce -> name ;
304
+ source [argc + j ] = path ;
305
+ destination [ argc + j ] =
306
+ prefix_path ( dst , dst_len , path + length + 1 ) ;
307
+ memset ( modes + argc + j , 0 , sizeof ( enum update_mode )) ;
308
+ modes [ argc + j ] |= ce_skip_worktree ( ce ) ? SPARSE : INDEX ;
309
+ submodule_gitfile [ argc + j ] = NULL ;
229
310
}
230
- } else if (!(ce = cache_file_exists (src , length , 0 ))) {
311
+ argc += last - first ;
312
+ goto act_on_entry ;
313
+ }
314
+ if (!(ce = cache_file_exists (src , length , 0 ))) {
231
315
bad = _ ("not under version control" );
232
- } else if (ce_stage (ce )) {
316
+ goto act_on_entry ;
317
+ }
318
+ if (ce_stage (ce )) {
233
319
bad = _ ("conflicted" );
234
- } else if (lstat (dst , & st ) == 0 &&
235
- (!ignore_case || strcasecmp (src , dst ))) {
320
+ goto act_on_entry ;
321
+ }
322
+ if (lstat (dst , & st ) == 0 &&
323
+ (!ignore_case || strcasecmp (src , dst ))) {
236
324
bad = _ ("destination exists" );
237
325
if (force ) {
238
326
/*
@@ -246,34 +334,40 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
246
334
} else
247
335
bad = _ ("Cannot overwrite" );
248
336
}
249
- } else if (string_list_has_string (& src_for_dst , dst ))
337
+ goto act_on_entry ;
338
+ }
339
+ if (string_list_has_string (& src_for_dst , dst )) {
250
340
bad = _ ("multiple sources for the same target" );
251
- else if (is_dir_sep (dst [strlen (dst ) - 1 ]))
341
+ goto act_on_entry ;
342
+ }
343
+ if (is_dir_sep (dst [strlen (dst ) - 1 ])) {
252
344
bad = _ ("destination directory does not exist" );
253
- else {
254
- /*
255
- * We check if the paths are in the sparse-checkout
256
- * definition as a very final check, since that
257
- * allows us to point the user to the --sparse
258
- * option as a way to have a successful run.
259
- */
260
- if (!ignore_sparse &&
261
- !path_in_sparse_checkout (src , & the_index )) {
262
- string_list_append (& only_match_skip_worktree , src );
263
- skip_sparse = 1 ;
264
- }
265
- if (!ignore_sparse &&
266
- !path_in_sparse_checkout (dst , & the_index )) {
267
- string_list_append (& only_match_skip_worktree , dst );
268
- skip_sparse = 1 ;
269
- }
270
-
271
- if (skip_sparse )
272
- goto remove_entry ;
345
+ goto act_on_entry ;
346
+ }
273
347
274
- string_list_insert (& src_for_dst , dst );
348
+ /*
349
+ * We check if the paths are in the sparse-checkout
350
+ * definition as a very final check, since that
351
+ * allows us to point the user to the --sparse
352
+ * option as a way to have a successful run.
353
+ */
354
+ if (!ignore_sparse &&
355
+ !path_in_sparse_checkout (src , & the_index )) {
356
+ string_list_append (& only_match_skip_worktree , src );
357
+ skip_sparse = 1 ;
275
358
}
359
+ if (!ignore_sparse &&
360
+ !path_in_sparse_checkout (dst , & the_index )) {
361
+ string_list_append (& only_match_skip_worktree , dst );
362
+ skip_sparse = 1 ;
363
+ }
364
+
365
+ if (skip_sparse )
366
+ goto remove_entry ;
367
+
368
+ string_list_insert (& src_for_dst , dst );
276
369
370
+ act_on_entry :
277
371
if (!bad )
278
372
continue ;
279
373
if (!ignore_errors )
@@ -304,11 +398,17 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
304
398
const char * src = source [i ], * dst = destination [i ];
305
399
enum update_mode mode = modes [i ];
306
400
int pos ;
401
+ struct checkout state = CHECKOUT_INIT ;
402
+ state .istate = & the_index ;
403
+
404
+ if (force )
405
+ state .force = 1 ;
307
406
if (show_only || verbose )
308
407
printf (_ ("Renaming %s to %s\n" ), src , dst );
309
408
if (show_only )
310
409
continue ;
311
- if (mode != INDEX && mode != SPARSE && rename (src , dst ) < 0 ) {
410
+ if (!(mode & (INDEX | SPARSE | SKIP_WORKTREE_DIR )) &&
411
+ rename (src , dst ) < 0 ) {
312
412
if (ignore_errors )
313
413
continue ;
314
414
die_errno (_ ("renaming '%s' failed" ), src );
@@ -322,12 +422,23 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
322
422
1 );
323
423
}
324
424
325
- if (mode == WORKING_DIRECTORY )
425
+ if (mode & ( WORKING_DIRECTORY | SKIP_WORKTREE_DIR ) )
326
426
continue ;
327
427
328
428
pos = cache_name_pos (src , strlen (src ));
329
429
assert (pos >= 0 );
330
430
rename_cache_entry_at (pos , dst );
431
+
432
+ if ((mode & SPARSE ) &&
433
+ (path_in_sparse_checkout (dst , & the_index ))) {
434
+ int dst_pos ;
435
+
436
+ dst_pos = cache_name_pos (dst , strlen (dst ));
437
+ active_cache [dst_pos ]-> ce_flags &= ~CE_SKIP_WORKTREE ;
438
+
439
+ if (checkout_entry (active_cache [dst_pos ], & state , NULL , NULL ))
440
+ die (_ ("cannot checkout %s" ), active_cache [dst_pos ]-> name );
441
+ }
331
442
}
332
443
333
444
if (gitmodules_modified )
0 commit comments