{"id":25,"date":"2019-12-05T19:56:47","date_gmt":"2019-12-05T18:56:47","guid":{"rendered":"https:\/\/www.famille-lafay.fr\/wordpress\/?p=25"},"modified":"2022-04-28T18:37:20","modified_gmt":"2022-04-28T16:37:20","slug":"git-and-line-endings","status":"publish","type":"post","link":"https:\/\/www.famille-lafay.fr\/wordpress\/?p=25","title":{"rendered":"Git and line endings"},"content":{"rendered":"\n<p>I&#8217;m reasonably proficient with git, but I came across the <a href=\"https:\/\/git-scm.com\/docs\/git-config#Documentation\/git-config.txt-coresafecrlf\"><code>core.safecrlf<\/code><\/a> configuration for the first time only today. This is the opportunity to consolidate my thoughts on the subject of line endings in git.<\/p>\n\n\n\n<h3>What happens inside git repo<\/h3>\n\n\n\n<p>Due to its origins in unix\/linux world, git thinks the &#8220;normal&#8221; way to end lines is with a line feed (<code>lf<\/code>, 0x0a). So this is <strong>always<\/strong> the way it will store files internally when it decides to normalize them. Now when does this normalization happen ? When git thinks it is a text file, which happens in two cases :<\/p>\n\n\n\n<ul><li>The preferred way : when there is an appropriate entry in a <a href=\"https:\/\/git-scm.com\/docs\/gitattributes\"><code>.gitattributes<\/code><\/a> file, typically a <code>* text=auto<\/code> line, where git will use its heuristics to decide if a file is text or not. The advantage is that the <code>.gitattributes<\/code> file(s) come with the repo, so there is no risk of local settings to come in the way.<\/li><li>When <code>core.autocrlf<\/code> is set to <code>true<\/code> or <code>input<\/code>, and the same heuristics as above identify a text file.<\/li><\/ul>\n\n\n\n<p>I used to think that on a pure Windows project, there was no reason not to keep the native line endings (carriage return followed by line feed, <code>crlf<\/code>, 0x0d 0x0a) all the way. However, the &#8220;new Microsoft&#8221; general openness means it is less and less frequent to purely stay in Windows world. Moreover, having git know additional info about files through <code>.gitattributes<\/code> has other advantages. So now I would advise to always include a <code>.gitattributes<\/code> file and let git do its magic with text files.<\/p>\n\n\n\n<h3>How about the working directory ?<\/h3>\n\n\n\n<p>This is where it gets a bit more complicated. One of the reasons is that git configuration comes from multiple places, so for instance the local <code>.git\/config<\/code> settings override the global <code>~\/.gitconfig<\/code> ones. A nice trick to better understand your configuration is the command <code>git config --list --show-origin<\/code>. Another invaluable command is <code>git ls-files --eol<\/code>, which will show you for each file its line ending style in the repo (index) and in the working directory, along with its attributes.<\/p>\n\n\n\n<ul><li>Of course any manipulation done by any tool or editor may affect the current state of your files, here we&#8217;re interested in what&#8217;s there after a clone or checkout.<\/li><li>First, if there is an attribute <code>eol<\/code> for a file (identified as text), the corresponding value (<code>lf<\/code> or <code>crlf<\/code>) is always used. A classical use is <code>*.sh text eol=lf<\/code>, where even on Windows, you want your bash to understand the script<\/li><li>Else, if <code>core.autocrlf<\/code> is set to <code>input<\/code>, nothing is done, which usually means <code>lf<\/code> are used<\/li><li>Else, if <code>core.autocrlf<\/code> is set to <code>true<\/code>, <code>crlf<\/code> are used<\/li><li>Else (i.e. <code>core.autocrlf<\/code> is set to <code>false<\/code>), the value of <code>core.eol<\/code> is used : either <code>lf<\/code>, <code>crlf<\/code>, or <code>native<\/code>, the default, where the platform usual ending is used.<\/li><\/ul>\n\n\n\n<h3>warn: CRLF would be replaced by LF in <code>file<\/code><\/h3>\n\n\n\n<p>Before staging a file, git checks if a round-trip <code>commit<\/code> then <code>checkout<\/code> will leave it unchanged. A rather frequent case when this is <strong>not<\/strong> the case, is when using cross-platform tools under Windows, with <code>core.autocrlf<\/code> set to <code>true<\/code>. If the tool generates of modifies a file so that it has <code>lf<\/code> endings, then it will of course also have <code>lf<\/code> within the repo, but theses will be changed back to <code>crlf<\/code> on checkout ! Similarly, if <code>core.autocrlf<\/code> is set to <code>false<\/code> or <code>input<\/code>, with a handling of line endings through <code>.gitattributes<\/code>, then a text file with <code>crlf<\/code> will be normalized to <code>lf<\/code> in the repo, and checked out the same, losing the <code>cr<\/code>.<\/p>\n\n\n\n<p> This is where <code>core.safecrlf<\/code> comes into the picture : when a staging is deemed not reversible, according to its value, git will either prevent the operation (if set to <code>true<\/code>), issue a warning (set to <code>warn<\/code>, the default), or do nothing (set to <code>false<\/code>).<\/p>\n\n\n\n<h2>Conclusion<\/h2>\n\n\n\n<p>With most tools on Windows now properly handling <code>lf<\/code>, I&#8217;m not sure that <code>core.autocrlf<\/code> set to <code>true<\/code> is that useful. So I think that I will go with <code>input<\/code> for the global setting, with possible overrides on per-repo basis.<\/p>\n\n\n\n<p>Since most of my repos have (or will have) an appropriate <code>.gitattributes<\/code> file, I&#8217;m confident enough that text files are handled properly, and since my tooling is not always consistent eol-wise, I&#8217;ll set <code>core.safecrlf<\/code> to <code>false<\/code> globally, trying not to forget overriding it in the few repos without <code>.gitattributes<\/code>.<\/p>\n\n\n\n<p>For any new project, I&#8217;ll have a .<code>gitattributes<\/code> file along the lines of :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>* text=auto\n\n*.sh text eol=lf\n\n*.sln text eol=crlf\n*.bat text eol=crlf\n*.cmd text eol=crlf\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m reasonably proficient with git, but I came across the core.safecrlf configuration for the first time only today. This is the opportunity to consolidate my thoughts on the subject of line endings in git. What happens inside git repo Due to its origins in unix\/linux world, git thinks the &#8220;normal&#8221; way to end lines is &hellip; <a href=\"https:\/\/www.famille-lafay.fr\/wordpress\/?p=25\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Git and line endings<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/www.famille-lafay.fr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/25"}],"collection":[{"href":"https:\/\/www.famille-lafay.fr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.famille-lafay.fr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.famille-lafay.fr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.famille-lafay.fr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=25"}],"version-history":[{"count":5,"href":"https:\/\/www.famille-lafay.fr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/25\/revisions"}],"predecessor-version":[{"id":30,"href":"https:\/\/www.famille-lafay.fr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/25\/revisions\/30"}],"wp:attachment":[{"href":"https:\/\/www.famille-lafay.fr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=25"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.famille-lafay.fr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=25"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.famille-lafay.fr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=25"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}