git checkout branch ends up modifying files












2















I have a Mac on which I clone a repo. When I checkout any branch, the .json files I have end up showing up as "modified".



Here is the list of things I tried.





  1. git clone <blah>.git

  2. git checkout release

  3. git checkout -- $(git ls-files -m)


Files still show as modified:



me@box> cat ~/.gitattributes
text=auto
-crlf

me@box> cat .gitconfig
[core]
autocrlf = true


I have tried autocrlf with auto and false, too.



Is there any way to fix this?










share|improve this question

























  • I think you are on the right track, and the problem is the line endings.

    – Tim Biegeleisen
    Nov 21 '18 at 1:43











  • Is it ok to ask git to not do anything related to ELF on the files? Then try adding this to .git/info/attributes: * -text. That is telling git to use the files as they are on the repo. Can also be set on a .gitattributes file on the working tree.

    – eftshift0
    Nov 21 '18 at 1:43











  • Didn't help. Same problem, json files are modified.

    – kgunjikar
    Nov 21 '18 at 2:20


















2















I have a Mac on which I clone a repo. When I checkout any branch, the .json files I have end up showing up as "modified".



Here is the list of things I tried.





  1. git clone <blah>.git

  2. git checkout release

  3. git checkout -- $(git ls-files -m)


Files still show as modified:



me@box> cat ~/.gitattributes
text=auto
-crlf

me@box> cat .gitconfig
[core]
autocrlf = true


I have tried autocrlf with auto and false, too.



Is there any way to fix this?










share|improve this question

























  • I think you are on the right track, and the problem is the line endings.

    – Tim Biegeleisen
    Nov 21 '18 at 1:43











  • Is it ok to ask git to not do anything related to ELF on the files? Then try adding this to .git/info/attributes: * -text. That is telling git to use the files as they are on the repo. Can also be set on a .gitattributes file on the working tree.

    – eftshift0
    Nov 21 '18 at 1:43











  • Didn't help. Same problem, json files are modified.

    – kgunjikar
    Nov 21 '18 at 2:20
















2












2








2








I have a Mac on which I clone a repo. When I checkout any branch, the .json files I have end up showing up as "modified".



Here is the list of things I tried.





  1. git clone <blah>.git

  2. git checkout release

  3. git checkout -- $(git ls-files -m)


Files still show as modified:



me@box> cat ~/.gitattributes
text=auto
-crlf

me@box> cat .gitconfig
[core]
autocrlf = true


I have tried autocrlf with auto and false, too.



Is there any way to fix this?










share|improve this question
















I have a Mac on which I clone a repo. When I checkout any branch, the .json files I have end up showing up as "modified".



Here is the list of things I tried.





  1. git clone <blah>.git

  2. git checkout release

  3. git checkout -- $(git ls-files -m)


Files still show as modified:



me@box> cat ~/.gitattributes
text=auto
-crlf

me@box> cat .gitconfig
[core]
autocrlf = true


I have tried autocrlf with auto and false, too.



Is there any way to fix this?







git






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 '18 at 1:45









paxdiablo

638k17212541677




638k17212541677










asked Nov 21 '18 at 1:40









kgunjikarkgunjikar

14810




14810













  • I think you are on the right track, and the problem is the line endings.

    – Tim Biegeleisen
    Nov 21 '18 at 1:43











  • Is it ok to ask git to not do anything related to ELF on the files? Then try adding this to .git/info/attributes: * -text. That is telling git to use the files as they are on the repo. Can also be set on a .gitattributes file on the working tree.

    – eftshift0
    Nov 21 '18 at 1:43











  • Didn't help. Same problem, json files are modified.

    – kgunjikar
    Nov 21 '18 at 2:20





















  • I think you are on the right track, and the problem is the line endings.

    – Tim Biegeleisen
    Nov 21 '18 at 1:43











  • Is it ok to ask git to not do anything related to ELF on the files? Then try adding this to .git/info/attributes: * -text. That is telling git to use the files as they are on the repo. Can also be set on a .gitattributes file on the working tree.

    – eftshift0
    Nov 21 '18 at 1:43











  • Didn't help. Same problem, json files are modified.

    – kgunjikar
    Nov 21 '18 at 2:20



















I think you are on the right track, and the problem is the line endings.

– Tim Biegeleisen
Nov 21 '18 at 1:43





I think you are on the right track, and the problem is the line endings.

– Tim Biegeleisen
Nov 21 '18 at 1:43













Is it ok to ask git to not do anything related to ELF on the files? Then try adding this to .git/info/attributes: * -text. That is telling git to use the files as they are on the repo. Can also be set on a .gitattributes file on the working tree.

– eftshift0
Nov 21 '18 at 1:43





Is it ok to ask git to not do anything related to ELF on the files? Then try adding this to .git/info/attributes: * -text. That is telling git to use the files as they are on the repo. Can also be set on a .gitattributes file on the working tree.

– eftshift0
Nov 21 '18 at 1:43













Didn't help. Same problem, json files are modified.

– kgunjikar
Nov 21 '18 at 2:20







Didn't help. Same problem, json files are modified.

– kgunjikar
Nov 21 '18 at 2:20














1 Answer
1






active

oldest

votes


















2














TL;DR



You may want .gitattributes (not ~/.gitattributes) to contain the line * -text or *.json -text. You may want to remove any autocrlf = true setting from .git/config or $XDG_CONFIG_HOME/git/config or $HOME/.config/git/config or $HOME/.gitconfig. You might want finer control of additional files, depending on how you and others are using these repositories, on which systems.



Long



For one thing, these lines are wrong:




text=auto
-crlf



The entries in .gitattributes should have the form of a file name or pattern, followed by white space (typically a tab but blanks are OK too), followed by one or more attributes. Here, the file name / pattern part is missing, though Git does not see it that way: what this tells Git to do is to apply no attributes to all files named text=auto, and apply no attribute to all files named -crlf. Since there probably are no files with these funny names, this applies no attributes to no files—so it has no effect.



(You probably wanted * text=auto and/or * -crlf, but see below.)



Similarly (but perhaps not the problem), this might be the wrong place:




cat ~/.gitattributes



Git looks for attribute files in several places. The most important one is .gitattributes in the top level of the repository work-tree, i.e., .gitattributes, not ~/.gitattributes. You can have Git consult core.attributesFile, which you can set to ~/.gitattributes. Modern Git looks for $XDG_CONFIG_HOME/git/attributes or $HOME/.config/git/attributes if core.attributesFile is not set, so unless you configured your global core.attributesFile setting, it won't be looking in $HOME/.gitattributes.



