0

I have deeply nested files that I would like to include in source control and have git track them.

Example is:

Projects/
    .git/
    StrategicProject/
        SpecificProject1/
            Method1/
                doc/
                   *.tex
    .gitignore

In each of the various folders there are other files/folders that I would not like to track. I only want to track, say, all of the .tex files in Projects/StrategicProject/SpecificProject1/Method1/doc/

As of now, to accomplish this, I have in my .gitignore file:

StrategicProject/* # ignore everything under this, exceptions below
!StrategicProject/SpecificProject1/ # don't ignore this
StrategicProject/SpecificProject1/* # ignore everything under this, exceptions below
!StrategicProject/SpecificProject1/Method1/ # don't ignore this
StrategicProject/SpecificProject1/Method1/* # ignore everything under this, exceptions below
!StrategicProject/SpecificProject1/Method1/doc/ # don't ignore this
StrategicProject/SpecificProject1/Method1/doc/* # ignore everything under this, exceptions below
!StrategicProject/SpecificProject1/Method1/doc/*.tex # don't ignore this

The above works, but is prone to error when I create a new folder structure in my working directory. It is also quite cumbersome. To track one set of .tex files in a nested folder needs creation of 8 lines in the .gitignore file. A fellow-SO user created an web-app to ease this specific difficult activity. See here

While that app works fine for now, it only works over the web. More generally, is there a gui app, that works offline (without having to use the internet), that can take a look at my folder structure and allows me to check/uncheck boxes (as part of its user interface) corresponding to files/folders and based on that automatically generate the appropriate .gitignore file?


ETA:

I use VSCode's default Git interface. While that does provide option to right click on a file and add it to .gitignore, that is not what I would like. I would like to not ignore a specific deeply nested set of files. I am open to trying out other editors for this task.

SymboLinker
  • 884
  • 6
  • 15
Tryer
  • 3,580
  • 1
  • 26
  • 49
  • Could you add information about the editor that you’re using? Maybe there is an extension available for the editor. – SymboLinker Apr 03 '22 at 17:49
  • 4
    You aren't restricted to a single `.gitignore` file. Entries in `./.gitignore` override entires in `../.gitignore`. – chepner Apr 03 '22 at 17:56
  • 1
    Or try something like `!StrategicProject/**/*.tex`. – Ron van der Heijden Apr 03 '22 at 18:38
  • 1
    @Tryer Could you change the title from “Easier way to create a .gitignore file” to something like “Gitignore: easier way to not-ignore a deeply nested set of files”? It seems to reflect better what specific case you meant and what people might search for. – SymboLinker Apr 04 '22 at 07:09

3 Answers3

1

There is one useful, albeit somewhat computationally expensive, trick you can use. As you've seen, if you ignore a directory, Git never looks inside the directory, making it impossible to un-ignore files nested deeper under the directory. This generally saves Git a lot of time: git status has to recursively look at everything in the working tree, except that every time it hits an ignored directory, it doesn't have to look at anything there. Since lstat-ing each entity in each directory in a recursive travel of the working tree is usually the slowest part of a Git working-tree operation, bypassing some of these calls helps out a lot.

Still, you can prevent Git from bypassing directories at all by simply making sure that !*/ is the last entry in each .gitignore file. No matter where Git is in its traversal, this last entry says if you encounter a directory, look inside it. Now you no longer need careful and explicit stuff like:

StrategicProject/*
!StrategicProject/SpecificProject1/
StrategicProject/SpecificProject1/*
!StrategicProject/SpecificProject1/Method1/
StrategicProject/SpecificProject1/Method1/*
!StrategicProject/SpecificProject1/Method1/doc/
StrategicProject/SpecificProject1/Method1/doc/*
!StrategicProject/SpecificProject1/Method1/doc/*.tex

as you can simply list files that should be ignored; Git will always be searching everywhere.

A proposed future enhancement (with no implementation)

I think Git should automatically insert exceptions as needed. That is, we should be able to write:

*.o
generated-docs
!generated-docs/*.in

and Git should figure out that this "means", e.g.:

generated-docs/*
!generated-docs/*.in

That is, the fact that we've excepted something within generated-docs means that Git should look inside generated-docs, even though the default is to skip over files that may be found there.

torek
  • 448,244
  • 59
  • 642
  • 775
1

As far as creating and maintaining the .gitignore you might look at plugins for your IDEs.

For example, with IntelliJ/PyCharm, this might be GUI enough for what you are trying to do: https://plugins.jetbrains.com/plugin/7495--ignore

astrochun
  • 1,642
  • 2
  • 7
  • 18
  • The title is no longer “Easier way to create a .gitignore file” and now better reflects the problem, which is not about creating a `.gitignore` file, so you may want to delete this answer. – SymboLinker Apr 06 '22 at 09:46
  • If you look at the feature list for this plugin, you will see: "Add a selected file/directory to Gitignore rules from the popup menu" and "Generate Gitignore rules basing on [GitHub's templates collection][github-gitignore]", so I still think this is a good solution – astrochun Apr 06 '22 at 13:24
1

For your sample by far the simplest is

StrategicProject/**
!StrategicProject/**/
!StrategicProject/SpecificProject1/Method1/doc/*.tex

which I'd pronounce "recursively exclude everything in StrategicProject but still scan all the directories for further exceptions, like these tex files".


Unless or until you've got a remarkably large and complicated source tree it's often more compact to put something like

!*/
build/

at the end of your .gitignore to simply shut off all directory exclusions except for example here any build directory, I'd call that idiomatic, something people who've seen it before immediately understand.

jthill
  • 55,082
  • 5
  • 77
  • 137