Using gitignore, what is the proper way to ignore a directory with everything in it, i.e. with double asterisk or single or none? - gitignore

I want to find out the proper way to exclude a subdirectory with everything in it in .gitignore For this, I am trying to understand the different ways of excluding a specific directory in .gitignore. For this, I performed a test (below), but it is a bit confusing and unclear what the difference between different uses is.
Test files:
$ tree hey/
hey/
├── a
├── ab
└── abc
└── a
2 directories, 2 files
Method 1: Only the name, without slash and asterisk (hey)
$ tail -1 .gitignore
hey
$ git check-ignore -v hey hey/ hey/* hey/*/*
.gitignore:10:hey hey
.gitignore:10:hey hey/
.gitignore:10:hey hey/a
.gitignore:10:hey hey/ab
.gitignore:10:hey hey/abc
.gitignore:10:hey hey/abc/a
Method 2: With slash, without asterisk (hey/)
$ tail -1 .gitignore
hey/
$ git check-ignore -v hey hey/ hey/* hey/*/*
.gitignore:10:hey/ hey
.gitignore:10:hey/ hey/
.gitignore:10:hey/ hey/a
.gitignore:10:hey/ hey/ab
.gitignore:10:hey/ hey/abc
.gitignore:10:hey/ hey/abc/a
Method 3: With slash and asterisk (hey/*)
$ tail -1 .gitignore
hey/*
$ git check-ignore -v hey hey/ hey/* hey/*/*
.gitignore:10:hey/* hey/
.gitignore:10:hey/* hey/a
.gitignore:10:hey/* hey/ab
.gitignore:10:hey/* hey/abc
.gitignore:10:hey/* hey/abc/a
Method 4: With slash and asterisk (hey/**)
$ tail -1 .gitignore
hey/**
$ git check-ignore -v hey hey/ hey/* hey/*/*
.gitignore:10:hey/** hey/
.gitignore:10:hey/** hey/a
.gitignore:10:hey/** hey/ab
.gitignore:10:hey/** hey/abc
.gitignore:10:hey/** hey/abc/a
The use of asterisks in .gitignore are defined as follows:
Expression
*
matches zero or additional characters
**
matches any file or zero or additional directories
The results of the test above suggest that:
Expression
Method 1 hey
Excludes everything that is hey (hey file, hey/ directory,hey/*/* etc)
Method 2 hey/
Same as hey
Method 3 hey/*
Does not exclude hey as a file, but excludes it if it is a directory
Method 4 hey/**
Same as hey/* for this specific case
My questions are:
In this use case, could there be any scenarios where there would be a difference between using hey/* and hey/**? Or would they work the same way?
Why does hey/ work the same way as hey?
What is the best practice for excluding a specific subdirectory with everything in it?

Related

GitHub - Remove a indexed file from "Languages" on first page

How can I remove this indexed HTML page, that are a documentation to one of the external librarys I use on my GitHub blob?
I have tried alot of diffrent commands, but don't find a way to remove this file from the GitHub Linguist indexer...
Here are the "Languages" that are indexed on the startpage:
[image] Languages on the startpage
The file that I want to exclude:
[image] HTML file that needs to be excluded
TestProject/wwwroot/lib/bootstrap-icons/docs/index.html
Code that I've tried to get it removed via ".attributes"-file in root-folder (the vendored, works... But not getting rid of this HTML-file... from the GitHub-Languages) :
### vendored:
TestProject/wwwroot/lib/* linguist-vendored
### documentations:
TestProject/wwwroot/lib/bootstrap-icons/* linguist-documentation
and tried:
TestProject/wwwroot/lib/bootstrap-icons/* -linguist-documentation
and this:
TestProject/wwwroot/lib/bootstrap-icons/docs/* linguist-documentation
and this:
TestProject/wwwroot/lib/bootstrap-icons/docs/* -linguist-documentation
and this:
TestProject/wwwroot/lib/* linguist-documentation
and this:
TestProject/wwwroot/lib/* -linguist-documentation
But I can't figure it out how to remove this file:
TestProject/wwwroot/lib/bootstrap-icons/docs/index.html
Please help me with the correct syntax to remove the file from being indexed as a Language in my GitHub repository, main branch. 🙂
You've got the right idea and the right Linguist overrides (either will do the trick). The problem is your path matching isn't quite right.
From the .gitattributes docs
The rules by which the pattern matches paths are the same as in .gitignore files (see gitignore[5]), with a few exceptions:
[...]
If we look in the .gitignore docs (emphasis is mine):
An asterisk "*" matches anything except a slash. The character "?" matches any one character except "/". The range notation, e.g. [a-zA-Z], can be used to match one of the characters in a range. See fnmatch(3) and the FNM_PATHNAME flag for a more detailed description.
Two consecutive asterisks ("**") in patterns matched against full pathname may have special meaning:
[...]
A trailing "/**" matches everything inside. For example, "abc/**" matches all files inside directory "abc", relative to the location of the .gitignore file, with infinite depth.
The files you're trying to ignore are in sub-directories of the paths you've specified so you need to either:
use TestProject/wwwroot/lib/** linguist-vendored to recurse, or
use TestProject/wwwroot/lib/bootstrap-icons/docs/* linguist-vendored to limit to this directory.
We can demonstrate this without even using Linguist thanks to git check-attr:
$ # Create a repo with just the one file
$ git init -q Test-Project
$ cd Test-Project
$ mkdir -p TestProject/wwwroot/lib/bootstrap-icons/docs/
$ echo "<html>" > TestProject/wwwroot/lib/bootstrap-icons/docs/index.html
$ git add -A
$ git commit -m 'Add file'
[main (root-commit) bed71b5] Add file
1 file changed, 1 insertion(+)
create mode 100644 TestProject/wwwroot/lib/bootstrap-icons/docs/index.html
$
$ # Add your initial override
$ git add -A && git commit -m 'attribs'
[main 7d0a0cf] attribs
1 file changed, 1 insertion(+)
create mode 100644 .gitattributes
$
$ # Check the attributes
$ git check-attr linguist-vendored TestProject/wwwroot/lib/bootstrap-icons/docs/index.html
TestProject/wwwroot/lib/bootstrap-icons/docs/index.html: linguist-vendored: unspecified
$ # So it doesn't have any effect.
$ # Now lets recurse
$ echo "TestProject/wwwroot/lib/** linguist-vendored" > .gitattributes
$ git add -A && git commit -m 'attribs'
[main 9007c34] attribs
1 file changed, 1 insertion(+), 1 deletion(-)
$ git check-attr linguist-vendored TestProject/wwwroot/lib/bootstrap-icons/docs/index.html
TestProject/wwwroot/lib/bootstrap-icons/docs/index.html: linguist-vendored: set
$ # Woohoo!!! It's work.
$ # Lets be specific to the docs dir
$ echo "TestProject/wwwroot/lib/bootstrap-icons/docs/* linguist-vendored" > .gitattributes
$ git add -A && git commit -m 'attribs'
[main a46f416] attribs
1 file changed, 1 insertion(+), 1 deletion(-)
$ git check-attr linguist-vendored TestProject/wwwroot/lib/bootstrap-icons/docs/index.html
TestProject/wwwroot/lib/bootstrap-icons/docs/index.html: linguist-vendored: set
$ # Woohoo!!! It's worked too
Some good troubleshooting from #lildude, shown that:
All the files was ignored correctly.
I had alot of CSHTML-files under my repository that was grouped as HTML+Razor (see this post on GitHub: GitHub linguist discussion ) .
When I clicked the "HTML"-link on startpage under language, it took me to: https://github.com/pownas/Test-Project/search?l=html
But the startpage under language was telling me that I had around 40% html from the HTML+Razor search: https://github.com/pownas/Test-Project/search?l=HTML%2BRazor

MobaXterm Busybox strange setup

I am using MobaXterm portable.
I found a strange setup, summarized here.
External commands in /bin work fine. E.g., with /bin/ssh.exe I can ssh ok.
Internal commands are
"redirected" to busybox, as
$ which cat
/bin/cat
$ ll /bin/cat
lrwxrwxrwx 1 USER001 UsersGrp 16 Jul 24 07:42 /bin/cat -> /bin/busybox.exe
at the same time aliased to files that apparently do not exist.
$ type cat
cat is aliased to `/bin/cat.exe'
These aliases apparently take precedence over files in PATH, so the commands do not work.
$ cat myfile
bash: /bin/cat.exe: No such file or directory
If I unalias, cat does not look for /bin/cat.exe but for /bin/busybox.exe, and everything is "back to normal".
$ unalias cat
$ cat myfile
Hello world
...
How can I get normal behaviour (either without aliases or with the presence of the alias targets)?
I mean not to write my own unaliases in .bashrc, this shouldn´t be needed.
Moreover, perhaps I would be breaking something.
Why would MobaXterm setup things like this?
PS: In the initial state, even ls does not work, for the same reason.
But ll works, since
$ type ll
ll is aliased to `_bbf ls -l'
$ type _bbf
_bbf is a function
...
How can I get normal behaviour?
Workarounds:
unaliasing by hand, so /bin/busybox.exe is actually used.
Below I add a script for that.
Copying .exe files from the temporary root dir when it is available, so the external versions are used.
Why would MobaXterm setup things like this?
When not using a Persistent root (/) directory, this is obtained
$ which cat
/bin/cat
$ ll /bin/cat
-rwxr-xr-x 1 RY16205 UsersGrp 49703 jul. 28 07:12 /bin/cat
$ type cat
cat is aliased to `/bin/cat.exe'
$ ll /bin/cat.exe
-rwxr-xr-x 1 USER001 UsersGrp 49703 jul. 28 07:12 /bin/cat.exe
$ cat myfile
Hello world
...
$ unalias cat
$ type cat
cat is hashed (/bin/cat)
$ cat myfile
Hello world
...
So any of the two cats work (internal busybox and external versions; I do not know if they are exactly the same).
This is because /bin points to C:\Users\user001\AppData\Local\Temp\Mxt108\bin and cat.exe is there.
But when using a Persistent root (/) directory, /bin points to <Persistent root (/) directory\bin, and cat.exe is not created there.
The former temporary root dir is removed as soon as MXT is closed.
So this is probably a configuration error from MobaXterm.
If so, the only option seems a workaround, as above.
Script for unaliasing:
#!/bin/bash
export ROOTDIR_WIN=$(cygpath -wl /)
if [[ ${ROOTDIR_WIN##*\\} == "Mxt108" ]] ; then
# Not using a Persistent root dir. Do not need to unalias.
echo "Not using a Persistent root dir. Do not need to unalias."
else
# Using a Persistent root dir. Need to unalias.
exe_linux_list="bash busybox chmod cygstart cygtermd cygwin-console-helper dircolors dwm_w32 echo grep ls MoTTY ssh ssh-pageant test twm_w32 wc xkbcomp_w32 XWin_MobaX"
for exe_linux in ${exe_linux_list} ; do
if [[ $(type -t ${exe_linux}) == "alias" ]] ; then
#type ${exe_linux}
unalias ${exe_linux}
fi
done
fi
On my MobaXterm system, /etc/profile sources /etc/baseprofile which includes aliases for all of these sorts of things, i.e.
alias "cat"="_bbf cat"
and checking that from my command prompt yields what I would expect:
$ type cat
cat is aliased to `_bbf cat'
Have you changed your system somehow so that /etc/baseprofile is not being sourced? Or have you changed /etc/baseprofile?
It also appears that you've installed the regular GNU Coreutils package, as I don't have a /bin/cat.exe.
$ ll /bin/cat.exe
ls: /bin/cat.exe: No such file or directory
Perhaps that's where your problem started but the _bbf function is supposed to handle that. Which again leads me to the belief that you've changed /etc/baseprofile somehow.
At most time, it is cool. This error maybe caused by wrong path match of cat.exe.
As for me, when I run git log, the same error message comes out. It is due to PATH variable. There are two dirs and both of them contain git.exe. One of them is half-done with a small size. And Mobaxterm choose it. :D
I confirm this by run which git and it will give the actual path out.
I fix it by
alias git='/drives/C/Program\ Files/Git/mingw64/bin/git.exe'
The following is my dirs.
├─cmd
│ git-gui.exe
│ git-lfs.exe
│ git.exe # oops
│ gitk.exe
│ start-ssh-agent.cmd
│ start-ssh-pageant.cmd
├─mingw64
│ ├─bin
│ │ git-upload-pack.exe
│ │ git.exe # the right one

Mercurial cat command using --include

Using version 4.1.1 of Mercurial, I would like to provide a file specifying a bunch of files as args to an hg cat command, so that each file is output to a different file. I thought the following would work:
hg cat -o 'catOut-%s' --include listfile:files.lst
where files.lst looks like this
foo01.txt
foo02.txt
But it yields an error message saying "invalid arguments" plus a usage message.
Here is an MWE that sets up a code repository with the required structure and then tries running the cat command shown above.
hg init mwe
cd mwe
echo abc > foo01.txt
echo def > foo02.txt
echo PQR > baz.txt
echo files.lst > .hgignore
hg add .hgignore
hg add foo*.txt
hg add baz.txt
echo foo01.txt >> files.lst
echo foo02.txt >> files.lst
hg ci -m "Adding all files"
hg cat -o 'catOut-%s' baz.txt
cat catOut-baz.txt
rm catOut*
hg cat -o 'catOut-%s' --include listfile:files.lst baz.txt
cat catOut-baz.txt
hg cat -o 'catOut-%s' --include listfile:files.lst
Here is a trace of these commands and their results as typed to a shell:
~/tmp $ hg init mwe
~/tmp $ cd mwe
~/tmp/mwe $ echo abc > foo01.txt
~/tmp/mwe $ echo def > foo02.txt
~/tmp/mwe $ echo PQR > baz.txt
~/tmp/mwe $ echo files.lst > .hgignore
~/tmp/mwe $ hg add .hgignore
~/tmp/mwe $ hg add foo*.txt
~/tmp/mwe $ hg add baz.txt
~/tmp/mwe $ echo foo01.txt >> files.lst
~/tmp/mwe $ echo foo02.txt >> files.lst
~/tmp/mwe $ hg ci -m "Adding all files"
~/tmp/mwe $ hg cat -o 'catOut-%s' baz.txt
~/tmp/mwe $ cat catOut-baz.txt
cat catOut-baz.txt
PQR
~/tmp/mwe $ rm catOut*
rm catOut*
~/tmp/mwe $ hg cat -o 'catOut-%s' --include listfile:files.lst baz.txt
~/tmp/mwe $ cat catOut-baz.txt
cat: catOut-baz.txt: No such file or directory
~/tmp/mwe $ hg cat -o 'catOut-%s' --include listfile:files.lst
hg cat -o 'catOut-%s' --include listfile:files.lst
hg cat: invalid arguments
hg cat [OPTION]... FILE...
output the current or given revision of files
options ([+] can be repeated):
-o --output FORMAT print output to file with formatted name
-r --rev REV print the given revision
--decode apply any matching decode filter
-I --include PATTERN [+] include names matching the given patterns
-X --exclude PATTERN [+] exclude names matching the given patterns
(use 'hg cat -h' to show more help)
~/tmp/mwe $
You have to supply a file argument to avoid the error message. But that argument is ignored if an --include and an -o are supplied.
I suspect no one has ever used the --include argument to cat before, because there is a dearth of explanation out there about how --include arguments are handled. Either that or I'm overlooking something obvious.
You have to supply a file argument to avoid the error message. But that argument is ignored if an --include and an -o are supplied.
It is not literally ignored. The problem is that --include means something odd.
... because there is a dearth of explanation out there about how --include arguments are handled.
That does seem to be the case! There is a description in hg help patterns but it is rather inadequate (in my opinion at least). What --include means is that only files matching the patterns in the file are used. Think of this as "include only", rather than "also include".
Thus, if your listfile has those two file names in it, you may run, e.g.:
hg cat -o 'catOut-%s' --include listfile:files.lst baz.txt foo01.txt
and Mercurial will extract foo01.txt since it's in the list.
You might think you could use:
hg cat -o 'catOut-%s' --include listfile:files.lst '*'
but you can't (well, you can on Windows, as hg does glob style matching there, but that's the wrong approach). The right trick is to direct hg cat to read a directory, namely the top level directory of the repository:
hg cat .
(though there are similar methods, such as using set:*; see hg help filesets). Then the filtering produced by --include strips you down to just the files you want included.
More "color", as they say in some circles - no need to read this!
(This is just side stuff I found while researching this answer a bit. I wondered how one made hg cat scan every file in a revision, so I plunged into the source.)
For reference, here is the snippet of Python code that implements hg cat:
#command('cat',
[('o', 'output', '',
_('print output to file with formatted name'), _('FORMAT')),
('r', 'rev', '', _('print the given revision'), _('REV')),
('', 'decode', None, _('apply any matching decode filter')),
] + walkopts,
_('[OPTION]... FILE...'),
inferrepo=True)
def cat(ui, repo, file1, *pats, **opts):
"""output the current or given revision of files
Print the specified files as they were at the given revision. If
no revision is given, the parent of the working directory is used.
Output may be to a file, in which case the name of the file is
given using a format string. The formatting rules as follows:
:``%%``: literal "%" character
:``%s``: basename of file being printed
:``%d``: dirname of file being printed, or '.' if in repository root
:``%p``: root-relative path name of file being printed
:``%H``: changeset hash (40 hexadecimal digits)
:``%R``: changeset revision number
:``%h``: short-form changeset hash (12 hexadecimal digits)
:``%r``: zero-padded changeset revision number
:``%b``: basename of the exporting repository
Returns 0 on success.
"""
ctx = scmutil.revsingle(repo, opts.get('rev'))
m = scmutil.match(ctx, (file1,) + pats, opts)
ui.pager('cat')
return cmdutil.cat(ui, repo, ctx, m, '', **opts)
The most critical line is:
def cat(ui, repo, file1, *pats, **opts):
This means that non-option FILE... arguments (as in the description just before the def) are bound with the first one going to file1 and the rest going to *pats (as a Python tuple). This forces you to pass one or more file-name or file-set arguments.
Those file name arguments (baz.txt or whatever) are passed in to scmutil.match, which is what is going to find the files in the manifest for the specified revision—the one now in ctx, obtained by the previous line calling scmutil.revsingle, which gets the last revision in the --rev option, defaulting to the current revision (the first parent of the working directory).
It's scmutil.match that handles the --include option. Unfortunately this code is rather impenetrable:
m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
default, listsubrepos=opts.get('subrepos'), badfn=badfn)
(with pats being the non-empty file names passed in as command line arguments), which invokes this code in context.py:
def match(self, pats=None, include=None, exclude=None, default='glob',
listsubrepos=False, badfn=None):
if pats is None:
pats = []
r = self._repo
return matchmod.match(r.root, r.getcwd(), pats,
include, exclude, default,
auditor=r.nofsauditor, ctx=self,
listsubrepos=listsubrepos, badfn=badfn)
which gets us into match.py's class match object, which is what implements the listfile: part. Here's a bit from that:
matchfns = []
if include:
kindpats = self._normalize(include, 'glob', root, cwd, auditor)
self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)',
listsubrepos, root)
roots, dirs = _rootsanddirs(kindpats)
self._includeroots.update(roots)
self._includedirs.update(dirs)
matchfns.append(im)
and self._normalize winds up reading the file given as the listfile argument, so that's what is in kindpats. (The string literal passed to _buildmatch is a regular expression glob suffix pattern, i.e., file names from the include file are followed by an implied trailing slash or end-of-string.)

Mercurial: Converting existing folders into sub-repos

I have a Mercurial repository that looks like this:
SWClients/
SWCommon
SWB
SWNS
...where SWCommon is a a library common to the other two projects. Now, I want to convert SWCommon into a sub-repository of SWClients, so I followed the instructions here and here. However, in contrast to the example in the first link I want my sub-repository to have the same name as the folder had at the beginning. In detail, this is what I have done:
Create a file map.txt as follows
include SWCommon
rename SWCommon .
Create a file .hgsub as follows
SWCommon = SWCommon
Then run
$ hg --config extensions.hgext.convert= convert --filemap map.txt . SWCommon-temp
...lots of stuff happens...
Then
$ cd SWCommon-temp
$ hg update
101 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd ..
$ mv SWCommon SWCommon-old
$ mv SWCommon-temp SWCommon
$ hg status
abort: path 'SWCommon/SWCommon.xcodeproj/xcuserdata/malte.xcuserdatad/xcschemes/SWCommon.xcscheme' is inside nested repo 'SWCommon'
...which is indeed the case, but why is that a reason to abort? The other strange thing is that if I do not do that last 'mv' above and I execute an 'hg status' then, I end up with lots of 'missing' files in SWCommon as you would expect. The example in the link never makes it this far and basically stops on the hg update above? How do you make it work in practice?
Not currently possible. You could create a new repo converting the original one like:
$ hg --filemap excludemap.txt SWClients SWClients-without-SWCommon
With a excludemap.txt like:
exclude "SWCommon"
And then add the subrepo there.
$ hg --filemap map.txt SWCommon SWClients-without-SWCommon/SWCommon
$ cd SWClients-without-SWCommon
$ hg add SWCommon
$ hg ci -m "Created subrepo"
See the mailing list thread that discusses this problem.

diff and patch using wrong line ending when creating new files or line end changed

I'm trying to create a patch using diff, but I can't get the patch to use the line end characters used in the files when creating a new file or to change the line ending when the file changes it. Basically, I'm doing:
cp -r dir1 dir3
diff -ruN dir1 dir2 > dir3\patch.txt
cd dir3
patch -p1 < patch.txt
All the changes between dir1 and dir2 properly apply, except the end of line character for new files is defaulting to CR+LF, even where the file in dir2 uses LF as an end of line marker. Also, any files where the difference between them is just a line end change are not patched in any way -- diff doesn't seem to see any change.
So running diff -rq dir2 dir3 gives a bunch of Files aaa and bbb differ, but diff -rwq dir2 dir3 works fine.
I'm using diff - GNU diffutils version 2.7 and patch 2.5 from UnxUtils on Windows XP.
Is there any way to make new and changed files included in the patch keep the line ending from the original file?
This works:
cp -r dir1 dir3
diff --binary -ruN dir1 dir2 > dir3\patch.txt
cd dir3
patch --no-backup-if-mismatch --binary -u -p1 < patch.txt
Not using the --binary flag means that the file is parsed line by line, ignoring EOL. For some reason, it won't always patch cleanly (gives a Hunk #1 succeeded at 1 with fuzz 1. message) so I had to include --no-backup-if-mismatch to prevent it making .orig files. The -u seems to be optional, since patch will figure the patch type out on it's own.