Opinion: core.autocrlf is not a good idea




cat .gitconfig
[core]
autocrlf = true



If this was from your home directory, this may be the source of the problem.



Setting core.autocrlf to true acts this way, as described in the git config documentation:




Setting this variable to "true" is the same as setting the text
attribute to "auto" on all files and core.eol to "crlf". Set to
true if you want to have CRLF line endings in your working
directory and the repository has LF line endings. This variable can
be set to input, in which case no output conversion is performed.




In general, I dislike text=auto, because it means Git has to guess whether your file is text. Will Git guess wrong? Sometimes, yes, it will. If you are on Linux, where the end-of-line conversion defaults to do nothing, this is harmless, but on Windows and MacOS, it's not so harmless. Here, a .gitattributes file listing specifically which line endings go in which files is useful.



It's worth looking at the core.eol description as well, since you mentioned setting core.autocrlf to false:




Sets the line ending type to use in the working directory for files
that have the text property set when core.autocrlfis false.
Alternatives are lf, crlf and native, which uses the platform’s
native line ending. The default value is native. See
gitattributes(5) for more information on end-of-line conversion.



I have tried autocrlf with auto and false, too.




The only valid settings are true, false, and input. Well, technically, setting it to 1, 0, and -1 respectively also work, as Git will try to convert it as an integer if it does not match one of these words. Setting it to the literal string auto makes Git treat it as an integer, which converts to the value 0, and hence means false. That's the default, in which case core.eol comes into play provided there are no overrides in .gitattributes files.



Much of the remaining things to know are buried in that gitattributes documentation, except for a few key items that are not properly described anywhere. These require a clear definition of Git's index and work-tree.



Commits, the index, and the work-tree



The first thing to realize is that any committed file is frozen into whatever data is in the committed form of that file, forever that way in that particular commit. That is, each commit holds a snapshot of every file—well, every file that's in that commit, but that seems a bit redundant—in the form it had in the index when whoever made the snapshot, made the snapshot (by running git commit).



If a committed file has a line that ends with CR-then-LF, followed by a second line that ends with CR-without-LF, followed by a third line that ends with LF-without-CR, that committed version of that file always has that form. There is nothing anyone can do about this. If you have that commit, you have that file, with those three line endings in that order. You can choose to check it out, or not; but whatever you do, or don't do, that file exists in that form in that commit.



But wait! The act of checking out some file—or a commit full of files, for that matter—does not mean put that file into the work-tree as-is. Let's consider a file such as x.json. First, the file has to go through your index. Git's index is a special data structure (stored in one big flat file, usually, although there are some optimizations that use more than one file sometimes: the flat file has various index slots, found partly by names like x.json, along with linkages to the internal data, which is really stored elsewhere: the index copy is actually just a pointer to the real data). The index has two more names, reflecting, perhaps, its importance in Git, or perhaps that the name index leaves something to be desired: it's also called the staging area, or sometimes the cache, depending on who / what part of Git is doing the calling.



In any case, the x.json inside the commit is frozen, as we just mentioned, but also is in a special, compressed (sometimes highly compressed) Git-only format. Git first copies that x.json to your index, unfreezing the file, but keeping it in the special Git-only format. Since the copy in your index currently matches the copy in the commit, it has the same line-endings. But since it's not frozen, you can change the line endings, if you like. Before we get there, let's look at the last step of checking out x.json.



The Git-only file is useless to anything other than Git. So, Git copies the unfrozen, Git-only file from the index to your work-tree, creating an actual, ordinary-format, x.json file. It's this last step that does the first pass of end-of-line manipulation, based on:




  • whether the file has been detected as "text"—a non-text file is never manipulated this way—and

  • the eol setting, if there is any, from the .gitattributes file or implied by core.eol or core.autocrlf, more or less in that order.


You can, of course, also copy from the work-tree to the index. At this time, Git will once again do end-of-line manipulation, based on those same two items, plus the input setting, which tells Git to do end-of-line conversions even if the output pass didn't.



The conversions



There are actually two possible conversions. The first, and most common, have to do with carriage-return and line-feed line endings. The second, which is new since commit 107642fe2661 (first appearing in Git 2.18.0), has to do with Unicode encodings.



CRLF conversions



While copying from index to work-tree, Git will replace LF-only line endings with CRLF line endings if you have told it to do so. It will not replace CR-LF with LF; it only does LF-to-CRLF here.



While copying from work-tree to index, Git will replace CRLF line endings with LF-only line endings if you have told it to do so. It will not replace LF with CRLF; it does onyl CRLF-to-LF here. There is some extra magic in modern Git: if the index copy of the file has any carriage-return (r or ^M characters), Git inhibits conversion unless it's doing a "renormalize" operation (git add --renormalize, plus a merge or cherry-pick with the renormalize flag turned on).



Unicode conversions



As I mentioned, these were new in Git 2.18 (and are still new to me). Git will now re-encode UTF-16 files into UTF-8, and vice versa, if you tell it to, through a .gitattributes entry. As with the end of line conversions, these are directional: git add, which copies from work-tree to index, prepares the file for storage inside Git and will convert to UTF-8, while git checkout or git checkout-index (or various additional cases like git reset --hard), which copies from index to work-tree, will convert from UTF-8.



Additional re-encodings may be available, based on whatever iconv --list prints. This, too, is described in the gitattributes documentation.



Changing text= and conversion-bypassing issues



The default for Git is to guess whether some file is text or not. If a file is text, it gets converted; if not, Git treats it as sacrosanct: whatever is in the index goes into the work-tree, and whatever is in the work-tree goes into the index. So * -text tells Git: never touch any file at all, and there are no issues. But what if Git was previously thinking * text=auto?



The answer is to this question is: this does not work well. Bad things happen! Except for git add --renormalize, Git will believe that the index and work-tree match—and hence not bother to copy one way or the other, if the file was recently extracted or added.



That is, in particular, watch out for this:



$ git checkout branch
$ echo '* -text' > .gitattributes # avoid conversions
$ git add file.ext # use whatever's in the work-tree


and this:



$ git checkout branch
$ echo '* -text' > .gitattributes # avoid conversions
$ git checkout -- file.ext # see what's actually in the commit


