Mercurial: How to add a file from an ignored folder? - version-control

I have added a folder to the file .hgignore and hence the files in it (and inside it subdirectories) are ignored. However, I just added a file to one of the subdirectories of the ignored folder. How do I add that file to list of tracked files?
I guess this is one of the downsides of using a GUI for version control. I am using SourceTree and have little direct exposure to Hg commands (although I have enabled the option to show the commands when they are executed and do observe what Hg is doing in the background). I tried googling the question but couldn't find any relevant result.

You can individually track an ignored file simply by adding it explicitly. From the .hgignore man page:
An untracked file X can be explicitly added with hg add X, even if X would be excluded by a pattern in .hgignore.
Your express intent to add this file is presumed to override your preferences in .hgignore.
The purpose of .hgignore is primarily to not have ignored files included when you add a directory in its entirety.

You need to edit your repository's ".hgignore" file and specify that you want the directory tree to be ignored except this file. For example if you have the following structure:
└── a
├── b.txt
└── c.txt
and you would like to ignore everything but not "c.txt", then depending on the .hgignore file contents you can have:
Without any .hgignore file:
$ hg status
? a/b.txt
? a/c.txt
With a line to ignore everything under "a":
$ cat .hgignore
syntax: regexp
^a/
$ hg status
? .hgignore
And with an other line to ignore everything under "a" but not the "c.txt" file:
$ cat .hgignore
syntax: regexp
^a/(?!c.txt).*
$ hg status
? .hgignore
? a/c.txt
Hope it'll help.

Related

Why doesn't this ignore my files recursively?

In my project's root directory there are directories like 'tools':
tools/evaluate/test/
tools/evaluate2
Under test, there are some .py and .csv files. I want to ignore all files except .py, so in my .gitignore, I have this entry:
!tools/**/*.py
I want to recursively ignore all non-python files under tools. What's wrong with that?
if the files you are trying to ignore have been already committed, you need to remove them from the staging area as well, that's done by:
git rm --cached !tools/**/*.py
check the status:
git status
add the files you want to delete to .gitignore i assume manually, i don't know of an automatic way, then finally:
git add .gitignore
git commit -m "Remove unused files"
Two parts are needed here:
# Recursively ignore everything in tools that has an extension:
**/tools/**/*.*
# Except .py files recursively in tools:
!tools/**/*.py

Ignore other .gitignore files than the one in root

