From 17712991a59824a8d22d5115c0c154d3122fc17b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 10 Oct 2005 16:31:08 -0700 Subject: Add ".git/config" file parser This is a first cut at a very simple parser for a git config file. The format of the file is a simple ini-file like thing, with simple variable/value pairs. You can (and should) make the variables have a simple single-level scope, ie a valid file looks something like this: # # This is the config file, and # a '#' or ';' character indicates # a comment # ; core variables [core] ; Don't trust file modes filemode = false ; Our diff algorithm [diff] external = "/usr/local/bin/gnu-diff -u" renames = true which parses into three variables: "core.filemode" is associated with the string "false", and "diff.external" gets the appropriate quoted value. Right now we only react to one variable: "core.filemode" is a boolean that decides if we should care about the 0100 (user-execute) bit of the stat information. Even that is just a parsing demonstration - this doesn't actually implement that st_mode compare logic itself. Different programs can react to different config options, although they should always fall back to calling "git_default_config()" on any config option name that they don't recognize. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- diff-files.c | 1 + 1 file changed, 1 insertion(+) (limited to 'diff-files.c') diff --git a/diff-files.c b/diff-files.c index 5e598322ff..96d2c7f19f 100644 --- a/diff-files.c +++ b/diff-files.c @@ -38,6 +38,7 @@ int main(int argc, const char **argv) const char *prefix = setup_git_directory(); int entries, i; + git_config(git_default_config); diff_setup(&diff_options); while (1 < argc && argv[1][0] == '-') { if (!strcmp(argv[1], "-q")) -- cgit v1.2.3 From 3e09cdfd114651fc61656dbd45d5ec3d9352cb2b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 11 Oct 2005 18:45:33 -0700 Subject: Use core.filemode. With "[core] filemode = false", you can tell git to ignore differences in the working tree file only in executable bit. * "git-update-index --refresh" does not say "needs update" if index entry and working tree file differs only in executable bit. * "git-update-index" on an existing path takes executable bit from the existing index entry, if the path and index entry are both regular files. * "git-diff-files" and "git-diff-index" without --cached flag pretend the path on the filesystem has the same executable bit as the existing index entry, if the path and index entry are both regular files. If you are on a filesystem with unreliable mode bits, you may need to force the executable bit after registering the path in the index. * "git-update-index --chmod=+x foo" flips the executable bit of the index file entry for path "foo" on. Use "--chmod=-x" to flip it off. Note that --chmod only works in index file and does not look at nor update the working tree. So if you are on a filesystem and do not have working executable bit, you would do: 1. set the appropriate .git/config option; 2. "git-update-index --add new-file.c" 3. "git-ls-files --stage new-file.c" to see if it has the desired mode bits. If not, e.g. to drop executable bit picked up from the filesystem, say "git-update-index --chmod=-x new-file.c". Signed-off-by: Junio C Hamano --- diff-files.c | 10 ++++++++-- diff-index.c | 11 +++++++++-- read-cache.c | 12 ++++++++---- update-index.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 70 insertions(+), 9 deletions(-) (limited to 'diff-files.c') diff --git a/diff-files.c b/diff-files.c index 96d2c7f19f..8a8f9b6dc7 100644 --- a/diff-files.c +++ b/diff-files.c @@ -81,7 +81,7 @@ int main(int argc, const char **argv) for (i = 0; i < entries; i++) { struct stat st; - unsigned int oldmode; + unsigned int oldmode, newmode; struct cache_entry *ce = active_cache[i]; int changed; @@ -111,7 +111,13 @@ int main(int argc, const char **argv) if (!changed && !diff_options.find_copies_harder) continue; oldmode = ntohl(ce->ce_mode); - show_modified(oldmode, DIFF_FILE_CANON_MODE(st.st_mode), + + newmode = DIFF_FILE_CANON_MODE(st.st_mode); + if (!trust_executable_bit && + S_ISREG(newmode) && S_ISREG(oldmode) && + ((newmode ^ oldmode) == 0111)) + newmode = oldmode; + show_modified(oldmode, newmode, ce->sha1, (changed ? null_sha1 : ce->sha1), ce->name); } diff --git a/diff-index.c b/diff-index.c index 62b36cc8ee..c9a9f4c74d 100644 --- a/diff-index.c +++ b/diff-index.c @@ -15,7 +15,7 @@ static void show_file(const char *prefix, } static int get_stat_data(struct cache_entry *ce, - unsigned char **sha1p, unsigned int *modep) + unsigned char ** sha1p, unsigned int *modep) { unsigned char *sha1 = ce->sha1; unsigned int mode = ce->ce_mode; @@ -35,6 +35,10 @@ static int get_stat_data(struct cache_entry *ce, changed = ce_match_stat(ce, &st); if (changed) { mode = create_ce_mode(st.st_mode); + if (!trust_executable_bit && + S_ISREG(mode) && S_ISREG(ce->ce_mode) && + ((mode ^ ce->ce_mode) == 0111)) + mode = ce->ce_mode; sha1 = no_sha1; } } @@ -49,7 +53,9 @@ static void show_new_file(struct cache_entry *new) unsigned char *sha1; unsigned int mode; - /* New file in the index: it might actually be different in the working copy */ + /* New file in the index: it might actually be different in + * the working copy. + */ if (get_stat_data(new, &sha1, &mode) < 0) return; @@ -174,6 +180,7 @@ int main(int argc, const char **argv) int allow_options = 1; int i; + git_config(git_default_config); diff_setup(&diff_options); for (i = 1; i < argc; i++) { const char *arg = argv[i]; diff --git a/read-cache.c b/read-cache.c index c7f3b26862..4ed369acf8 100644 --- a/read-cache.c +++ b/read-cache.c @@ -36,8 +36,11 @@ int ce_match_stat(struct cache_entry *ce, struct stat *st) switch (ntohl(ce->ce_mode) & S_IFMT) { case S_IFREG: changed |= !S_ISREG(st->st_mode) ? TYPE_CHANGED : 0; - /* We consider only the owner x bit to be relevant for "mode changes" */ - if (0100 & (ntohl(ce->ce_mode) ^ st->st_mode)) + /* We consider only the owner x bit to be relevant for + * "mode changes" + */ + if (trust_executable_bit && + (0100 & (ntohl(ce->ce_mode) ^ st->st_mode))) changed |= MODE_CHANGED; break; case S_IFLNK: @@ -393,7 +396,7 @@ int add_cache_entry(struct cache_entry *ce, int option) int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK; pos = cache_name_pos(ce->name, ntohs(ce->ce_flags)); - /* existing match? Just replace it */ + /* existing match? Just replace it. */ if (pos >= 0) { active_cache_changed = 1; active_cache[pos] = ce; @@ -416,7 +419,8 @@ int add_cache_entry(struct cache_entry *ce, int option) if (!ok_to_add) return -1; - if (!skip_df_check && check_file_directory_conflict(ce, pos, ok_to_replace)) { + if (!skip_df_check && + check_file_directory_conflict(ce, pos, ok_to_replace)) { if (!ok_to_replace) return -1; pos = cache_name_pos(ce->name, ntohs(ce->ce_flags)); diff --git a/update-index.c b/update-index.c index 01b4088ad6..1eeb45dbb1 100644 --- a/update-index.c +++ b/update-index.c @@ -67,13 +67,23 @@ static int add_file_to_cache(const char *path) return error("lstat(\"%s\"): %s", path, strerror(errno)); } + namelen = strlen(path); size = cache_entry_size(namelen); ce = xmalloc(size); memset(ce, 0, size); memcpy(ce->name, path, 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 (0 <= pos) + ce->ce_mode = active_cache[pos]->ce_mode; + } ce->ce_flags = htons(namelen); if (index_path(ce->sha1, path, &st, !info_only)) @@ -253,8 +263,32 @@ static int add_cacheinfo(const char *arg1, const char *arg2, const char *arg3) return add_cache_entry(ce, option); } -static struct cache_file cache_file; +static int chmod_path(int flip, const char *path) +{ + int pos; + struct cache_entry *ce; + unsigned int mode; + pos = cache_name_pos(path, strlen(path)); + if (pos < 0) + return -1; + ce = active_cache[pos]; + mode = ntohl(ce->ce_mode); + if (!S_ISREG(mode)) + return -1; + switch (flip) { + case '+': + ce->ce_mode |= htonl(0111); break; + case '-': + ce->ce_mode &= htonl(~0111); break; + default: + return -1; + } + active_cache_changed = 1; + return 0; +} + +static struct cache_file cache_file; static void update_one(const char *path, const char *prefix, int prefix_length) { @@ -328,6 +362,8 @@ int main(int argc, const char **argv) const char *prefix = setup_git_directory(); int prefix_length = prefix ? strlen(prefix) : 0; + git_config(git_default_config); + newfd = hold_index_file_for_update(&cache_file, get_index_file()); if (newfd < 0) die("unable to create new cachefile"); @@ -376,6 +412,14 @@ int main(int argc, const char **argv) i += 3; continue; } + if (!strcmp(path, "--chmod=-x") || + !strcmp(path, "--chmod=+x")) { + if (argc <= i+1) + die("git-update-index: %s ", path); + if (chmod_path(path[8], argv[++i])) + die("git-update-index: %s cannot chmod %s", path, argv[i]); + continue; + } if (!strcmp(path, "--info-only")) { info_only = 1; continue; -- cgit v1.2.3 From ea51d416c02bb26e9d7600f87b27deb42752e6b5 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 18 Oct 2005 00:16:45 -0700 Subject: Teach "git diff" to handle filenames starting with '-' It adds "--" to the git-diff.sh scripts, to keep any filenames that start with a "-" from being confused with an option. But in order to do that, it needs to teach git-diff-files to honor "--". Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- diff-files.c | 5 +++++ git-diff.sh | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'diff-files.c') diff --git a/diff-files.c b/diff-files.c index 8a8f9b6dc7..17899390b8 100644 --- a/diff-files.c +++ b/diff-files.c @@ -41,6 +41,11 @@ int main(int argc, const char **argv) git_config(git_default_config); diff_setup(&diff_options); while (1 < argc && argv[1][0] == '-') { + if (!strcmp(argv[1], "--")) { + argv++; + argc--; + break; + } if (!strcmp(argv[1], "-q")) silent = 1; else if (!strcmp(argv[1], "-r")) diff --git a/git-diff.sh b/git-diff.sh index 84a152af20..b3ec84be69 100755 --- a/git-diff.sh +++ b/git-diff.sh @@ -28,16 +28,16 @@ case "$rev" in ?*' '^?*) begin=$(expr "$rev" : '.*^.\([0-9a-f]*\).*') && end=$(expr "$rev" : '.\([0-9a-f]*\). .*') || exit - cmd="git-diff-tree $flags $begin $end $files" + cmd="git-diff-tree $flags $begin $end -- $files" ;; ?*' '?*) - cmd="git-diff-tree $flags $rev $files" + cmd="git-diff-tree $flags $rev -- $files" ;; ?*' ') - cmd="git-diff-index $flags $rev $files" + cmd="git-diff-index $flags $rev -- $files" ;; '') - cmd="git-diff-files $flags $files" + cmd="git-diff-files $flags -- $files" ;; *) die "I don't understand $*" -- cgit v1.2.3