prune_directory(dir, pathspec, baselen);
}
-static int add_file_to_index(const char *path, int verbose)
-{
- int size, namelen;
- struct stat st;
- struct cache_entry *ce;
-
- if (lstat(path, &st))
- die("%s: unable to stat (%s)", path, strerror(errno));
-
- if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode))
- die("%s: can only add regular files or symbolic links", path);
-
- namelen = strlen(path);
- size = cache_entry_size(namelen);
- ce = xcalloc(1, size);
- memcpy(ce->name, path, namelen);
- ce->ce_flags = htons(namelen);
- fill_stat_cache_info(ce, &st);
-
- ce->ce_mode = create_ce_mode(st.st_mode);
- if (!trust_executable_bit) {
- /* If there is an existing entry, pick the mode bits
- * from it.
- */
- int pos = cache_name_pos(path, namelen);
- if (pos >= 0)
- ce->ce_mode = active_cache[pos]->ce_mode;
- }
-
- if (index_path(ce->sha1, path, &st, 1))
- die("unable to index file %s", path);
- if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD))
- die("unable to add %s to index",path);
- if (verbose)
- printf("add '%s'\n", path);
- cache_tree_invalidate_path(active_cache_tree, path);
- return 0;
-}
-
static struct lock_file lock_file;
- int cmd_add(int argc, const char **argv, char **envp)
+ int cmd_add(int argc, const char **argv, const char *prefix)
{
int i, newfd;
int verbose = 0, show_only = 0;
--- /dev/null
- int cmd_mv(int argc, const char **argv, char **envp)
+/*
+ * "git mv" builtin command
+ *
+ * Copyright (C) 2006 Johannes Schindelin
+ */
+#include <fnmatch.h>
+
+#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)
+{
+ const char **result = xmalloc((count + 1) * sizeof(const char *));
+ memcpy(result, pathspec, count * sizeof(const char *));
+ result[count] = NULL;
+ if (base_name) {
+ int i;
+ for (i = 0; i < count; i++) {
+ 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);
+ strcat(with_slash + len, "/");
+ return with_slash;
+ }
+ return path;
+}
+
+static struct lock_file lock_file;
+
- const char *prefix = setup_git_directory();
++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());
+ if (newfd < 0)
+ die("unable to create new index file");
+
+ 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;
+ }
+ die(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 (!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 *bad = NULL;
+
+ if (show_only)
+ printf("Checking rename of '%s' to '%s'\n",
+ source[i], destination[i]);
+
+ if (lstat(source[i], &st) < 0)
+ bad = "bad source";
+
+ if (S_ISDIR(st.st_mode)) {
+ const char *dir = source[i], *dest_dir = destination[i];
+ int first, last, len = strlen(dir);
+
+ if (lstat(dest_dir, &st) == 0) {
+ bad = "cannot move directory over file";
+ goto next;
+ }
+
+ modes[i] = WORKING_DIRECTORY;
+
+ first = cache_name_pos(source[i], len);
+ if (first >= 0)
+ die ("Huh? %s/ is in index?", dir);
+
+ first = -1 - first;
+ for (last = first; last < active_nr; last++) {
+ const char *path = active_cache[last]->name;
+ if (strncmp(path, dir, len) || path[len] != '/')
+ break;
+ }
+
+ if (last - first < 1)
+ bad = "source directory is empty";
+ else if (!bad) {
+ int j, dst_len = strlen(dest_dir);
+
+ if (last - first > 0) {
+ source = realloc(source,
+ (count + last - first)
+ * sizeof(char *));
+ destination = realloc(destination,
+ (count + last - first)
+ * sizeof(char *));
+ modes = realloc(modes,
+ (count + last - first)
+ * sizeof(enum update_mode));
+ }
+
+ dest_dir = add_slash(dest_dir);
+
+ for (j = 0; j < last - first; j++) {
+ const char *path =
+ active_cache[first + j]->name;
+ source[count + j] = path;
+ destination[count + j] =
+ prefix_path(dest_dir, dst_len,
+ path + len);
+ modes[count + j] = INDEX;
+ }
+ count += last - first;
+ }
+
+ goto next;
+ }
+
+ if (!bad && lstat(destination[i], &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(destination[i],
+ &overwritten);
+ } else
+ bad = "Cannot overwrite";
+ }
+ }
+
+ if (!bad &&
+ !strncmp(destination[i], source[i], strlen(source[i])))
+ bad = "can not move directory into itself";
+
+ if (!bad && cache_name_pos(source[i], strlen(source[i])) < 0)
+ bad = "not under version control";
+
+ if (!bad) {
+ if (path_list_has_path(&src_for_dst, destination[i]))
+ bad = "multiple sources for the same target";
+ else
+ path_list_insert(destination[i], &src_for_dst);
+ }
+
+next:
+ 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, source[i], destination[i]);
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ if (show_only || verbose)
+ printf("Renaming %s to %s\n",
+ source[i], destination[i]);
+ if (!show_only && modes[i] != INDEX &&
+ rename(source[i], destination[i]) < 0 &&
+ !ignore_errors)
+ die ("renaming %s failed: %s",
+ source[i], strerror(errno));
+
+ if (modes[i] == WORKING_DIRECTORY)
+ continue;
+
+ if (cache_name_pos(source[i], strlen(source[i])) >= 0) {
+ path_list_insert(source[i], &deleted);
+
+ /* destination can be a directory with 1 file inside */
+ if (path_list_has_path(&overwritten, destination[i]))
+ path_list_insert(destination[i], &changed);
+ else
+ path_list_insert(destination[i], &added);
+ } else
+ path_list_insert(destination[i], &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 i = cache_name_pos(path, strlen(path));
+ struct cache_entry *ce = active_cache[i];
+
+ if (i < 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);
+ }
+
+ 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;
+}
#endif
;
- extern int cmd_help(int argc, const char **argv, char **envp);
- extern int cmd_version(int argc, const char **argv, char **envp);
+ extern int cmd_help(int argc, const char **argv, const char *prefix);
+ extern int cmd_version(int argc, const char **argv, const char *prefix);
- extern int cmd_whatchanged(int argc, const char **argv, char **envp);
- extern int cmd_show(int argc, const char **argv, char **envp);
- extern int cmd_log(int argc, const char **argv, char **envp);
- extern int cmd_diff(int argc, const char **argv, char **envp);
- extern int cmd_format_patch(int argc, const char **argv, char **envp);
- extern int cmd_count_objects(int argc, const char **argv, char **envp);
+ extern int cmd_whatchanged(int argc, const char **argv, const char *prefix);
+ extern int cmd_show(int argc, const char **argv, const char *prefix);
+ extern int cmd_log(int argc, const char **argv, const char *prefix);
+ extern int cmd_diff(int argc, const char **argv, const char *prefix);
+ extern int cmd_format_patch(int argc, const char **argv, const char *prefix);
+ extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
- extern int cmd_prune(int argc, const char **argv, char **envp);
+ extern int cmd_prune(int argc, const char **argv, const char *prefix);
- extern int cmd_push(int argc, const char **argv, char **envp);
- extern int cmd_grep(int argc, const char **argv, char **envp);
- extern int cmd_rm(int argc, const char **argv, char **envp);
- extern int cmd_add(int argc, const char **argv, char **envp);
- extern int cmd_rev_list(int argc, const char **argv, char **envp);
- extern int cmd_check_ref_format(int argc, const char **argv, char **envp);
- extern int cmd_init_db(int argc, const char **argv, char **envp);
- extern int cmd_tar_tree(int argc, const char **argv, char **envp);
- extern int cmd_upload_tar(int argc, const char **argv, char **envp);
- extern int cmd_get_tar_commit_id(int argc, const char **argv, char **envp);
- extern int cmd_ls_files(int argc, const char **argv, char **envp);
- extern int cmd_ls_tree(int argc, const char **argv, char **envp);
- extern int cmd_read_tree(int argc, const char **argv, char **envp);
- extern int cmd_commit_tree(int argc, const char **argv, char **envp);
- extern int cmd_apply(int argc, const char **argv, char **envp);
- extern int cmd_show_branch(int argc, const char **argv, char **envp);
- extern int cmd_diff_files(int argc, const char **argv, char **envp);
- extern int cmd_diff_index(int argc, const char **argv, char **envp);
- extern int cmd_diff_stages(int argc, const char **argv, char **envp);
- extern int cmd_diff_tree(int argc, const char **argv, char **envp);
- extern int cmd_cat_file(int argc, const char **argv, char **envp);
- extern int cmd_rev_parse(int argc, const char **argv, char **envp);
- extern int cmd_update_index(int argc, const char **argv, char **envp);
- extern int cmd_update_ref(int argc, const char **argv, char **envp);
- extern int cmd_fmt_merge_msg(int argc, const char **argv, char **envp);
- extern int cmd_mv(int argc, const char **argv, char **envp);
+ extern int cmd_push(int argc, const char **argv, const char *prefix);
+ extern int cmd_grep(int argc, const char **argv, const char *prefix);
+ extern int cmd_rm(int argc, const char **argv, const char *prefix);
+ extern int cmd_add(int argc, const char **argv, const char *prefix);
+ extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
+ extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
+ extern int cmd_init_db(int argc, const char **argv, const char *prefix);
+ extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_upload_tar(int argc, const char **argv, const char *prefix);
+ extern int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix);
+ extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
+ extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_apply(int argc, const char **argv, const char *prefix);
+ extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+ extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
+ extern int cmd_diff_index(int argc, const char **argv, const char *prefix);
+ extern int cmd_diff_stages(int argc, const char **argv, const char *prefix);
+ extern int cmd_diff_tree(int argc, const char **argv, const char *prefix);
+ extern int cmd_cat_file(int argc, const char **argv, const char *prefix);
+ extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
+ extern int cmd_update_index(int argc, const char **argv, const char *prefix);
+ extern int cmd_update_ref(int argc, const char **argv, const char *prefix);
+ extern int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix);
++extern int cmd_mv(int argc, const char **argv, const char *prefix);
- extern int cmd_write_tree(int argc, const char **argv, char **envp);
+ extern int cmd_write_tree(int argc, const char **argv, const char *prefix);
extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
- extern int cmd_mailsplit(int argc, const char **argv, char **envp);
+ extern int cmd_mailsplit(int argc, const char **argv, const char *prefix);
extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
- extern int cmd_mailinfo(int argc, const char **argv, char **envp);
+ extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
- extern int cmd_stripspace(int argc, const char **argv, char **envp);
+ extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
extern void stripspace(FILE *in, FILE *out);
#endif
{ "mailsplit", cmd_mailsplit },
{ "mailinfo", cmd_mailinfo },
{ "stripspace", cmd_stripspace },
- { "update-index", cmd_update_index },
- { "update-ref", cmd_update_ref },
- { "fmt-merge-msg", cmd_fmt_merge_msg },
- { "prune", cmd_prune },
- { "mv", cmd_mv },
+ { "update-index", cmd_update_index, NEEDS_PREFIX },
+ { "update-ref", cmd_update_ref, NEEDS_PREFIX },
+ { "fmt-merge-msg", cmd_fmt_merge_msg, NEEDS_PREFIX },
+ { "prune", cmd_prune, NEEDS_PREFIX },
++ { "mv", cmd_mv, NEEDS_PREFIX },
};
int i;