My Actual Question
I would like that only the .gitignore file in the root of my directory structure ignore files, i.e, the .gitignore files in subdirectories shouldn't ignore files.
To be clear
I don't want to gitignore other .gitignore files. I want them to be commited to git but I don't want them to gitignore other files.
Specific use-case
Let's say I want to commit a boilerplate project structure to git. Let's say the project structure looks like this:
project-root/
│
├── boilerplate/
│ ├──directory/
│ ├──some-other-directory/
│ ├──.env
└── └──.gitignore // Has a line ".env" which will ignore the .env file in this directory
│
├── boilerplate2/
│ ├──directory/
│ ├──some-other-directory/
│ ├──.env
└── └──.gitignore
│
└── .gitignore // The .gitignore in root
Now the .gitignore file in boilerplate directory will gitignore .env which I don't want. How can I stop nested .gitignore files from taking action?
What I tried?
I tried the negation (!) operator in the main .gitignore file. For the sample structure above, it's equivalent to !boilerplate/.env. The .gitignore in root simply doesn't have any power over the .gitignore file in the specified directory. It doesn't override it. Why does it work like that? Is there a workaround?
Edit:
VonC suggests to automate that using scripts, but that's not the question. The question is, how to do that using only .gitignore, if it is possible at all.
Now the .gitignore file in boilerplate directory will gitignore .env which I don't want.
It will not.
If boilerplate/.env is already added (git add --force) and committed, any change to that particular .env file would still be detected, not ignored.
The OP adds:
But when I do git status, git ignores boilerplate/.env due to boilerplate/.gitignore (which isn't commited either)
Then, yes, it will ignore all .env, unless they are themselves versions.
The .gitignore in root simply doesn't have any power over the .gitignore file in the specified directory.
It doesn't override it.
That follows the precedence rules for a .gitignore:
Patterns read from a .gitignore file in the same directory as the path, or in any parent directory (up to the top-level of the working tree), with patterns in the higher level files being overridden by those in lower level files down to the directory containing the file.
In your case, I would:
keep the .env rule
version only .env.tpl template files with default initial value
add a .gitattributes file with a smudge content filter driver script declaration for *.tpl
That smudge script (for instance, 'script_tpl', which can be versioned as well) would be a bash script (which does work even on Windows, since Git for Windows comes with bash.exe):
#!/bin/bash
file="${f%.tpl}" # ex: .env.tpl => .env
if [[ ! "${file}" ]]; then cp "${f}" "${file}"; fi
I would add an senv script to be executed by any collaborator using a local cloned of the repository, in order to register automatically the content filter driver. It would include:
#!/bin/bash
DIR="$( cd "$( dirname "$(readlink -f "${BASH_SOURCE[0]}")" )" && pwd )"
# assuming the smudge script is at the root of the repository
which script_tpl || export PATH=${PATH}:${DIR}
git config --global filter.tpl.smudge 'script_tpl'
That way, any time you switch branch, the smudge script with check if .env does exist and, if not, will create one (which will be ignored by all the various .gitignore files)

How to use gitignore with asterisks? [duplicate]

I have a directory structure like this:
.git/
.gitignore
main/
...
tools/
...
...
Inside main and tools, and any other directory, at any level, there can be a 'bin' directory, which I want to ignore (and I want to ignore everything under it too). I've tried each of these patterns in .gitignore but none of them work:
/**/bin/**/*
/./**/bin/**/*
./**/bin/**/*
**/bin/**/*
*/bin/**/*
bin/**/*
/**/bin/* #and the others with just * at the end too
Can anyone help me out? The first pattern (the one I think should be working) works just fine if I do this:
/main/**/bin/**/*
But I don't want to have an entry for every top-level directory and I don't want to have to modify .gitignore every time I add a new one.
This is on Windows using the latest msysgit.
EDIT: one more thing, there are files and directories that have the substring 'bin' in their names, I don't want those to be ignored :)
Before version 1.8.2, ** didn't have any special meaning in the .gitignore. As of 1.8.2 git supports ** to mean zero or more sub-directories (see release notes).
The way to ignore all directories called bin anywhere below the current level in a directory tree is with a .gitignore file with the pattern:
bin/
In the man page, there an example of ignoring a directory called foo using an analogous pattern.
Edit:
If you already have any bin folders in your git index which you no longer wish to track then you need to remove them explicitly. Git won't stop tracking paths that are already being tracked just because they now match a new .gitignore pattern. Execute a folder remove (rm) from index only (--cached) recursivelly (-r). Command line example for root bin folder:
git rm -r --cached bin
The .gitignore of your dream seems to be:
bin/
on the top level.
I think it is worth to mention for git beginners:
If you already have a file checked in, and you want to ignore it, Git
will not ignore the file if you add a rule later. In those cases, you
must untrack the file first, by running the following command in your
terminal:
git rm --cached
So if you want add to ignore some directories in your local repository (which already exist) after editing .gitignore you want to run this on your root dir
git rm --cached -r .
git add .
It will basically 'refresh' your local repo and unstage ignored files.
See:
http://git-scm.com/docs/git-rm,
https://help.github.com/articles/ignoring-files/
The ** never properly worked before, but since git 1.8.2 (March, 8th 2013), it seems to be explicitly mentioned and supported:
The patterns in .gitignore and .gitattributes files can have **/, as a pattern that matches 0 or more levels of subdirectory.
E.g. "foo/**/bar" matches "bar" in "foo" itself or in a subdirectory of "foo".
In your case, that means this line might now be supported:
/main/**/bin/
[Bb]in/
matches both upper and lower case
I didn't see it mentioned here, but this appears to be case sensitive. Once I changed to /Bin the files were ignored as expected.
Step 1: Add following content to the file .gitignore.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
Step 2: Make sure take effect
If the issue still exists, that's because settings in .gitignore can only ignore files that were originally not tracked. If some files have already been included in the version control system, then modifying .gitignore is invalid.
To solve this issue completely, you need to open Git Bash or Package Manager Console (see screenshot below) to run following commands in the repository root folder.
git rm -r --cached .
git add .
git commit -m "Update .gitignore"
Then the issue will be completely solved.
[Bb]in will solve the problem, but...
Here a more extensive list of things you should ignore (sample list by GitExtension):
#ignore thumbnails created by windows
Thumbs.db
#Ignore files build by Visual Studio
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.bak
*.cache
*.ilk
*.log
[Bb]in
[Dd]ebug*/
*.sbr
obj/
[Rr]elease*/
_ReSharper*/
If you're looking for a great global .gitignore file for any Visual Studio ( .NET ) solution - I recommend you to use this one: https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
AFAIK it has the most comprehensive .gitignore for .NET projects.
Literally none of the answers actually worked for me; the only one that worked for me was (on Linux):
**/bin
(yes without the / in the end)
git version 2.18.0
for 2.13.3 and onwards,writing just bin in your .gitignore file should ignore the bin and all its subdirectories and files
bin
As a notice;
If you think about .gitignore does not work in a way (so added foo/* folder in it but git status still showing that folder content(s) as modified or something like this), then you can use this command;
git checkout -- foo/*
Adding **/bin/ to the .gitignore file did the trick for me (Note: bin folder wasn't added to index).
In addition to #CB Bailey's answer:
I tried to remove multiple folders (in subfolders) named et-cache (caching folder from Wordpress divi theme) from the index and from being tracked.
I added
et-cache/
to the .gitignore file. But
git rm -r --cached et-cache
resulted in an error:
fatal: pathspec 'et-cache' did not match any files
So the solution was to use powershell:
Get-ChildItem et-cache -Recurse |% {git rm -r --cached $_.FullName}
This searches for all subfolders named et-cache. Each of the folders path (fullname) is then used to remove it from tracking in git.
If the pattern inside .gitignore ends with a slash /, it will only find a match with a directory.
In other words, bin/ will match a directory bin and paths underneath it, but will not match a regular file or a symbolic link bin.
If the pattern does not contain a slash, like in bin Git treats it as a shell glob pattern (greedy). So best would be to use simple /bin.
bin would not be the best solution for this particular problem.
In my case encoding of gitignore file was problematic, check if it is UTF-8

Removing file from .gitignore in webstorm

I was searching the web for hour now...
I can't seem to find where the gitignore file is located,and it's ruining my life. I have to remove one file from there. I'm using WebStorm 8
Any help?
.gitignore can be in any folder inside your git repository. And the patterns in .gitignore of child folder will overwrite the ones in parent folder.
It may be hidden when you use ls in your Git Bash. Just use ls -a.
From the doc:
Patterns read from a .gitignore file in the same directory as the
path, or in any parent directory, with patterns in the higher level
files (up to the toplevel of the work tree) being overridden by those
in lower level files down to the directory containing the file. These
patterns match relative to the location of the .gitignore file.

Force Mercurial (Hg) to add new files automatically

I'm looking for the opposite mechanism to the .ignore file, which should add all files of a given pattern automatically, for example *.tex for any LaTeX documentation project or *.def for any file that was added by OASIS (an MS Access addin for version control).
hg add with no arguments will add all files not explicitly ignored. You can also use hg commit --addremove to add all unknown files (and remove all deleted files, i.e. hg rm any which hg status lists as '!') to do this automatically when committing.
Adding files only happens when you run hg add. If you want to add all files matching a pattern, use the --include (-I) switch.