diff options
-rw-r--r-- | Documentation/config.txt | 7 | ||||
-rw-r--r-- | Documentation/git-update-index.txt | 5 | ||||
-rw-r--r-- | builtin-apply.c | 2 | ||||
-rw-r--r-- | builtin-update-index.c | 6 | ||||
-rw-r--r-- | cache.h | 6 | ||||
-rw-r--r-- | config.c | 5 | ||||
-rw-r--r-- | diff-lib.c | 3 | ||||
-rw-r--r-- | entry.c | 9 | ||||
-rw-r--r-- | environment.c | 1 | ||||
-rw-r--r-- | read-cache.c | 10 | ||||
-rwxr-xr-x | t/t2005-checkout-index-symlinks.sh | 28 | ||||
-rwxr-xr-x | t/t2102-update-index-symlinks.sh | 31 |
12 files changed, 101 insertions, 12 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt index d2b4a05ca5..b809772b86 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -117,6 +117,13 @@ core.fileMode:: the working copy are ignored; useful on broken filesystems like FAT. See gitlink:git-update-index[1]. True by default. +core.symlinks:: + If false, symbolic links are checked out as small plain files that + contain the link text. gitlink:git-update-index[1] and + gitlink:git-add[1] will not change the recorded type to regular + file. Useful on filesystems like FAT that do not support + symbolic links. True by default. + core.gitProxy:: A "proxy command" to execute (as 'command host port') instead of establishing direct connection to the remote server when diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index b161c8b32b..cd5e014d48 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -295,6 +295,11 @@ in the index and the file mode on the filesystem if they differ only on executable bit. On such an unfortunate filesystem, you may need to use `git-update-index --chmod=`. +Quite similarly, if `core.symlinks` configuration variable is set +to 'false' (see gitlink:git-config[1]), symbolic links are checked out +as plain files, and this command does not modify a recorded file mode +from symbolic link to regular file. + The command looks at `core.ignorestat` configuration variable. See 'Using "assume unchanged" bit' section above. diff --git a/builtin-apply.c b/builtin-apply.c index 38f647510a..53935109a3 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2359,7 +2359,7 @@ static int try_create_file(const char *path, unsigned int mode, const char *buf, char *nbuf; unsigned long nsize; - if (S_ISLNK(mode)) + if (has_symlinks && S_ISLNK(mode)) /* Although buf:size is counted string, it also is NUL * terminated. */ diff --git a/builtin-update-index.c b/builtin-update-index.c index 65246dad8d..71cef633c0 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -109,11 +109,11 @@ static int add_file_to_cache(const char *path) ce->ce_flags = htons(namelen); fill_stat_cache_info(ce, &st); - if (trust_executable_bit) + if (trust_executable_bit && has_symlinks) ce->ce_mode = create_ce_mode(st.st_mode); else { - /* If there is an existing entry, pick the mode bits - * from it, otherwise assume unexecutable. + /* If there is an existing entry, pick the mode bits and type + * from it, otherwise assume unexecutable regular file. */ struct cache_entry *ent; int pos = cache_name_pos(path, namelen); @@ -108,7 +108,10 @@ static inline unsigned int create_ce_mode(unsigned int mode) } static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode) { - extern int trust_executable_bit; + extern int trust_executable_bit, has_symlinks; + if (!has_symlinks && S_ISREG(mode) && + ce && S_ISLNK(ntohl(ce->ce_mode))) + return ce->ce_mode; if (!trust_executable_bit && S_ISREG(mode)) { if (ce && S_ISREG(ntohl(ce->ce_mode))) return ce->ce_mode; @@ -215,6 +218,7 @@ extern int delete_ref(const char *, unsigned char *sha1); /* Environment bits from configuration mechanism */ extern int use_legacy_headers; extern int trust_executable_bit; +extern int has_symlinks; extern int assume_unchanged; extern int prefer_symlink_refs; extern int log_all_ref_updates; @@ -269,6 +269,11 @@ int git_default_config(const char *var, const char *value) return 0; } + if (!strcmp(var, "core.symlinks")) { + has_symlinks = git_config_bool(var, value); + return 0; + } + if (!strcmp(var, "core.bare")) { is_bare_repository_cfg = git_config_bool(var, value); return 0; diff --git a/diff-lib.c b/diff-lib.c index 2e91619906..f70888f8af 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -346,6 +346,9 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed) S_ISREG(newmode) && S_ISREG(oldmode) && ((newmode ^ oldmode) == 0111)) newmode = oldmode; + else if (!has_symlinks && + S_ISREG(newmode) && S_ISLNK(oldmode)) + newmode = oldmode; diff_change(&revs->diffopt, oldmode, newmode, ce->sha1, (changed ? null_sha1 : ce->sha1), ce->name, NULL); @@ -111,9 +111,12 @@ static int write_entry(struct cache_entry *ce, char *path, struct checkout *stat return error("git-checkout-index: unable to write file %s", path); break; case S_IFLNK: - if (to_tempfile) { - strcpy(path, ".merge_link_XXXXXX"); - fd = mkstemp(path); + if (to_tempfile || !has_symlinks) { + if (to_tempfile) { + strcpy(path, ".merge_link_XXXXXX"); + fd = mkstemp(path); + } else + fd = create_file(path, 0666); if (fd < 0) { free(new); return error("git-checkout-index: unable to create " diff --git a/environment.c b/environment.c index 570e32ac3c..49486dd9f1 100644 --- a/environment.c +++ b/environment.c @@ -13,6 +13,7 @@ char git_default_email[MAX_GITNAME]; char git_default_name[MAX_GITNAME]; int use_legacy_headers = 1; int trust_executable_bit = 1; +int has_symlinks = 1; int assume_unchanged; int prefer_symlink_refs; int is_bare_repository_cfg = -1; /* unspecified */ diff --git a/read-cache.c b/read-cache.c index 7a104e3512..4a972b4ab7 100644 --- a/read-cache.c +++ b/read-cache.c @@ -125,7 +125,9 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st) changed |= MODE_CHANGED; break; case S_IFLNK: - changed |= !S_ISLNK(st->st_mode) ? TYPE_CHANGED : 0; + if (!S_ISLNK(st->st_mode) && + (has_symlinks || !S_ISREG(st->st_mode))) + changed |= TYPE_CHANGED; break; default: die("internal error: ce_mode is %o", ntohl(ce->ce_mode)); @@ -344,11 +346,11 @@ int add_file_to_index(const char *path, int verbose) ce->ce_flags = htons(namelen); fill_stat_cache_info(ce, &st); - if (trust_executable_bit) + if (trust_executable_bit && has_symlinks) ce->ce_mode = create_ce_mode(st.st_mode); else { - /* If there is an existing entry, pick the mode bits - * from it, otherwise assume unexecutable. + /* If there is an existing entry, pick the mode bits and type + * from it, otherwise assume unexecutable regular file. */ struct cache_entry *ent; int pos = cache_name_pos(path, namelen); diff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh new file mode 100755 index 0000000000..e34a515333 --- /dev/null +++ b/t/t2005-checkout-index-symlinks.sh @@ -0,0 +1,28 @@ +#!/bin/sh +# +# Copyright (c) 2007 Johannes Sixt +# + +test_description='git-checkout-index on filesystem w/o symlinks test. + +This tests that git-checkout-index creates a symbolic link as a plain +file if core.symlinks is false.' + +. ./test-lib.sh + +test_expect_success \ +'preparation' ' +git-config core.symlinks false && +l=$(echo -n file | git-hash-object -t blob -w --stdin) && +echo "120000 $l symlink" | git-update-index --index-info' + +test_expect_success \ +'the checked-out symlink must be a file' ' +git-checkout-index symlink && +test -f symlink' + +test_expect_success \ +'the file must be the blob we added during the setup' ' +test "$(git-hash-object -t blob symlink)" = $l' + +test_done diff --git a/t/t2102-update-index-symlinks.sh b/t/t2102-update-index-symlinks.sh new file mode 100755 index 0000000000..969ef891d3 --- /dev/null +++ b/t/t2102-update-index-symlinks.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# +# Copyright (c) 2007 Johannes Sixt +# + +test_description='git-update-index on filesystem w/o symlinks test. + +This tests that git-update-index keeps the symbolic link property +even if a plain file is in the working tree if core.symlinks is false.' + +. ./test-lib.sh + +test_expect_success \ +'preparation' ' +git-config core.symlinks false && +l=$(echo -n file | git-hash-object -t blob -w --stdin) && +echo "120000 $l symlink" | git-update-index --index-info' + +test_expect_success \ +'modify the symbolic link' ' +echo -n new-file > symlink && +git-update-index symlink' + +test_expect_success \ +'the index entry must still be a symbolic link' ' +case "`git-ls-files --stage --cached symlink`" in +120000" "*symlink) echo ok;; +*) echo fail; git-ls-files --stage --cached symlink; (exit 1);; +esac' + +test_done |