I use the ever living hell out of .git/info/exclude. Works great for scripts/Makefiles I only want locally and collaborators wouldn’t care about or be able to use.
~/.config/git/ignore and ~/.config/git/config is the proper place for your global git config and ignore instead of creating a ~/.gitignore_global and changing the config. IMO.
my dotfiles are a lot smaller at the root level taking advantage of the ~/.config/ for a lot more things.
the git exclude isn't used as much because it doesn't get committed to the repository so you'd have to recreate it each time you wanted to use it. that doesn't mean they're bad just why they are not used.
Not sure where I picked up this, but I’ve added this to my global Git ignore:
attic
That way you can just create an attic directory in any project where you can keep random stuff that should never be committed. I’ve yet to find a repo which actually has such a directory checker in.
One point of clarification: with git, "global" means per-user, not "machine-wide. (I never understood why "--global" wasn't better named, maybe "--user".) That's why these pathnames are in a user's home (the "~" means the current user's home directory).
Machine-wide configuration is called "system" in git, and generally lives under "/etc".
Magit has good support for these other methods. You press <i> and then select if you want the ignore to be shared (.gitignore) or private (.git/info/exclude).
The global/user wide exclude is a feature that should be more widely known. I frequently have people submitting changes to add their IDE/OS/AI/... files to every project's .gitignore. They are almost always pleasantly surprised when I tell them that they can add them to their standard configuration and have them ignored everywhere without bothering every project and without risk of accidentally committing them on a project where they haven't updated the .gitignore yet.
My general rule is that in-repo .gitignore should only be used for repo-specific things (build outputs, dependency folders, ...) and most user tools should be in their own user config.
Or if your editor is happy to store them in a subfolder that is useful. I use Sublime with the AutoProjects extension and it puts .sublime-project snd .sublime-workspace under a .sublime folder that I can have a .gitignore * underneath.
I couldn't say for sure where it came from, but both my Macs (one with Ventura, one with Sequoia) have a ~/.gitignore_global file with an entry for .DS_Store, plus whatever stuff in the global git config makes git ignore stuff mentioned in that file.
This file on my newer Mac is dated 2 days before I ordered it, and I don't remember setting any of this up, so I assume it came like this out of the box. I can't remember the dates for my older Mac, but I assume it's the same thing - and the macOS versions suggest that the default setup might have been like this for a while now.
So, perhaps the days of having to add .DS_Store/ to your .gitignore file are over!
allows for remote specific configs, overriding say email or other required options depending on where you send contributions - without having to have per repo config
works for dir too
[includeIf "gitdir:/home/user/src/work1/"]
Git is REAL bitch about exact syntax here; the first snippet won't work with just :*, it needs :/* ; the second won't work without trailing slash
Wow! How did I not know this? I am a professional software dev for 20 years… and only ever used .gitignore !
I just realized that I never even „asked“ myself if there might exist a better way than to clutter .gitignore with all kinds of specific excluded only relevant to me. I just accepted the world as it appeared to me…
Fun article, but it leaves out my favorite "almost ignore" feature in Git: `.gitattributes`.
This file lets you specify that git should "ignore" the diff from certain files. For instance, Node projects have a `package-lock.json` that is pure noise from a Git standpoint (it's just massive amounts of diff specifying specific versions of libraries, and the real human-readable version is in a separate `package.json` file).
With `.gitattributes` in the root of your project, you can just add a line:
`package-lock.json -diff`
Now, that file will still get staged/committed (which you want) ... but when you `git diff` you won't see the massive amounts of pointless diff in that file.
It shouldn't be noise. Don't update it if you're not intentionally trying to, otherwise you're exposing yourself to supply-chain risk for no reason. If you are regularly getting unexpected `package-lock.json` changes then you are doing something wrong.
package-lock.json shows all your transitive dependencies, package.json just shows your direct dependencies. It is simply not true that the latter is "the real human-readable version". They serve different purposes and it is dangerous to say you can always ignore the diff in your lock file.
as someone who deals with dep upgrades and forensics when trying to figure out a bug I would get _so mad_ if `git diff` didn't show the diffs to lock files.
I get what you're saying about it being line noise but when you need it you need it!
People are jumping on it being an important file to review. You don't want to ignore the diff.
Even if that's true, you definitely do not want to attempt merge two lock files, and using the .gitattributes file to set the merge strategy is a good idea!
There are also "semantic" diff and merge tools for a variety of languages, and a few specialized for JSON. That stuff was always pretty niche, but it's becoming more popular with AI agents and not wanting to or not being able to review every merge by hand.
To me it still sounds like a build artifact, and not source code: yes, you want to keep it and track changes to it, but freeze tools should allow one to easily get a reproducible build of package-lock.json too (eg. by passing a timestamp, it should be able to regenerate the lock file with latest-as-of-timestamp).
Maybe they do — I am not too deep in JS ecosystem — but that should be the basis of a true SBoM (generated, static artifact tied to a release build) and reproducible builds (able to regenerate byte-for-byte identical artifacts from actual source of truth which is your package.json).
This is probably the most batshit insane insecure advice I've ever read on Hacker News ever. And everyone is wondering why NPM based attacks are so prevalent? Advice like this is being followed.
Explain the attack that gets mitigated by reading the diff of a lockfile?
Every major npm attack I can think of essentially follows the pattern of "version X.Y.Z is secretly evil". How does seeing package@X.Y.Z in your lockfile alert you to that?
It also leaves my favorite way of ignoring files in Git: actually just ignore them yourself and never use shortcuts that break that (like "git commit -a" or "git add .")!
for files that are already tracked. This can be useful for some local experimentation... it's just a bit annoying to use because it's not really surfaced anywhere by git (kinda). You need to remember that you set it; otherwise other operations like checkouts may be blocked.
> The ignore file lives in your machine’s home directory in ~/.config/git/ignore. Whatever filenames are added to this file are ignored globally at a machine-level.
The wording here is slightly wrong: ~/.config/git/ignore will ignore files per-user on the machine, not "at a machine level". And it's not "your machine's home directory", it's your user's home directory on that machine. Any other users on the same machine will not see this. Git calls this "global", as in "global for the user".
Git config does also have a --system option which modifies the system-level config file, /etc/gitignore. You could probably ignore stuff at the system/machine level (hint: you don't want to), with this. I'd do something like:
Note however that user config will override this, so any user who has a core.excludesFile setting will not also look at your system level excludes file. Which is a pretty big caveat.
One trick I’ve used is creating a folder and then adding a .gitignore inside it with *. Then nothing in that folder gets tracked, without needing to add anything to the public gitignore. Didn’t know about .git/config though!
58 comments
[ 2.7 ms ] story [ 61.1 ms ] threadmy dotfiles are a lot smaller at the root level taking advantage of the ~/.config/ for a lot more things.
the git exclude isn't used as much because it doesn't get committed to the repository so you'd have to recreate it each time you wanted to use it. that doesn't mean they're bad just why they are not used.
Let's say you have a directory like attic; you can put inside a `attic/.gitignore`:
& then that directory (and anything in it) is ignored, including the ignore file itself.I usually name my version of this directory the single character U+1F4A9, which HN refuses to permit me to put in a comment ;)
Machine-wide configuration is called "system" in git, and generally lives under "/etc".
My general rule is that in-repo .gitignore should only be used for repo-specific things (build outputs, dependency folders, ...) and most user tools should be in their own user config.
> For example, if you’re on macOS, adding .DS_Store here would be ideal.
As long as every Mac user on your project does. If you have more than one, it may be better off taken out of everyone's hands.
This file on my newer Mac is dated 2 days before I ordered it, and I don't remember setting any of this up, so I assume it came like this out of the box. I can't remember the dates for my older Mac, but I assume it's the same thing - and the macOS versions suggest that the default setup might have been like this for a while now.
So, perhaps the days of having to add .DS_Store/ to your .gitignore file are over!
Set a global hooks dir, and then block binary files in pre-commit by using file or checking the git index
Or block large changes, because binary mods are often larger than a real diff.works for dir too
Git is REAL bitch about exact syntax here; the first snippet won't work with just :*, it needs :/* ; the second won't work without trailing slashI just realized that I never even „asked“ myself if there might exist a better way than to clutter .gitignore with all kinds of specific excluded only relevant to me. I just accepted the world as it appeared to me…
And Today, it got s little bit better :-)
This file lets you specify that git should "ignore" the diff from certain files. For instance, Node projects have a `package-lock.json` that is pure noise from a Git standpoint (it's just massive amounts of diff specifying specific versions of libraries, and the real human-readable version is in a separate `package.json` file).
With `.gitattributes` in the root of your project, you can just add a line:
`package-lock.json -diff`
Now, that file will still get staged/committed (which you want) ... but when you `git diff` you won't see the massive amounts of pointless diff in that file.
It shouldn't be noise. Don't update it if you're not intentionally trying to, otherwise you're exposing yourself to supply-chain risk for no reason. If you are regularly getting unexpected `package-lock.json` changes then you are doing something wrong.
I get what you're saying about it being line noise but when you need it you need it!
Even if that's true, you definitely do not want to attempt merge two lock files, and using the .gitattributes file to set the merge strategy is a good idea!
Maybe they do — I am not too deep in JS ecosystem — but that should be the basis of a true SBoM (generated, static artifact tied to a release build) and reproducible builds (able to regenerate byte-for-byte identical artifacts from actual source of truth which is your package.json).
Every major npm attack I can think of essentially follows the pattern of "version X.Y.Z is secretly evil". How does seeing package@X.Y.Z in your lockfile alert you to that?
https://laszlo.nu/blog/project-level-git-config.html
Git config does also have a --system option which modifies the system-level config file, /etc/gitignore. You could probably ignore stuff at the system/machine level (hint: you don't want to), with this. I'd do something like:
Note however that user config will override this, so any user who has a core.excludesFile setting will not also look at your system level excludes file. Which is a pretty big caveat.