.gitignoreWhat if you have files in your subdirectory you don’t want Git to pay any attention to? Like maybe you have some temporary files you don’t want to see in the repo. Or maybe you have an executable you built from a C project and you don’t want that checked in because your incredibly strict instructor won’t grade your project if the repo contains any build products? For example.
That’s what this part of the guide is all about.
.gitignore FileIn any directory of a Git repository, you can add a .gitignore (“dot gitignore”) file.
This is a simple textfile that contains a list of file names to ignore.
Let’s say I have a C project that builds an executable called “doom”. I wouldn’t want to check that into my source repo because it’s not source, and it’s just a big binary that takes a bunch of disk.
But when I get the status, it’s annoying to see Git complaining about it:
$ git status
On branch main
Untracked files:
(use "git add <file>..." to include in what will be committed)
doom
nothing added to commit but untracked files present (use "git
add" to track)So I edit a .gitignore file in that directory and add this one line to it:
doomNow I run status again:
$ git status
On branch main
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)What? Same thing? Not quite! Read the fine print!
It used to be complaining that doom was untracked, but now it’s not complaining. So the .gitignore worked. Woo hoo!
But Git has found another untracked file in the brand new .gitignore. So we should add that to the repo.
Always put your .gitignore files in the repo unless you have a compelling reason not to. This way they’ll exist in all your clones, which is handy.
$ git add .gitignore
$ git commit -m Added
[main 07582ad] Added
1 file changed, 1 insertion(+)
create mode 100644 .gitignoreNow we get the status:
$ git status
On branch main
nothing to commit, working tree cleanand we’re all clear. That doom file is still there in the working tree, but Git pays it no heed since it’s in the .gitignore.
.gitignore?Yes!
You can be as specific or as non-specific as you like with file matches.
Here’s a .gitignore looking for a very specific file:
subdir/subdir2/foo.txtThat will match anywhere in the repo. If you want to only match a specific file from the repo root, you can prepend a slash:
/subdir/subdir2/foo.txtNote that means subdir in the root of the repo, not the root directory of your entire filesystem.
If you put this in your .gitignore:
foo.txtit will ignore foo.txt in all subdirectories of the repo.
.gitignore?You can add .gitignore files to any subdirectories of your repo. But how they behave depends on where they are.
The rule is this: each .gitignore file applies to its containing directory and all the subdirectories below it.
So if you put a .gitignore in your repo’s root directory that has foo.txt in it, every single foo.txt in every subdirectory of your repo will be ignored.
Use the highest-level .gitignore file to block things you know you don’t want anywhere in your repo.
If you add additional .gitignore files to subdirectories, those only apply to that subdirectory and below.
The idea is that you start with the most broadly applicable set of ignored files in your repo root, and then get more specific in the subdirectories.
For simple repos, you’re fine just having one .gitignore in the repo root directory.
And we’ll also talk about overriding .gitignore entries soon.
Do I have to individually list all the files I don’t want in the .gitignore? What a pain!
Luckily Git supports wildcards in ignored file naming.
For example, if we wanted to block all the files that ended with a .tmp or .swp (Vim’s temp file name) extension, we could use the * (“splat”) wildcard for that. Let’s make a .gitignore that blocks those:
*.tmp
*.swpAnd now any files ending with .tmp or .swp will be ignored.
Turns out that Vim has two kinds of swap files, .swp and .swo. So could we add them like this?
*.tmp
*.swo
*.swpSure! That works, but there’s a shorter way where you can tell Git to match any character in a bracketed set. This is equivalent to the above:
*.tmp
*.sw[op]You can read that last line as, “Match file names that begins with any sequence of characters, followed by .sw, followed by either o or p.”
.gitignore RulesWhat if your root .gitignore is ignoring *.tmp files for the entire repo. No problem.
But then later in development you have some deeply nested subdirectory that has a file needed.tmp that you really need to get into Git.
Bad news, though, since *.tmp is ignored at the root level across all subdirectories in the repo! Can we fix it?
Yes! You can add a new .gitignore to the subdirectory with needed.tmp in it, with these contents:
!needed.tmpThis tells Git, “Hey, if you were ignoring needed.tmp because of some higher-up ignore rule, please stop ignoring it.”
So while needed.tmp was being ignored because of the root level ignore file, this more-specific file overrides that.
If you needed to allow all .tmp files in this subdirectory, you could use wildcards:
!*.tmpAnd that would make it so all .tmp files in this subdirectory were not ignored
You can use the negated rules for that.
Here’s a .gitignore that ignores everything except files called *.c or Makefile:
*
!*.c
!MakefileThe first line ignores everything. The next two lines negate that rule for those specific files.
.gitignore FilesHere’s a repo20 with a whole bunch.
But you can also roll your own as needed. Use git status often to see if any files are there you want to ignore.
When you create a new repo on GitHub, it also gives you the option to choose a prepopulated .gitignore. Warning! Only do this if you’re not planning to push an already-existing repo into this newly-made GitHub repo. If you plan to do this, GitHub’s .gitignore will get in the way.