The git add or git checkout step here may do nothing on the assumption that the work-tree and index already match, even if they only used to match based on the previous .gitattributes setting (or lack thereof). You can force the extraction, or the adding, by modifying (or even removing, if you're going to re-extract) the file, so that the work-tree copy is now clearly different. But in general, it's annoying and tricky to get a .gitattributes change to take effect, because Git doesn't realize that modifying .gitattributes can change the conversions Git will perform.



For that matter, the same is true of core.eol and core.autocrlf: changing these configuration items changes the conversion Git might perform, yet Git is not aware that the index and work-tree may now be out of sync with each other. The index's cache aspect works against you here.



Finally, note that Git will tell you that some file is or would be modified if Git sees that git add-ing the file would change the line endings. Sometimes Git guesses wrong, especially after altering .gitattributes entries so that files that were classified as text are now classified as binary, or vice versa. In these cases, you have to git add the file anyway, so that Git updates the index copy, after which Git realizes that the updated index copy still matches the HEAD commit and that the file isn't modified after all.



In other words, sometimes fixing the .gitattributes file is not sufficient, even if the file isn't going to change. Note also that sometimes, the committed version of the file has the wrong line endings if the .gitattributes entry was missing or incorrect. The work-tree copy may well be right, but until you make a new commit that has the frozen copy built from a correct index copy, Git will—this time correctly—tell you that the file is modified!






share|improve this answer
























  • Regarding the UTF-8 conversion: stackoverflow.com/a/50435869/6309

    – VonC
    Nov 21 '18 at 5:46











  • Thanks torek will try and get back

    – kgunjikar
    Nov 21 '18 at 18:55











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53404150%2fgit-checkout-branch-ends-up-modifying-files%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









2














TL;DR



You may want .gitattributes (not ~/.gitattributes) to contain the line * -text or *.json -text. You may want to remove any autocrlf = true setting from .git/config or $XDG_CONFIG_HOME/git/config or $HOME/.config/git/config or $HOME/.gitconfig. You might want finer control of additional files, depending on how you and others are using these repositories, on which systems.



Long



For one thing, these lines are wrong:




text=auto
-crlf



The entries in .gitattributes should have the form of a file name or pattern, followed by white space (typically a tab but blanks are OK too), followed by one or more attributes. Here, the file name / pattern part is missing, though Git does not see it that way: what this tells Git to do is to apply no attributes to all files named text=auto, and apply no attribute to all files named -crlf. Since there probably are no files with these funny names, this applies no attributes to no files—so it has no effect.



(You probably wanted * text=auto and/or * -crlf, but see below.)



Similarly (but perhaps not the problem), this might be the wrong place:




cat ~/.gitattributes



Git looks for attribute files in several places. The most important one is .gitattributes in the top level of the repository work-tree, i.e., .gitattributes, not ~/.gitattributes. You can have Git consult core.attributesFile, which you can set to ~/.gitattributes. Modern Git looks for $XDG_CONFIG_HOME/git/attributes or $HOME/.config/git/attributes if core.attributesFile is not set, so unless you configured your global core.attributesFile setting, it won't be looking in $HOME/.gitattributes.



Opinion: core.autocrlf is not a good idea




cat .gitconfig
[core]
autocrlf = true



If this was from your home directory, this may be the source of the problem.



Setting core.autocrlf to true acts this way, as described in the git config documentation:




Setting this variable to "true" is the same as setting the text
attribute to "auto" on all files and core.eol to "crlf". Set to
true if you want to have CRLF line endings in your working
directory and the repository has LF line endings. This variable can
be set to input, in which case no output conversion is performed.




In general, I dislike text=auto, because it means Git has to guess whether your file is text. Will Git guess wrong? Sometimes, yes, it will. If you are on Linux, where the end-of-line conversion defaults to do nothing, this is harmless, but on Windows and MacOS, it's not so harmless. Here, a .gitattributes file listing specifically which line endings go in which files is useful.



It's worth looking at the core.eol description as well, since you mentioned setting core.autocrlf to false:




Sets the line ending type to use in the working directory for files
that have the text property set when core.autocrlfis false.
Alternatives are lf, crlf and native, which uses the platform’s
native line ending. The default value is native. See
gitattributes(5) for more information on end-of-line conversion.



I have tried autocrlf with auto and false, too.




The only valid settings are true, false, and input. Well, technically, setting it to 1, 0, and -1 respectively also work, as Git will try to convert it as an integer if it does not match one of these words. Setting it to the literal string auto makes Git treat it as an integer, which converts to the value 0, and hence means false. That's the default, in which case core.eol comes into play provided there are no overrides in .gitattributes files.



Much of the remaining things to know are buried in that gitattributes documentation, except for a few key items that are not properly described anywhere. These require a clear definition of Git's index and work-tree.



Commits, the index, and the work-tree



The first thing to realize is that any committed file is frozen into whatever data is in the committed form of that file, forever that way in that particular commit. That is, each commit holds a snapshot of every file—well, every file that's in that commit, but that seems a bit redundant—in the form it had in the index when whoever made the snapshot, made the snapshot (by running git commit).



If a committed file has a line that ends with CR-then-LF, followed by a second line that ends with CR-without-LF, followed by a third line that ends with LF-without-CR, that committed version of that file always has that form. There is nothing anyone can do about this. If you have that commit, you have that file, with those three line endings in that order. You can choose to check it out, or not; but whatever you do, or don't do, that file exists in that form in that commit.



But wait! The act of checking out some file—or a commit full of files, for that matter—does not mean put that file into the work-tree as-is. Let's consider a file such as x.json. First, the file has to go through your index. Git's index is a special data structure (stored in one big flat file, usually, although there are some optimizations that use more than one file sometimes: the flat file has various index slots, found partly by names like x.json, along with linkages to the internal data, which is really stored elsewhere: the index copy is actually just a pointer to the real data). The index has two more names, reflecting, perhaps, its importance in Git, or perhaps that the name index leaves something to be desired: it's also called the staging area, or sometimes the cache, depending on who / what part of Git is doing the calling.



In any case, the x.json inside the commit is frozen, as we just mentioned, but also is in a special, compressed (sometimes highly compressed) Git-only format. Git first copies that x.json to your index, unfreezing the file, but keeping it in the special Git-only format. Since the copy in your index currently matches the copy in the commit, it has the same line-endings. But since it's not frozen, you can change the line endings, if you like. Before we get there, let's look at the last step of checking out x.json.



The Git-only file is useless to anything other than Git. So, Git copies the unfrozen, Git-only file from the index to your work-tree, creating an actual, ordinary-format, x.json file. It's this last step that does the first pass of end-of-line manipulation, based on:




  • whether the file has been detected as "text"—a non-text file is never manipulated this way—and

  • the eol setting, if there is any, from the .gitattributes file or implied by core.eol or core.autocrlf, more or less in that order.


You can, of course, also copy from the work-tree to the index. At this time, Git will once again do end-of-line manipulation, based on those same two items, plus the input setting, which tells Git to do end-of-line conversions even if the output pass didn't.



The conversions



There are actually two possible conversions. The first, and most common, have to do with carriage-return and line-feed line endings. The second, which is new since commit 107642fe2661 (first appearing in Git 2.18.0), has to do with Unicode encodings.



CRLF conversions



While copying from index to work-tree, Git will replace LF-only line endings with CRLF line endings if you have told it to do so. It will not replace CR-LF with LF; it only does LF-to-CRLF here.



While copying from work-tree to index, Git will replace CRLF line endings with LF-only line endings if you have told it to do so. It will not replace LF with CRLF; it does onyl CRLF-to-LF here. There is some extra magic in modern Git: if the index copy of the file has any carriage-return (r or ^M characters), Git inhibits conversion unless it's doing a "renormalize" operation (git add --renormalize, plus a merge or cherry-pick with the renormalize flag turned on).



Unicode conversions



As I mentioned, these were new in Git 2.18 (and are still new to me). Git will now re-encode UTF-16 files into UTF-8, and vice versa, if you tell it to, through a .gitattributes entry. As with the end of line conversions, these are directional: git add, which copies from work-tree to index, prepares the file for storage inside Git and will convert to UTF-8, while git checkout or git checkout-index (or various additional cases like git reset --hard), which copies from index to work-tree, will convert from UTF-8.



Additional re-encodings may be available, based on whatever iconv --list prints. This, too, is described in the gitattributes documentation.



Changing text= and conversion-bypassing issues



The default for Git is to guess whether some file is text or not. If a file is text, it gets converted; if not, Git treats it as sacrosanct: whatever is in the index goes into the work-tree, and whatever is in the work-tree goes into the index. So * -text tells Git: never touch any file at all, and there are no issues. But what if Git was previously thinking * text=auto?



The answer is to this question is: this does not work well. Bad things happen! Except for git add --renormalize, Git will believe that the index and work-tree match—and hence not bother to copy one way or the other, if the file was recently extracted or added.



That is, in particular, watch out for this:



$ git checkout branch
$ echo '* -text' > .gitattributes # avoid conversions
$ git add file.ext # use whatever's in the work-tree


and this:



$ git checkout branch
$ echo '* -text' > .gitattributes # avoid conversions
$ git checkout -- file.ext # see what's actually in the commit


The git add or git checkout step here may do nothing on the assumption that the work-tree and index already match, even if they only used to match based on the previous .gitattributes setting (or lack thereof). You can force the extraction, or the adding, by modifying (or even removing, if you're going to re-extract) the file, so that the work-tree copy is now clearly different. But in general, it's annoying and tricky to get a .gitattributes change to take effect, because Git doesn't realize that modifying .gitattributes can change the conversions Git will perform.



For that matter, the same is true of core.eol and core.autocrlf: changing these configuration items changes the conversion Git might perform, yet Git is not aware that the index and work-tree may now be out of sync with each other. The index's cache aspect works against you here.



Finally, note that Git will tell you that some file is or would be modified if Git sees that git add-ing the file would change the line endings. Sometimes Git guesses wrong, especially after altering .gitattributes entries so that files that were classified as text are now classified as binary, or vice versa. In these cases, you have to git add the file anyway, so that Git updates the index copy, after which Git realizes that the updated index copy still matches the HEAD commit and that the file isn't modified after all.



In other words, sometimes fixing the .gitattributes file is not sufficient, even if the file isn't going to change. Note also that sometimes, the committed version of the file has the wrong line endings if the .gitattributes entry was missing or incorrect. The work-tree copy may well be right, but until you make a new commit that has the frozen copy built from a correct index copy, Git will—this time correctly—tell you that the file is modified!






share|improve this answer
























  • Regarding the UTF-8 conversion: stackoverflow.com/a/50435869/6309

    – VonC
    Nov 21 '18 at 5:46











  • Thanks torek will try and get back

    – kgunjikar
    Nov 21 '18 at 18:55
















2














TL;DR



You may want .gitattributes (not ~/.gitattributes) to contain the line * -text or *.json -text. You may want to remove any autocrlf = true setting from .git/config or $XDG_CONFIG_HOME/git/config or $HOME/.config/git/config or $HOME/.gitconfig. You might want finer control of additional files, depending on how you and others are using these repositories, on which systems.



Long



For one thing, these lines are wrong:




text=auto
-crlf



The entries in .gitattributes should have the form of a file name or pattern, followed by white space (typically a tab but blanks are OK too), followed by one or more attributes. Here, the file name / pattern part is missing, though Git does not see it that way: what this tells Git to do is to apply no attributes to all files named text=auto, and apply no attribute to all files named -crlf. Since there probably are no files with these funny names, this applies no attributes to no files—so it has no effect.



(You probably wanted * text=auto and/or * -crlf, but see below.)



Similarly (but perhaps not the problem), this might be the wrong place:




cat ~/.gitattributes



Git looks for attribute files in several places. The most important one is .gitattributes in the top level of the repository work-tree, i.e., .gitattributes, not ~/.gitattributes. You can have Git consult core.attributesFile, which you can set to ~/.gitattributes. Modern Git looks for $XDG_CONFIG_HOME/git/attributes or $HOME/.config/git/attributes if core.attributesFile is not set, so unless you configured your global core.attributesFile setting, it won't be looking in $HOME/.gitattributes.



Opinion: core.autocrlf is not a good idea




cat .gitconfig
[core]
autocrlf = true



If this was from your home directory, this may be the source of the problem.



Setting core.autocrlf to true acts this way, as described in the git config documentation:




Setting this variable to "true" is the same as setting the text
attribute to "auto" on all files and core.eol to "crlf". Set to
true if you want to have CRLF line endings in your working
directory and the repository has LF line endings. This variable can
be set to input, in which case no output conversion is performed.




In general, I dislike text=auto, because it means Git has to guess whether your file is text. Will Git guess wrong? Sometimes, yes, it will. If you are on Linux, where the end-of-line conversion defaults to do nothing, this is harmless, but on Windows and MacOS, it's not so harmless. Here, a .gitattributes file listing specifically which line endings go in which files is useful.



It's worth looking at the core.eol description as well, since you mentioned setting core.autocrlf to false:




Sets the line ending type to use in the working directory for files
that have the text property set when core.autocrlfis false.
Alternatives are lf, crlf and native, which uses the platform’s
native line ending. The default value is native. See
gitattributes(5) for more information on end-of-line conversion.



I have tried autocrlf with auto and false, too.




The only valid settings are true, false, and input. Well, technically, setting it to 1, 0, and -1 respectively also work, as Git will try to convert it as an integer if it does not match one of these words. Setting it to the literal string auto makes Git treat it as an integer, which converts to the value 0, and hence means false. That's the default, in which case core.eol comes into play provided there are no overrides in .gitattributes files.



Much of the remaining things to know are buried in that gitattributes documentation, except for a few key items that are not properly described anywhere. These require a clear definition of Git's index and work-tree.



Commits, the index, and the work-tree



The first thing to realize is that any committed file is frozen into whatever data is in the committed form of that file, forever that way in that particular commit. That is, each commit holds a snapshot of every file—well, every file that's in that commit, but that seems a bit redundant—in the form it had in the index when whoever made the snapshot, made the snapshot (by running git commit).



If a committed file has a line that ends with CR-then-LF, followed by a second line that ends with CR-without-LF, followed by a third line that ends with LF-without-CR, that committed version of that file always has that form. There is nothing anyone can do about this. If you have that commit, you have that file, with those three line endings in that order. You can choose to check it out, or not; but whatever you do, or don't do, that file exists in that form in that commit.



But wait! The act of checking out some file—or a commit full of files, for that matter—does not mean put that file into the work-tree as-is. Let's consider a file such as x.json. First, the file has to go through your index. Git's index is a special data structure (stored in one big flat file, usually, although there are some optimizations that use more than one file sometimes: the flat file has various index slots, found partly by names like x.json, along with linkages to the internal data, which is really stored elsewhere: the index copy is actually just a pointer to the real data). The index has two more names, reflecting, perhaps, its importance in Git, or perhaps that the name index leaves something to be desired: it's also called the staging area, or sometimes the cache, depending on who / what part of Git is doing the calling.



In any case, the x.json inside the commit is frozen, as we just mentioned, but also is in a special, compressed (sometimes highly compressed) Git-only format. Git first copies that x.json to your index, unfreezing the file, but keeping it in the special Git-only format. Since the copy in your index currently matches the copy in the commit, it has the same line-endings. But since it's not frozen, you can change the line endings, if you like. Before we get there, let's look at the last step of checking out x.json.



The Git-only file is useless to anything other than Git. So, Git copies the unfrozen, Git-only file from the index to your work-tree, creating an actual, ordinary-format, x.json file. It's this last step that does the first pass of end-of-line manipulation, based on:




  • whether the file has been detected as "text"—a non-text file is never manipulated this way—and

  • the eol setting, if there is any, from the .gitattributes file or implied by core.eol or core.autocrlf, more or less in that order.


You can, of course, also copy from the work-tree to the index. At this time, Git will once again do end-of-line manipulation, based on those same two items, plus the input setting, which tells Git to do end-of-line conversions even if the output pass didn't.



The conversions



There are actually two possible conversions. The first, and most common, have to do with carriage-return and line-feed line endings. The second, which is new since commit 107642fe2661 (first appearing in Git 2.18.0), has to do with Unicode encodings.



CRLF conversions



While copying from index to work-tree, Git will replace LF-only line endings with CRLF line endings if you have told it to do so. It will not replace CR-LF with LF; it only does LF-to-CRLF here.



While copying from work-tree to index, Git will replace CRLF line endings with LF-only line endings if you have told it to do so. It will not replace LF with CRLF; it does onyl CRLF-to-LF here. There is some extra magic in modern Git: if the index copy of the file has any carriage-return (r or ^M characters), Git inhibits conversion unless it's doing a "renormalize" operation (git add --renormalize, plus a merge or cherry-pick with the renormalize flag turned on).



Unicode conversions



As I mentioned, these were new in Git 2.18 (and are still new to me). Git will now re-encode UTF-16 files into UTF-8, and vice versa, if you tell it to, through a .gitattributes entry. As with the end of line conversions, these are directional: git add, which copies from work-tree to index, prepares the file for storage inside Git and will convert to UTF-8, while git checkout or git checkout-index (or various additional cases like git reset --hard), which copies from index to work-tree, will convert from UTF-8.



Additional re-encodings may be available, based on whatever iconv --list prints. This, too, is described in the gitattributes documentation.



Changing text= and conversion-bypassing issues



The default for Git is to guess whether some file is text or not. If a file is text, it gets converted; if not, Git treats it as sacrosanct: whatever is in the index goes into the work-tree, and whatever is in the work-tree goes into the index. So * -text tells Git: never touch any file at all, and there are no issues. But what if Git was previously thinking * text=auto?



The answer is to this question is: this does not work well. Bad things happen! Except for git add --renormalize, Git will believe that the index and work-tree match—and hence not bother to copy one way or the other, if the file was recently extracted or added.



That is, in particular, watch out for this:



$ git checkout branch
$ echo '* -text' > .gitattributes # avoid conversions
$ git add file.ext # use whatever's in the work-tree


and this:



$ git checkout branch
$ echo '* -text' > .gitattributes # avoid conversions
$ git checkout -- file.ext # see what's actually in the commit


The git add or git checkout step here may do nothing on the assumption that the work-tree and index already match, even if they only used to match based on the previous .gitattributes setting (or lack thereof). You can force the extraction, or the adding, by modifying (or even removing, if you're going to re-extract) the file, so that the work-tree copy is now clearly different. But in general, it's annoying and tricky to get a .gitattributes change to take effect, because Git doesn't realize that modifying .gitattributes can change the conversions Git will perform.



For that matter, the same is true of core.eol and core.autocrlf: changing these configuration items changes the conversion Git might perform, yet Git is not aware that the index and work-tree may now be out of sync with each other. The index's cache aspect works against you here.



Finally, note that Git will tell you that some file is or would be modified if Git sees that git add-ing the file would change the line endings. Sometimes Git guesses wrong, especially after altering .gitattributes entries so that files that were classified as text are now classified as binary, or vice versa. In these cases, you have to git add the file anyway, so that Git updates the index copy, after which Git realizes that the updated index copy still matches the HEAD commit and that the file isn't modified after all.



In other words, sometimes fixing the .gitattributes file is not sufficient, even if the file isn't going to change. Note also that sometimes, the committed version of the file has the wrong line endings if the .gitattributes entry was missing or incorrect. The work-tree copy may well be right, but until you make a new commit that has the frozen copy built from a correct index copy, Git will—this time correctly—tell you that the file is modified!






share|improve this answer
























  • Regarding the UTF-8 conversion: stackoverflow.com/a/50435869/6309

    – VonC
    Nov 21 '18 at 5:46











  • Thanks torek will try and get back

    – kgunjikar
    Nov 21 '18 at 18:55














2












2








2







TL;DR



You may want .gitattributes (not ~/.gitattributes) to contain the line * -text or *.json -text. You may want to remove any autocrlf = true setting from .git/config or $XDG_CONFIG_HOME/git/config or $HOME/.config/git/config or $HOME/.gitconfig. You might want finer control of additional files, depending on how you and others are using these repositories, on which systems.



Long



For one thing, these lines are wrong:




text=auto
-crlf



The entries in .gitattributes should have the form of a file name or pattern, followed by white space (typically a tab but blanks are OK too), followed by one or more attributes. Here, the file name / pattern part is missing, though Git does not see it that way: what this tells Git to do is to apply no attributes to all files named text=auto, and apply no attribute to all files named -crlf. Since there probably are no files with these funny names, this applies no attributes to no files—so it has no effect.



(You probably wanted * text=auto and/or * -crlf, but see below.)



Similarly (but perhaps not the problem), this might be the wrong place:




cat ~/.gitattributes



Git looks for attribute files in several places. The most important one is .gitattributes in the top level of the repository work-tree, i.e., .gitattributes, not ~/.gitattributes. You can have Git consult core.attributesFile, which you can set to ~/.gitattributes. Modern Git looks for $XDG_CONFIG_HOME/git/attributes or $HOME/.config/git/attributes if core.attributesFile is not set, so unless you configured your global core.attributesFile setting, it won't be looking in $HOME/.gitattributes.



Opinion: core.autocrlf is not a good idea




cat .gitconfig
[core]
autocrlf = true



If this was from your home directory, this may be the source of the problem.



Setting core.autocrlf to true acts this way, as described in the git config documentation:




Setting this variable to "true" is the same as setting the text
attribute to "auto" on all files and core.eol to "crlf". Set to
true if you want to have CRLF line endings in your working
directory and the repository has LF line endings. This variable can
be set to input, in which case no output conversion is performed.




In general, I dislike text=auto, because it means Git has to guess whether your file is text. Will Git guess wrong? Sometimes, yes, it will. If you are on Linux, where the end-of-line conversion defaults to do nothing, this is harmless, but on Windows and MacOS, it's not so harmless. Here, a .gitattributes file listing specifically which line endings go in which files is useful.



It's worth looking at the core.eol description as well, since you mentioned setting core.autocrlf to false:




Sets the line ending type to use in the working directory for files
that have the text property set when core.autocrlfis false.
Alternatives are lf, crlf and native, which uses the platform’s
native line ending. The default value is native. See
gitattributes(5) for more information on end-of-line conversion.



I have tried autocrlf with auto and false, too.




The only valid settings are true, false, and input. Well, technically, setting it to 1, 0, and -1 respectively also work, as Git will try to convert it as an integer if it does not match one of these words. Setting it to the literal string auto makes Git treat it as an integer, which converts to the value 0, and hence means false. That's the default, in which case core.eol comes into play provided there are no overrides in .gitattributes files.



Much of the remaining things to know are buried in that gitattributes documentation, except for a few key items that are not properly described anywhere. These require a clear definition of Git's index and work-tree.



Commits, the index, and the work-tree



The first thing to realize is that any committed file is frozen into whatever data is in the committed form of that file, forever that way in that particular commit. That is, each commit holds a snapshot of every file—well, every file that's in that commit, but that seems a bit redundant—in the form it had in the index when whoever made the snapshot, made the snapshot (by running git commit).



If a committed file has a line that ends with CR-then-LF, followed by a second line that ends with CR-without-LF, followed by a third line that ends with LF-without-CR, that committed version of that file always has that form. There is nothing anyone can do about this. If you have that commit, you have that file, with those three line endings in that order. You can choose to check it out, or not; but whatever you do, or don't do, that file exists in that form in that commit.



But wait! The act of checking out some file—or a commit full of files, for that matter—does not mean put that file into the work-tree as-is. Let's consider a file such as x.json. First, the file has to go through your index. Git's index is a special data structure (stored in one big flat file, usually, although there are some optimizations that use more than one file sometimes: the flat file has various index slots, found partly by names like x.json, along with linkages to the internal data, which is really stored elsewhere: the index copy is actually just a pointer to the real data). The index has two more names, reflecting, perhaps, its importance in Git, or perhaps that the name index leaves something to be desired: it's also called the staging area, or sometimes the cache, depending on who / what part of Git is doing the calling.



In any case, the x.json inside the commit is frozen, as we just mentioned, but also is in a special, compressed (sometimes highly compressed) Git-only format. Git first copies that x.json to your index, unfreezing the file, but keeping it in the special Git-only format. Since the copy in your index currently matches the copy in the commit, it has the same line-endings. But since it's not frozen, you can change the line endings, if you like. Before we get there, let's look at the last step of checking out x.json.



The Git-only file is useless to anything other than Git. So, Git copies the unfrozen, Git-only file from the index to your work-tree, creating an actual, ordinary-format, x.json file. It's this last step that does the first pass of end-of-line manipulation, based on:




  • whether the file has been detected as "text"—a non-text file is never manipulated this way—and

  • the eol setting, if there is any, from the .gitattributes file or implied by core.eol or core.autocrlf, more or less in that order.


You can, of course, also copy from the work-tree to the index. At this time, Git will once again do end-of-line manipulation, based on those same two items, plus the input setting, which tells Git to do end-of-line conversions even if the output pass didn't.



The conversions



There are actually two possible conversions. The first, and most common, have to do with carriage-return and line-feed line endings. The second, which is new since commit 107642fe2661 (first appearing in Git 2.18.0), has to do with Unicode encodings.



CRLF conversions



While copying from index to work-tree, Git will replace LF-only line endings with CRLF line endings if you have told it to do so. It will not replace CR-LF with LF; it only does LF-to-CRLF here.



While copying from work-tree to index, Git will replace CRLF line endings with LF-only line endings if you have told it to do so. It will not replace LF with CRLF; it does onyl CRLF-to-LF here. There is some extra magic in modern Git: if the index copy of the file has any carriage-return (r or ^M characters), Git inhibits conversion unless it's doing a "renormalize" operation (git add --renormalize, plus a merge or cherry-pick with the renormalize flag turned on).



Unicode conversions



As I mentioned, these were new in Git 2.18 (and are still new to me). Git will now re-encode UTF-16 files into UTF-8, and vice versa, if you tell it to, through a .gitattributes entry. As with the end of line conversions, these are directional: git add, which copies from work-tree to index, prepares the file for storage inside Git and will convert to UTF-8, while git checkout or git checkout-index (or various additional cases like git reset --hard), which copies from index to work-tree, will convert from UTF-8.



Additional re-encodings may be available, based on whatever iconv --list prints. This, too, is described in the gitattributes documentation.



Changing text= and conversion-bypassing issues



The default for Git is to guess whether some file is text or not. If a file is text, it gets converted; if not, Git treats it as sacrosanct: whatever is in the index goes into the work-tree, and whatever is in the work-tree goes into the index. So * -text tells Git: never touch any file at all, and there are no issues. But what if Git was previously thinking * text=auto?



The answer is to this question is: this does not work well. Bad things happen! Except for git add --renormalize, Git will believe that the index and work-tree match—and hence not bother to copy one way or the other, if the file was recently extracted or added.



That is, in particular, watch out for this:



$ git checkout branch
$ echo '* -text' > .gitattributes # avoid conversions
$ git add file.ext # use whatever's in the work-tree


and this:



$ git checkout branch
$ echo '* -text' > .gitattributes # avoid conversions
$ git checkout -- file.ext # see what's actually in the commit


The git add or git checkout step here may do nothing on the assumption that the work-tree and index already match, even if they only used to match based on the previous .gitattributes setting (or lack thereof). You can force the extraction, or the adding, by modifying (or even removing, if you're going to re-extract) the file, so that the work-tree copy is now clearly different. But in general, it's annoying and tricky to get a .gitattributes change to take effect, because Git doesn't realize that modifying .gitattributes can change the conversions Git will perform.



For that matter, the same is true of core.eol and core.autocrlf: changing these configuration items changes the conversion Git might perform, yet Git is not aware that the index and work-tree may now be out of sync with each other. The index's cache aspect works against you here.



Finally, note that Git will tell you that some file is or would be modified if Git sees that git add-ing the file would change the line endings. Sometimes Git guesses wrong, especially after altering .gitattributes entries so that files that were classified as text are now classified as binary, or vice versa. In these cases, you have to git add the file anyway, so that Git updates the index copy, after which Git realizes that the updated index copy still matches the HEAD commit and that the file isn't modified after all.



In other words, sometimes fixing the .gitattributes file is not sufficient, even if the file isn't going to change. Note also that sometimes, the committed version of the file has the wrong line endings if the .gitattributes entry was missing or incorrect. The work-tree copy may well be right, but until you make a new commit that has the frozen copy built from a correct index copy, Git will—this time correctly—tell you that the file is modified!






share|improve this answer













TL;DR



You may want .gitattributes (not ~/.gitattributes) to contain the line * -text or *.json -text. You may want to remove any autocrlf = true setting from .git/config or $XDG_CONFIG_HOME/git/config or $HOME/.config/git/config or $HOME/.gitconfig. You might want finer control of additional files, depending on how you and others are using these repositories, on which systems.



Long



For one thing, these lines are wrong:




text=auto
-crlf



The entries in .gitattributes should have the form of a file name or pattern, followed by white space (typically a tab but blanks are OK too), followed by one or more attributes. Here, the file name / pattern part is missing, though Git does not see it that way: what this tells Git to do is to apply no attributes to all files named text=auto, and apply no attribute to all files named -crlf. Since there probably are no files with these funny names, this applies no attributes to no files—so it has no effect.



(You probably wanted * text=auto and/or * -crlf, but see below.)



Similarly (but perhaps not the problem), this might be the wrong place:




cat ~/.gitattributes



Git looks for attribute files in several places. The most important one is .gitattributes in the top level of the repository work-tree, i.e., .gitattributes, not ~/.gitattributes. You can have Git consult core.attributesFile, which you can set to ~/.gitattributes. Modern Git looks for $XDG_CONFIG_HOME/git/attributes or $HOME/.config/git/attributes if core.attributesFile is not set, so unless you configured your global core.attributesFile setting, it won't be looking in $HOME/.gitattributes.



Opinion: core.autocrlf is not a good idea




cat .gitconfig
[core]
autocrlf = true



If this was from your home directory, this may be the source of the problem.



Setting core.autocrlf to true acts this way, as described in the git config documentation:




Setting this variable to "true" is the same as setting the text
attribute to "auto" on all files and core.eol to "crlf". Set to
true if you want to have CRLF line endings in your working
directory and the repository has LF line endings. This variable can
be set to input, in which case no output conversion is performed.




In general, I dislike text=auto, because it means Git has to guess whether your file is text. Will Git guess wrong? Sometimes, yes, it will. If you are on Linux, where the end-of-line conversion defaults to do nothing, this is harmless, but on Windows and MacOS, it's not so harmless. Here, a .gitattributes file listing specifically which line endings go in which files is useful.



It's worth looking at the core.eol description as well, since you mentioned setting core.autocrlf to false:




Sets the line ending type to use in the working directory for files
that have the text property set when core.autocrlfis false.
Alternatives are lf, crlf and native, which uses the platform’s
native line ending. The default value is native. See
gitattributes(5) for more information on end-of-line conversion.



I have tried autocrlf with auto and false, too.




The only valid settings are true, false, and input. Well, technically, setting it to 1, 0, and -1 respectively also work, as Git will try to convert it as an integer if it does not match one of these words. Setting it to the literal string auto makes Git treat it as an integer, which converts to the value 0, and hence means false. That's the default, in which case core.eol comes into play provided there are no overrides in .gitattributes files.



Much of the remaining things to know are buried in that gitattributes documentation, except for a few key items that are not properly described anywhere. These require a clear definition of Git's index and work-tree.



Commits, the index, and the work-tree



The first thing to realize is that any committed file is frozen into whatever data is in the committed form of that file, forever that way in that particular commit. That is, each commit holds a snapshot of every file—well, every file that's in that commit, but that seems a bit redundant—in the form it had in the index when whoever made the snapshot, made the snapshot (by running git commit).



If a committed file has a line that ends with CR-then-LF, followed by a second line that ends with CR-without-LF, followed by a third line that ends with LF-without-CR, that committed version of that file always has that form. There is nothing anyone can do about this. If you have that commit, you have that file, with those three line endings in that order. You can choose to check it out, or not; but whatever you do, or don't do, that file exists in that form in that commit.



But wait! The act of checking out some file—or a commit full of files, for that matter—does not mean put that file into the work-tree as-is. Let's consider a file such as x.json. First, the file has to go through your index. Git's index is a special data structure (stored in one big flat file, usually, although there are some optimizations that use more than one file sometimes: the flat file has various index slots, found partly by names like x.json, along with linkages to the internal data, which is really stored elsewhere: the index copy is actually just a pointer to the real data). The index has two more names, reflecting, perhaps, its importance in Git, or perhaps that the name index leaves something to be desired: it's also called the staging area, or sometimes the cache, depending on who / what part of Git is doing the calling.



In any case, the x.json inside the commit is frozen, as we just mentioned, but also is in a special, compressed (sometimes highly compressed) Git-only format. Git first copies that x.json to your index, unfreezing the file, but keeping it in the special Git-only format. Since the copy in your index currently matches the copy in the commit, it has the same line-endings. But since it's not frozen, you can change the line endings, if you like. Before we get there, let's look at the last step of checking out x.json.



The Git-only file is useless to anything other than Git. So, Git copies the unfrozen, Git-only file from the index to your work-tree, creating an actual, ordinary-format, x.json file. It's this last step that does the first pass of end-of-line manipulation, based on:




  • whether the file has been detected as "text"—a non-text file is never manipulated this way—and

  • the eol setting, if there is any, from the .gitattributes file or implied by core.eol or core.autocrlf, more or less in that order.


You can, of course, also copy from the work-tree to the index. At this time, Git will once again do end-of-line manipulation, based on those same two items, plus the input setting, which tells Git to do end-of-line conversions even if the output pass didn't.



The conversions



There are actually two possible conversions. The first, and most common, have to do with carriage-return and line-feed line endings. The second, which is new since commit 107642fe2661 (first appearing in Git 2.18.0), has to do with Unicode encodings.



CRLF conversions



While copying from index to work-tree, Git will replace LF-only line endings with CRLF line endings if you have told it to do so. It will not replace CR-LF with LF; it only does LF-to-CRLF here.



While copying from work-tree to index, Git will replace CRLF line endings with LF-only line endings if you have told it to do so. It will not replace LF with CRLF; it does onyl CRLF-to-LF here. There is some extra magic in modern Git: if the index copy of the file has any carriage-return (r or ^M characters), Git inhibits conversion unless it's doing a "renormalize" operation (git add --renormalize, plus a merge or cherry-pick with the renormalize flag turned on).



Unicode conversions



As I mentioned, these were new in Git 2.18 (and are still new to me). Git will now re-encode UTF-16 files into UTF-8, and vice versa, if you tell it to, through a .gitattributes entry. As with the end of line conversions, these are directional: git add, which copies from work-tree to index, prepares the file for storage inside Git and will convert to UTF-8, while git checkout or git checkout-index (or various additional cases like git reset --hard), which copies from index to work-tree, will convert from UTF-8.



Additional re-encodings may be available, based on whatever iconv --list prints. This, too, is described in the gitattributes documentation.



Changing text= and conversion-bypassing issues



The default for Git is to guess whether some file is text or not. If a file is text, it gets converted; if not, Git treats it as sacrosanct: whatever is in the index goes into the work-tree, and whatever is in the work-tree goes into the index. So * -text tells Git: never touch any file at all, and there are no issues. But what if Git was previously thinking * text=auto?



The answer is to this question is: this does not work well. Bad things happen! Except for git add --renormalize, Git will believe that the index and work-tree match—and hence not bother to copy one way or the other, if the file was recently extracted or added.



That is, in particular, watch out for this:



$ git checkout branch
$ echo '* -text' > .gitattributes # avoid conversions
$ git add file.ext # use whatever's in the work-tree


and this:



$ git checkout branch
$ echo '* -text' > .gitattributes # avoid conversions
$ git checkout -- file.ext # see what's actually in the commit


The git add or git checkout step here may do nothing on the assumption that the work-tree and index already match, even if they only used to match based on the previous .gitattributes setting (or lack thereof). You can force the extraction, or the adding, by modifying (or even removing, if you're going to re-extract) the file, so that the work-tree copy is now clearly different. But in general, it's annoying and tricky to get a .gitattributes change to take effect, because Git doesn't realize that modifying .gitattributes can change the conversions Git will perform.



For that matter, the same is true of core.eol and core.autocrlf: changing these configuration items changes the conversion Git might perform, yet Git is not aware that the index and work-tree may now be out of sync with each other. The index's cache aspect works against you here.



Finally, note that Git will tell you that some file is or would be modified if Git sees that git add-ing the file would change the line endings. Sometimes Git guesses wrong, especially after altering .gitattributes entries so that files that were classified as text are now classified as binary, or vice versa. In these cases, you have to git add the file anyway, so that Git updates the index copy, after which Git realizes that the updated index copy still matches the HEAD commit and that the file isn't modified after all.



In other words, sometimes fixing the .gitattributes file is not sufficient, even if the file isn't going to change. Note also that sometimes, the committed version of the file has the wrong line endings if the .gitattributes entry was missing or incorrect. The work-tree copy may well be right, but until you make a new commit that has the frozen copy built from a correct index copy, Git will—this time correctly—tell you that the file is modified!







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 21 '18 at 3:16









torektorek

193k18239321




193k18239321













  • Regarding the UTF-8 conversion: stackoverflow.com/a/50435869/6309

    – VonC
    Nov 21 '18 at 5:46











  • Thanks torek will try and get back

    – kgunjikar
    Nov 21 '18 at 18:55



















  • Regarding the UTF-8 conversion: stackoverflow.com/a/50435869/6309

    – VonC
    Nov 21 '18 at 5:46











  • Thanks torek will try and get back

    – kgunjikar
    Nov 21 '18 at 18:55

















Regarding the UTF-8 conversion: stackoverflow.com/a/50435869/6309

– VonC
Nov 21 '18 at 5:46





Regarding the UTF-8 conversion: stackoverflow.com/a/50435869/6309

– VonC
Nov 21 '18 at 5:46













Thanks torek will try and get back

– kgunjikar
Nov 21 '18 at 18:55





Thanks torek will try and get back

– kgunjikar
Nov 21 '18 at 18:55




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53404150%2fgit-checkout-branch-ends-up-modifying-files%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

How to change which sound is reproduced for terminal bell?

Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

Can I use Tabulator js library in my java Spring + Thymeleaf project?