* Copyright (C) 2006 Johannes Schindelin
*/
#include "builtin.h"
+ #include "pathspec.h"
#include "lockfile.h"
#include "dir.h"
#include "cache-tree.h"
#define DUP_BASENAME 1
#define KEEP_TRAILING_SLASH 2
- static const char **internal_copy_pathspec(const char *prefix,
- const char **pathspec,
- int count, unsigned flags)
+ static const char **internal_prefix_pathspec(const char *prefix,
+ const char **pathspec,
+ int count, unsigned flags)
{
int i;
const char **result;
+ int prefixlen = prefix ? strlen(prefix) : 0;
ALLOC_ARRAY(result, count + 1);
- COPY_ARRAY(result, pathspec, count);
- result[count] = NULL;
+
+ /* Create an intermediate copy of the pathspec based on the flags */
for (i = 0; i < count; i++) {
- int length = strlen(result[i]);
+ int length = strlen(pathspec[i]);
int to_copy = length;
+ char *it;
while (!(flags & KEEP_TRAILING_SLASH) &&
- to_copy > 0 && is_dir_sep(result[i][to_copy - 1]))
+ to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
to_copy--;
- if (to_copy != length || flags & DUP_BASENAME) {
- char *it = xmemdupz(result[i], to_copy);
- if (flags & DUP_BASENAME) {
- result[i] = xstrdup(basename(it));
- free(it);
- } else
- result[i] = it;
+
+ it = xmemdupz(pathspec[i], to_copy);
+ if (flags & DUP_BASENAME) {
+ result[i] = xstrdup(basename(it));
+ free(it);
+ } else {
+ result[i] = it;
}
}
- return get_pathspec(prefix, result);
+ result[count] = NULL;
+
+ /* Prefix the pathspec and free the old intermediate strings */
+ for (i = 0; i < count; i++) {
+ const char *match = prefix_path(prefix, prefixlen, result[i]);
+ free((char *) result[i]);
+ result[i] = match;
+ }
+
+ return result;
}
static const char *add_slash(const char *path)
if (--argc < 1)
usage_with_options(builtin_mv_usage, builtin_mv_options);
- hold_locked_index(&lock_file, 1);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
if (read_cache() < 0)
die(_("index file corrupt"));
- source = internal_copy_pathspec(prefix, argv, argc, 0);
+ source = internal_prefix_pathspec(prefix, argv, argc, 0);
modes = xcalloc(argc, sizeof(enum update_mode));
/*
* Keep trailing slash, needed to let
flags = KEEP_TRAILING_SLASH;
if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
flags = 0;
- dest_path = internal_copy_pathspec(prefix, argv + argc, 1, flags);
+ dest_path = internal_prefix_pathspec(prefix, argv + argc, 1, flags);
submodule_gitfile = xcalloc(argc, sizeof(char *));
if (dest_path[0][0] == '\0')
/* special case: "." was normalized to "" */
- destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
+ destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
else if (!lstat(dest_path[0], &st) &&
S_ISDIR(st.st_mode)) {
dest_path[0] = add_slash(dest_path[0]);
- destination = internal_copy_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
+ destination = internal_prefix_pathspec(dest_path[0], argv, argc, DUP_BASENAME);
} else {
if (argc != 1)
die(_("destination '%s' is not a directory"), dest_path[0]);
#define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
- extern const char **get_pathspec(const char *prefix, const char **pathspec);
extern void setup_work_tree(void);
extern const char *setup_git_directory_gently(int *);
extern const char *setup_git_directory(void);
extern const char *git_hooks_path;
extern int zlib_compression_level;
extern int core_compression_level;
-extern int core_compression_seen;
+extern int pack_compression_level;
extern size_t packed_git_window_size;
extern size_t packed_git_limit;
extern size_t delta_base_cache_limit;
return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
}
int is_directory(const char *);
+char *strbuf_realpath(struct strbuf *resolved, const char *path,
+ int die_on_error);
const char *real_path(const char *path);
const char *real_path_if_valid(const char *path);
+char *real_pathdup(const char *path);
const char *absolute_path(const char *path);
const char *remove_leading_path(const char *in, const char *prefix);
const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, unsigned char *sha1, unsigned flags);
extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
extern int force_object_loose(const unsigned char *sha1, time_t mtime);
-extern int git_open(const char *name);
+extern int git_open_cloexec(const char *name, int flags);
+#define git_open(name) git_open_cloexec(name, O_RDONLY)
extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
extern int git_config_from_file(config_fn_t fn, const char *, void *);
extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
const char *name, const char *buf, size_t len, void *data);
+extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,
+ const unsigned char *sha1, void *data);
extern void git_config_push_parameter(const char *text);
extern int git_config_from_parameters(config_fn_t fn, void *data);
extern void git_config(config_fn_t fn, void *);
#include "varint.h"
#include "ewah/ewok.h"
- struct path_simplify {
- int len;
- const char *path;
- };
-
/*
* Tells read_directory_recursive how a file or directory should be treated.
* Values are ordered by significance, e.g. if a directory contains both
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
const char *path, int len, struct untracked_cache_dir *untracked,
- int check_only, const struct path_simplify *simplify);
+ int check_only, const struct pathspec *pathspec);
static int get_dtype(struct dirent *de, const char *path, int len);
int fspathcmp(const char *a, const char *b)
int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
{
- size_t len;
+ char *prefix;
+ size_t prefix_len;
/*
* Calculate common prefix for the pathspec, and
* use that to optimize the directory walk
*/
- len = common_prefix_len(pathspec);
+ prefix = common_prefix(pathspec);
+ prefix_len = prefix ? strlen(prefix) : 0;
/* Read the directory and prune it */
- read_directory(dir, pathspec->nr ? pathspec->_raw[0] : "", len, pathspec);
- return len;
+ read_directory(dir, prefix, prefix_len, pathspec);
+
+ free(prefix);
+ return prefix_len;
}
int within_depth(const char *name, int namelen,
static enum path_treatment treat_directory(struct dir_struct *dir,
struct untracked_cache_dir *untracked,
const char *dirname, int len, int baselen, int exclude,
- const struct path_simplify *simplify)
+ const struct pathspec *pathspec)
{
/* The "len-1" is to strip the final '/' */
switch (directory_exists_in_index(dirname, len-1)) {
untracked = lookup_untracked(dir->untracked, untracked,
dirname + baselen, len - baselen);
return read_directory_recursive(dir, dirname, len,
- untracked, 1, simplify);
+ untracked, 1, pathspec);
}
/*
* reading - if the path cannot possibly be in the pathspec,
* return true, and we'll skip it early.
*/
- static int simplify_away(const char *path, int pathlen, const struct path_simplify *simplify)
+ static int simplify_away(const char *path, int pathlen,
+ const struct pathspec *pathspec)
{
- if (simplify) {
- for (;;) {
- const char *match = simplify->path;
- int len = simplify->len;
+ int i;
- if (!match)
- break;
- if (len > pathlen)
- len = pathlen;
- if (!memcmp(path, match, len))
- return 0;
- simplify++;
- }
- return 1;
+ if (!pathspec || !pathspec->nr)
+ return 0;
+
+ GUARD_PATHSPEC(pathspec,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE |
+ PATHSPEC_EXCLUDE);
+
+ for (i = 0; i < pathspec->nr; i++) {
+ const struct pathspec_item *item = &pathspec->items[i];
+ int len = item->nowildcard_len;
+
+ if (len > pathlen)
+ len = pathlen;
+ if (!ps_strncmp(item, item->match, path, len))
+ return 0;
}
- return 0;
+
+ return 1;
}
/*
* 2. the path is a directory prefix of some element in the
* pathspec
*/
- static int exclude_matches_pathspec(const char *path, int len,
- const struct path_simplify *simplify)
- {
- if (simplify) {
- for (; simplify->path; simplify++) {
- if (len == simplify->len
- && !memcmp(path, simplify->path, len))
- return 1;
- if (len < simplify->len
- && simplify->path[len] == '/'
- && !memcmp(path, simplify->path, len))
- return 1;
- }
+ static int exclude_matches_pathspec(const char *path, int pathlen,
+ const struct pathspec *pathspec)
+ {
+ int i;
+
+ if (!pathspec || !pathspec->nr)
+ return 0;
+
+ GUARD_PATHSPEC(pathspec,
+ PATHSPEC_FROMTOP |
+ PATHSPEC_MAXDEPTH |
+ PATHSPEC_LITERAL |
+ PATHSPEC_GLOB |
+ PATHSPEC_ICASE |
+ PATHSPEC_EXCLUDE);
+
+ for (i = 0; i < pathspec->nr; i++) {
+ const struct pathspec_item *item = &pathspec->items[i];
+ int len = item->nowildcard_len;
+
+ if (len == pathlen &&
+ !ps_strncmp(item, item->match, path, pathlen))
+ return 1;
+ if (len > pathlen &&
+ item->match[pathlen] == '/' &&
+ !ps_strncmp(item, item->match, path, pathlen))
+ return 1;
}
return 0;
}
struct untracked_cache_dir *untracked,
struct strbuf *path,
int baselen,
- const struct path_simplify *simplify,
+ const struct pathspec *pathspec,
int dtype, struct dirent *de)
{
int exclude;
case DT_DIR:
strbuf_addch(path, '/');
return treat_directory(dir, untracked, path->buf, path->len,
- baselen, exclude, simplify);
+ baselen, exclude, pathspec);
case DT_REG:
case DT_LNK:
return exclude ? path_excluded : path_untracked;
struct cached_dir *cdir,
struct strbuf *path,
int baselen,
- const struct path_simplify *simplify)
+ const struct pathspec *pathspec)
{
strbuf_setlen(path, baselen);
if (!cdir->ucd) {
* with check_only set.
*/
return read_directory_recursive(dir, path->buf, path->len,
- cdir->ucd, 1, simplify);
+ cdir->ucd, 1, pathspec);
/*
* We get path_recurse in the first run when
* directory_exists_in_index() returns index_nonexistent. We
struct cached_dir *cdir,
struct strbuf *path,
int baselen,
- const struct path_simplify *simplify)
+ const struct pathspec *pathspec)
{
int dtype;
struct dirent *de = cdir->de;
if (!de)
return treat_path_fast(dir, untracked, cdir, path,
- baselen, simplify);
+ baselen, pathspec);
if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
return path_none;
strbuf_setlen(path, baselen);
strbuf_addstr(path, de->d_name);
- if (simplify_away(path->buf, path->len, simplify))
+ if (simplify_away(path->buf, path->len, pathspec))
return path_none;
dtype = DTYPE(de);
- return treat_one_path(dir, untracked, path, baselen, simplify, dtype, de);
+ return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);
}
static void add_untracked(struct untracked_cache_dir *dir, const char *name)
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
const char *base, int baselen,
struct untracked_cache_dir *untracked, int check_only,
- const struct path_simplify *simplify)
+ const struct pathspec *pathspec)
{
struct cached_dir cdir;
enum path_treatment state, subdir_state, dir_state = path_none;
while (!read_cached_dir(&cdir)) {
/* check how the file or directory should be treated */
- state = treat_path(dir, untracked, &cdir, &path, baselen, simplify);
+ state = treat_path(dir, untracked, &cdir, &path,
+ baselen, pathspec);
if (state > dir_state)
dir_state = state;
path.buf + baselen,
path.len - baselen);
subdir_state =
- read_directory_recursive(dir, path.buf, path.len,
- ud, check_only, simplify);
+ read_directory_recursive(dir, path.buf,
+ path.len, ud,
+ check_only, pathspec);
if (subdir_state > dir_state)
dir_state = subdir_state;
}
else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
((dir->flags & DIR_COLLECT_IGNORED) &&
exclude_matches_pathspec(path.buf, path.len,
- simplify)))
+ pathspec)))
dir_add_ignored(dir, path.buf, path.len);
break;
return name_compare(e1->name, e1->len, e2->name, e2->len);
}
- static struct path_simplify *create_simplify(const char **pathspec)
- {
- int nr, alloc = 0;
- struct path_simplify *simplify = NULL;
-
- if (!pathspec)
- return NULL;
-
- for (nr = 0 ; ; nr++) {
- const char *match;
- ALLOC_GROW(simplify, nr + 1, alloc);
- match = *pathspec++;
- if (!match)
- break;
- simplify[nr].path = match;
- simplify[nr].len = simple_length(match);
- }
- simplify[nr].path = NULL;
- simplify[nr].len = 0;
- return simplify;
- }
-
- static void free_simplify(struct path_simplify *simplify)
- {
- free(simplify);
- }
-
static int treat_leading_path(struct dir_struct *dir,
const char *path, int len,
- const struct path_simplify *simplify)
+ const struct pathspec *pathspec)
{
struct strbuf sb = STRBUF_INIT;
int baselen, rc = 0;
strbuf_add(&sb, path, baselen);
if (!is_directory(sb.buf))
break;
- if (simplify_away(sb.buf, sb.len, simplify))
+ if (simplify_away(sb.buf, sb.len, pathspec))
break;
- if (treat_one_path(dir, NULL, &sb, baselen, simplify,
+ if (treat_one_path(dir, NULL, &sb, baselen, pathspec,
DT_DIR, NULL) == path_none)
break; /* do not recurse into it */
if (len <= baselen) {
return root;
}
- int read_directory(struct dir_struct *dir, const char *path, int len, const struct pathspec *pathspec)
+ int read_directory(struct dir_struct *dir, const char *path,
+ int len, const struct pathspec *pathspec)
{
- struct path_simplify *simplify;
struct untracked_cache_dir *untracked;
- /*
- * Check out create_simplify()
- */
- if (pathspec)
- GUARD_PATHSPEC(pathspec,
- PATHSPEC_FROMTOP |
- PATHSPEC_MAXDEPTH |
- PATHSPEC_LITERAL |
- PATHSPEC_GLOB |
- PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE);
-
if (has_symlink_leading_path(path, len))
return dir->nr;
- /*
- * exclude patterns are treated like positive ones in
- * create_simplify. Usually exclude patterns should be a
- * subset of positive ones, which has no impacts on
- * create_simplify().
- */
- simplify = create_simplify(pathspec ? pathspec->_raw : NULL);
untracked = validate_untracked_cache(dir, len, pathspec);
if (!untracked)
/*
* e.g. prep_exclude()
*/
dir->untracked = NULL;
- if (!len || treat_leading_path(dir, path, len, simplify))
- read_directory_recursive(dir, path, len, untracked, 0, simplify);
- free_simplify(simplify);
+ if (!len || treat_leading_path(dir, path, len, pathspec))
+ read_directory_recursive(dir, path, len, untracked, 0, pathspec);
QSORT(dir->entries, dir->nr, cmp_name);
QSORT(dir->ignored, dir->ignored_nr, cmp_name);
if (dir->untracked) {
{
untracked_cache_invalidate_path(istate, path);
}
+
+/* Update gitfile and core.worktree setting to connect work tree and git dir */
+void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_)
+{
+ struct strbuf file_name = STRBUF_INIT;
+ struct strbuf rel_path = STRBUF_INIT;
+ char *git_dir = xstrdup(real_path(git_dir_));
+ char *work_tree = xstrdup(real_path(work_tree_));
+
+ /* Update gitfile */
+ strbuf_addf(&file_name, "%s/.git", work_tree);
+ write_file(file_name.buf, "gitdir: %s",
+ relative_path(git_dir, work_tree, &rel_path));
+
+ /* Update core.worktree setting */
+ strbuf_reset(&file_name);
+ strbuf_addf(&file_name, "%s/config", git_dir);
+ git_config_set_in_file(file_name.buf, "core.worktree",
+ relative_path(work_tree, git_dir, &rel_path));
+
+ strbuf_release(&file_name);
+ strbuf_release(&rel_path);
+ free(work_tree);
+ free(git_dir);
+}
+
+/*
+ * Migrate the git directory of the given path from old_git_dir to new_git_dir.
+ */
+void relocate_gitdir(const char *path, const char *old_git_dir, const char *new_git_dir)
+{
+ if (rename(old_git_dir, new_git_dir) < 0)
+ die_errno(_("could not migrate git directory from '%s' to '%s'"),
+ old_git_dir, new_git_dir);
+
+ connect_work_tree_and_git_dir(path, new_git_dir);
+}