Search Unity

Empty directories and GIT

Discussion in 'Formats & External Tools' started by Immanuel-Scholz, Nov 27, 2014.

  1. Immanuel-Scholz

    Immanuel-Scholz

    Joined:
    Jun 8, 2013
    Posts:
    221
    Hi,

    to everyone using GIT and Unity: How did you solve the problem that GIT does not remove empty directories, Unity keeps creating empty directories and .meta files for directories when only one of both are missing?

    More specific the following workflow hickup occurs in our team. Assume Alan is an experienced coder and Bob is an intern beginner.

    • User Alan deletes a directory "DIR" in the Editor. Unity will delete the DIR.meta file.
    • Alan commits and pushes his changes.
    • Bob pulls, but GIT will not remove the empty directory. (Of course, it will remove DIR.meta)
    • Bob starts Unity Editor and Unity creates the DIR.meta again.
    • Bob tries to commits his stuff. An "uncommited file change: new DIR.meta" appears.
    Now, Bob has severaly options, most of them are just wrong but routinely taken by Beginners to GIT and Unity:
    • Deleting the file doesn't help as it gets constantly recreated when Unity launches. In my experience, beginner try that a couple of times until they give up.
    • Just not commiting the file doesn't help a lot, as these uncommited meta files get more and more and it become very difficult to find what need to be checked in and what not. What's worse is, that some Beginner will do this option and start to miss essential commits of other meta files, causing merge conflicts and broken scene links. Badbadbad.
    • Just commiting the file as new in is "working" for that developer, but when e.g. Alan pulls the next time, the DIR/ is recreated by unity again.

    For Bob, the only correct approach I can think of would be:
    • Fire up some File Explorer
    • Locate the DIR.meta
    • Recognize that the DIR.meta is actually a meta file corresponding to a directoy. (remember: Bob never had anything to do with "DIR" or "DIR.meta"). If its a file, the guy who checked it in just forgot to commit the meta. Bad guy, but not bad Bob.
    • If its a directory, open the directoy and recognize that its empty. (If its not empty, then someeone just forgot to checkin the DIR.meta when creating DIR).
    • Ok, its empty. Now delete the directory and the DIR.meta.
    Note that every single developer except Alan has to go through this steps. And there is nothing Alan can do to ease this pain.


    So how did you solve this? BTW.. we wrote an Editor - script that runs when Unity starts (actually on every assembly reload) and removes all empty directories and (if present) their corresponding .meta files. Takes some time to scan the about 1500 directories we have in our Assets/ folder. But at least it can be multi-threaded... Isn't there a simpler solution?
     
    Last edited: Nov 27, 2014
    AndyKorth likes this.
  2. Kirk Clawson

    Kirk Clawson

    Joined:
    Nov 4, 2014
    Posts:
    65
    Have you tried incorporating a git clean step in your workflow? with the -d option, it will remove untracked directories. It's kind of a bull in a china shop solution, though so it may kill too much stuff unless you use the exclude option.

    http://git-scm.com/docs/git-clean
     
  3. Immanuel-Scholz

    Immanuel-Scholz

    Joined:
    Jun 8, 2013
    Posts:
    221
    That would only remove the directories but not the meta file so when Unity starts, it will immediately re-create the directory.

    Beside, it would remove untracked files too, right? That would be a disaster for some of our co-workers who don't bother using .gitignore and just keep their working files (like preliminate versions) next to versioned files.

    Also, all git operations are extremely slow now and so we try to avoid them as much as possible.


    Is there an option for Unity to not generate meta files for directories? I don't see any need to reference directories anyway..

    Or maybe someone knows an awesome git-hack to have it ignore directory - meta files, but not file - meta files? (Like some script that decides whether a file is ignored or not instead of file pattern/regex based only on the file path)
     
  4. Kirk Clawson

    Kirk Clawson

    Joined:
    Nov 4, 2014
    Posts:
    65
    If you're tracking meta files in your Git repo, then Bob's pull will have removed the meta file, so the clean only needs to remove the directory.
    You might be able to use the exclude option on clean so that it only removes directories (e.g. excluding "*.*" will work as long as your directory names don't have periods in them). And yes, that means when a directory gets deleted, it the deleter's responsibility to check in the corresponding .meta delete as well (which git will see anyway, so it's not like it's an extra step for them).
    Perhaps something like this in .gitignore?
    *.meta
    !*.*.meta

    would first ignore all meta files, then un-ignore any meta files that have an extra period in them (again, assuming you don't use periods in your directory names). Never tried that though, so it may need some testing.
     
  5. Immanuel-Scholz

    Immanuel-Scholz

    Joined:
    Jun 8, 2013
    Posts:
    221
    Yes, you are right.. as long as you run the "git clean" always after a pull and not giving Unity editor a chance to recreate anything (i.e. don't keep the editor open and focused while doing a git pull), that could work. Still a bit wiggly.. ;)

    Awesome.. not allowing dots in directory names is probably a feasable restriction we can punch through the team.. :). Thanks Kirk, I'll try that out.
     
  6. v2k

    v2k

    Joined:
    Mar 16, 2012
    Posts:
    15
    Or a script that removes empty directories: (OSX version)

    Code (CSharp):
    1. #! /usr/bin/env sh
    2.  
    3. #rm DS_Store files first
    4. find Assets -type f -name .DS_Store -exec rm {} \;
    5.  
    6. while [ -n "$(find ./Assets -type d -empty)" ]
    7. do
    8.         echo "Found empty directories... removing...";
    9.         find ./Assets -type d -empty -exec rm -rf {}.meta \;
    10.         find ./Assets -type d -empty -exec rm -rf {} \; &> /dev/null
    11. done
    12.  
    13. echo "Clean.";
     
    ledlamp likes this.
  7. mrwellmann

    mrwellmann

    Joined:
    Nov 27, 2015
    Posts:
    37
  8. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    jorgegalvaominiclip likes this.
  9. okaybenji

    okaybenji

    Joined:
    Mar 10, 2017
    Posts:
    3
    Looks like Unity's Feedback Forum is gone? Is there some other place I can lend weight to the idea of stopping Unity from generating .meta files for empty directories?
     
  10. CraigGraff

    CraigGraff

    Joined:
    May 7, 2013
    Posts:
    44
    Since this still seems useful, here is a copy of the script linked above (found using the wayback machine).


    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4. using System.IO;
    5.  
    6. namespace IdeaPlusPlus.Unity
    7. {
    8.     class EmptyDirectoriesRemover : AssetPostprocessor
    9.     {
    10.         const string AssetsString = "Assets";
    11.  
    12.         static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    13.         {
    14.             DeleteEmptyDirectories(deletedAssets);
    15.             DeleteEmptyDirectories(movedFromAssetPaths);
    16.         }
    17.  
    18.         static void DeleteEmptyDirectories(string[] paths)
    19.         {
    20.             foreach (string path in paths)
    21.                 DeleteUpmostEmptyDirectory(path);
    22.         }
    23.  
    24.         static void DeleteUpmostEmptyDirectory(string assetPath)
    25.         {
    26.             try
    27.             {
    28.                 string assetDir = Path.GetDirectoryName(assetPath);
    29.                 if (assetDir == AssetsString)
    30.                     return;
    31.                 string absoluteDir = AssetPathToAbsolutePath(assetDir);
    32.                 string[] files = Directory.GetFiles(absoluteDir, "*.*", SearchOption.AllDirectories);
    33.                 if (files.Length == 0)
    34.                 {
    35.                     AssetDatabase.DeleteAsset(assetDir);
    36.                     DeleteUpmostEmptyDirectory(Path.GetDirectoryName(assetPath));
    37.                 }
    38.             }
    39.             catch
    40.             {
    41.             }
    42.         }
    43.  
    44.  
    45.         static string AssetPathToAbsolutePath(string assetPath)
    46.         {
    47.             if (assetPath == AssetsString)
    48.                 return Application.dataPath;
    49.             else
    50.                 return Path.Combine(Application.dataPath, assetPath.Substring(AssetsString.Length + 1));
    51.         }
    52.     }
    53. }
    54.  
     
    Thaina, nikolay_i and neonblitzer like this.