URI:
        _______               __                   _______
       |   |   |.---.-..----.|  |--..-----..----. |    |  |.-----..--.--.--..-----.
       |       ||  _  ||  __||    < |  -__||   _| |       ||  -__||  |  |  ||__ --|
       |___|___||___._||____||__|__||_____||__|   |__|____||_____||________||_____|
                                                             on Gopher (inofficial)
  HTML Visit Hacker News on the Web
       
       
       COMMENT PAGE FOR:
  HTML   Don't create .gitkeep files, use .gitignore instead (2023)
       
       
        phelm wrote 5 hours 56 min ago:
        could you just add "!.gitkeep" to .gitignore?
       
        JuniperMesos wrote 7 hours 15 min ago:
        Maybe the correct thing to do is to modify git so that it can track an
        otherwise-empty directory and then never have to worry about this
        problem again. Is there a reason why this is hard to integrate into
        git's existing model of the filesystem?
       
          1718627440 wrote 2 hours 40 min ago:
          Git only tracks files not directories, so yeah you would need to
          change a lot.  It is also unclear what the semantics should be.  What
          is with a directory that is tracked as r--, but then files get added?
       
          lucketone wrote 6 hours 50 min ago:
          1. Nobody sees this as a big issue.
          
          2. As-is situation is good enough.
          
          3. I guarantee that you will have colleagues that will accidentally
          add empty dirs. (I definitely have seen when they accidentally add
          built artefacts; dirs would be lesser issue as they would not
          increase repo size by much, but still)
          
          4. Actually only first two reasons matter, but for nitpickers there
          would be also a bit dishonest but formally correct pointing to some
          doc saying that it is file or content tracker (and formally directory
          is not a content)
       
        Joker_vD wrote 19 hours 31 min ago:
        Why did Git decide to have no means to track fully empty directories?
        Like, I understand that e.g. doing "git rm *" inside a directory should
        probably delete this directory from the repository as well (although
        "git rm -r dir_to_delete" exists so...) but why not have a command to
        explicitly force a directory to be tracked, whether it's empty or not?
       
          lofaszvanitt wrote 17 hours 59 min ago:
          Why didn't anyone implement it? And an option to keep attrs, rights,
          owners, groups etc.
       
        globular-toast wrote 19 hours 35 min ago:
        I find this use of .gitignore far more common than .gitkeep. I did see
        one js tool creating them and did wonder what it was about.
       
        hollasch wrote 20 hours 37 min ago:
        My preference is to use the build system to create built artifacts, and
        I consider the build/ directory to be a built artifact. Wrangling Git
        into doing the first fundamental build step is off, in my opinion.
        
        However, if you disagree, my favorite "Git keep" filename is
        "README.md". Why is this otherwise empty directory here, how does it
        fit into my source tree, how is it populated, and so forth.
        
        One of my pet peeves with the latest AI wave is the time we spend
        creating files to help AI coding agents, but don't give the same
        consideration to the humans who have to maintain and update our code.
       
          taftster wrote 19 hours 33 min ago:
          Both points here are appreciated. One that a README file as a
          "placeholder" for a directory gives the opportunity to describe why
          said empty directory exists. I would be slightly concerned though if
          my build process picked up this file during packaging. But that's
          probably a minor concern and your point stands.
          
          Additionally, the AI comment is ironic as well. It's like we're
          finally writing good documentation for the sake of agents, in a way
          that we should have been writing all along for other sentient
          consumers. It's funny to see documentation now as basically the horse
          instead of the cart.
       
        zahlman wrote 20 hours 48 min ago:
        Oh, man, I'd forgotten about these negated .gitignore patterns
        entirely. It actually hadn't occurred to me that they could override
        the behaviour of ignoring empty directories.
        
        This is potentially actually useful for me, because I have a project
        with test data that consists of miniature filesystem sub-trees — that
        should include empty directories to ensure edge cases are covered. I've
        been zipping them up and having the test harness unpack them in the
        test environment, but that's an unnecessary extra point of failure (and
        it stuffs undiffable binary files into the commit history).
        
        Edit: Ah, no, if this doesn't work from the project-global .gitignore
        (specifying a folder to keep, even though it's empty and doesn't even
        have its own .gitignore) then it doesn't solve the problem. :(
       
          ivan_gammel wrote 18 hours 52 min ago:
          Why not having a txt file with indented tree, a bootstrap function
          that parses the file and creates the tree and a test for that
          function?
          
          You will have proper diff for the tree this way.
       
            zahlman wrote 17 hours 19 min ago:
            Well, partly because I already have a tool similar to that in mind
            as a separate project :) (The files also need to have certain
            content, so I need something a bit more complex that can specify
            that.)
            
            But mainly because, as you acknowledge, that process needs its own
            tests. Basic unzipping functionality is already tested for me.
       
        prmoustache wrote 1 day ago:
        How about fixing your build scripts and makefiles instead? Convoluted
        solutions for a non-existing problem.
       
        jiffygist wrote 1 day ago:
        I don't understand why would you ever want to have an empty directory.
        Besides if I see a directory named "build" I expect to be able to just
        nuke it any time without consequences.
       
        deafpolygon wrote 1 day ago:
        Claims the wrong thing is common and tells you not to do it , then
        tells you to do the right thing.
        
        I have never heard of .gitkeep before today, and if you need an empty
        directory to exist, use a build script.
        
        Don’t do stupid workarounds.
       
        leecommamichael wrote 1 day ago:
        This doesn’t solve a problem.
       
        dmarinus wrote 1 day ago:
        if possible you can also just create directories if they don't exist
        (ie. mkdir -p) and just exclude it in your root .gitignore (ie. ignore
        all build directories). That would safe you from creating multiple
        .gitignore files.
       
        cyberrock wrote 1 day ago:
        File filtering is so delightfully broken everywhere. Everytime I
        revisit git, rsync, restic, borg, etc. something just goes wrong
        somewhere on this seemingly simple task, and SO and thus LLMs are
        filled to the brim with slightly wrong answers. We need a xkcd/927
        because it can't possibly get any worse.
       
        GreenDolphinSys wrote 1 day ago:
        .gitkeep is intuitive and easy to understand. Unignoring a .gitignore
        is not intuitive. This falls squarely into "clever optimization tricks
        that obscure intent and readability". Don't do things like this.
        
        It's not that hard to update a .gitignore file every now and then.
       
          throwaway290 wrote 10 hours 53 min ago:
          .gitkeep is not a standard and also because it starts with dot it is
          hidden by default in file listings which makes it even less
          intuitive.
       
          rswail wrote 1 day ago:
          Then put a comment in the .gitignore.
          
          Using the actual tools built in to git directly removes steps in the
          process, which is always a good thing, it's documented as part of the
          git documentation, so you don't have to create a wiki page explaining
          why there is a ".gitkeep" file that git doesn't recognize itself.
          
          Saying "It's not that hard..." is fine for projects with a few
          contributors but does not scale.
       
            trelbutate wrote 14 hours 9 min ago:
            If someone doesn't know what .gitkeep is they should be able to
            derive from the name that it's some special file intended for git. 
            
            If they then google it they will immediately find out what it's
            for.  
            Yes, git itself has no concept of it but it's common enough that
            there's plenty documentation on the internet.
       
              rswail wrote 11 hours 20 min ago:
              Yes, because relying on google-fu is the way to ensure your build
              environment is consistent. /s
              
              .gitkeep is explicitly not intended for git, because git doesn't
              recognize it at all.
              
              Having the .gitignore, which is actually recognized by the git
              tools, means you can rely on the .gitignore functionality,
              including ensuring that things other than the .gitignore cannot
              be added to the repo.
       
        beej71 wrote 1 day ago:
        What am I missing about this use case? It seems like you should just
        create `build/.gitignore` with `*` in it and `add -f` it and be done.
        
        I'd use `.gitkeep` (or an empty `.gitignore`) if I needed to commit an
        otherwise-empty hierarchy. But if I'm going to have a `.gitignore` in
        there anyway, it's not empty.
        
        > The directory is now “tracked” with a single, standard file that
        will work even after renames.
        
        Does `.gitkeep` not work after renames? Or `.gitignore`?
        
        So I am missing something. :)
       
          aezart wrote 1 day ago:
          It makes the behavior more obvious from simply looking at the file,
          for one thing, and it means you can just lump it into your next `git
          add -A` without needing to handle it specially.
       
          KPGv2 wrote 1 day ago:
          That's a hack. What you should do is a .gitignore with * and then a
          whitelist of paths like src/**/*.
          
          If you rely on `add -f` you will forget to commit something
          important.
          
          For example, for a tree sitter grammar I developed a couple years
          ago, here is my .gitignore:
          
          ```
          
          # Ignore everything
          
          *
          
          # Top-level whitelist
          
          CHANGELOG.md
          
          # Allow git to see inside subdirectories
          
          !*/
          
          # Whitelist the grammar and tests
          
          !/grammar/*.js
          
          !/test/corpus/*.txt
          
          # Whitelist any grammar and tests in subdirectories
          
          !/grammar/**/*.js
          
          !/test/corpus/**/*.txt
          
          ```*
       
            beej71 wrote 1 day ago:
            > If you rely on `add -f` you will forget to commit something
            important.
            
            But isn't the idea in TFA to blacklist the entire `build/` tree? We
            don't want to add anything there.
       
              KPGv2 wrote 17 hours 9 min ago:
              I have much more than `build` to block. IDE-specific stuff,
              smalls scripts I write to help me (and go in root) but don't
              belong in the repo, etc.
              
              And what if for some reason you accidentally copied a big Linux
              ISO to that directory by mistake. Without a whitelist, you might
              accidentally add and commit a 700MB file to your main and not
              even notice. What a pain when you push later and have to git
              amend, rebase -i, etc.
              
              Better to block all except whitelist. The only downside is it's
              less obvious how to do this than allowing all except blacklist to
              new git users.
       
        OptionOfT wrote 1 day ago:
        For me, I put them in directories that have to be there, because the
        underlying code doesn't create the directory, and without it, it fails.
        
        Another example is where you want an empty directory mounted in Docker.
        If the directory is not there it is created with root permissions and
        then I can't even look into it.
       
        kderbyma wrote 1 day ago:
        Arent Gitkeep files specifically for empty folders that are intended to
        be there?
        
        That is what I have always used them for....
       
          wlonkly wrote 17 hours 46 min ago:
          .gitkeep has no meaning to Git, only to us meatsacks that recognize
          the name. As far as Git is concerned, it's just another file.
       
        Kuraj wrote 1 day ago:
        If you need to do this, I think .gitkeep communicates intent better.
        You don't need to document it or risk it being removed as thought to be
        a left over.
       
        jkubicek wrote 1 day ago:
        I'm not sure if I'm the one to blame for this or not, but the earliest
        reference to ".gitkeep" I can find online is my 2010 answer on Stack
        Overflow: [1] If this is all my fault, I'm sorry.
        
  HTML  [1]: https://stackoverflow.com/a/4250082/28422
       
          kazinator wrote 11 hours 44 min ago:
          Dummy empty files such as .keepme were used in CVS repositories for
          exactly the same purpose, and probably other version controls systems
          long before Git existed.
          
          The Peter Cederqvist manual recommended the practice.
          
          Here is a 1993 dated copy someone left hosted: [1] The paragraph
          which recommends the .keepme files is: [1] #SEC63
          
          "if you want an empty directory then put a dummy file (for example
          `.keepme') in it to prevent `-P' from removing it."
          
  HTML    [1]: https://www.astro.princeton.edu/~rhl/cvs/cvs.html
  HTML    [2]: https://www.astro.princeton.edu/~rhl/cvs/cvs.html#SEC63
       
          hn92726819 wrote 1 day ago:
          Yeah... I don't think you were wrong. Having 100 tiny gitignores
          makes finding out why something is excluded annoying. Our policy is
          one root level gitgnore and gitkeeps where required.
          
          Some devs will just open the first gitignore they see and throw stuff
          into it. No thank you.
       
            taftster wrote 19 hours 39 min ago:
            I agree with you. Empty .gitignore would be a "smell" to me.
            Whereas .gitkeep tells me exactly what purpose it serves. I like
            the semantic difference here that you describe. I don't like when
            multiple .gitignore files are littered throughout the codebase.
       
            nickysielicki wrote 20 hours 33 min ago:
            > Having 100 tiny gitignores makes finding out why something is
            excluded annoying. Our policy is one root level gitgnore and
            gitkeeps where required.
            
            This is not a complicated or important enough problem to justify a
            team-wide policy. Let it work itself out naturally. [1] makes it
            trivial to debug repo-wide gitignore behavior.
            
  HTML      [1]: https://git-scm.com/docs/git-check-ignore
       
              lucketone wrote 7 hours 0 min ago:
              We could say that practically all problems would work them self
              out one way or another.
              
              I heard facebook allows any language as long as you have packaged
              it neatly with all required build chain. (I.e. Even a choice of
              language works out)
              
              Some lowest common denominator will be reached. (1 :) )
              
              On the other hand: Are we happy with the lowest or do we want to
              aim higher?
       
            zahlman wrote 20 hours 46 min ago:
            I like to make a .local folder at the top of the project, which
            contains a .gitignore that ignores everything. Then I can
            effortlessly stash my development notes there without affecting the
            project .gitignore or messing around within the .git directory.
       
              beAbU wrote 6 hours 9 min ago:
              Why not put '.local' in your toplevel gitignore, and not commit
              an empty .local folder up to the forge?
       
            predkambrij wrote 20 hours 54 min ago:
            I share your view. .keep and .gitignore are different things.
            Having one .gitignore caputuring everything is less mental load.
       
          pilaf wrote 1 day ago:
          This Rails commit from May 2010 mentions gitkeeps and it's a few
          months older than your SO post, so it seems you're absolved from
          guilt:
          
  HTML    [1]: https://github.com/rails/rails/commit/785493ffed41abcca0686b...
       
          selridge wrote 1 day ago:
          This is delightful. Accidental load-bearing SO post.
       
            jkubicek wrote 1 day ago:
            It's especially funny since my answer is wrong anyway! The other
            top answer is much better. I did get a lot of early SO brownie
            points from that one answer though.
       
        8cvor6j844qw_d6 wrote 1 day ago:
        Is .gitkeep an established convention somewhere? I'm curious where the
        name originated.
       
          abustamam wrote 1 day ago:
          Seems to originate form this SO post
          
  HTML    [1]: https://stackoverflow.com/a/4250082/28422
       
        Arrowmaster wrote 1 day ago:
        The author makes a very common mistake of not reading the very first
        line of the documentation for .gitignore.
        
          A gitignore file specifies intentionally untracked files that Git
        should ignore. Files already tracked by Git are not affected; see the
        NOTES below for details.
        
        You should never be putting "!.gitignore" in .gitignore. Just do `echo
        "*" > .gitignore; git add -f .gitignore`. Once a file is tracked any
        changes to it will be tracked without needing to use --force with git
        add.
       
          xg15 wrote 1 day ago:
          I think I'd prefer to have all ignores and un-ignores explicitly in
          the file and not have some of them defined implicitly because a file
          was added to tracking at some point.
       
            1718627440 wrote 2 hours 47 min ago:
            But ignore files are only for untracked files anyway.  Maybe you
            want them to specify what can be in the repo and what not, but this
            is not how Git works.
       
          BlackFly wrote 1 day ago:
          The point of that line is to robustly survive a rename of the
          directory which won't be automatically tracked without that line. You
          have to read between the lines to see this: they complain about this
          problem with .gitkeep files.
       
          nebezb wrote 1 day ago:
          This is functionally the same. What do you mean by “you should
          never”? According to who?
          
          What an arrogant take. This is preference. Don’t mistake it for
          correctness.
       
          smrq wrote 1 day ago:
          Why is this approach better than the author's?
       
          AgentME wrote 1 day ago:
          If you have a project template or a tool that otherwise sets up a
          project but leaves it in the user's hands to create a git repo for it
          or commit the project into an existing repo, then it would be better
          for it to create a self-excepting .gitignore file than to have to
          instruct the user on special git commands to use later.
       
          ekipan wrote 1 day ago:
          Yeah, this. Plus a mistake from the article:
          
            $ echo '*\n!.gitignore' > build/.gitignore
          
          The \n won't be interpreted specially by echo unless it gets the -e
          option.
          
          Personally if I need a build directory I just have it mkdir itself in
          my Makefile and rm -rf it in `make clean`. With the article's scheme
          this would cause `git status` noise that a `/build/` line in a root
          .gitignore wouldn't. I'm not really sure there's a good tradeoff
          there.
       
            Aaron2222 wrote 1 day ago:
            > The \n won't be interpreted specially by echo unless it gets the
            -e option.
            
            Author's probably using Zsh, which interprets them by default.
       
              _kst_ wrote 11 hours 31 min ago:
              If you want any kind of non-trivial formatting, use the printf
              command, not echo.
       
        peter-m80 wrote 1 day ago:
        No, thanks
       
        macote wrote 1 day ago:
        The author is misusing .gitkeep. I use it to keep source code folders
        that don’t contain any code yet, but whose structure is already
        defined.
       
          CGamesPlay wrote 1 day ago:
          You can rename `.gitkeep` to `.gitignore` and both be happy in that
          case.
       
          xyzzy_plugh wrote 1 day ago:
          Truly, what purpose does this serve? Defining a hierarchy without
          using is injecting immediate debt. Just introduce it when stuff goes
          there! If you really insist then at least put something in the
          folder. It doesn't take much effort to make the change at least a
          tiny bit meaningful.
          
          Better yet just do the work. If you want make a commit in a branch
          that's destined to be squashed or something, sure, but keep it away
          from the shared history and certainly remove it when it's not needed
          anymore.
       
            abustamam wrote 1 day ago:
            I play around with ComfyUI on my computer to make silly images.
            
            To manually install it, you must clone the repo. Then you have to
            download models into the right place. Where's the right place?
            Well, there's an empty directory called models. They go in there.
            
            IMO that's an effective use of gitkeep.
       
              xyzzy_plugh wrote 1 day ago:
              It's not.
              
                  echo >repo/models/README.md "this is the directory you place
              models in"
              
              Is infinitely better.
       
                abustamam wrote 23 hours 12 min ago:
                It could be better sure. In fact I think they use a file called
                PUT_MODELS_HERE not gitkeep [1] But in any case, that
                instruction was already in the readme as well.
                
  HTML          [1]: https://github.com/Comfy-Org/ComfyUI/blob/master/model...
       
            akoboldfrying wrote 1 day ago:
            > Truly, what purpose does this serve?
            
            The simplest answer is that sometimes other existing software that
            I need to use treats an empty directory (or, hopefully, a directory
            containing just an irrelevant file like .gitkeep) differently from
            an absent directory, and I want that software to behave in the
            first way instead of the second.
            
            A more thorough answer would be: Filesystems can represent empty
            directories, so a technology that supports versioned filesystems
            should be able to as well. And if that technology can't quite
            support fully versioned filesystems -- perhaps because it was never
            designed with that goal in mind -- but can nevertheless support
            them well enough to cover a huge number of use cases that people
            actually have, then massaging it a bit to handle those rough edges
            still makes sense.
       
              xyzzy_plugh wrote 1 day ago:
              Legitimately asking, please share the name of software that
              expects/requires an empty directory and interprets .gitkeep in
              this way, but chokes on a README file.
              
              Many filesystems cannot represent empty directories. Many archive
              formats also do not. I don't think this a problem in practice. I
              find this argument extremely weak.
       
                akoboldfrying wrote 17 hours 2 min ago:
                > please share the name of software that expects/requires an
                empty directory and interprets .gitkeep in this way, but chokes
                on a README file.
                
                Every mail server since postfix supports Maildir, in which
                every email is a file in one of 3 subdirectories (tmp, new or
                cur) of a user directory. If there's no jbloggs/tmp dir,
                postfix will think user jbloggs does not exist. So if you want
                to take a restorable snapshot of this with git, there needs to
                be a file there. I don't know if jbloggs/tmp/README would cause
                a problem, because I don't know how postfix will treat the
                presence of a file with a name that violates its expected
                syntax (which includes a timestamp and other metadata), but
                what I do know is that, after running `git clone any-repo`, I
                can safely delete every .gitkeep file to restore the system to
                its original state without having to understand that repo in
                detail -- while I cannot safely delete every README file.
                That's because the commonly understood semantics of .gitkeep is
                "I exist solely to shoehorn this empty dir into git", which
                does not apply to other files.
                
                > Many filesystems cannot represent empty directories
                
                Your turn -- name one.
       
                Joker_vD wrote 19 hours 29 min ago:
                > Many filesystems cannot represent empty directories.
                
                Like which ones? And how does mkdir(1) work on such
                filesystems?
       
        suralind wrote 1 day ago:
        I want to like it, but I pretty much always have a "cleanup" script
        that just deletes the entire directory and touches a .gitkeep file.
        Obviously an even better pattern is to not have any .gitkeep files, but
        sometimes they are just handy.
       
        cortesoft wrote 1 day ago:
        Not sure why you can’t just have your build script create the build
        directory?
       
          twic wrote 21 hours 7 min ago:
          Usually, you can. But occasionally you get mildly defective tools
          that require some directory to exist, even though it's empty. It's
          easier to add a gitkeep than fix them.
       
            taftster wrote 19 hours 30 min ago:
            This used to happen a lot. But I don't think that many modern
            builders require existing directory these days.
            
            Your point is valid though. It would be much preferable to include
            build/ in your root .gitignore so that the directory is never
            tracked.
       
          xg15 wrote 1 day ago:
          There may be other directories. I think it's useful to be able to see
          the entire directory structure of a repo when you check it out, and
          not just after running some scripts.
       
          andybak wrote 1 day ago:
          Because you might not have a build script?
       
            cortesoft wrote 1 day ago:
            Then how is anything ending up in the build directory?
       
            drdec wrote 1 day ago:
            Then why do you need a build directory?
       
              himata4113 wrote 1 day ago:
              qemu: mkdir build; cd build; ../configure, some projects are like
              that
       
                xigoi wrote 1 day ago:
                Why can’t the configure script do this?
       
                  1718627440 wrote 2 hours 42 min ago:
                  Because the standard for configure scripts says that the
                  current directory at invocation is the build directory and
                  the location of the configure script is the source directory.
                   You are expected to be able to have multiple build
                  directories if you want them.  If you have written your
                  configure script correctly, than in-tree builds (srcdir ==
                  builddir) also work, but most people don't want that anyway.
       
                  hn92726819 wrote 1 day ago:
                  You can. But this makes intent clear. If you clone a git repo
                  and see build/ with only a gitkeep, you are safe to bet your
                  life savings on that being the compiled assets dir.
       
        yjftsjthsd-h wrote 1 day ago:
        I'm confused. Having a file gitignored doesn't stop you from committing
        it; AFAIK you can just
        
          touch build/.gitkeep
          git add build/.gitkeep
          git commit build/.gitkeep
        
        And that's it? There's no need to exclude anything.
       
          williadc wrote 1 day ago:
          The idea is that you don't want to check-in any builds.
       
            yjftsjthsd-h wrote 1 day ago:
            Sure, so gitignore build/ or whatever. But you don't need to
            unignore .gitkeep
       
              akerl_ wrote 1 day ago:
              The idea is that instead of adding a nonsense file, you use the
              native .gitignore functionality.
              
              ".gitkeep" is just a human thing; it would work the same if you
              called it ".blahblah".
              
              So their pitch is that if you want to explicitly keep the
              existence of the directory as a committed part of the repo,
              you're better off using the actual .gitignore functionality to
              check in the .gitignore file but ignore anything else in the
              directory.
              
              I don't find it amazingly compelling; .gitkeep isn't breaking
              anything.
       
                dwattttt wrote 1 day ago:
                This still confuses me. Do you mean to say "use the .gitignore
                functionality, and check in the .gitkeep file"?
       
                  akerl_ wrote 1 day ago:
                  No. Use a .gitignore instead of .gitkeep. Instead of checking
                  in build/.gitkeep, check in build/.gitignore.
       
                    dwattttt wrote 1 day ago:
                    I don't know that I like this approach. It certainly works,
                    but it's not specifically what (people expect) a .gitignore
                    file to be used for. That confusion isn't good: [1] and
                    
  HTML              [1]: https://thecodelesscode.com/case/222
  HTML              [2]: https://thecodelesscode.com/case/223
       
                      akerl_ wrote 1 day ago:
                      .gitignore is the officially recommended way to do this:
                      
  HTML                [1]: https://archive.kernel.org/oldwiki/git.wiki.kern...
       
                        Supermancho wrote 19 hours 49 min ago:
                        Granted, naming is hard. Routinely using a file named
                        .deleteme or .rememberwalkthedog because it's
                        recommended instead of a more readable solution, is not
                        a compelling reason to switch.
       
       
   DIR <- back to front page