Gitignore files
So I've been trying to make my way through Progit. I have accumulated a whole lot of information so far and I was afraid for how not so often I used it. That I was going to forget it all. Hence my decision to share some of that with you, and with my future self.
In this post we'll look at something you probably have never read about in isolation, gitignore files.
If you want to just look at a summary of what rules you can use for creating your files, there's one at the very end of this article
Okay. Gitignore files hold entries for all information you would like to
keep untracked. That could be temporary files, or database files (say
sqlite3 files) or something else. In git, they are located in the repo's
base directory. They exist under the name .gitignore. Creating a new
repo does not auto create a '.gitignore' file so you have to create it
yourself.
touch .gitignore
Rules in a .gitignore file are applied recursively to all files and
subdirectories in the same folder as the file. Blank lines have no
effect and can be used as separators for that reason. Lines starting
with # are treated as comments. We'll look at some special characters
(/, *). Ecaping any can be done by prepending it with \. Also, you
could have multiple .gitignore files, but let's keep that for
another
article. Let's call the entries in a .gitignore file rules from now
on. Here's a sample rules file that includes what I think will be the
commonest usecases you'll come to need.
Rule's we shall look at in this article.
a a/ *.ext !lib.ext a/*.txt a/**/*.txt *.[oa] /a */a/*.txt **/a/*.txt
Before anything, for a folder to be tracked, it should have at least a file. Any folder that does not have at least a file or a sub directory with one will not be tracked. This does not need any .gitignore rule to be true. We'll also assume the .gitignore file above is in the repo's root or base directory.
Okay, so first rule matches all files and directories whose name is
exactly 'a'. This rule is applied recursively in the the folder
rootdirectory. All folders named 'a' that have files in them won't be
tracked. All files named 'a' located anywhere in the repo won't be
tracked. Anything in a folder named 'a' by implication, won't be
tracked.
Now how about if I only want to not track directories named 'a'. That's
the second rule a/. Adding a forward slash to a name pattern tells git
to ignore only matching directories, and not files. So to match only
directories with some name pattern, you'd have to append a forward slash
to it.
Git also supports globbing patterns. For instance , the rule ,=*.ext=,
ignores all files (and directories but I wonder why a directory would
have that name) ending in .ext in a repo. The seventh rule *.[oa]
ignores all files endign with characters 'o' or 'a'. So both
'/somedir/bo.a' and 'gop.o'/ would have been ignored by this rule.
Now you could run into times when you want to have exceptions for your
rules. And Git supports that too. In the fourth rule !lib.ext, right
after *.ext, the '!' at the start tells git to make an exception for
the file 'lib.ext' to any rule that would ignore it. From the sample
ruleset, Git knows to ignore all files ending in '.ext' but also to
include 'lib.ext'.
What if you don't some rule to be applied recursively? You could prepend
the rule with a forward slash. The rule /a only applies to the files
and directories in the same location as the .gitignore file called 'a'.
Appending a forward slash to this rule /a/ means ignoring only folders
named 'a' but applying this rule only in the same folder as the
'.gitignore' file.
How about ignoring all files and or directories matching a certain
pattern under some directory located elsewhere than in the root
directory? That's what's applied in the rule a/*.txt. It ignores all
files (or folders) with the names ending in .txt that are directly
under folders named a/. But there's a caveat! It only does this if the
pattern's root folder , a for this example, is in the root directory.
Say rootdirectory/a. To apply this to folders one level deep, say
rootdirectory/b/a, it'd have to change to */a/*.txt. The * char
would match anything in the root directory (but a forward slash) then
the pattern a/*.txt. Say,
rootdirectory/somedir/a/file.txt
It however wouldn't match rootdirectory/somedir/anotherdir/a/file.txt.
For unrestricted depth, we'd apply
**/a/*.txt
From this we can see that Git applies all rules relative to the root directory.
Here's another sample rule to match all files ending in .txt at any
depth in any a directory named a located at the project's root.
a/**/*.txt
You can mix these rule formations and do make all sorts of interesting rulesets but why would you do that? To have fun? Anyways.
Lastly, on templates. So there's a whole lot of '.gitignore' templates
out there for different kinds of projects. Pre written rules ready for
you to copy and paste into your .gitignore.. And that's a good thing.
It probably saves time that'd be taken writing your own. Or helps you
include patterns you could otherwise have forgotten.
But personally, I maintain a single .gitignore template. Keep adding to it all sorts of patterns for files and folders I tend to ignore (and that could include online templates too but I haven't sourced from any online templates before.). Then I have means to auto populate every project's .gitignore from the same global file.
And here's what's interesting, I ignore my .gitignore too! I mean, I
might be ignoring certain things I don't want folk to know am ignoring..
so..
Anyways, that's a whole lot on such a small topic. So let's have the summary. Just in case you skipped to the end.
Rules Summary (TLDR)
- Recursively ignoring all files and folders whose names match some
pattern
a
a
- Recursively ignoring only folders whose names match some pattern
a
a/
- Ignoring all files and folders whose names match some pattern
athat are located in the root directory
/a
- Ignoring all files in directory named
athat's located one level deep below the root directory say root is/and we want to ignoreain/b/a/somefiles.
*/a
- Ignoring all files and folders located any number of levels deep below
the root directory say ignoring
ain/b/c/a/somefiles.
**/a
With the building blocks and conceptual understanding from this article,
I'm sure there's not much extra that you'll need. But when you do, you
can look at man gitignore.
I sure do hope this helped somehow. See you in the next one and… HAPPY HACKING.