{"thread":{"id":"2049","subject":"Seeing various mode changes on cygwin","startedAt":"2005-10-08T18:00:23Z","lastAt":"2005-10-12T07:43:21Z","messageCount":18,"participants":["Jonas Fonseca","Junio C Hamano","Alex Riesen","Linus Torvalds","H. Peter Anvin","Daniel Barkalow"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"9838","messageId":"20051008180023.GC28875@diku.dk","threadId":"2049","inReplyTo":null,"subject":"Seeing various mode changes on cygwin","fromName":"Jonas Fonseca","fromEmail":"fonseca@diku.dk","sentAt":"2005-10-08T18:00:23Z","receivedAt":"2005-10-08T18:00:23Z","isPatch":false,"sender":{"key":"fonseca@diku.dk","avatar":"https://gravatar.com/avatar/f82f3ad698717c51873b020c750a92438c820a24056dc39fe4d07baa10a92264?d=mp&s=160"},"body":"Hi,\n\nIt seems that git on cygwin still have a few problems. I've experienced it both\nwhen cloning with git and Cogito. It seems that cygwin overrides the previous\nmodes and sets the executable bit. git-reset doesn't fix it. Can this even be\nfixed then?\n\nA few examples below ...\n\njonas@cygwin /usr/local/dev/git/git\n$ git reset\nDocumentation/sort_glossary.pl: needs update\nt/lib-read-tree-m-3way.sh: needs update\nt/t4109-apply-multifrag.sh: needs update\nt/t4110-apply-scan.sh: needs update\nt/t6000lib.sh: needs update\nt/t6101-rev-parse-parents.sh: needs update\ntemplates/hooks--applypatch-msg: needs update\ntemplates/hooks--commit-msg: needs update\ntemplates/hooks--post-commit: needs update\ntemplates/hooks--post-update: needs update\ntemplates/hooks--pre-applypatch: needs update\ntemplates/hooks--pre-commit: needs update\ntemplates/hooks--update: needs update\n\njonas@cygwin /usr/local/dev/git/git\n$ git diff\ndiff --git a/Documentation/sort_glossary.pl b/Documentation/sort_glossary.pl\nold mode 100644\nnew mode 100755\ndiff --git a/t/lib-read-tree-m-3way.sh b/t/lib-read-tree-m-3way.sh\nold mode 100755\nnew mode 100644\ndiff --git a/t/t4109-apply-multifrag.sh b/t/t4109-apply-multifrag.sh\nold mode 100644\nnew mode 100755\ndiff --git a/t/t4110-apply-scan.sh b/t/t4110-apply-scan.sh\nold mode 100644\nnew mode 100755\ndiff --git a/t/t6000lib.sh b/t/t6000lib.sh\nold mode 100755\nnew mode 100644\ndiff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh\nold mode 100644\nnew mode 100755\ndiff --git a/templates/hooks--applypatch-msg b/templates/hooks--applypatch-msg\nold mode 100644\nnew mode 100755\ndiff --git a/templates/hooks--commit-msg b/templates/hooks--commit-msg\nold mode 100644\nnew mode 100755\ndiff --git a/templates/hooks--post-commit b/templates/hooks--post-commit\nold mode 100644\nnew mode 100755\ndiff --git a/templates/hooks--post-update b/templates/hooks--post-update\nold mode 100644\nnew mode 100755\ndiff --git a/templates/hooks--pre-applypatch b/templates/hooks--pre-applypatch\nold mode 100644\nnew mode 100755\ndiff --git a/templates/hooks--pre-commit b/templates/hooks--pre-commit\nold mode 100644\nnew mode 100755\ndiff --git a/templates/hooks--update b/templates/hooks--update\nold mode 100644\nnew mode 100755\n\njonas@cygwin /usr/local/dev/git/cogito\n$ cg diff debian/\ndiff --git a/debian/helper-scripts/make-orig.tgz\nb/debian/helper-scripts/make-orig.tgz\nold mode 100644\nnew mode 100755\ndiff --git a/debian/helper-scripts/make-package\nb/debian/helper-scripts/make-package\nold mode 100644\nnew mode 100755\ndiff --git a/debian/helper-scripts/make-test\nb/debian/helper-scripts/make-test\nold mode 100644\nnew mode 100755\n\njonas@cygwin /usr/local/dev/elinks/0.11\n$ cg diff\ndiff --git a/config/config.guess b/config/config.guess\nold mode 100644\nnew mode 100755\ndiff --git a/config/config.sub b/config/config.sub\nold mode 100644\nnew mode 100755\ndiff --git a/contrib/conv/w3m2links.awk.in b/contrib/conv/w3m2links.awk.in\nold mode 100644\nnew mode 100755\ndiff --git a/contrib/lua/bm-to-elinks-bookmarks.lua b/contrib/lua/bm-to-elinks-bookmarks.lua\nold mode 100644\nnew mode 100755\ndiff --git a/contrib/wipe-out-ssl.awk b/contrib/wipe-out-ssl.awk\nold mode 100644\nnew mode 100755\ndiff --git a/debian/elinks.postinst b/debian/elinks.postinst\nold mode 100644\nnew mode 100755\ndiff --git a/debian/elinks.preinst b/debian/elinks.preinst\nold mode 100644\nnew mode 100755\ndiff --git a/debian/elinks.prerm b/debian/elinks.prerm\nold mode 100644\nnew mode 100755\ndiff --git a/po/gen_translations_stats.sh b/po/gen_translations_stats.sh\nold mode 100644\nnew mode 100755\n\n-- \nJonas Fonseca\n"},{"id":"9844","messageId":"7vfyrbrgdw.fsf@assigned-by-dhcp.cox.net","threadId":"2049","inReplyTo":"20051008180023.GC28875@diku.dk","subject":"Re: Seeing various mode changes on cygwin","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-08T18:51:55Z","receivedAt":"2005-10-08T18:51:55Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonas Fonseca <fonseca@diku.dk> writes:\n\n> ... It seems that cygwin overrides the previous\n> modes and sets the executable bit. git-reset doesn't fix it. Can this even be\n> fixed then?\n>\n> A few examples below ...\n>\n> jonas@cygwin /usr/local/dev/git/git\n> $ git reset\n> Documentation/sort_glossary.pl: needs update\n> t/lib-read-tree-m-3way.sh: needs update\n\nI do not have an access to Cygwin environment so cannot be of\nhelp on this directly, but 'git reset' without flags defaults\n\"--mixed\" and leaves the modified files intact.  Maybe hard\nreset would help here, but the real solution is to figure out\nwhy these files acquired the extra executable bits in the first\nplace.\n"},{"id":"9848","messageId":"20051008213612.GA5794@steel.home","threadId":"2049","inReplyTo":"7vfyrbrgdw.fsf@assigned-by-dhcp.cox.net","subject":"Re: Seeing various mode changes on cygwin","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2005-10-08T21:36:12Z","receivedAt":"2005-10-08T21:36:12Z","isPatch":false,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"Junio C Hamano, Sat, Oct 08, 2005 20:51:55 +0200:\n> > ... It seems that cygwin overrides the previous modes and sets the\n> > executable bit. git-reset doesn't fix it. Can this even be fixed\n> > then?\n> >\n> > A few examples below ...\n> >\n> > jonas@cygwin /usr/local/dev/git/git\n> > $ git reset\n> > Documentation/sort_glossary.pl: needs update\n> > t/lib-read-tree-m-3way.sh: needs update\n> \n> I do not have an access to Cygwin environment so cannot be of\n> help on this directly, but 'git reset' without flags defaults\n> \"--mixed\" and leaves the modified files intact.  Maybe hard\n> reset would help here, but the real solution is to figure out\n> why these files acquired the extra executable bits in the first\n> place.\n\nThese are not real attributes, cygwin emulates them from the names,\nlike .exe will always be 0755, for example.\n"},{"id":"9850","messageId":"7vzmpjoa32.fsf@assigned-by-dhcp.cox.net","threadId":"2049","inReplyTo":"20051008213612.GA5794@steel.home","subject":"Re: Seeing various mode changes on cygwin","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-08T23:36:17Z","receivedAt":"2005-10-08T23:36:17Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Alex Riesen <raa.lkml@gmail.com> writes:\n\n> These are not real attributes, cygwin emulates them from the names,\n> like .exe will always be 0755, for example.\n\nOuch.  Is this true in general, or only on FAT-derived\nfilesystems?\n\nWe may need to worry about this on the core side after all.\nSome people need to mount FAT even on Linux systems, \n"},{"id":"9851","messageId":"Pine.LNX.4.64.0510081909250.31407@g5.osdl.org","threadId":"2049","inReplyTo":"7vzmpjoa32.fsf@assigned-by-dhcp.cox.net","subject":"Re: Seeing various mode changes on cygwin","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-09T02:19:35Z","receivedAt":"2005-10-09T02:19:35Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sat, 8 Oct 2005, Junio C Hamano wrote:\n>\n> Alex Riesen <raa.lkml@gmail.com> writes:\n> > These are not real attributes, cygwin emulates them from the names,\n> > like .exe will always be 0755, for example.\n> \n> Ouch.  Is this true in general, or only on FAT-derived\n> filesystems?\n> \n> We may need to worry about this on the core side after all.\n> Some people need to mount FAT even on Linux systems, \n\nI think we might want to have a flag that says \"don't care about \nfilesystem modes\". That should be pretty easy, I think we'd get most of \nthem by just adding some logic to \"ce_match_stat()\".\n\nThen add a \"git chmod\" to set the mode in the index (which should end up \nbeing just a wrapper around the regular \"git-update-index\" using the \n\"--cacheinfo\" flag, I think).\n\nThose parts should be trivial.\n\nThe more interesting issue is how to set the _flag_ that we should do \nthis. We may have to add a config file, and it should be per-repository \n(ie something like \".git/config\" or \".git/info/config\"). Or do we just do \nyet another environment variable?\n\n\t\tLinus\n"},{"id":"9852","messageId":"434891DA.7070905@zytor.com","threadId":"2049","inReplyTo":"7vzmpjoa32.fsf@assigned-by-dhcp.cox.net","subject":"Re: Seeing various mode changes on cygwin","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-10-09T03:43:22Z","receivedAt":"2005-10-09T03:43:22Z","isPatch":false,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Junio C Hamano wrote:\n> Alex Riesen <raa.lkml@gmail.com> writes:\n> \n>>These are not real attributes, cygwin emulates them from the names,\n>>like .exe will always be 0755, for example.\n> \n> Ouch.  Is this true in general, or only on FAT-derived\n> filesystems?\n> \n> We may need to worry about this on the core side after all.\n> Some people need to mount FAT even on Linux systems, \n> \n\nAt least on Cygwin/NTFS, you can do chmod just fine.\n\n\t-hpa\n"},{"id":"9853","messageId":"7vmzljkx0m.fsf@assigned-by-dhcp.cox.net","threadId":"2049","inReplyTo":"Pine.LNX.4.64.0510081909250.31407@g5.osdl.org","subject":"Re: Seeing various mode changes on cygwin","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-09T06:46:49Z","receivedAt":"2005-10-09T06:46:49Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> The more interesting issue is how to set the _flag_ that we should do \n> this. We may have to add a config file, and it should be per-repository \n> (ie something like \".git/config\" or \".git/info/config\"). Or do we just do \n> yet another environment variable?\n\nPer-repository configuration file like .git/info/config sounds\nlike the way to go.  Long time ago, the core never read any\nper-repository nor per-odb configuration file, but after grafts\nand then now alternates, we started doing it, and there is no\nreason to shy away from having an official configuration file\nmechanism.  Maybe recent HTTP related environment variables\ncould also be folded into it.\n\nWhile we are at it, we may want to move things around to\nconsolidate per-repository configuration into a single placek.\nSpecifically, I have moving .git/remotes/ in mind.\n"},{"id":"9857","messageId":"20051009130253.GA14237@steel.home","threadId":"2049","inReplyTo":"7vzmpjoa32.fsf@assigned-by-dhcp.cox.net","subject":"Re: Seeing various mode changes on cygwin","fromName":"Alex Riesen","fromEmail":"raa.lkml@gmail.com","sentAt":"2005-10-09T13:02:53Z","receivedAt":"2005-10-09T13:02:53Z","isPatch":false,"sender":{"key":"raa.lkml@gmail.com","avatar":"https://avatars.githubusercontent.com/u/324101?v=4"},"body":"Junio C Hamano, Sun, Oct 09, 2005 01:36:17 +0200:\n> > These are not real attributes, cygwin emulates them from the names,\n> > like .exe will always be 0755, for example.\n> \n> Ouch.  Is this true in general, or only on FAT-derived\n> filesystems?\n> \n\nBefore they are chmod'ed by cygwin (with chmod): probably everywhere\non windows (I'm sure about vfat, were chmod wont help at all).  Even\nif you can save user (unix) attributes somewhere, initial clone will\nstill always have this problem.\n"},{"id":"9868","messageId":"Pine.LNX.4.63.0510100220330.23242@iabervon.org","threadId":"2049","inReplyTo":"Pine.LNX.4.64.0510081909250.31407@g5.osdl.org","subject":"Re: Seeing various mode changes on cygwin","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-10-10T06:48:18Z","receivedAt":"2005-10-10T06:48:18Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Sat, 8 Oct 2005, Linus Torvalds wrote:\n\n> I think we might want to have a flag that says \"don't care about \n> filesystem modes\". That should be pretty easy, I think we'd get most of \n> them by just adding some logic to \"ce_match_stat()\".\n> \n> Then add a \"git chmod\" to set the mode in the index (which should end up \n> being just a wrapper around the regular \"git-update-index\" using the \n> \"--cacheinfo\" flag, I think).\n> \n> Those parts should be trivial.\n> \n> The more interesting issue is how to set the _flag_ that we should do \n> this. We may have to add a config file, and it should be per-repository \n> (ie something like \".git/config\" or \".git/info/config\"). Or do we just do \n> yet another environment variable?\n\nPerhaps have a bit in the index mode for the file to say that the mode in \nthe filesystem is unreliable, which gets set if a stat of the \nnewly-written file doesn't match the mode it was supposed to have, or if \ngit chmod is used to change it; then, if the bit is set, ignore the mode \nin the filesystem and just use the mode in the index.\n\nThis should prevent modes from magically changing, even if the user \ndoesn't do anything special.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"9869","messageId":"7vu0fpbz43.fsf@assigned-by-dhcp.cox.net","threadId":"2049","inReplyTo":"Pine.LNX.4.63.0510100220330.23242@iabervon.org","subject":"Re: Seeing various mode changes on cygwin","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-10T07:38:36Z","receivedAt":"2005-10-10T07:38:36Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Daniel Barkalow <barkalow@iabervon.org> writes:\n\n> Perhaps have a bit in the index mode for the file to say that the mode in \n> the filesystem is unreliable, which gets set if a stat of the \n> newly-written file doesn't match the mode it was supposed to have, or if \n> git chmod is used to change it; then, if the bit is set, ignore the mode \n> in the filesystem and just use the mode in the index.\n\nIn effect, you are making the \"per-repo configuration\" Linus\nmentioned a non configuration but a property recorded in the\nindex file.  I think this is a clever solution which is very\nhelpful to the end user.  I have to think about this a bit, but\nmy gut feeling tells me that it is the right direction if it\nworks.\n\nI do not think you have to necessarily record it in the \"index\nmode\" -- which implies this is per path -- nor even in the index\nfile itself.  We might even be able to get away with doing this\ncheck at git-init-db time just once, and record it in a file,\nsay \".git/fs-mode-unreliable\".\n"},{"id":"9894","messageId":"Pine.LNX.4.63.0510101354520.23242@iabervon.org","threadId":"2049","inReplyTo":"7vu0fpbz43.fsf@assigned-by-dhcp.cox.net","subject":"Re: Seeing various mode changes on cygwin","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-10-10T17:59:40Z","receivedAt":"2005-10-10T17:59:40Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Mon, 10 Oct 2005, Junio C Hamano wrote:\n\n> Daniel Barkalow <barkalow@iabervon.org> writes:\n> \n> > Perhaps have a bit in the index mode for the file to say that the mode in \n> > the filesystem is unreliable, which gets set if a stat of the \n> > newly-written file doesn't match the mode it was supposed to have, or if \n> > git chmod is used to change it; then, if the bit is set, ignore the mode \n> > in the filesystem and just use the mode in the index.\n> \n> In effect, you are making the \"per-repo configuration\" Linus\n> mentioned a non configuration but a property recorded in the\n> index file.  I think this is a clever solution which is very\n> helpful to the end user.  I have to think about this a bit, but\n> my gut feeling tells me that it is the right direction if it\n> works.\n> \n> I do not think you have to necessarily record it in the \"index\n> mode\" -- which implies this is per path -- nor even in the index\n> file itself.  We might even be able to get away with doing this\n> check at git-init-db time just once, and record it in a file,\n> say \".git/fs-mode-unreliable\".\n\nActually, you're right; it is information about the behavior of the \nworking tree, and is also needed if you want to compare the working tree \nagainst a tree object, in which case you aren't using the index at all.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"9897","messageId":"Pine.LNX.4.64.0510101120410.14597@g5.osdl.org","threadId":"2049","inReplyTo":"Pine.LNX.4.63.0510101354520.23242@iabervon.org","subject":"Re: Seeing various mode changes on cygwin","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-10T18:22:46Z","receivedAt":"2005-10-10T18:22:46Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 10 Oct 2005, Daniel Barkalow wrote:\n> \n> Actually, you're right; it is information about the behavior of the \n> working tree, and is also needed if you want to compare the working tree \n> against a tree object, in which case you aren't using the index at all.\n\nGit _always_ uses the index for working tree operations.\n\nIt may take the actual file _data_ from the working tree, but it will take \nthe list of files from the index, so it's certainly possible to link the \nindex to the working tree.\n\nThat said, I don't think it's necessarily a good idea. You can have \ntemporary indexes for various operations that ignore the main one (ie any \nrandom\n\n\tGIT_INDEX_FILE=tmp git-read-tree ...\n\nwill create a new index).\n\nSo I think it's much better to have a config file.\n\nI'll write something up. Make it extensible while at it.\n\n\t\tLinus\n"},{"id":"9937","messageId":"Pine.LNX.4.64.0510101415080.14597@g5.osdl.org","threadId":"2049","inReplyTo":"Pine.LNX.4.64.0510101120410.14597@g5.osdl.org","subject":"Add \".git/config\" file parser","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-10T21:35:36Z","receivedAt":"2005-10-10T21:35:36Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThis is a first cut at a very simple parser for a git config file.\n\nThe format of the file is a simple ini-file like thing, with simple \nvariable/value pairs. You can (and should) make the variables have a \nsimple single-level scope, ie a valid file looks something like this:\n\n\t#\n\t# This is the config file, and\n\t# a '#' or ';' character indicates\n\t# a comment\n\t#\n\n\t; core variables\n\t[core]\n\t\t; Don't trust file modes\n\t\tfilemode = false\n\n\t; Our diff algorithm \n\t[diff]\n\t\texternal = \"/usr/local/bin/gnu-diff -u\"\n\t\trenames = true\n\nwhich parses into two variables: \"core.filemode\" is associated with the \nstring \"false\", and \"diff.external\" gets the appropriate quoted value.\n\nRight now we only react to one variable: \"core.filemode\" is a boolean that \ndecides if we should care about the 0100 (user-execute) bit of the stat \ninformation. Even that is just a parsing demonstration - this doesn't \nactually implement that st_mode compare logic itself.\n\nDifferent programs can react to different config options, although they \nshould always fall back to calling \"git_default_config()\" on any config \noption name that they don't recognize.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n----\n\nOk, so it's stupid. But quite frankly, I think the Windows ini-file format \nis a hell of a lot more readable than something over-engineered like XML \nfiles or other crap.\n\nThe interface is really easy to use, imho. You can do things like\n\n\tstatic int enable_renames = 0;\n\n\tstatic int my_options(const char *var, const char *value)\n\t{\n\t\tif (!strcmp(\"diff.renames\", var)) {\n\t\t\tenable_renames = git_config_bool(var, value);\n\t\t\treturn 0;\n\t\t}\n\n\t\t/*\n\t\t * Put other local option parsing for this program\n\t\t * here .. \n\t\t */\n\n\t\t/* Fall back on the default ones */\n\t\treturn git_default_config(var, value);\n\t}\n\nand then in the \"main()\" routine you just do\n\n\t\tgit_config(my_options);\n\nat the top (or, more precisely, just after the \"git_setup_directory()\" if \nyou have one).\n\nAnd as usual, it's not like this has gotten a whole lot of testing.\n\nFlames, comments, whatever? The code is actually written so that the \nconfig file parsing should really be pretty neutral. It doesn't even have \nany git-specific in it, except for the naming and the actual initial \n\"fopen()\" pathname used, I think.\n\n---\ndiff --git a/Makefile b/Makefile\nindex a201187..e8b46f1 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -158,7 +158,7 @@ LIB_OBJS = \\\n \tobject.o pack-check.o patch-delta.o path.o pkt-line.o \\\n \tquote.o read-cache.o refs.o run-command.o \\\n \tserver-info.o setup.o sha1_file.o sha1_name.o strbuf.o \\\n-\ttag.o tree.o usage.o $(DIFF_OBJS)\n+\ttag.o tree.o usage.o config.o $(DIFF_OBJS)\n \n LIBS = $(LIB_FILE)\n LIBS += -lz\ndiff --git a/cache.h b/cache.h\nindex 5987d4c..0571282 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -178,6 +178,8 @@ extern int hold_index_file_for_update(st\n extern int commit_index_file(struct cache_file *);\n extern void rollback_index_file(struct cache_file *);\n \n+extern int trust_executable_bit;\n+\n #define MTIME_CHANGED\t0x0001\n #define CTIME_CHANGED\t0x0002\n #define OWNER_CHANGED\t0x0004\n@@ -372,4 +374,10 @@ extern int gitfakemunmap(void *start, si\n \n #endif\n \n+typedef int (*config_fn_t)(const char *, const char *);\n+extern int git_default_config(const char *, const char *);\n+extern int git_config(config_fn_t fn);\n+extern int git_config_int(const char *, const char *);\n+extern int git_config_bool(const char *, const char *);\n+\n #endif /* CACHE_H */\ndiff --git a/config.c b/config.c\nnew file mode 100644\nindex 0000000..f3c4fa4\n--- /dev/null\n+++ b/config.c\n@@ -0,0 +1,222 @@\n+#include <ctype.h>\n+\n+#include \"cache.h\"\n+\n+#define MAXNAME (256)\n+\n+static FILE *config_file;\n+static int config_linenr;\n+static int get_next_char(void)\n+{\n+\tint c;\n+\tFILE *f;\n+\n+\tc = '\\n';\n+\tif ((f = config_file) != NULL) {\n+\t\tc = fgetc(f);\n+\t\tif (c == '\\n')\n+\t\t\tconfig_linenr++;\n+\t\tif (c == EOF) {\n+\t\t\tconfig_file = NULL;\n+\t\t\tc = '\\n';\n+\t\t}\n+\t}\n+\treturn c;\n+}\n+\n+static char *parse_value(void)\n+{\n+\tstatic char value[1024];\n+\tint quote = 0, comment = 0, len = 0, space = 0;\n+\n+\tfor (;;) {\n+\t\tint c = get_next_char();\n+\t\tif (len >= sizeof(value))\n+\t\t\treturn NULL;\n+\t\tif (c == '\\n') {\n+\t\t\tif (quote)\n+\t\t\t\treturn NULL;\n+\t\t\tvalue[len] = 0;\n+\t\t\treturn value;\n+\t\t}\n+\t\tif (comment)\n+\t\t\tcontinue;\n+\t\tif (isspace(c) && !quote) {\n+\t\t\tspace = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (space) {\n+\t\t\tif (len)\n+\t\t\t\tvalue[len++] = ' ';\n+\t\t\tspace = 0;\n+\t\t}\n+\t\tif (c == '\\\\') {\n+\t\t\tc = get_next_char();\n+\t\t\tswitch (c) {\n+\t\t\tcase '\\n':\n+\t\t\t\tcontinue;\n+\t\t\tcase 't':\n+\t\t\t\tc = '\\t';\n+\t\t\t\tbreak;\n+\t\t\tcase 'b':\n+\t\t\t\tc = '\\b';\n+\t\t\t\tbreak;\n+\t\t\tcase 'n':\n+\t\t\t\tc = '\\n';\n+\t\t\t\tbreak;\n+\t\t\treturn NULL;\n+\t\t\t}\n+\t\t\tvalue[len++] = c;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (c == '\"') {\n+\t\t\tquote = 1-quote;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!quote) {\n+\t\t\tif (c == ';' || c == '#') {\n+\t\t\t\tcomment = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t}\n+\t\tvalue[len++] = c;\n+\t}\n+}\n+\n+static int get_value(config_fn_t fn, char *name, unsigned int len)\n+{\n+\tint c;\n+\tchar *value;\n+\n+\t/* Get the full name */\n+\tfor (;;) {\n+\t\tc = get_next_char();\n+\t\tif (c == EOF)\n+\t\t\tbreak;\n+\t\tif (!isalnum(c))\n+\t\t\tbreak;\n+\t\tname[len++] = tolower(c);\n+\t\tif (len >= MAXNAME)\n+\t\t\treturn -1;\n+\t}\n+\tname[len] = 0;\n+\twhile (c == ' ' || c == '\\t')\n+\t\tc = get_next_char();\n+\n+\tvalue = NULL;\n+\tif (c != '\\n') {\n+\t\tif (c != '=')\n+\t\t\treturn -1;\n+\t\tvalue = parse_value();\n+\t\tif (!value)\n+\t\t\treturn -1;\n+\t}\n+\treturn fn(name, value);\n+}\n+\n+static int get_base_var(char *name)\n+{\n+\tint baselen = 0;\n+\n+\tfor (;;) {\n+\t\tint c = get_next_char();\n+\t\tif (c == EOF)\n+\t\t\treturn -1;\n+\t\tif (c == ']')\n+\t\t\treturn baselen;\n+\t\tif (!isalnum(c))\n+\t\t\treturn -1;\n+\t\tif (baselen > MAXNAME / 2)\n+\t\t\treturn -1;\n+\t\tname[baselen++] = tolower(c);\n+\t}\n+}\n+\n+static int git_parse_file(config_fn_t fn)\n+{\n+\tint comment = 0;\n+\tint baselen = 0;\n+\tstatic char var[MAXNAME];\n+\n+\tfor (;;) {\n+\t\tint c = get_next_char();\n+\t\tif (c == '\\n') {\n+\t\t\t/* EOF? */\n+\t\t\tif (!config_file)\n+\t\t\t\treturn 0;\n+\t\t\tcomment = 0;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (comment || isspace(c))\n+\t\t\tcontinue;\n+\t\tif (c == '#' || c == ';') {\n+\t\t\tcomment = 1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (c == '[') {\n+\t\t\tbaselen = get_base_var(var);\n+\t\t\tif (baselen <= 0)\n+\t\t\t\tbreak;\n+\t\t\tvar[baselen++] = '.';\n+\t\t\tvar[baselen] = 0;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!isalpha(c))\n+\t\t\tbreak;\n+\t\tvar[baselen] = c;\n+\t\tif (get_value(fn, var, baselen+1) < 0)\n+\t\t\tbreak;\n+\t}\n+\tdie(\"bad config file line %d\", config_linenr);\n+}\n+\n+int git_config_int(const char *name, const char *value)\n+{\n+\tif (value && *value) {\n+\t\tchar *end;\n+\t\tint val = strtol(value, &end, 0);\n+\t\tif (!*end)\n+\t\t\treturn val;\n+\t}\n+\tdie(\"bad config value for '%s'\", name);\n+}\n+\n+int git_config_bool(const char *name, const char *value)\n+{\n+\tif (!value)\n+\t\treturn 1;\n+\tif (!*value)\n+\t\treturn 0;\n+\tif (!strcasecmp(value, \"true\"))\n+\t\treturn 1;\n+\tif (!strcasecmp(value, \"false\"))\n+\t\treturn 0;\n+\treturn git_config_int(name, value) != 0;\n+}\n+\n+int git_default_config(const char *var, const char *value)\n+{\n+\t/* This needs a better name */\n+\tif (!strcmp(var, \"core.filemode\")) {\n+\t\ttrust_executable_bit = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Add other config variables here.. */\n+\treturn 0;\n+}\n+\n+int git_config(config_fn_t fn)\n+{\n+\tint ret;\n+\tFILE *f = fopen(git_path(\"config\"), \"r\");\n+\n+\tret = -1;\n+\tif (f) {\n+\t\tconfig_file = f;\n+\t\tconfig_linenr = 1;\n+\t\tret = git_parse_file(fn);\n+\t\tfclose(f);\n+\t}\n+\treturn ret;\n+}\ndiff --git a/diff-files.c b/diff-files.c\nindex 5e59832..96d2c7f 100644\n--- a/diff-files.c\n+++ b/diff-files.c\n@@ -38,6 +38,7 @@ int main(int argc, const char **argv)\n \tconst char *prefix = setup_git_directory();\n \tint entries, i;\n \n+\tgit_config(git_default_config);\n \tdiff_setup(&diff_options);\n \twhile (1 < argc && argv[1][0] == '-') {\n \t\tif (!strcmp(argv[1], \"-q\"))\ndiff --git a/diff-tree.c b/diff-tree.c\nindex b2d74eb..2203fa5 100644\n--- a/diff-tree.c\n+++ b/diff-tree.c\n@@ -408,6 +408,7 @@ int main(int argc, const char **argv)\n \tunsigned char sha1[2][20];\n \tconst char *prefix = setup_git_directory();\n \n+\tgit_config(git_default_config);\n \tnr_sha1 = 0;\n \tdiff_setup(&diff_options);\n \ndiff --git a/read-cache.c b/read-cache.c\nindex d2aebdd..c7f3b26 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -5,6 +5,7 @@\n  */\n #include \"cache.h\"\n \n+int trust_executable_bit = 1;\n struct cache_entry **active_cache = NULL;\n unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;\n \n"},{"id":"9939","messageId":"Pine.LNX.4.64.0510101446180.14597@g5.osdl.org","threadId":"2049","inReplyTo":"Pine.LNX.4.64.0510101415080.14597@g5.osdl.org","subject":"Re: Add \".git/config\" file parser","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-10T21:47:12Z","receivedAt":"2005-10-10T21:47:12Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 10 Oct 2005, Linus Torvalds wrote:\n> \n> \t; core variables\n> \t[core]\n> \t\t; Don't trust file modes\n> \t\tfilemode = false\n> \n> \t; Our diff algorithm \n> \t[diff]\n> \t\texternal = \"/usr/local/bin/gnu-diff -u\"\n> \t\trenames = true\n> \n> which parses into two variables: \"core.filemode\" is associated with the \n> string \"false\", and \"diff.external\" gets the appropriate quoted value.\n\n_Three_ variables. Duh. I added the \"renames\" thing later, as I was \nlooking at what kinds of default flags the \"git-diff-xyz\" family might be \ninterested in having.\n\n\t\tLinus\n"},{"id":"9940","messageId":"434AE209.60605@zytor.com","threadId":"2049","inReplyTo":"Pine.LNX.4.64.0510101446180.14597@g5.osdl.org","subject":"Re: Add \".git/config\" file parser","fromName":"H. Peter Anvin","fromEmail":"hpa@zytor.com","sentAt":"2005-10-10T21:50:01Z","receivedAt":"2005-10-10T21:50:01Z","isPatch":false,"sender":{"key":"hpa@zytor.com","avatar":null},"body":"Linus Torvalds wrote:\n> \n> On Mon, 10 Oct 2005, Linus Torvalds wrote:\n> \n>>\t; core variables\n>>\t[core]\n>>\t\t; Don't trust file modes\n>>\t\tfilemode = false\n>>\n>>\t; Our diff algorithm \n>>\t[diff]\n>>\t\texternal = \"/usr/local/bin/gnu-diff -u\"\n>>\t\trenames = true\n>>\n>>which parses into two variables: \"core.filemode\" is associated with the \n>>string \"false\", and \"diff.external\" gets the appropriate quoted value.\n>  \n> _Three_ variables. Duh. I added the \"renames\" thing later, as I was \n> looking at what kinds of default flags the \"git-diff-xyz\" family might be \n> interested in having.\n> \n\nA suggestion: if you make your basic types (integer, string, boolean) \nrecognizable by the parser, you can present them in that way.  This \npretty much means strings will have to always be double-quoted, but that \navoids a bunch of ambiguities.\n\n\t-hpa\n"},{"id":"9941","messageId":"Pine.LNX.4.64.0510101456570.14597@g5.osdl.org","threadId":"2049","inReplyTo":"434AE209.60605@zytor.com","subject":"Re: Add \".git/config\" file parser","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-10-10T22:12:30Z","receivedAt":"2005-10-10T22:12:30Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 10 Oct 2005, H. Peter Anvin wrote:\n> \n> A suggestion: if you make your basic types (integer, string, boolean)\n> recognizable by the parser, you can present them in that way.  This pretty\n> much means strings will have to always be double-quoted, but that avoids a\n> bunch of ambiguities.\n\nWell, the parser is already pretty unambiguous, purely by virtue of being \nstupid as hell.\n\nIn particular, the only thing quoting does is to actually make whitespace \nmeaningful, and as a way to allow comments inside strings (otherwise a \"#\" \nor \";\" is always a \"comment starts here\" marker).\n\nOutside of quotes, any whitespace will just collapse to a single space \n(and be removed from beginning and end).\n\nAnd quite frankly, always keeping the things as strings just makes things \nso much easier and the interfaces very simple. And if/when you want to \nturn the string into a boolean or a regular integer, there are two helper \nfunctions that do exactly that, so it's not very hard.\n\nI considered using some \"smart\" parser (ie using something like \nflex/bison), but the thing is, I didn't want smart. I personally think \nit's a lot more important for the file format to be _nice_, and there I \nthink it's fine if\n\n\t[diff]\n\t\texternal=/usr/local/bin/gnu-diff\n\ndoesn't need quotes, even if it's obviously a string. Simplicity is a \nvirtue (both in parsing and in the \"language\" parsed).\n\nIn fact, even the example I had - with a space and an argument - doesn't \nneed quotes (since the single space will be collapsed to a single space), \nI just put that as an example.\n\nSide note: the design is meant to allow different programs to share the \nsame config file without having to know about each others config \nvariables. Anything they don't recognize is just ignored. The downside is \nthat if you mistype an option name, nobody will recognize it, and nobody \nwill complain either. \n\nThat was one of the reasons for the \"scoping\". It not only allows grouping \nof variables, but it means that the \"git-diff-xyz\" family of programs \nmight decide that they'll report anything that starts with \"diff.\" but \nthat they don't understand as a warning (but preferably not error, since \nit might be a newer option that an older version of git just doesn't \nunderstand).\n\n\t\tLinus\n"},{"id":"9986","messageId":"7vvf03r36y.fsf@assigned-by-dhcp.cox.net","threadId":"2049","inReplyTo":"Pine.LNX.4.64.0510101415080.14597@g5.osdl.org","subject":"Re: Add \".git/config\" file parser","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-12T00:25:57Z","receivedAt":"2005-10-12T00:25:57Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is a WIP to implement update-index that does not care the\nfilesystem mode change.  When you have the following in\n.git/config:\n\n        [core]\n                filemode = false\n\nthe following things happen:\n\n * \"git-update-index --refresh\" does not consider the executable\n   bit change significant.\n\n * \"git-update-index\" on an existing path takes executable bit\n   from the existing index entry, if the blob types are the\n   same.\n\n * \"git-diff-files\" pretends the path on the filesystem has the\n   same executable bit as the existing index entry, if the blob\n   types are the same.\n\nYet to be done items are:\n\n * Other programs from diff-* family that compares with the\n   filesystem needs to be covered.\n\n * \"git-update-index --chmod=+x\" and \"--chmod=-x\".\n\n * Refector code that takes the executable bit change from an\n   existing index entry.\n\nWIP-not-worth-signing-off-yet-by: Junio C Hamano <junkio.cox.net>\n---\ncd /opt/packrat/playpen/public/in-place/git/git.junio/\ngit diff HEAD\ndiff --git a/diff-files.c b/diff-files.c\nindex 96d2c7f..014f74e 100644\n--- a/diff-files.c\n+++ b/diff-files.c\n@@ -81,7 +81,7 @@ int main(int argc, const char **argv)\n \n \tfor (i = 0; i < entries; i++) {\n \t\tstruct stat st;\n-\t\tunsigned int oldmode;\n+\t\tunsigned int oldmode, newmode;\n \t\tstruct cache_entry *ce = active_cache[i];\n \t\tint changed;\n \n@@ -111,7 +111,12 @@ int main(int argc, const char **argv)\n \t\tif (!changed && !diff_options.find_copies_harder)\n \t\t\tcontinue;\n \t\toldmode = ntohl(ce->ce_mode);\n-\t\tshow_modified(oldmode, DIFF_FILE_CANON_MODE(st.st_mode),\n+\n+\t\tnewmode = DIFF_FILE_CANON_MODE(st.st_mode);\n+\t\tif (!trust_executable_bit &&\n+\t\t    S_ISREG(newmode) && ((newmode ^ oldmode) == 0111))\n+\t\t\tnewmode = oldmode;\n+\t\tshow_modified(oldmode, newmode,\n \t\t\t      ce->sha1, (changed ? null_sha1 : ce->sha1),\n \t\t\t      ce->name);\n \t}\ndiff --git a/read-cache.c b/read-cache.c\nindex c7f3b26..4ed369a 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -36,8 +36,11 @@ int ce_match_stat(struct cache_entry *ce\n \tswitch (ntohl(ce->ce_mode) & S_IFMT) {\n \tcase S_IFREG:\n \t\tchanged |= !S_ISREG(st->st_mode) ? TYPE_CHANGED : 0;\n-\t\t/* We consider only the owner x bit to be relevant for \"mode changes\" */\n-\t\tif (0100 & (ntohl(ce->ce_mode) ^ st->st_mode))\n+\t\t/* We consider only the owner x bit to be relevant for\n+\t\t * \"mode changes\"\n+\t\t */\n+\t\tif (trust_executable_bit &&\n+\t\t    (0100 & (ntohl(ce->ce_mode) ^ st->st_mode)))\n \t\t\tchanged |= MODE_CHANGED;\n \t\tbreak;\n \tcase S_IFLNK:\n@@ -393,7 +396,7 @@ int add_cache_entry(struct cache_entry *\n \tint skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;\n \tpos = cache_name_pos(ce->name, ntohs(ce->ce_flags));\n \n-\t/* existing match? Just replace it */\n+\t/* existing match? Just replace it. */\n \tif (pos >= 0) {\n \t\tactive_cache_changed = 1;\n \t\tactive_cache[pos] = ce;\n@@ -416,7 +419,8 @@ int add_cache_entry(struct cache_entry *\n \tif (!ok_to_add)\n \t\treturn -1;\n \n-\tif (!skip_df_check && check_file_directory_conflict(ce, pos, ok_to_replace)) {\n+\tif (!skip_df_check &&\n+\t    check_file_directory_conflict(ce, pos, ok_to_replace)) {\n \t\tif (!ok_to_replace)\n \t\t\treturn -1;\n \t\tpos = cache_name_pos(ce->name, ntohs(ce->ce_flags));\ndiff --git a/update-index.c b/update-index.c\nindex 01b4088..fd3a882 100644\n--- a/update-index.c\n+++ b/update-index.c\n@@ -67,13 +67,23 @@ static int add_file_to_cache(const char \n \t\t\treturn error(\"lstat(\\\"%s\\\"): %s\", path,\n \t\t\t\t     strerror(errno));\n \t}\n+\n \tnamelen = strlen(path);\n \tsize = cache_entry_size(namelen);\n \tce = xmalloc(size);\n \tmemset(ce, 0, size);\n \tmemcpy(ce->name, path, namelen);\n \tfill_stat_cache_info(ce, &st);\n+\n \tce->ce_mode = create_ce_mode(st.st_mode);\n+\tif (!trust_executable_bit) {\n+\t\t/* If there is an existing entry, pick the mode bits\n+\t\t * from it.\n+\t\t */\n+\t\tint pos = cache_name_pos(path, namelen);\n+\t\tif (0 <= pos)\n+\t\t\tce->ce_mode = active_cache[pos]->ce_mode;\n+\t}\n \tce->ce_flags = htons(namelen);\n \n \tif (index_path(ce->sha1, path, &st, !info_only))\n@@ -328,6 +338,8 @@ int main(int argc, const char **argv)\n \tconst char *prefix = setup_git_directory();\n \tint prefix_length = prefix ? strlen(prefix) : 0;\n \n+\tgit_config(git_default_config);\n+\n \tnewfd = hold_index_file_for_update(&cache_file, get_index_file());\n \tif (newfd < 0)\n \t\tdie(\"unable to create new cachefile\");\n"},{"id":"10005","messageId":"7v1x2rji3q.fsf@assigned-by-dhcp.cox.net","threadId":"2049","inReplyTo":"7vvf03r36y.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] Use core.filemode.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-10-12T07:43:21Z","receivedAt":"2005-10-12T07:43:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> This is a WIP to implement update-index that does not care the\n> filesystem mode change...\n\nI finished this one and have it in the master branch.  I'd\nappreciate feedback from folks on affected platforms, most\nnotably Cygwin.\n\nIt might not be a bad idea to populate a new repository with a\ndefault .git/config file that sets \"core.filemode = false\" on\nCygwin platform, using the templates mechanism.  People on NTFS\nmight not like that -- I do not know.\n\nAnyway, that is a separate topic.\n\n -- >8 -- cut here -- >8 --\n\nWith \"[core] filemode = false\", you can tell git to ignore\ndifferences in the working tree file only in executable bit.\n\n * \"git-update-index --refresh\" does not say \"needs update\" if index\n   entry and working tree file differs only in executable bit.\n\n * \"git-update-index\" on an existing path takes executable bit\n   from the existing index entry, if the path and index entry are\n   both regular files.\n\n * \"git-diff-files\" and \"git-diff-index\" without --cached flag\n   pretend the path on the filesystem has the same executable\n   bit as the existing index entry, if the path and index entry\n   are both regular files.\n\nIf you are on a filesystem with unreliable mode bits, you may need to\nforce the executable bit after registering the path in the index.\n\n * \"git-update-index --chmod=+x foo\" flips the executable bit of the\n   index file entry for path \"foo\" on.  Use \"--chmod=-x\" to flip it\n   off.\n\nNote that --chmod only works in index file and does not look at nor\nupdate the working tree.\n\nSo if you are on a filesystem and do not have working executable bit,\nyou would do:\n\n 1. set the appropriate .git/config option;\n\n 2. \"git-update-index --add new-file.c\"\n\n 3. \"git-ls-files --stage new-file.c\" to see if it has the desired\n   mode bits.  If not, e.g. to drop executable bit picked up from the\n   filesystem, say \"git-update-index --chmod=-x new-file.c\".\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n diff-files.c   |   10 ++++++++--\n diff-index.c   |   11 +++++++++--\n read-cache.c   |   12 ++++++++----\n update-index.c |   46 +++++++++++++++++++++++++++++++++++++++++++++-\n 4 files changed, 70 insertions(+), 9 deletions(-)\n\napplies-to: 8c8a7c6987bcb0eeab559a58170fccd767ce0218\n3e09cdfd114651fc61656dbd45d5ec3d9352cb2b\ndiff --git a/diff-files.c b/diff-files.c\nindex 96d2c7f..8a8f9b6 100644\n--- a/diff-files.c\n+++ b/diff-files.c\n@@ -81,7 +81,7 @@ int main(int argc, const char **argv)\n \n \tfor (i = 0; i < entries; i++) {\n \t\tstruct stat st;\n-\t\tunsigned int oldmode;\n+\t\tunsigned int oldmode, newmode;\n \t\tstruct cache_entry *ce = active_cache[i];\n \t\tint changed;\n \n@@ -111,7 +111,13 @@ int main(int argc, const char **argv)\n \t\tif (!changed && !diff_options.find_copies_harder)\n \t\t\tcontinue;\n \t\toldmode = ntohl(ce->ce_mode);\n-\t\tshow_modified(oldmode, DIFF_FILE_CANON_MODE(st.st_mode),\n+\n+\t\tnewmode = DIFF_FILE_CANON_MODE(st.st_mode);\n+\t\tif (!trust_executable_bit &&\n+\t\t    S_ISREG(newmode) && S_ISREG(oldmode) &&\n+\t\t    ((newmode ^ oldmode) == 0111))\n+\t\t\tnewmode = oldmode;\n+\t\tshow_modified(oldmode, newmode,\n \t\t\t      ce->sha1, (changed ? null_sha1 : ce->sha1),\n \t\t\t      ce->name);\n \t}\ndiff --git a/diff-index.c b/diff-index.c\nindex 62b36cc..c9a9f4c 100644\n--- a/diff-index.c\n+++ b/diff-index.c\n@@ -15,7 +15,7 @@ static void show_file(const char *prefix\n }\n \n static int get_stat_data(struct cache_entry *ce,\n-\t\t\t unsigned char **sha1p, unsigned int *modep)\n+\t\t\t unsigned char ** sha1p, unsigned int *modep)\n {\n \tunsigned char *sha1 = ce->sha1;\n \tunsigned int mode = ce->ce_mode;\n@@ -35,6 +35,10 @@ static int get_stat_data(struct cache_en\n \t\tchanged = ce_match_stat(ce, &st);\n \t\tif (changed) {\n \t\t\tmode = create_ce_mode(st.st_mode);\n+\t\t\tif (!trust_executable_bit &&\n+\t\t\t    S_ISREG(mode) && S_ISREG(ce->ce_mode) &&\n+\t\t\t    ((mode ^ ce->ce_mode) == 0111))\n+\t\t\t\tmode = ce->ce_mode;\n \t\t\tsha1 = no_sha1;\n \t\t}\n \t}\n@@ -49,7 +53,9 @@ static void show_new_file(struct cache_e\n \tunsigned char *sha1;\n \tunsigned int mode;\n \n-\t/* New file in the index: it might actually be different in the working copy */\n+\t/* New file in the index: it might actually be different in\n+\t * the working copy.\n+\t */\n \tif (get_stat_data(new, &sha1, &mode) < 0)\n \t\treturn;\n \n@@ -174,6 +180,7 @@ int main(int argc, const char **argv)\n \tint allow_options = 1;\n \tint i;\n \n+\tgit_config(git_default_config);\n \tdiff_setup(&diff_options);\n \tfor (i = 1; i < argc; i++) {\n \t\tconst char *arg = argv[i];\ndiff --git a/read-cache.c b/read-cache.c\nindex c7f3b26..4ed369a 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -36,8 +36,11 @@ int ce_match_stat(struct cache_entry *ce\n \tswitch (ntohl(ce->ce_mode) & S_IFMT) {\n \tcase S_IFREG:\n \t\tchanged |= !S_ISREG(st->st_mode) ? TYPE_CHANGED : 0;\n-\t\t/* We consider only the owner x bit to be relevant for \"mode changes\" */\n-\t\tif (0100 & (ntohl(ce->ce_mode) ^ st->st_mode))\n+\t\t/* We consider only the owner x bit to be relevant for\n+\t\t * \"mode changes\"\n+\t\t */\n+\t\tif (trust_executable_bit &&\n+\t\t    (0100 & (ntohl(ce->ce_mode) ^ st->st_mode)))\n \t\t\tchanged |= MODE_CHANGED;\n \t\tbreak;\n \tcase S_IFLNK:\n@@ -393,7 +396,7 @@ int add_cache_entry(struct cache_entry *\n \tint skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;\n \tpos = cache_name_pos(ce->name, ntohs(ce->ce_flags));\n \n-\t/* existing match? Just replace it */\n+\t/* existing match? Just replace it. */\n \tif (pos >= 0) {\n \t\tactive_cache_changed = 1;\n \t\tactive_cache[pos] = ce;\n@@ -416,7 +419,8 @@ int add_cache_entry(struct cache_entry *\n \tif (!ok_to_add)\n \t\treturn -1;\n \n-\tif (!skip_df_check && check_file_directory_conflict(ce, pos, ok_to_replace)) {\n+\tif (!skip_df_check &&\n+\t    check_file_directory_conflict(ce, pos, ok_to_replace)) {\n \t\tif (!ok_to_replace)\n \t\t\treturn -1;\n \t\tpos = cache_name_pos(ce->name, ntohs(ce->ce_flags));\ndiff --git a/update-index.c b/update-index.c\nindex 01b4088..1eeb45d 100644\n--- a/update-index.c\n+++ b/update-index.c\n@@ -67,13 +67,23 @@ static int add_file_to_cache(const char \n \t\t\treturn error(\"lstat(\\\"%s\\\"): %s\", path,\n \t\t\t\t     strerror(errno));\n \t}\n+\n \tnamelen = strlen(path);\n \tsize = cache_entry_size(namelen);\n \tce = xmalloc(size);\n \tmemset(ce, 0, size);\n \tmemcpy(ce->name, path, namelen);\n \tfill_stat_cache_info(ce, &st);\n+\n \tce->ce_mode = create_ce_mode(st.st_mode);\n+\tif (!trust_executable_bit) {\n+\t\t/* If there is an existing entry, pick the mode bits\n+\t\t * from it.\n+\t\t */\n+\t\tint pos = cache_name_pos(path, namelen);\n+\t\tif (0 <= pos)\n+\t\t\tce->ce_mode = active_cache[pos]->ce_mode;\n+\t}\n \tce->ce_flags = htons(namelen);\n \n \tif (index_path(ce->sha1, path, &st, !info_only))\n@@ -253,8 +263,32 @@ static int add_cacheinfo(const char *arg\n \treturn add_cache_entry(ce, option);\n }\n \n-static struct cache_file cache_file;\n+static int chmod_path(int flip, const char *path)\n+{\n+\tint pos;\n+\tstruct cache_entry *ce;\n+\tunsigned int mode;\n+\n+\tpos = cache_name_pos(path, strlen(path));\n+\tif (pos < 0)\n+\t\treturn -1;\n+\tce = active_cache[pos];\n+\tmode = ntohl(ce->ce_mode);\n+\tif (!S_ISREG(mode))\n+\t\treturn -1;\n+\tswitch (flip) {\n+\tcase '+':\n+\t\tce->ce_mode |= htonl(0111); break;\n+\tcase '-':\n+\t\tce->ce_mode &= htonl(~0111); break;\n+\tdefault:\n+\t\treturn -1;\n+\t}\n+\tactive_cache_changed = 1;\n+\treturn 0;\n+}\n \n+static struct cache_file cache_file;\n \n static void update_one(const char *path, const char *prefix, int prefix_length)\n {\n@@ -328,6 +362,8 @@ int main(int argc, const char **argv)\n \tconst char *prefix = setup_git_directory();\n \tint prefix_length = prefix ? strlen(prefix) : 0;\n \n+\tgit_config(git_default_config);\n+\n \tnewfd = hold_index_file_for_update(&cache_file, get_index_file());\n \tif (newfd < 0)\n \t\tdie(\"unable to create new cachefile\");\n@@ -376,6 +412,14 @@ int main(int argc, const char **argv)\n \t\t\t\ti += 3;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(path, \"--chmod=-x\") ||\n+\t\t\t    !strcmp(path, \"--chmod=+x\")) {\n+\t\t\t\tif (argc <= i+1)\n+\t\t\t\t\tdie(\"git-update-index: %s <path>\", path);\n+\t\t\t\tif (chmod_path(path[8], argv[++i]))\n+\t\t\t\t\tdie(\"git-update-index: %s cannot chmod %s\", path, argv[i]);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(path, \"--info-only\")) {\n \t\t\t\tinfo_only = 1;\n \t\t\t\tcontinue;\n---\n0.99.8.GIT\n"}]}