Hacker News new | past | comments | ask | show | jobs | submit login
Git ignores .gitignore with .gitignore in .gitignore (rubenerd.com)
655 points by Tomte on May 18, 2022 | hide | past | favorite | 231 comments



This is my favourite feature of gitignores. Everytime I need "drafts", sample code, etc, in a repo, I create a folder in that repo, but then I have to remember to not add it to commits, and I don't want to add it to the .gitignore that is versioned, so I do "mkdir drafts && echo '*' > ./drafts/.gitignore", and it ignores my drafts without having to add a new ignored dir in the versioned .gitignores.

And obviously, it also "ignores" the .gitignore itself because it matches "*", while still taking it into account, which is what I need.


Additionally git supports a global git ignore.

    $ git config --global core.excludesfile ~/.gitignore
Then you can put all the standard things you want to ignore into it:

    $ cat ~/.gitignore
    .DS_Store
    ./drafts/
    *.swp
And it will apply to all git commands on your computer.


I heavily advise AGAINST using this for anything apart from OS level file spam (.DS_Store etc).

We spent a good part of a day rebuilding a repo after a junior dev. left, when we found out they'd misused global gitignore and hadn't commited several important files due to an ignore they had set for a seperate project.

Lessons learnt. Ensure new devs don't use it, and code review on another machine than theirs...


If they did not commit all the important files and your CI system didn't catch that, that's definitely the fault of your CI system, not global gitignore.


Because there isn't a CI?

Shocking I know /s.

But not everyone on here is part of a 20 man SV tech startup making the next social media for beagles and deploying 50 times a day...


You don’t have to be at a tech startup to have things like CI and/or code review platforms.


Agreed. If the code is in GitHub, it's incredibly easy to create a simple github actions workflow that could run the app.


so glad i don't work with you.


Why? They're right imo


fishywang's attitude


What attitude lmao. They’re very matter-of-fact in expressing an objective opinion from what I can see.


what perceptive skills lmao! i couldn't stand talking to you for 2 minutes.

lmao!


I don't understand, you'd rather work without a CI pipeline?


i'd rather not work with fishywang


You might have learned the wrong lesson.

A broken code should not be able to make it to production, there should be several steps to prevent that, including: Peer review, CI, QA, a staging environment, manual testing, etc.

Always assume that developers can screw up in trivial ways, and build your delivery system such that trivial screw ups will be caught early, rather then dictate how your devs setup their work stations.

Also don’t code review the code it self, review the diff.


Yeah exactly, if I `require important.rb` in this file, and `important.rb` wasn't committed how did that project even build and get deployed. Any sane build system will instantly fail for this situations. Looks like an issue with dev ops/engineering culture rather than .gitignore


>Also don’t code review the code it self, review the diff.

A significant percentage of the most critical problems I detect during reviews is in the parts that have not been changed, invisible in the diff. A good diff is necessary, but not sufficient.


Telling developers to not use the global .gitignore seems to be the wrong response. For example, I use VS Code, its extensions, and various other development tools that create local files that should not be in repositories. Those files and directories do not belong in a repository's .gitignore file, unless it's a personal project. They most often belong in a global .gitignore unless a team uses a common set of tools. Having a single developer's custom tools be handled by a repository's .gitignore seems to be the wrong approach.


.git/info/exclude seems like the right place for this.


That's only per repository, isn't it? It won't really be convenient when you're working across several repositories or languages.


how did that project ever build on ci :)


hint: there was no CI


I heavily advise AGAINST not using CI. If properly applied it solves .gitignore mistakes and many more, made by those infamous junior devs. On second thought, not just juniors. Oh well.


but it worked on my machine


Ship your machine as CI, problem solved /s


docker wants to know your location


Probably the dev made the code review before leaving


The global gitignore is super useful! I add a “.x” entry to it so that I can create scripts, drafts, etc in a “.x” folder in any of my projects.

Wrote more details about how I do this here: https://alexplescan.com/posts/2022/04/17/the-x-files/


You had me - before clicking - at the url-slug "the-x-files". Loved the content and learned something useful. Thanks for pointing it out. Will be another little tool in my belt.


just set this up on my machine! Thank you so much!

I'd just been bumping into this problem, but hadn't conceptualized such an elegant solution, so kept fumbling around, adding/moving things, futzing around with git way more than I wanted to.

Thank you!


This seems like it could potentially be a source of confusion - different devs on the same project would see different ignore behavior.


In many ways that’s a good thing. I don’t want to have ignore entries for 10 different text editors in every project’s .gitignore. Put that stuff in your personal .gitignore. In general, I don’t want commit history to contain any of these “just for me” changes even aside from .gitignore. Project .gitignore should mostly just ignore the stuff that your build/CI produces, which itself should hopefully be just a single `build` directory.


As far as I can see, this only comes into play when newly adding files to be tracked. If you created a 'source.file', but your global gitignore ignores all '.file' files, then you'd notice immediately. You wouldn't commit and push because you were unable to add the file in the first place.

If another developer has added a 'source.file' and you pulled it in, your global gitignore would not be triggered, since the file is already tracked in the repo.


It would also come into play of you add code that generates files which should be ignored, but you don't realize the gitignore has to be updated because it's ignored in your own global gitignore.


Very good observation. That's a reason I'm itching to try out an approach akin to this (in a future project): https://jasonstitt.com/gitignore-whitelisting-patterns


Excellent point!

Tangentially, to prevent scenarios where generated code becomes out of sync, in your CI you should always re-run generators and check that `git status` shows no entries (and fail the build if it does).


I am surprised this isn't expected. Sure, it's nice to have common build files ignored. But I have all kinds of files locally (editor files, etc) that are specific to me, not common to my team. I don't expect my team to have the same ignore list as me, nor would I want my ignore list cluttered with entries that only apply to them. I see it the same as an editor/IDE config; each person has their own, and putting them in version control tends to cause issues/noise.


