Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
git-mirror
/
git
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
0
Pull requests
0
Actions
Projects
0
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security
Insights
Files
8b5157e
Documentation
arm
compat
contrib
gitweb
mozilla-sha1
perl
ppc
t
templates
xdiff
.gitignore
.mailmap
COPYING
GIT-VERSION-GEN
INSTALL
Makefile
README
alloc.c
archive-tar.c
archive-zip.c
archive.h
base85.c
blob.c
blob.h
builtin-add.c
builtin-annotate.c
builtin-apply.c
builtin-archive.c
builtin-blame.c
builtin-branch.c
builtin-cat-file.c
builtin-check-ref-format.c
builtin-checkout-index.c
builtin-commit-tree.c
builtin-count-objects.c
builtin-describe.c
builtin-diff-files.c
builtin-diff-index.c
builtin-diff-stages.c
builtin-diff-tree.c
builtin-diff.c
builtin-fmt-merge-msg.c
builtin-for-each-ref.c
builtin-grep.c
builtin-init-db.c
builtin-log.c
builtin-ls-files.c
builtin-ls-tree.c
builtin-mailinfo.c
builtin-mailsplit.c
builtin-merge-file.c
builtin-mv.c
builtin-name-rev.c
builtin-pack-objects.c
builtin-pack-refs.c
builtin-prune-packed.c
builtin-prune.c
builtin-push.c
builtin-read-tree.c
builtin-reflog.c
builtin-repo-config.c
builtin-rerere.c
builtin-rev-list.c
builtin-rev-parse.c
builtin-rm.c
builtin-runstatus.c
builtin-shortlog.c
builtin-show-branch.c
builtin-show-ref.c
builtin-stripspace.c
builtin-symbolic-ref.c
builtin-tar-tree.c
builtin-unpack-objects.c
builtin-update-index.c
builtin-update-ref.c
builtin-upload-archive.c
builtin-verify-pack.c
builtin-write-tree.c
builtin.h
cache-tree.c
cache-tree.h
cache.h
check-builtins.sh
check-racy.c
color.c
color.h
combine-diff.c
commit.c
commit.h
config.c
config.mak.in
configure.ac
connect.c
convert-objects.c
copy.c
csum-file.c
csum-file.h
ctype.c
daemon.c
date.c
delta.h
diff-delta.c
diff-lib.c
diff.c
diff.h
diffcore-break.c
diffcore-delta.c
diffcore-order.c
diffcore-pickaxe.c
diffcore-rename.c
diffcore.h
dir.c
dir.h
dump-cache-tree.c
entry.c
environment.c
exec_cmd.c
exec_cmd.h
fetch-pack.c
fetch.c
fetch.h
fsck-objects.c
generate-cmdlist.sh
git-add--interactive.perl
git-am.sh
git-applymbox.sh
git-applypatch.sh
git-archimport.perl
git-bisect.sh
git-checkout.sh
git-clean.sh
git-clone.sh
git-commit.sh
git-compat-util.h
git-cvsexportcommit.perl
git-cvsimport.perl
git-cvsserver.perl
git-fetch.sh
git-gc.sh
git-instaweb.sh
git-lost-found.sh
git-ls-remote.sh
git-merge-octopus.sh
git-merge-one-file.sh
git-merge-ours.sh
git-merge-resolve.sh
git-merge-stupid.sh
git-merge.sh
git-p4import.py
git-parse-remote.sh
git-pull.sh
git-quiltimport.sh
git-rebase.sh
git-relink.perl
git-remote.perl
git-repack.sh
git-request-pull.sh
git-reset.sh
git-resolve.sh
git-revert.sh
git-send-email.perl
git-sh-setup.sh
git-svn.perl
git-svnimport.perl
git-tag.sh
git-verify-tag.sh
git.c
git.spec.in
gitk
grep.c
grep.h
hash-object.c
help.c
http-fetch.c
http-push.c
http.c
http.h
ident.c
imap-send.c
index-pack.c
interpolate.c
interpolate.h
list-objects.c
list-objects.h
local-fetch.c
lockfile.c
log-tree.c
log-tree.h
merge-base.c
merge-file.c
merge-index.c
merge-recursive.c
merge-tree.c
mktag.c
mktree.c
object-refs.c
object.c
object.h
pack-check.c
pack-redundant.c
pack.h
pager.c
patch-delta.c
patch-id.c
path-list.c
path-list.h
path.c
peek-remote.c
pkt-line.c
pkt-line.h
quote.c
quote.h
reachable.c
reachable.h
read-cache.c
receive-pack.c
reflog-walk.c
reflog-walk.h
refs.c
refs.h
revision.c
revision.h
rsh.c
rsh.h
run-command.c
run-command.h
send-pack.c
server-info.c
setup.c
sha1_file.c
sha1_name.c
shallow.c
shell.c
show-index.c
sideband.c
sideband.h
ssh-fetch.c
ssh-pull.c
ssh-push.c
ssh-upload.c
strbuf.c
strbuf.h
tag.c
tag.h
tar.h
test-date.c
test-delta.c
test-sha1.c
test-sha1.sh
trace.c
tree-diff.c
tree-walk.c
tree-walk.h
tree.c
tree.h
unpack-file.c
unpack-trees.c
unpack-trees.h
update-server-info.c
upload-pack.c
usage.c
utf8.c
utf8.h
var.c
write_or_die.c
wt-status.c
wt-status.h
xdiff-interface.c
xdiff-interface.h
Breadcrumbs
git
/
builtin-mv.c
Blame
Blame
Latest commit
History
History
294 lines (261 loc) · 7.45 KB
Breadcrumbs
git
/
builtin-mv.c
Top
File metadata and controls
Code
Blame
294 lines (261 loc) · 7.45 KB
Raw
/* * "git mv" builtin command * * Copyright (C) 2006 Johannes Schindelin */ #include "cache.h" #include "builtin.h" #include "dir.h" #include "cache-tree.h" #include "path-list.h" static const char builtin_mv_usage[] = "git-mv [-n] [-f] (<source> <destination> | [-k] <source>... <destination>)"; static const char **copy_pathspec(const char *prefix, const char **pathspec, int count, int base_name) { int i; const char **result = xmalloc((count + 1) * sizeof(const char *)); memcpy(result, pathspec, count * sizeof(const char *)); result[count] = NULL; for (i = 0; i < count; i++) { int length = strlen(result[i]); if (length > 0 && result[i][length - 1] == '/') { char *without_slash = xmalloc(length); memcpy(without_slash, result[i], length - 1); without_slash[length - 1] = '\0'; result[i] = without_slash; } if (base_name) { const char *last_slash = strrchr(result[i], '/'); if (last_slash) result[i] = last_slash + 1; } } return get_pathspec(prefix, result); } static void show_list(const char *label, struct path_list *list) { if (list->nr > 0) { int i; printf("%s", label); for (i = 0; i < list->nr; i++) printf("%s%s", i > 0 ? ", " : "", list->items[i].path); putchar('\n'); } } static const char *add_slash(const char *path) { int len = strlen(path); if (path[len - 1] != '/') { char *with_slash = xmalloc(len + 2); memcpy(with_slash, path, len); with_slash[len++] = '/'; with_slash[len] = 0; return with_slash; } return path; } static struct lock_file lock_file; int cmd_mv(int argc, const char **argv, const char *prefix) { int i, newfd, count; int verbose = 0, show_only = 0, force = 0, ignore_errors = 0; const char **source, **destination, **dest_path; enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes; struct stat st; struct path_list overwritten = {NULL, 0, 0, 0}; struct path_list src_for_dst = {NULL, 0, 0, 0}; struct path_list added = {NULL, 0, 0, 0}; struct path_list deleted = {NULL, 0, 0, 0}; struct path_list changed = {NULL, 0, 0, 0}; git_config(git_default_config); newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1); if (read_cache() < 0) die("index file corrupt"); for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (arg[0] != '-') break; if (!strcmp(arg, "--")) { i++; break; } if (!strcmp(arg, "-n")) { show_only = 1; continue; } if (!strcmp(arg, "-f")) { force = 1; continue; } if (!strcmp(arg, "-k")) { ignore_errors = 1; continue; } usage(builtin_mv_usage); } count = argc - i - 1; if (count < 1) usage(builtin_mv_usage); source = copy_pathspec(prefix, argv + i, count, 0); modes = xcalloc(count, sizeof(enum update_mode)); dest_path = copy_pathspec(prefix, argv + argc - 1, 1, 0); if (dest_path[0][0] == '\0') /* special case: "." was normalized to "" */ destination = copy_pathspec(dest_path[0], argv + i, count, 1); else if (!lstat(dest_path[0], &st) && S_ISDIR(st.st_mode)) { dest_path[0] = add_slash(dest_path[0]); destination = copy_pathspec(dest_path[0], argv + i, count, 1); } else { if (count != 1) usage(builtin_mv_usage); destination = dest_path; } /* Checking */ for (i = 0; i < count; i++) { const char *src = source[i], *dst = destination[i]; int length, src_is_dir; const char *bad = NULL; if (show_only) printf("Checking rename of '%s' to '%s'\n", src, dst); length = strlen(src); if (lstat(src, &st) < 0) bad = "bad source"; else if (!strncmp(src, dst, length) && (dst[length] == 0 || dst[length] == '/')) { bad = "can not move directory into itself"; } else if ((src_is_dir = S_ISDIR(st.st_mode)) && lstat(dst, &st) == 0) bad = "cannot move directory over file"; else if (src_is_dir) { const char *src_w_slash = add_slash(src); int len_w_slash = length + 1; int first, last; modes[i] = WORKING_DIRECTORY; first = cache_name_pos(src_w_slash, len_w_slash); if (first >= 0) die ("Huh? %.*s is in index?", len_w_slash, src_w_slash); first = -1 - first; for (last = first; last < active_nr; last++) { const char *path = active_cache[last]->name; if (strncmp(path, src_w_slash, len_w_slash)) break; } free((char *)src_w_slash); if (last - first < 1) bad = "source directory is empty"; else { int j, dst_len; if (last - first > 0) { source = xrealloc(source, (count + last - first) * sizeof(char *)); destination = xrealloc(destination, (count + last - first) * sizeof(char *)); modes = xrealloc(modes, (count + last - first) * sizeof(enum update_mode)); } dst = add_slash(dst); dst_len = strlen(dst) - 1; for (j = 0; j < last - first; j++) { const char *path = active_cache[first + j]->name; source[count + j] = path; destination[count + j] = prefix_path(dst, dst_len, path + length); modes[count + j] = INDEX; } count += last - first; } } else if (lstat(dst, &st) == 0) { bad = "destination exists"; if (force) { /* * only files can overwrite each other: * check both source and destination */ if (S_ISREG(st.st_mode)) { fprintf(stderr, "Warning: %s;" " will overwrite!\n", bad); bad = NULL; path_list_insert(dst, &overwritten); } else bad = "Cannot overwrite"; } } else if (cache_name_pos(src, length) < 0) bad = "not under version control"; else if (path_list_has_path(&src_for_dst, dst)) bad = "multiple sources for the same target"; else path_list_insert(dst, &src_for_dst); if (bad) { if (ignore_errors) { if (--count > 0) { memmove(source + i, source + i + 1, (count - i) * sizeof(char *)); memmove(destination + i, destination + i + 1, (count - i) * sizeof(char *)); } } else die ("%s, source=%s, destination=%s", bad, src, dst); } } for (i = 0; i < count; i++) { const char *src = source[i], *dst = destination[i]; enum update_mode mode = modes[i]; if (show_only || verbose) printf("Renaming %s to %s\n", src, dst); if (!show_only && mode != INDEX && rename(src, dst) < 0 && !ignore_errors) die ("renaming %s failed: %s", src, strerror(errno)); if (mode == WORKING_DIRECTORY) continue; if (cache_name_pos(src, strlen(src)) >= 0) { path_list_insert(src, &deleted); /* destination can be a directory with 1 file inside */ if (path_list_has_path(&overwritten, dst)) path_list_insert(dst, &changed); else path_list_insert(dst, &added); } else path_list_insert(dst, &added); } if (show_only) { show_list("Changed : ", &changed); show_list("Adding : ", &added); show_list("Deleting : ", &deleted); } else { for (i = 0; i < changed.nr; i++) { const char *path = changed.items[i].path; int j = cache_name_pos(path, strlen(path)); struct cache_entry *ce = active_cache[j]; if (j < 0) die ("Huh? Cache entry for %s unknown?", path); refresh_cache_entry(ce, 0); } for (i = 0; i < added.nr; i++) { const char *path = added.items[i].path; add_file_to_index(path, verbose); } for (i = 0; i < deleted.nr; i++) { const char *path = deleted.items[i].path; remove_file_from_cache(path); cache_tree_invalidate_path(active_cache_tree, path); } if (active_cache_changed) { if (write_cache(newfd, active_cache, active_nr) || close(newfd) || commit_lock_file(&lock_file)) die("Unable to write new index file"); } } return 0; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
You can’t perform that action at this time.