Git Ignore Case-Sensitive Folder Names - windows

There's lots of questions/answers on committing filename changes on case-insensitive OS's, but my problem is git-ignoring a case sensitive folder (on both linux and windows).
Example: key 3rd-party software tool generates folder Test/ with build artifacts for testing.
Standard location for test files in our system are test/ folders.
The gitignore has **/Test/ (what we don't want to see/commit), but then test/ folders don't show up (what we do want to see/commit).
Testing this on latest windows git-bash, setting/toggling core.ignorecase = false doesn't seem to change the behavior.
Edit: From VonC's useful command to check per-file gitignore status, a demo
git init
mkdir -p d1/Test d2/test
touch d1/Test/hidden d2/test/visible
git config -f .gitconfig --add core.ignorecase false
echo "**/Test/" > .gitignore
git status
Untracked files:
.gitconfig
.gitignore
# Missing d2/test/visible
git -c core.ignorecase=false check-ignore -v -- d1/Test/hidden
.gitignore:1:**/Test/ d1/Test/hidden
git -c core.ignorecase=false check-ignore -v -- d2/test/visible
# Nothing, which is correct
Second Edit:
Which leads to the (less) obvious problem: forgetting to add .gitconfig to local config: (of course it won't behave like it's changed if it's not actually changed...)
git config --local include.path ../.gitconfig

setting/toggling core.ignorecase = false doesn't seem to change the behavior.
It should though.
Test it out with a file within that folder:
git -c core.ignorecase=false check-ignore -v -- Test/a/File
Another approach would be to sidestep the issue entirely and make sure:
the standard location is, for instance, in tests/ instead of test/,
or the key software generates tests in Tests/ instead of Test/.

Related

git checkout from bash script and from terminal behaves differently

I am trying to do a regression test of my code using git and a bash script.
So I have written a script to run a sample with the current version and with some previous version.
The source files are located in the src directory, and samples are in the samples directory.
Both the src and samples directories are tracked by git under the same project.
I want to roll back only src files and not touch files in samples.
I have tried git reset and git checkout.
Problem:
When I go to src in terminal and type:
git checkout -- *.F90
It does what is should - it changes only Fortran files in this directory.
If I do the same command in a bash script, it changes everything: files in src and in samples! Like if it is run from the main directory, as git checkout or git reset origin/master... How can it be?
Somewhere I have found suggestion to use env -i in a script, but it did not work either.
The whole script is about 500 lines, here is the git related part:
cd $dsrc # go to src directory
ls # debuging, just to see , that I am there
git stash
git checkout origin/master -- *.F90
with the ls command I do see the source files, so I know I am in the right place.
Any ideas?
From the Git glossary for "pathspec":
[...] in particular, * and ? can match directory separators.
So *.F90 matches all .F90 files everywhere. To limit to the current directory, you could use
git checkout origin/master -- "$PWD"/*.F90
Notice that (as pointed out by torek in their comment) the manual refers to what Git does. If the shell can expand the glob first, it will – for example, if there are files in the current directory that do match *.F90.
Only when there aren't any will Git get the unexpanded literal *.F90 and match the * with any prefix, including /. To prevent expansion by the shell, you could quote the glob:
git checkout origin/master -- "$PWD/*.F90"
or use . in the pathspec:
git checkout origin/master -- ./*.F90

On Windows git can't handle files with the same name but in different case properly

I use git on windows. In my project I changed case of filename. After that checkout of previous commits failed (commands are in Git Bash):
mkdir repofolder
cd repofolder
git init # create empty repo
git config core.ignorecase false # turn on case-dependent filenames
# create 'readme.txt'
$ echo "blahblahblah" > readme.txt
$ git add readme.txt
$ git commit -m "+readme.txt"
# rename it to 'README.txt'
$ git mv -f readme.txt README.txt
$ git commit -m "readme.txt => README.txt"
$ git status
On branch master
nothing to commit, working directory clean
$ git checkout HEAD~1
error: The following untracked working tree files would be overwritten by checkout:
readme.txt
Please move or remove them before you can switch branches.
Aborting
Why git doesn't allow to checkout previos commits?
You face with the same problem when delete one file and append another one with the same name, but different case. No matter how many commits you do: one (removing and appending in the same commit) or two commits (in first commit you remove file, in second you add another one).
On Windows git can't handle files with the same name but in different case properly
Git on Windows can't handle it because Windows itself can't handle it (emphasis mine):
As part of the requirements for POSIX compliance, the Windows NT File System (NTFS) provides a case-sensitive file and directory naming convention. Even though NTFS and the POSIX subsystem each handle case-sensitivity well, 16-bit Windows-based, MS-DOS-based, OS/2-based, and Win32-based applications do not.
In truth, Windows does have some level of support for NTFS case-sensitivity, but it's pretty flaky:
However, if you attempt to open one of these files in a Win32 application, such as Notepad, you would only have access to one of the files, regardless of the case of the filename you type in the Open File dialog box.
Other inconsistencies also exist. The Windows NT Command Prompt and File Manager correctly display the names of the files. However, normal commands, such as COPY, fail when you attempt to access one or more filenames that differ only in case.

Git: File Rename

I wanted to rename a folder from "Frameworks" to "frameworks", but git would not let me add the new lowercase name. I guess it treats filenames case insensitive, does it?
A git add frameworks/ -f didn't help
You can try:
"git mv -f foo.txt Foo.txt" (note: this is no longer needed since git 2.0.1)
to set ignorecase to false in the config file.
But the issue of case (on Windows for instance) is described in the msysgit issue 228 (again: this should now -- June 2014 -- work with git 2.0.1)
there is always an option to set ignorecase to false in the config file that will force Unix like Git semantics on top of NTFS.
Git supports this behavior but it is not the default - from NTFS point of view a.txt
and A.txt are the same thing - so Git tries to preserve that as most users would expect
As a better workaround, you can
git mv foo.txt foo.txt.tmp && git mv foo.txt.tmp Foo.txt
, which also changes the case of the file as stored on disk.
This blog post illustrates the same issue on MacOs during a rebase:
The default on Mac OS X file systems is that they are case-insensitive. FFFFFF.gif is the same as ffffff.gif.
If you delete the file in question, just from the file system, not from the Git index, mind you, you can merge the branch in question, and have it restore the file as if nothing happened.
The steps are pretty simple:
$ rm file/in/question.gif
$ git merge trunk
Anyhow, remember what git mv stands for:
mv oldname newname
git add newname
git rm oldname
, so if newname and oldname clash, you need to make them different (even if it is only for a short period of time), hence the git mv foo.txt foo.txt.tmp && git mv foo.txt.tmp Foo.txt
If you happen to host on Github, you can use the rename function on their website. Had to change the casing for 5 files and found it worked really well.
I was having a similar problem and couldn't get a new folder name (different case) to change on remote repos. I found that the easiest solution was just to move the file out of the repo and commit. Triggering a delete action. Then re-add and when I added, it came in with the proper case.

git mv and only change case of directory

While I found similar question I didn't find an answer to my problem
When I try to rename the directory from FOO to foo via git mv FOO foo I get
fatal: renaming 'FOO' failed: Invalid argument
OK. So I try git mv FOO foo2 && git mv foo2 foo
But when I try to commit via git commit . I get
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# foo
nothing added to commit but untracked files present (use "git add" to track)
When I add the directory via git add foo nothing changes and git commit . gives me the same message again.
What am I doing wrong? I thought I'm using a case-sensitive system (OSX) why can't I simply rename the directory?
You are in a case insensitive environment. Further, adding without the -A will not take care of the remove side of the mv as Git understands it. Warning! Ensure that no other changes or untracked files are around when you do this or they will get committed as part of this change! git stash -u first, do this and then git stash pop after. Continuing: To get around this, do the following:
mv foo foo2
git add -A
git commit -m "renaming"
mv foo2 FOO
git add -A
git commit --amend -m "renamed foo to FOO"
That's the drawn out way of changing the working directory, committing and then collapsing the 2 commits. You can just move the file in the index, but to someone that is new to git, it may not be explicit enough as to what is happening. The shorter version is
git mv foo foo2
git mv foo2 FOO
git commit -m "changed case of dir"
As suggested in one of the comments, you can also do an interactive rebase (git rebase -i HEAD~5 if the wrong case was introduced 5 commits ago) to fix the case there and not have the wrong case appear anywhere in the history at all. You have to be careful if you do this as the commit hashes from then on will be different and others will have to rebase or re-merge their work with that recent past of the branch.
This is related to correcting the name of a file: Is git not case sensitive?
You want to set the option core.ignorecase to false, which will make Git pay attention to case on file systems that don't natively support it. To enable in your repo:
$ git config core.ignorecase false
Then you can rename the file with git mv and it'll work as expected.
I was able to resolve this, using git 1.7.7 by using a temporary filename:
$ git mv improper_Case improve_case2
$ git mv improve_case2 improve_case
$ git commit -m "<your message>"
(git mv-free variant.)
I ran into this problem in Git on Mac OS X 10.9. I solved it as follows:
git rm -r --cached /path/to/directory
That stages the directory for deletion in Git but does not actually remove any physical files (--cached). This also makes the directory, now with the proper case, show up in untracked files.
So you can do this:
mv /path/to/directory /path/to/DIRECTORY
git add -A /path/to/DIRECTORY
Git will then recognize that you have renamed the files, and when you do git status you should see a number of renamed: lines. Inspect them and ensure they look correct, and if so, you can commit the changes normally.
This is a quick and bug-safe solution:
git mv -f path/to/foo/* path/to/FOO/
Warning! Always rename all files in the renamed folder (use /*).
Do not rename single files. This leads to a bug, described in this answer.
If you first want to see the outcome first, use -n:
git mv -f -n path/to/foo/* path/to/FOO/
After you've made an mv:
Commit changes
Checkout to any other revision
Checkout back.
Now Git should have renamed the folder BOTH in its internal files and in file system.
Force it with -f option:
git mv -f FOO foo
I had one related issue.
One folder named 'Pro' (created first) and another 'pro' (created by mistake). In Mac, it is the same thing, but different according to git.
$ git config core.ignorecase false
the git config rename the files to the right folder(thanks), and also created ghost files in 'pro' (No!!). I could not add ghost file changes to the track and I could not checkout other branches unless carry those those files with me, and i also could not reset it somehow.
Instead of that, i did
$ git rm -r --cached pro
$ git status // => pro files removed, new Pro files untracked
$ git add Pro
To make it extra safe, i did it in a separated fix branch, and then i merged back to main branch
For the ghost file issue created by , can any guru explain How and Why?
Thanks in advance.
This worked great for me on Windows. Used powershell with the following:
mv .\Folder-With-Wrong-Casing .\temp
git add -A
git commit -m "renamed folder with wrong casing to temp"
mv .\temp .\Folder-with-Correct-Casing
git add -A
git commit --amend -m "Renamed to proper casing"
(optional) git push
Thanks to Adam's answer above.
You're not using a case-sensitive filesystem in OS X unless you explicitly choose such. HFS+ can be case-sensitive, but the default is case-insensitive.
Here's a really simple solution around all the gitfoo on this page.
Copy the files out of your project manually.
git rm all the files.
git commit like normal.
add the files back manually.
git add all the files.
git commit like normal.
profit.
Improving Adam Dymitruk's answer (silly that SO doesn't let me comment his answer), using "git mv" will automatically stage exactly the moved files. No stashing is needed and the risky "git add -A" can be avoided:
old="abc"; new="ABC";
tmp="$old-renamed";
git mv "$old" "$tmp";
git commit -m "Renamed '$old' to '$tmp'.";
git mv "$tmp" "$new";
git commit --amend -m "Renamed '$old' to '$new'.";
Here is a simple way of doing it.
Make sure your working directory is empty.
Temporarily disable git ignore case
git config core.ignorecase false
Rename any directories (e.g. Folder => folder)
Add changes to working directory
git add --all
Stash your changes.
git stash
The original directories should be now deleted. Make a local commit.
git add --all
git commit -m "Rename directories"
Pop changes
git stash pop
Amend this to your previous commit.
git add --all
git commit --amend
You should now have a commit with directories renamed. You may now restore the original ignorecase config:
git config core.ignorecase true

Ignoring directories in Git repositories on Windows

How can I ignore directories or folders in Git using msysgit on Windows?
Create a file named .gitignore in your project's directory. Ignore directories by entering the directory name into the file (with a slash appended):
dir_to_ignore/
More information is here.
By default, Windows Explorer will display .gitignore when in fact the file name is .gitignore.txt.
Git will not use .gitignore.txt
And you can't rename the file to .gitignore, because Windows Explorer thinks it's a file of type gitignore without a name.
Non command line solution:
You can rename a file to ".gitignore.", and it will create ".gitignore"
It seems that for ignoring files and directories there are two main ways:
.gitignore
Placing .gitignore file into the root of your repository besides the .git folder (in Windows, make sure you see the true file extension and then make .gitignore. (with the point at the end to make an empty file extension))
Making the global configuration ~/.gitignore_global and running git config --global core.excludesfile ~/.gitignore_global to add this to your Git configuration
Note: files tracked before can be untracked by running git rm --cached filename
Repository exclude - For local files that do not need to be shared, you just add the file pattern or directory to the file .git/info/exclude. Theses rules are not committed, so they are not seen by other users. More information is here.
To make exceptions in the list of ignored files, see this question.
To ignore an entire directory place a .gitignore of “*” there.
For example,
Example System
/root/
.gitignore
/dirA/
someFile1.txt
someFile2.txt
/dirB/
.gitignore
someFile3.txt
someFile4.txt
Goal
ignore the contents of dirB/
Top Level (/root/.gitignore)
You could just “dirB/“ here
Ignored Directory (/root/dirB/.gitignore)
Or you could “*” here
Git watches for gitignore at every step of the file system. So here I choose dirB/.gitignore as “*” to ignore dirB/, including all files and subdirs within.
Done ☺️
To instruct Git to ignore certain files or folders, you have to create .gitignore file.
But in Windows Explorer you have to provide a name for the file. You just cannot create file with just an extension. The trick is that create a empty text file and go to command prompt and change the name of the file to .gitignore:
ren "New Text Document.txt" .gitignore
Now open the file with your favorite text editor and add the file/folder names you wish you ignore. You can also use wildcards like this: *.txt.
I had some issues creating a file in Windows Explorer with a . at the beginning.
A workaround was to go into the commandshell and create a new file using "edit".
If you want to maintain a folder and not the files inside it, just put a ".gitignore" file in the folder with "*" as the content. This file will make Git ignore all content from the repository. But .gitignore will be included in your repository.
$ git add path/to/folder/.gitignore
If you add an empty folder, you receive this message (.gitignore is a hidden file)
The following paths are ignored by one of your .gitignore files:
path/to/folder/.gitignore
Use -f if you really want to add them.
fatal: no files added
So, use "-f" to force add:
$ git add path/to/folder/.gitignore -f
You can create the ".gitignore" file with the contents:
*
!.gitignore
It works for me.
In Windows there's an extra catch with slashes. Excluding a single directory in .gitignore with
dir_to_exclude/
will possibly work, but excluding all directories with
/
causes problems when you have file names with spaces (like my file.txt) in your directory: Git Bash escapes these spaces with a backslash (like my\ file.txt) and Git for Windows doesn't distinguish between / and \.
To exclude all directories, better use:
**/
Two consecutive asterisks signify directory contents.
Just in case you need to exclude sub folders you can use the ** wildcard to exclude any level of sub directory.
**/build/output/Debug/
Also in your \.git\info projects directory there is an exclude file that is effectively the same thing as .gitignore (I think). You can add files and directories to ignore in that.
When everything else fails try editing the file
/.git/info/exclude
and adding the directories you want to the end of the file, like this:
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
assets/
compiled/
I added the folders "assets" and "compiled" to the list of files and directories to ignore.
I've had some problems getting Git to pick up the .gitignore file on Windows. The $GIT_DIR/info/exclude file always seems to work though.
The downside of this approach, however, is that the files in the $GIT_DIR directory are not included in the check-in, and therefore not shared.
p.s. $GIT_DIR is usually the hidden folder named .git
On Unix:
touch .gitignore
On Windows:
echo > .gitignore
These commands executed in a terminal will create a .gitignore file in the current location.
Then just add information to this .gitignore file (using Notepad++ for example) which files or folders should be ignored. Save your changes. That's it :)
More information: .gitignore
I assume the problem is that your working tree is like:
a-cache/foo
a-cache/index.html
b-cache/bar
b-cache/foo
b-cache/index.html
.gitignore
... with the .gitignore you describe. This will give you git status output like:
$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# .gitignore
# a-cache/
# b-cache/
... if the index.html files have not yet been added to the repository. (Git sees that there are unignored files in the cache directories, but it only reports the directories.) To fix this, make sure that you have added and committed the index.html files:
git add *cache/index.html
git commit -m "Adding index.html files to the cache directories"
... and your git status will then look like:
$ git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# .gitignore
nothing added to commit but untracked files present (use "git add" to track)
(Obviously you do want to commit .gitignore as well. I was just being lazy with this test case.)
On Windows and Mac, if you want to ignore a folder named Flower_Data_Folder in the current directory, you can do:
echo Flower_Data_Folder >> .gitignore
If it's a file named data.txt:
echo data.txt >> .gitignore
If it's a path like "Data/passwords.txt"
echo "Data/passwords.txt" >> .gitignore.
I had similar issues. I work on a Windows tool chain with a shared repository with Linux guys, and they happily create files with the same (except for case) names in a given folder.
The effect is that I can clone the repository and immediately have dozens of 'modified' files that, if I checked in, would create havoc.
I have Windows set to case sensitive and Git to not ignore case, but it still fails (in the Win32 API calls apparently).
If I gitignore the files then I have to remember to not track the .gitignore file.
But I found a good answer here:
http://archive.robwilkerson.org/2010/03/02/git-tip-ignore-changes-to-tracked-files/index.html
Just create .gitignore file in your project folder Then add the name of the folder in it for ex:
frontend/node_modules
This might be extremely obvious for some, but I did understand this from the other answers.
Making a .gitignore file in a directory does nothing by itself. You have to open the .gitignore as a text file and write the files/directories you want it to ignore, each on its own line.
so cd to the Git repository directory
touch .gitignore
nano .gitignore
and then write the names of the files and or directories that you want to be ignored and their extensions if relevant.
Also, .gitignore is a hidden file on some OS (Macs for example) so you need ls -a to see it, not just ls.
Temporarily ignore a directory/file that was already in git:
I have a lot of projects in a multi-project gradle project and they can take a long time to delete them, and they're all pretty much the same but different. From time to time I want to remove those from the gradle build by deleting them altogether. git can get them back after all. However I don't want them showing up in git status either. So I use the following simple procedure;
delete files and folders I don't want.
verify build still works
tell git to ignore the deleted files for a bit (we can get them back)
git ls-files --deleted -z | git update-index --assume-unchanged -z
--stdin
go about life without the dirs until you want them back. Then run the same command as before but switch out assume-unchanged for no-assume-unchanged
git ls-files --deleted -z | git update-index --no-assume-unchanged -z
--stdin

Resources