Is this a problem though? I can see the upsides of ignoring the files in the shared gitignore. Are we trying to save space??


Yes it is a problem when a project involves more than a few people. If there are really common ignores that multiple people use, it’s fine to share those. But one-off folder & file ignores should not be dumped into the shared space. It has nothing to do with disk space, and everything to do with clean semantic project organization. Shared ignores should be primarily a declaration of temporary files & folders that the project produces during build/run/etc. - things that everyone will need. Adding personal folder ignores to the shared .gitignore can not only be confusing about what intermediate artifacts are expected, it can cause problems or conflicts for other people. A small dumb example is if someone tries to make a new shared folder and someone else already shared an ignore. I’ve seen it happen, and it’s not a big deal, but caused temporary confusion. You can cause issues with git history and pulls and bisects when there’s churn with the ignores.


Back on earth, a few lines in an ignore file would not make anyone blink. I guess you're a purist and everything about your software shines! Perfection.


> Back on earth, a few lines in an ignore file would not make anyone blink. I guess you're a purist and everything about your software shines! Perfection.

I didn’t downvote you, and I don’t understand your sarcasm toward me when I’m trying to explain the practical answer to the question you asked. This isn’t just a few lines on a large project, and it’s not even about the extra lines at all. The issue is that personal preferences don’t belong in a shared file, and their presence can cause real and actual problems in a large project, problems I’ve witnessed and experienced first hand. One single bad line in .gitignore can cause trouble for everyone on the team when they need to checkout different branches. If you have 50 or 100 people adding their own ignores, they can and do easily conflict with each other. The shared .gitignore just isn’t the spot to list your personal folders, which is why git designed other places for you to put those.


As long as you know your own ignore behaviour, I don't see how it can cause confusion... except maybe if you share the drive the repo is stored (either as a network drive or you share the physical drive via sneakernet) but why would you do that instead of cloning the repo?


This is by design, and not a problem in practice: ignores are declaring unshared files & folders. If ignores change the state or behavior of the project, it means someone didn’t use ignores correctly, didn’t think through what ignore behavior should be shared and what shouldn’t. Sometimes there are folders everyone will have that should be ignored, like a “build/“ folder, and sometimes there are folders you make yourself inside your repo and don’t want them checked in, like test scripts or output images or whatever. The personally ignored artifacts should be different ignore behavior.


Global gitignore should in general only be used for things that's "unique" in your local environment, like:

