3

My Actual Question

I would like that only the .gitignore file in the root of my directory structure ignore files, i.e, the .gitignore files in subdirectories shouldn't ignore files.

To be clear

I don't want to gitignore other .gitignore files. I want them to be commited to git but I don't want them to gitignore other files.

Specific use-case

Let's say I want to commit a boilerplate project structure to git. Let's say the project structure looks like this:

project-root/
│
├── boilerplate/
│   ├──directory/
│   ├──some-other-directory/
│   ├──.env
└── └──.gitignore // Has a line ".env" which will ignore the .env file in this directory 
│
├── boilerplate2/
│   ├──directory/
│   ├──some-other-directory/
│   ├──.env
└── └──.gitignore
│
└── .gitignore // The .gitignore in root 

Now the .gitignore file in boilerplate directory will gitignore .env which I don't want. How can I stop nested .gitignore files from taking action?

What I tried?

I tried the negation (!) operator in the main .gitignore file. For the sample structure above, it's equivalent to !boilerplate/.env. The .gitignore in root simply doesn't have any power over the .gitignore file in the specified directory. It doesn't override it. Why does it work like that? Is there a workaround?

Edit:

VonC suggests to automate that using scripts, but that's not the question. The question is, how to do that using only .gitignore, if it is possible at all.

Shivang Kakkar
  • 421
  • 3
  • 15

1 Answers1

1

Now the .gitignore file in boilerplate directory will gitignore .env which I don't want.

It will not.

If boilerplate/.env is already added (git add --force) and committed, any change to that particular .env file would still be detected, not ignored.

The OP adds:

But when I do git status, git ignores boilerplate/.env due to boilerplate/.gitignore (which isn't commited either)

Then, yes, it will ignore all .env, unless they are themselves versions.


The .gitignore in root simply doesn't have any power over the .gitignore file in the specified directory.
It doesn't override it.

That follows the precedence rules for a .gitignore:

Patterns read from a .gitignore file in the same directory as the path, or in any parent directory (up to the top-level of the working tree), with patterns in the higher level files being overridden by those in lower level files down to the directory containing the file.


In your case, I would:

  • keep the .env rule
  • version only .env.tpl template files with default initial value
  • add a .gitattributes file with a smudge content filter driver script declaration for *.tpl

That smudge script (for instance, 'script_tpl', which can be versioned as well) would be a bash script (which does work even on Windows, since Git for Windows comes with bash.exe):

#!/bin/bash

file="${f%.tpl}" # ex: .env.tpl => .env
if [[ ! "${file}" ]]; then cp "${f}" "${file}"; fi

I would add an senv script to be executed by any collaborator using a local cloned of the repository, in order to register automatically the content filter driver. It would include:

#!/bin/bash
DIR="$( cd "$( dirname "$(readlink -f "${BASH_SOURCE[0]}")" )" && pwd )"
# assuming the smudge script is at the root of the repository
which script_tpl || export PATH=${PATH}:${DIR} 
git config --global filter.tpl.smudge 'script_tpl'

That way, any time you switch branch, the smudge script with check if .env does exist and, if not, will create one (which will be ignored by all the various .gitignore files)

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Neither `.env` not `boilerplate/` is commited. Only the root `.gitignore` is commited. But when I do `git status`, git ignores `boilerplate/.env` due to `boilerplate/.gitignore` (which isn't commited either) – Shivang Kakkar Mar 08 '22 at 15:04
  • @StarkProgrammer OK. I have updated my answer to propose an alternative approach. – VonC Mar 08 '22 at 16:09
  • If I understand you right, the first thing you say is to rename `.env` to `.env.tpl` as a template file. Then you provide a script that creates a `.env.tpl` if it doesn't exist. This whole thing isn't needed if I rename the file, because `.gitignore` will not ignore `.env.tpl` anyway. Then I can rename the file to `.env`. But that defeats the purpose of question as it should relate to `How to do that using .gitignore`, and not `bash script` – Shivang Kakkar Mar 08 '22 at 19:14
  • @StarkProgrammer to create .env, not to create .env.tpl. – VonC Mar 08 '22 at 19:45