Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to ignore/revert changes of case in file-content?

I am versioning Microsoft Access VBA code, which is in general case insensitive. However changes the case of variable names happen every now in then (by the Access compiler or by the developer). This often leads to huge change set in my git workspace.

How can I revert or ignore changes, that only concern upper- or lowercase of file contents?

An example:

git init
echo "public sub example()\nend sub" > mdlExample.ACM
#                ^-- lower e
git add --all
git commit --all --message "Initial Commit"
echo "public sub Example()\nend sub" > mdlExample.ACM
#                ^-- upper E

I would love something like:

git restore --only-case-changes # not working

And then:

git status
> On branch master
> nothing to commit, working tree clean
like image 973
slartidan Avatar asked Jul 24 '20 05:07

slartidan


People also ask

How do I ignore all files that end with a specific extension?

If you wanted to ignore all files that end with a specific file extension, you would need to use the * wildcard selector followed by the file extension you want to ignore. This pattern will match any file ending with the .md extension located anywhere in the project. Earlier, you saw how to ignore all files ending with a specific suffix.

How do I ignore all files with a specific name?

If you want to ignore all files with a specific name, you need to write the literal name of the file. In this case, you don't need to provide the full path to a specific file. This pattern will ignore all files with that particular name that are located anywhere in the project.

What is the use of ignorecaseinternal in Git?

Git Documentationsays: core.ignoreCaseInternal variable which enables various workarounds to enable Git to work better on filesystems that are not case sensitive, like APFS, HFS+, FAT, NTFS, etc.

What is a Git ignore file?

A .gitignore file is a plain text file that contains a list of all the specified files and folders from the project that Git should ignore and not track. Inside .gitignore, you can tell Git to ignore only a single file or a single folder by mentioning the name or pattern of that specific file or folder.


2 Answers

Consider changing example="example" to Example="Example". How do you propose Git could decide which case change to ignore here? Now consider code snippets in comments, or stored as strings for code generators. I get wanting Git to make an annoying chore go away, but I think if you try to imagine telling Git exactly what you want you'll understand the context of your question a little better.

How can I revert or ignore changes, that only concern upper- or lowercase of file contents

When you want to temporarily ignore changes, when you want to do a diff or a blame without seeing those changes, you can use a "textconv" filter that normalizes the text you diff. I use those to do things like strip embedded timestamps out of generated html when diffing, quickest to hand atm is

[diff "doc-html"]
    textconv = "sed  's,<span class=\"version\">Factorio [0-9.]*</span>,,;s,<[^/>][^>]*>,\\n&,g'"
    wordRegex = "<[^>]*\\>|[^< \\t\\n]*"

in .git/config, and

doc-html/*.html diff=doc-html
*.cfg -diff

in .git/info/attributes.

so my what-changed diffs don't show me things I don't care about.

If you want to see the results of a diff ignoring case, try

[diff "nocase"]
        textconv="tr A-Z a-z"

and drop * diff=nocase (or maybe*.vba diff=nocase) into .git/info/attributes. When you're done, take it out.

but for merging, my leadoff example should convince you that Git automatically and silently making case changes in repo content, even just in the text that looks like identifiers, is a Bad Idea. When there's a conflict, not just a one-sided change but two different changes, it's still going to take some human judgement to decide what the result should be. Fortunately, with any decent merge tool, resolving simple conflicts is down around subsecond range each.

like image 74
jthill Avatar answered Nov 10 '22 20:11

jthill


You don't have to git restore anything: You could setup a clean content filter driver as illustrated here, which will automatically convert those cases on git diff/git commit.
That means:

  • you won't even see there is a diff
  • you won't add /commit anything because of that content filter driver.

https://git-scm.com/book/en/v2/images/clean.png Image from "Keyword Expansion" section of the "ProGit book"

This is done through:

  • a .gitattributes filter declaration, which means you can associate it only to certain files (through, for instance, their extension)
    *.ACM filter=ignoreCase
    
  • a local git config filter.<driver>.clean to declare the actual script (which should be in your PATH)
    git config filter.ignoreCase.clean ignoreCase.sh
    
    # that give a .git/config file with:
    
    [filter "ignoreCase"]
      clean = ignoreCase.sh
    

The trick is:

Can you write a script which takes the content of an ACM file as input and produces the same ACM file as output, but with its strings converted?
You can have the filename in those scripts so you can do a diff and detect if said difference has to be adjusted, but you still need to write the right command to replace only "xxx" strings when their case changes in ACM files.

Note: jthill suggests in the comments to set the merge.renormalize config settings to tell Git that canonical representation of files in the repository has changed over time.

like image 43
VonC Avatar answered Nov 10 '22 20:11

VonC