* IDE/Editor (for example, add `.vscode` to your global gitignore if you use VSCode, add `.idea` if you use IntelliJ family, NOT add `.editorconfig` because that's intended to be cross environment)

* OS level spam (`.DS_Store`, etc.)

* Any file generated by a tool you use locally

Also a pro tip, I have this alias in my global git config:

    why-ignore = check-ignore -v --no-index
So I can use `git why-ignore path/to/file` to show why a file is ignored (e.g. it shows which line in which gitignore file excluded it).


Thanks for pro tip, git clean -ndx is my friend.


Not really, because they only see differences they have caused themselves, so they know about it.


And so they forget about it.


I agree. The same problem (different devs with different settings) is solved by specifying line endings in per-repo .gitattributes files instead of global autocrlf settings. And we all know how much confusion that causes.


I wouldn't use this for system files, but I have the pattern "loz_*" and it lets me keep "my" odd scripts in the repo folder but permanently untracked.


This is the reality of the global .gitignore. Unless you have a full team of super competent and well rounded devs that think alike, one is going to come up with a strategy of "ok, everyone should obviously put stuff like .vscode in their global gitignore; it has no place in the local one" while somebody else doesn't care a bit, and it's really kind of a silly thing to try and enforce protocol around. Much bikeshedding detected.


It is as soon as you forget about that-but, speaking of myself, it is not because I'm aware of the fact that I'm using it


I also got in my ~/.gitignore:

    .envrc   # direnv, where I store my local project configuration
    .vscode
and when I remember to use them:

    *.gitlocal
    *.gitlocal*
To store files and directories I don't ever want to push, mostly for scratch files and logs


Why to ignore .vscode? We collect there workspace wide team settings.


I don't think editor-related settings should be committed, unless it's a company repo and everybody is forced to use the same editor. Otherwise all projects would be littered with .vscode, .atom, .sublime, .dir-locals.el, etc. which isn't great.

Anyway, stuff in .gitignore can still be added to the index if you so wish.


If almost everyone uses some editor, then it’s not really “littered”. We do the same and it’s nice for new teammates to quickly get set up. If they are one of the few folks that want to use some other editor, who cares? Files are free.


When almost everyone uses the same editor, it doesn't mean that everyone wants to have the same configuration.

Editors and IDEs are crafting tools. Crafting tools are meant to be mastered by workers (here: developers), not to enforce some team/company policy.

There are tools that already exists to enforce team policies like formatters, linters and so on. These tools generally integrate well with your editor of choice and can also be integrated on your CI pipelines.


I feel like a better option than committing is to have developers submit sample configurations and make them available in a subfolder or a dedicated configuration repo -- this way, newcomers to the team can pull in existing configurations and tweak them, rather than having to start from zero.


I said it makes sense iff everyone uses the same editor and the same settings. But many times this is not the case.

What do you need to share btw? There's editorconfig, prettier, git hooks, etc. for style. direnv for configuration (I usually commit a .envrc.example file). I can't think of anything else.


At my last job we had a mono-repo with the .idea directory (for IntelliJ) commited. For Java projects IntelliJ needs to sometimes be directed to understand what folders are “resources” to allow better autocompletion and highlighting.

For example specifying custom java faces components directory that will be used once the application is packaged into a war file, so IntelliJ knows they are accessible from JSP html files, and will autocomplete and show you what attributes you can modify on the component.


I had a dev check in their .idea directory and all the files for a project. This resulted in them checking in the file that had windows and cursor positions checked in too. Each time you went to switch to a different branch, you got the workspace configuration of the last person to commit that file.

Another spot of problems was the plugin specific files (that inevitably also got checked in). When someone checked them in again and you hadn't updated this particular plugin, the newer file format caused it to crash. Not a problem for the dev who checked it in, but a problem for everyone else.

I am a strong proponent now of not checking in files that are IDE specific unless the developers are all completely aware of what files do what and the associated churn that a file may have through normal use.

Having maven and editorconfig instruct IntelliJ on how to make a workspace consistent results in less config file churn and avoids people accidentally checking in the compiler settings on their computer, database configurations (with passwords), run configurations (with passwords) and similar.

Checking in IDE files can be done, just that the developers all need to be diligent in checking what they check in. I've rarely been in an environment where that is the case for everyone.


I've seen a few big repositories upload their .vscode (pretty sure at least one of the Microsoft repos on Github had this).

I have a few team who does commit their .vscode folder, they use it to set up their environment the same way (usually when a project differs from another).


What about .editorconfig?


That's perfectly fine, mandatory even if more than one person touches the code.


you didn't list .idea :'(


Please never commit IDE config. It doesn't belong in repositories. It is not a source file of your project.


Actually, this can be quite useful (at least with IntelliJ) to share common run configurations (e.g., run all tests, start this server with these settings) and other settings.

IntelliJ recommends not checking in a few types of files that are specific to the individual: https://intellij-support.jetbrains.com/hc/en-us/articles/206...


Makefile or adding those scripts to package.json is a much better idea than vscode's own task configuration file which might not work if someone uses another editor.


Why not both?


'never' is a strong word.

A .vscode/extensions.json file just specifies extension 'recommendations', and I find, really accelerates developers becoming productive in a project.

If I want to encourage small, one-off contributions, I want to support a user workflow that's as close as possible to:

   git clone <project>
   git switch -t <branch>
   code <project>
   npm ci | dotnet restore | terraform init | go get | <whatever>
   <change and test>
   git add <changes>
   git commit
   git push
With the right set of extension recommendations and default code settings, a VS code user can automatically be prompted to get the right test executors, linters, prettifiers, and so on so that they get instant feedback on their changes.

It doesn't even matter if many users who work on the codebase day to day actually use emacs or a highly customized IntelliJ setup or whatever - the vscode settings specifically enable the driveby coder to get a working environment fast, and that helps enable the power users to not be bothered by feature requests that could be pull requests.


Never is a strong word, and I mean it. No your fancy extensions mean nothing to many devs. That configuration is not required to run the code in the repository. Do not include it.


Java projects can get complex and editors (like IntelliJ can provide much better tooling when configured).

At my last job we had a mono-repo with the .idea directory (for IntelliJ) commited. For Java projects IntelliJ needs to sometimes be directed to understand what folders are “resources” to allow better autocompletion and highlighting. For example specifying custom java faces components directory that will be used once the application is packaged into a war file, so IntelliJ knows they are accessible from JSP html files, and will autocomplete and show you what attributes you can modify on the component.

It’s definitely not a never situation. You can commit only certain files from the configuration (project settings not editor preferences)


So... are you also against having any hints as to how to set up a working local dev environment in the README.md file? Because that's also not necessary to run the project, but it's a courtesy to contributors.

Also, the idea that there is some universal rule of 'what should be checked in to source control' that applies to EVERYTHING from personal projects to corporate internal monorepos to open source projects to undergrad joint coding projects to video games is... absurd.


No, because that's documentation, but I think that was obvious.


Well, no it's not obvious.

If I can provide machine readable documentation on how to get your VSCode environment set up (in the form of a .vscode/extensions.json file), isn't that strictly better than merely human-readable documentation in README.md under a 'Recommended VSCode Extensions to work with this project' header?


No, because that doesn't translate to other IDEs and one user programmatically changing things to suit themselves causes fluff in PRs and diffs. You also can't guarantee every environment is going to respond correctly.


One user programmatically changing things to suit themselves is supposed to do so in their user settings, which has precedence over the checked-in copy. That way, you have the best of both worlds: easy set-up for everyone who wants it but you can override it without touching the VCS.


Update: turns out the precedence rules are a little more subtle than I thought.

See also: https://code.visualstudio.com/docs/getstarted/settings#_sett...


Can you override user settings at the project level?


Yes, project-level (aka workspace) settings generally override user settings.

But then again, language-specific settings will trump all other settings. And that’s one way to override workspace-level settings in your user settings if you want.

Here’s a detailed list of all levels of settings in VS Code, ordered by precedence: https://code.visualstudio.com/docs/getstarted/settings#_sett...


I think I disagree, though the only person who should be messing with it is the maintainer. One of the easiest ways to ensure that everyone follows the same coding standard for a project (particularly for open source projects).

I usually add something like specified in:

https://editorconfig.org/


But there's a difference between editorconfig and vscode specific stuff in that editorconfig is IDE agnostic...


Yes; would be silly to dictate people's font sizes and the like. Perhaps we can then agree that there are certain configs that do belong, and others that might be less wise to include [if your boss dictates that you use Arial 10pt, get another job!]


For the love of God no. I had someone commit theirs and it override my preferred setup and even changed my gd font. You're basically telling your teammates: i am forcing you to work my way so shove it.


Most teams I worked on did not standardize the team's OS or editor. The "canonical" build was a CI server and the development environment was available as a VM or container.


I do the same with with *gitignored*. Handy for output files of tests, and log files. For example: "log_gitignored.txt" or "mesh_transformed_gitignored.stl".

I add it to the repository settings, so all collogues have the same behavior.


Standard path is ~/.config/git/ignore


You mean $XDG_CONFIG_HOME/git/ignore


"For writing options: write to global ~/.gitconfig file rather than the repository .git/config, write to $XDG_CONFIG_HOME/git/config file if this file exists and the ~/.gitconfig file doesn’t."

Everyone aren't using all the freedesktop conventions, so no.


To supply context: the above quote is from the man page, therefore authoritative.

  $ man git-config
It is however densely conditional wording -- could be simplified.


I don't think that XDG_CONFIG_HOME is a thing with Windows or macOS.


I've got a slightly different version of that last rule in mine:

    *.sw?
Since I'm messy enough to sometimes end up with multiple of them for a few files. (Also, not messing with flash files in git, or in general...)

But have since moved my vim swap files to ~/.vim/swap with `set directory=~/.vim/swap,.` in .vimrc.


ignoring .swf is a bonus :P


Or simply put the file at the default location for core.excludefile, which is

    ~/.config/git/ignore 
on Unixy platforms.


Hard agree. Even though I tend to work on only a couple of different kinds of things - at least for now - the global ignore file is a godsend.

So good.


Do you know about .git/info/exclude? It only exists in your local git file so it isn’t shared with a remote repo and achieves this same purpose.


I also (mis)used .gitignore before I realised that there was an easy way to ignore stuff that I have locally without having to commit/ignore a .gitignore file.


I didn't! Good to know, even if my way is really quick and simple to set up so I might continue doing the same. Thanks!


Not at a term, but would this prevent `git clean -fdx` from removing the dir? That’d be quite useful!


No, since -x means to “disregard standard ignore rules”, such as .gitignore and .git/info/exclude.

> Don’t use the standard ignore rules (see gitignore[5]), but still use the ignore rules given with -e options from the command line.


Another comment already mentioned the `.git/info/exclude` directory. For completeness link to the online docs: https://git-scm.com/docs/gitignore

git will take 3 files into consideration for "ignoring" files:

> $XDG_CONFIG_HOME/git/ignore, $GIT_DIR/info/exclude, .gitignore

How I use them:

* ~/.gitignore: stuff I want to ignore everywhere (`/myNotes`, `.DS_STORE`, ...)

* <project>/.gitignore: stuff that should be ignore for this projects and shared with others

* <project>/.git/info/exclude; stuff for this project that only I want to ignore

** this is also super useful in combination with `git-bisect`


This is my strategy for dotfiles. My home directory has a .gitignore with "*" in it. I will "git add -f" any files I want tracked; git is extremely efficient at ignoring the rest. It doesn't require any frameworks, symlinks, installation scripts, elaborate tutorials/manpages, or any other voodoo.

To move in to a new machine - unfortunately you can't git clone into a non-empty directory, but the commands to work around that are simple enough to remember.

https://github.com/rollcat/dotfiles


I prefer to list individual directories and files in my ~/.gitignore so that I see when new files show up and I can decide whether to ignore them, commit them, or prevent them from getting generated.


It tends to blow up "git status" if some random new piece of software (or random me) makes a random new subfolder, full of random things. You can override .gitignore for specific subfolders like .config, .emacs.d, etc.


That's what I used to do, but I switched to Josh's strategy a couple years ago.[1] It doesn't "blow up" git-status. If some new piece of software creates a new directory with a bunch of random stuff in it, git-status will just show you the directory since it is is untracked, and not everything in it.

[1]: https://github.com/BurntSushi/dotfiles/blob/965383e6eeb0bad4...


.git/info/exclude is a local .gitignore file which is never committed which you can also use for this kind of purpose.


I mean this is only a problem if your commit work flow is "git add . && git commit".

A bad habit, in my opinion.


Disagree. How is that a bad habit? My workflow is "git status" to check what I've changed, "git add --all" and then "git commit".

"git status" needs to be clean. I don't want to see any untracked temporary files. If it's untracked either it needs to be ignored or it's a new source file to add to the index.

Keeping untracked files lying around not gitignored is a recipe for one day committing one by mistake, or conversely, that some of them are source files you've forgot to commit. I've seen both things from junior developers, that do not know of .gitignore.


>"git status" needs to be clean. I don't want to see any untracked temporary files.

Why do you not want to see any untracked files? What harm does it cause? What is the problem that you are trying to solve?

> If it's untracked either it needs to be ignored or it's a new source file to add to the index.

Or it is a file that stores your notes or experiments that don't necessarily belong in a branch, do not want to include in your next commit, but you also don't want to be invisible to ".gitignore" aware tools - and increasingly many modern tools are (vscode, ripgrep, emacs's projectile to name a few).

>Keeping untracked files lying around not gitignored is a recipe for one day committing one by mistake, or conversely, that some of them are source files you've forgot to commit.

Neither of those are a factor if you consciously check what you are committing using "git status" and "git diff --cached".

This is the habit you want to inculcate in your junior developers, that they should consciously think about the commit they are sending for code review, not that they should meticulously manage and be completely dependent on .gitignore (and i presume you also mean .git/info/exclude - because of course they would also have local files that they don't want to commit but are not worthy of being put into the repo's .gitignore).


There is value in "making a decision" for each untracked file, of whether to explicitly add it or ignore it. This combines well with things like a PS1 that indicates if you have any unclean state (including both changes and untracked files). Every single time I find myself with an untracked file, I can either add it because I want it tracked, put it in .gitignore if it's something generated that I want my whole team to ignore, or put it in .git/info/exclude if it's something I've done locally that doesn't fit either of the above.


>There is value in "making a decision" for each untracked file, of whether to explicitly add it or ignore it.

I would argue that you should decide between explicitly adding it or ignoring it, or deliberately doing neither.

>This combines well with things like a PS1 that indicates if you have any unclean state (including both changes and untracked files).

If you intend to keep untracked files in your directory, choose a PS1 that does not bother you about untracked files.

You are losing important information from git status when you exclude untracked files that you are actually working on and not just some random junk your ide generated. What if you look at the git status and conclude that there are no unchanged files worth tracking and then with that false sense of safety decide to run 'git clean -fdx'? You would lose those files permanently!

I honestly don't understand why the presence of untracked files in your git status is such a bother to you!? Like how exactly does it hurt?


Cognitive clutter. Some people don’t care but it distracts me to no end. I want `git status` to tell me things that matter.

I certainly don’t want a meaningful code change sandwiched between an open editor swap file and some for-my-eyes-only temporary design scratch pad.

> then with that false sense of safety decide to run 'git clean -fdx'? You would lose those files permanently!

Correct, and that’s one of the reasons why the `-f` switch might be a poor fit. I use `-i` instead.


>I certainly don’t want a meaningful code change sandwiched between an open editor swap file

We are specifically not talking about the junk files created by editors and ides here.

We are talking about things like notes and exploratory code that you have written that you have no intention of committing, at least not right away. Why wouldn't you want to see them in your `git status`?

Another problem with putting such files in gitignore is that those files will become invisible to an increasingly large number of tools (vscode, ag aka silversearcher, ripgrep, emacs's projectile to name a few) that rely on gitignore to filter out unwanted files. So now, as far as these tools are concerned you have put your notes and experiments in the same category of files as editor junk and build artifacts. You either search them all or none at all.


> Why wouldn't you want to see them in your `git status`?

I tend to function poorly around cognitive clutter. It distracts me from the important stuff: the files I’ve decided to put under version control. YMMV.

> will become invisible to an increasingly large number of tools (vscode, ag aka silversearcher, ripgrep, emacs's projectile to name a few)

That doesn’t really seem to be the case with VS Code. Ignored files appear grey but they’re still showing up for me.


>Ignored files appear grey but they’re still showing up for me.

They show up greyed out in the explorer yes, but they won't appear when you navigate with "Go to File" (ctrl+p) and they won't be searched through with "Search" (ctrl+shift+f).


Good point!


This is what I do. Is there a "better" habit?


Try `git add --patch` (or just `-p`). git will go through each change and you can decide if you want to stage it. You can even stage individual changes in a file.

This doesn't cover new files though. For those you can use `git add $filename` or even globs with `git add src/some/dir/*.$extension`.


For new files I use `git add -N` (if memory serves right; I am on mobile) to mark them as "I want this file to be included in `git add -p`"

Edit: The flag is -N or --intent-to-add


You can use `git add -i` to pick files to add interactivelly


This is cool, wasn't aware of it.


I use `git add -p` regularly, and it's one of my major pet peeves that it doesn't include new files. I constantly forget to include those in commits because of that.


came here to say this, git add -p is such a brilliant thing.

alias ga="clear ; git add -p" is an alias i always seem to keep


What type of workflow do you use where you regularly want to commit only some of your changes to a file? I honestly don't think I've ever had that need.


It's an extremely common and useful way to use git if you are making small and directed commits. This allows you to write code for some feature which includes multiple changes to a file, then make a few different commits with useful commit messages which describe and explain the changes - e.g. the first to include the definition of a new function and why/how it works, a second to modify some constant variable, and a final one to add calls to your new function at some callsite.

Working in this way creates more commits, but with them comes the context of the change, written in the commit message body as prose. This sadly isn't a common way to use git at lots of companies unfortunately, but it unlocks a ton of gits power and makes the commit log and tools like `git blame` and `git bisect` actually useful.

If you're making single commits that affect lots of files and descriptions like "Updated foo.py", you're missing out on a lot of the benefits that git provides.


While some might be more rigorous about working on a commit at a time, a couple other helpful bits are:

- Cleaning up print() calls and similar debug - It's a first-pass review of your own changes; re-read docstrings/comments, and easily go right back to them and update them etc. The diff view is different from the coding view and you gain insights, etc.

This might apply moreso to my often script-oriented coding that does 20 new things, rather than e.g. unit-test backed "formal" coding that does a few specific things.

My own workflow isn't quite at the "commit often" level of frequency, but instead I'm simultaneously crafting several related but separately-reviewable commits in one branch for one PR.


`git add -u` for changes to existing files, and manually `git add` new files. `git diff --staged` to review what's staged. You can use `git gui` to do all this using a GUI.


Yes, the moment you construct a commit by 'git add' is the moment you review the changes you made. Very often you will find results or configuration files get added without you realising it; or you added a breakpoint() that you shouldn't commit, etc. Second, for meaningful commit messages, the commit should include changes that are related to each other. In summary `git add --all` or `git add .` should be used only after a careful inspection of `git status` or `git diff` showed you indeed need all changes, and that they belong to the same commit message.


Logical changes aren't necessarily partitioned by file. Very often I find they are not. I might make a feature or fix or cleanup that is say 10 related changes that each affect some subset of say half a dozen files, often even the same code multiple times.

Adding individual files can help partition out some changes, but it's very rare for me, it's much more often I have to go back and manually shuffle sub-file changes around if I didn't get the splits right the first time.


You could use `git add -p`

It lets you stage individual changes inside files instead of the whole file.


Right, I can do those things and sometimes do. Similarly to per-file I generally don't need to because I try to write and commit a logical change at a time.

I have no problem with people who do it some other way, it just seems odd to hear people proclaim a particular way to work with git is wrong, because it does not match how they work. Not sure if it's because they can't imagine any other way of working, or they just think all other ways are also wrong.


Just use git-gui


Even if you don't want to go the whole "git add -p" route, at the very least:

1. Use "git add <filename>" manually for the files you want to add.

2. Do a "git status" and "git diff --cached" to review what you are about to commit before committing it.


I quite like my habit of adding stuff with `git add --patch` since it forces me to re-read stuff before I commit it. Graphical git clients like Fork or Sourcetree also allow to commit stuff in chunks.


Agreed. This is the only way I ever add anything.


What's also useful is to set "commit.verbose" to true; then you get the diff in your editor when composing the commit message. This allows reviewing the diff and you can abort the commit if it's wrong.


To add to sibling comments which describe various uses of `git add`, I'll also recommend `git commit -a`, which adds all changes from tracked files (but unlike `git add .`, not untracked files) before committing.


I use fzf in multi-select mode

    fza = "!git ls-files -m -o --exclude-standard | fzf -m --print0 | xargs -0 git add"
That lets you interactively choose which files to stage.


I've started using lazygit and/or tig, these present a UI in the terminal and easily allow staging files. Lazygit also easily allows staging parts of a file; not quite sure about tig.


git gui

Add hunks, write the message, add more hunks, write more message. Once you are happy commit it, close the window. Don't try to use the CLI only because you are a power user who only uses the command line.

If you really can't use the gui (like your on a remote SSH session or something), the non-gui equivalent is git add -p, write your message in another editor, then git commit -F message.txt


Magit also makes this easy. One of the main features of magit, I think.


It also keeps them from polluting git status


How is the git status "polluted" by reporting untracked files that you don't intend to commit?

If anything, I would say that such tricks make git status lie to you. What if you look at the git status and conclude that there are no unchanged files worth tracking and then with that false sense of safety decide to run 'git clean -fdx'? Sounds like an easy way to lose work.

Why is presence of untracked files in git status bothersome to anyone, especially when that is exactly what they are intentionally doing?


if you do a `git clean -f`, untracked files get deleted. Ignoring files that should stick around helps ensure that command can be used nicely. I've never used `git clean -fdx`, not sure why you would use the `-x` flag at all.

(but agreed if you use `-fdx` that doesn't work)


You can also add lines to `.git/info/exclude` for permanent, local only ignores for a specific repo.


Thanks for sharing that idea. I'd simply never thought to do this and I'm adopting this in future.

The main drawback is something I do from time-to-time which is nuking and re-creating directories.


I'm in the habit of just adding these things directly to .gitignore for repos which I'm a core contributor to.

Things like:

    drafts/
    backup/
    *.bak
    ignored/
etc.

I don't really see the downside to just adding them to the tracked gitignore. If other people have a different convention and want to add these files/paths for some reason, it's easily discoverable to them why the files can't be added, and then we can have a discussion about what naming conventions we want.


The only problem I can see it "leaking" some information?

"I see this guy has 'passwords/'" on his local machine, let's somehow sneakily merge new .gitignore to make them available publicly.


sure, if "this guy" does "git add '*'" and neither reviews the commit, nor even does git status to see a file list of it and just pushes it straight to remote. if that's happening i think your repo might have other problems though


I mean this doesn't really leak anything; passwords are usually stored in `.env` files anyway


It's not exactly best practice to store passwords in version control.


yes I'm aware.. this is why .env should always be in .gitignore


> mkdir drafts && echo '' > ./drafts/.gitignore

thanks for the tip, is there a way to hide files at root level? I want to hide some .env. files


That's cool!

You can also put local gitignore rules in .git/info/exclude , but i have a hard time remembering that exact path for some reason.


This is awesome! Will probably use this at some point. Thanks for sharing.


I think this is quite genius, never thought about it before.


This is a fantastic tip, thanks!


brilliant! Thank you!


There's a misunderstanding: "ignoring" means "not tracking as part of version control". But the author overloads the term "ignore" with "not look at it as a .gitignore configuration file".


I'm willing to assume this is not a misunderstanding at all. It's either satirical or pointing out an effect which at first blush might seem counterintuitive. I found it amusing.


I would agree with you.


exactly,

> Therefore, we can see Git ignores .gitignore because its in .gitignore, which means it didn’t ignore .gitignore for instructions.

> Is any of this informative, surprising, or useful? … Absolutely.

it's interesting to notice, but nothing surprising. git isn't supposed to ignore it for instructions


This is a recipe for disaster. Especially if somebody else commits a gitignore in your repository.

If you want an untracked list of files to not track, use .git/info/exclude, it's literally made for this. This is not a hidden feature, it is documented https://git-scm.com/docs/gitignore


If someone else commits a .gitignore in your repository, .gitignore is in your repository and will stay there. .gitignore is only used in deciding if an untracked file should be added. It makes no difference to existing files.


You'll get a conflict when you try and pull I think.


If you do `echo .gitignore > .gitignore` and then somebody elses commit a git ignore, and you pull from that repository, your local .gitignore will be silently overriden, and you might add untracked files if you have the bad habit of `git commit -a`.

    $ for repo in alice bob; git init $repo
    $ git init --bare shared
    $ cd bob
    $ touch foo
    $ git add foo
    $ git commit -m "Initial commit"
    $ git push ../shared
    $ cd ../alice 
    $ git pull ../shared
    $ echo bar > .gitignore
    $ git add .gitignore 
    $ git commit -m "Add gitignore"
    $ git push ../shared
    $ cd ../bob
    $ echo .gitignore > .gitignore
    $ git pull ../shared
    remote: Enumerating objects: 4, done.
    remote: Counting objects: 100% (4/4), done.
    remote: Compressing objects: 100% (2/2), done.
    remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
    Unpacking objects: 100% (3/3), 272 bytes | 272.00 KiB/s, done.
    From ../shared
     * branch            HEAD       -> FETCH_HEAD
    Updating 343eb88..3701fae
    Fast-forward
     .gitignore | 1 +
     1 file changed, 1 insertion(+)
     create mode 100644 .gitignore
    $ cat .gitignore
    bar


This is true (and surprising! and TIL!), but it doesn't seem to have anything to do with the fact that .gitignore is the file being ignored.

Instead, it appears that when merging, the --overwrite-ignore option[1] is the default. It doesn't get overwritten if (instead of "git pull") you do this:

    $ git fetch
    $ git merge FETCH_HEAD --no-overwrite-ignore
    Updating cc80208..0a917b9
    error: The following untracked working tree files would be overwritten by merge:
     .gitignore
    Please move or remove them before you merge.
    Aborting
    $ 
I'm not sure I can see a good justification for this default, really. You could argue that many ignored files are junk or can be recreated, and that's why they got ignored in the first place, so it should be OK to overwrite them. (For example, when working in C, you might ignore *.o for object files.)

But then, if it is something that needs to be merged, then that means somebody bothered to track it, which refutes the idea that it was unimportant or ephemeral or whatever.

----

[1] https://git-scm.com/docs/git-merge#Documentation/git-merge.t...


Fair point but outside of the context of demonstrating this... _why would you actually ever `echo .gitignore > .gitignore`?_

Seems a bit like pointing out that running `sudo rm -rfv /` will let you watch your shell eat your whole system a file at a time.

I could be wildly wrong here, though, and I'm interested in some clarification.


That's my point, that `echo .gitignore > .gitginore` as advertised as "a cool hack" in the article can lead to disasters.


I can't see how you'd interpret this as "advertising a cool hack."

The entire original article:

I initialised a new Git repository, and added a .gitignore file instructing git to ignore .gitignore:

git init . echo ".gitignore" > .gitignore git status

And the result:

On branch trunk No commits yet nothing to commit (create/copy files and use "git add" to track)

Therefore, we can see Git ignores .gitignore because its in .gitignore, which means it didn’t ignore .gitignore for instructions.

Is any of this informative, surprising, or useful? … Absolutely.


nitpick: `git commit -a` does not add untracked files:

           -a, --all
           Tell the command to automatically stage files that have been modified and deleted, but new files you have not told Git about are not affected.


You're right. My bad. I meant `git add -A . && git commit`.


Yo dawg, I heard you like .gitignore, so we put a .gitignore in your .gitignore so you can .gitignore while you .gitignore.


Did you know that Pimp My Ride first aired in 2004. That is 18 years ago. A whole generation of now growns ups don't know the show.


I've seen reruns of that some three years ago. The new generation knows about the show, and shitty cars being made more shitty is timeless.


I miss that show. It was so over the top and encapsulated it's own era so well.


I'm old enough to remember the show Pimp My Ride, but I don't recall Xzibit ever having that "catchphrase" on it.


It wasn't an exact catchphrase, but a common theme of the series was that they would figure out some non-car-related thing that the person liked, and work that into the car. Then Xzibit presenting the car to the person would be like, yo, we heard that you like fish, so we installed this 20 gallon fishtank in your trunk. Thus spawned the meme.

Like the Bear Grylls thing, it's not like he drinks his own urine in every episode, yet it was enough to spawn a meme.


Maybe someone liked cars and he put a car inside their car!


It's a meme now, don't worry, they know - I never watched the show myself


the hen ate the egg


> Is any of this [...] surprising [...] … Absolutely.

Not at all - .gitignore is for ignoring working tree files in git operations, essentially it specifies which files are not part of the repository. It is not for disabling config files and I don't think why anyone would expect that. Putting .git in .gitignore also does not make git think there is no repo because why would it?


The following .gitignore is my favorite way to commit an (almost) empty folder to git:

  # Ignore everything in this directory 
  *
  # Except this file
  !.gitignore
.gitignore can be present in any directory and there is a way to unignore a wildcard


I was looking at someone's dotfiles on Github a while back and they employed this method. Essentially they made their entire home directory a git repo but used gitignore to ignore everything but the dotfiles they wanted to backup. It was a pretty nifty setup


A nifty setup until you run a git command like `git clean -fx` somewhere under your home directory that you think is another git directory but isn't. Happy restore from backups time.


I feel obligated to point out vcsh [1], which is likely already packaged for your operating system.

[1] https://github.com/RichiH/vcsh

The main selling point is that you can set up various git repos for different things. I have one for SSH keys (and no, that does not get pushed anywhere except to my own private server), VIM, neovim, bash, and 'other' (for misc config files like .dir_colors, .gitconfig, etc.).


Another option is to clone the dotfiles repo to your workspace. Then create symbolic links in your home directory. Like:

ln -fs ~/workspace/dotfiles/vimrc ~/.vimrc


Surprising? No. Under that same expectations untracked .gitignores wouldn't work either and we know that's not the case. But there are things that are both obvious once you know about them, but might not otherwise cross your mind. So this is definitely useful and informative.


It's following the instructions to not track changes of that file, if he was expecting it to follow instructions to "treat as if this file isn't a configuration", he's excpecting wrong.


I've considered (overuse of) .gitignore an antipattern for several years now. I've been bitten too many times by it hiding the differences between my local repo and someone else's.

With some projects that ignore build artifacts it's very difficult to know whether you've successfully performed a clean or not.

I don't see a problem with having a dirty repo. It makes it clear how the state of my local directory is different from what's in source control. Isn't that the whole point?

I'm sure I'm missing something, but so far I haven't missed .gitignore.


You can easily use git status --ignored for those cases where you really want to see all the cruft you’ve accumulated. Or you can make an alias to mask status and add that flag, then use git status --ignored=no when you don’t want the behavior.


In my experience, people tend to `git commit -am "nonsense"` no matter how many times I tell them not to. .gitignore at least ensures they don't add too much nonsense to the repository.



This is exactly how I would expect it to work. It's just the title that's confusing.


Yes. I interpreted the title to mean "If you put .gitnore in your.gitignore, the .gitignore stops working". And so I immediatly thought "that's wrong".

Why would anyone thing you wouldn't be able to put .gitignore in your .gitignore?


Something I've always wanted from gitignore: a way to ignore changes to a file that is already present in the repo. So, for example, I can commit a config file that should contain secure credentials with the credentials redacted, and then ignore it so the credentials don't accidentally get pushed from someone's working dir.

For now what I do is ignore the config path and commit an "x.conf.example" file, but that is a bit more of a pain to use.


I think the .conf.example approach is probably better, but the answer to your implied question is here: https://git-scm.com/docs/git-update-index

If you use --assume-unchanged on a file, then git will stop noticing changes at that point. I believe this only applies to your copy of the repo, though.


i'm using Intellij, so for scenarios like this I create a separate "changelist" with name "LOCAL-ONLY" and include passwords and any local config that only applies to me.

That way I can clearly see that these changes don't get commited. You can also put line changes on the same file on different changelists.

Changelists concept is native with P4, but not sure with git. Maybe that's why Intellij only have it coz they've implemented their own on top of git.


It's a good example of how subtle requirements can be and how unlikely it is you could get them right until people are actually using your software in real life.


Are you implying this is a bug?


the opposite : it's exactly how it should work, but how likely is it that someone sitting down to write requirements in advance would have managed to get this right? So many things obvious in hindsight are nearly impossible to anticipate up front.


I disagree, this is just a side effect of good software design. Understanding how git works at the lower level makes this an obvious behavior. There was no PM/PO that sat down and decided this is explicitly what should happen.


It's turtles all the way down :)

I just found out (from @RupertWiser https://news.ycombinator.com/item?id=31420446) about the .git/info/exclude, I find that more interesting


What working at several engie roles teaches you about git:

Don't expect people to know how to gitignore.

Or submodule.

Or tag.

Or interactive rebase.

Or squash.

Or branch.

But when you encounter a team that knows a thing or two, they git fascist and demand you re-enter the Jira ticket number three times in every commit message (in ALL CAPS).


Is it actually surprising though? Doesn't seem to me, you quickly figure out in regular usage that it's not the committed content of this file that matters, and this is just a natural consequence.


Does what it says on the tin! Probably useful if you want a seperate dev-preferenced-specific gitignore in a subfolder. For example to ignore editor droppings for an editor that only you use.


I'm delighted by this. I'm not entirely sure why but I am.


That made my morning, thanks :)



pip uninstall pip also works, I found out the hard way.


Ha! This is the tech savvy version of that gif where a old man drags the "my computer" icon to the trash and then see the computer disappearing in front of his eyes.


Love it. Git obviously ignores the instructions on what to ignore that tell it to ignore instructions on what it ignore.


Why on earth is there a picture of a school girl in the upper right of the page?!

It feels creepy, and unprofessional. I've seen this sort of thing before and I really don't understand it.

Can anyone explain this phenomenon?


[EDIT:] See https://rubenerd.com/about/#mascot and https://rubenerd.com/anime-restore-my-blog/ . Looks like a typical harmless Anime nerd to me. [/EDIT]

Not just any schoolgirl, but a schoolgirl drawn in "Manga"[1] or "Anime"[2] style, AFAICS. Lots of people are Manga and/or Anime fans, and many of those perhaps to such an extent that they feel it's a major part of their identity, so they want to show it some way. And a lot of those Japanese comics and animated films just happen to have young people of both sexes as their protagonists, so of course there will be schoolgirls in them. And much of that is, as I've understood it, "perfectly ordinary" comics and animations, like any "Young Adult" literature in Western culture; no more (explicitly) sexualised than Harry Potter or Star Wars.

So not necessarily "creepy", in the sense of sexualising schoolgirls... But yeah, from what (little) I understand of Japanese popular culture, sexualising schoolgirls is a pretty big part of current more-or-less accepted Japanese social mores, which is reflected in Manga and Anime too; see the whole phenomenon of "Hentai".[3] And I suppose there's a whole lot of Manga and Anime that is just titillating -- not quite explicitly, but borderline sexualised.

I have no idea about the proportions between the categories: I read quite a lot of Marvel and DC comics (and, ahem, some porn -- but those were wildly different things back then) in my youth, but that's so long ago that it was before the rise of Japanese popular culture phenomena in the West, so I've never been into any of that stuff. For all I know, the "creepy" stuff could be a majority of it; or it could be just a comparatively tiny fringe phenomenon.

So, summing up: Not necessarily creepy, but certainly gives at least me vibes of "potentially rather creepy". But, in the absence of any proof to the contrary, I guess I'd go with the guidelines and assume the best.

___

[1]: https://en.m.wikipedia.org/wiki/Manga

[2]: https://en.m.wikipedia.org/wiki/Anime#Genres

[3]: https://en.m.wikipedia.org/wiki/Hentai (NSFW![4])

[4]: Well, depending.


How much ignore would a git gitignore ignore if that gitignore was a git?


Kinda works w/ mercurial.

$ hg init foo

$ cd foo

$ echo ".hgignore" > .hgignore

$ hg st

$ rm .hgignore

$ touch .hgignore

$ hg st

? .hgignore

... apart from the ignored folder. Mercurial can't do that.


Git has to read .gitignore to get the instruction to ignore .gitignore, but since it's already read .gitignore, it can't go back and ignore .gitignore.


Git also ignores things you add into the `.git` folder (where your git history lives).

You can use that as a place to store things quickly rather than say, doing a stash.


Thanks, I hate that I know this now.


Don't do this. It's a quick way to corrupt your repository.


When this happens, I usually create ./tmp/ and add it to .gitignore.


This is also a bad decision because now you have to tip toe around the modified .gitignore.


You can add it to .git/info/exclude. That's a gitignore that's repo-local.


yep, that's the best solution.


Only proves that devs are susceptible to dad humor.


Hi, author here. Yes this was just a bit of silly/pointless fun, though people overanalysing it here is just as delightful.


If it does, that's impressive.

Someone should generalize their approach to solve the halting problem.


git couldn't take .gitignore into account when deciding to look at .gitignore, even if it wanted to, because it's not read .gitignore yet. It's like "Is 'No' the answer to this question?"


Git IS looking at it. It's just nod adding it or showing it in the status. There's a difference between reading/parsing and adding/committing.


Well. It does what you told it to do, right?


I was ignoring it!


r/WordAvalanches




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: