We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Modify stale files warning to ignore .htaccess, .gitignore and .git
I am not sure if this is the same as issue #167 or not, or if there a better workaround than the setup I am using.

I have the mkdocs project in one folder, and I am building to a sibling folder ( `site_dir: ../site` )
My site dir contains its own git repo, and .htaccess and .gitignore, which I want to keep there, but I get that stale warning.

This causes two issues:
1. Someone may actually run this clean command and delete files I want to keep
2. I cannot run `--clean`

Perhaps the behavior of that warning (and of `--clean`) should be changed to accommodate such scenario? 

If it cannot be solved automatically, then perhaps by a directive in the config? `build_ignore: [file, folder]`


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mkdocs/utils.py`
Content:
```
1 # coding: utf-8
2 
3 """
4 Standalone file utils.
5 
6 Nothing in this module should have an knowledge of config or the layout
7 and structure of the site and pages in the site.
8 """
9 
10 import os
11 import shutil
12 
13 from mkdocs.compat import urlparse
14 
15 
16 def copy_file(source_path, output_path):
17     """
18     Copy source_path to output_path, making sure any parent directories exist.
19     """
20     output_dir = os.path.dirname(output_path)
21     if not os.path.exists(output_dir):
22         os.makedirs(output_dir)
23     shutil.copy(source_path, output_path)
24 
25 
26 def write_file(content, output_path):
27     """
28     Write content to output_path, making sure any parent directories exist.
29     """
30     output_dir = os.path.dirname(output_path)
31     if not os.path.exists(output_dir):
32         os.makedirs(output_dir)
33     open(output_path, 'wb').write(content)
34 
35 
36 def clean_directory(directory):
37     """
38     Remove the content of a directory recursively but not the directory itself.
39     """
40     if os.path.exists(directory):
41         for entry in os.listdir(directory):
42             path = os.path.join(directory, entry)
43             if os.path.isdir(path):
44                 shutil.rmtree(path, True)
45             else:
46                 os.unlink(path)
47 
48 
49 def copy_media_files(from_dir, to_dir):
50     """
51     Recursively copy all files except markdown and HTML into another directory.
52     """
53     for (source_dir, dirnames, filenames) in os.walk(from_dir):
54         relative_path = os.path.relpath(source_dir, from_dir)
55         output_dir = os.path.normpath(os.path.join(to_dir, relative_path))
56 
57         for filename in filenames:
58             if not is_markdown_file(filename) and not is_html_file(filename):
59                 source_path = os.path.join(source_dir, filename)
60                 output_path = os.path.join(output_dir, filename)
61                 copy_file(source_path, output_path)
62 
63 
64 def get_html_path(path):
65     """
66     Map a source file path to an output html path.
67 
68     Paths like 'index.md' will be converted to 'index.html'
69     Paths like 'about.md' will be converted to 'about/index.html'
70     Paths like 'api-guide/core.md' will be converted to 'api-guide/core/index.html'
71     """
72     path = os.path.splitext(path)[0]
73     if os.path.basename(path) == 'index':
74         return path + '.html'
75     return "/".join((path, 'index.html'))
76 
77 
78 def get_url_path(path, use_directory_urls=True):
79     """
80     Map a source file path to an output html path.
81 
82     Paths like 'index.md' will be converted to '/'
83     Paths like 'about.md' will be converted to '/about/'
84     Paths like 'api-guide/core.md' will be converted to '/api-guide/core/'
85 
86     If `use_directory_urls` is `False`, returned URLs will include the a trailing
87     `index.html` rather than just returning the directory path.
88     """
89     path = get_html_path(path)
90     url = '/' + path.replace(os.path.sep, '/')
91     if use_directory_urls:
92         return url[:-len('index.html')]
93     return url
94 
95 
96 def is_homepage(path):
97     return os.path.splitext(path)[0] == 'index'
98 
99 
100 def is_markdown_file(path):
101     """
102     Return True if the given file path is a Markdown file.
103 
104     http://superuser.com/questions/249436/file-extension-for-markdown-files
105     """
106     ext = os.path.splitext(path)[1].lower()
107     return ext in [
108         '.markdown',
109         '.mdown',
110         '.mkdn',
111         '.mkd',
112         '.md',
113     ]
114 
115 
116 def is_css_file(path):
117     """
118     Return True if the given file path is a CSS file.
119     """
120     ext = os.path.splitext(path)[1].lower()
121     return ext in [
122         '.css',
123     ]
124 
125 
126 def is_javascript_file(path):
127     """
128     Return True if the given file path is a Javascript file.
129     """
130     ext = os.path.splitext(path)[1].lower()
131     return ext in [
132         '.js',
133         '.javascript'
134     ]
135 
136 
137 def is_html_file(path):
138     """
139     Return True if the given file path is an HTML file.
140     """
141     ext = os.path.splitext(path)[1].lower()
142     return ext in [
143         '.html',
144         '.htm',
145     ]
146 
147 
148 def create_media_urls(nav, url_list):
149     """
150     Return a list of URLs that have been processed correctly for inclusion in a page.
151     """
152     final_urls = []
153     for url in url_list:
154         # Allow links to fully qualified URL's
155         parsed = urlparse(url)
156         if parsed.netloc:
157             final_urls.append(url)
158         else:
159             relative_url = '%s/%s' % (nav.url_context.make_relative('/'), url)
160             final_urls.append(relative_url)
161     return final_urls
162
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mkdocs/utils.py b/mkdocs/utils.py
--- a/mkdocs/utils.py
+++ b/mkdocs/utils.py
@@ -54,6 +54,13 @@
         relative_path = os.path.relpath(source_dir, from_dir)
         output_dir = os.path.normpath(os.path.join(to_dir, relative_path))
 
+        # Filter filenames starting with a '.'
+        filenames = [f for f in filenames if not f.startswith('.')]
+
+        # Filter the dirnames that start with a '.' and update the list in
+        # place to prevent us walking these.
+        dirnames[:] = [d for d in dirnames if not d.startswith('.')]
+
         for filename in filenames:
             if not is_markdown_file(filename) and not is_html_file(filename):
                 source_path = os.path.join(source_dir, filename)

{"golden_diff": "diff --git a/mkdocs/utils.py b/mkdocs/utils.py\n--- a/mkdocs/utils.py\n+++ b/mkdocs/utils.py\n@@ -54,6 +54,13 @@\n         relative_path = os.path.relpath(source_dir, from_dir)\n         output_dir = os.path.normpath(os.path.join(to_dir, relative_path))\n \n+        # Filter filenames starting with a '.'\n+        filenames = [f for f in filenames if not f.startswith('.')]\n+\n+        # Filter the dirnames that start with a '.' and update the list in\n+        # place to prevent us walking these.\n+        dirnames[:] = [d for d in dirnames if not d.startswith('.')]\n+\n         for filename in filenames:\n             if not is_markdown_file(filename) and not is_html_file(filename):\n                 source_path = os.path.join(source_dir, filename)\n", "issue": "Modify stale files warning to ignore .htaccess, .gitignore and .git\nI am not sure if this is the same as issue #167 or not, or if there a better workaround than the setup I am using.\n\nI have the mkdocs project in one folder, and I am building to a sibling folder ( `site_dir: ../site` )\nMy site dir contains its own git repo, and .htaccess and .gitignore, which I want to keep there, but I get that stale warning.\n\nThis causes two issues:\n1. Someone may actually run this clean command and delete files I want to keep\n2. I cannot run `--clean`\n\nPerhaps the behavior of that warning (and of `--clean`) should be changed to accommodate such scenario? \n\nIf it cannot be solved automatically, then perhaps by a directive in the config? `build_ignore: [file, folder]`\n\n", "before_files": [{"content": "# coding: utf-8\n\n\"\"\"\nStandalone file utils.\n\nNothing in this module should have an knowledge of config or the layout\nand structure of the site and pages in the site.\n\"\"\"\n\nimport os\nimport shutil\n\nfrom mkdocs.compat import urlparse\n\n\ndef copy_file(source_path, output_path):\n    \"\"\"\n    Copy source_path to output_path, making sure any parent directories exist.\n    \"\"\"\n    output_dir = os.path.dirname(output_path)\n    if not os.path.exists(output_dir):\n        os.makedirs(output_dir)\n    shutil.copy(source_path, output_path)\n\n\ndef write_file(content, output_path):\n    \"\"\"\n    Write content to output_path, making sure any parent directories exist.\n    \"\"\"\n    output_dir = os.path.dirname(output_path)\n    if not os.path.exists(output_dir):\n        os.makedirs(output_dir)\n    open(output_path, 'wb').write(content)\n\n\ndef clean_directory(directory):\n    \"\"\"\n    Remove the content of a directory recursively but not the directory itself.\n    \"\"\"\n    if os.path.exists(directory):\n        for entry in os.listdir(directory):\n            path = os.path.join(directory, entry)\n            if os.path.isdir(path):\n                shutil.rmtree(path, True)\n            else:\n                os.unlink(path)\n\n\ndef copy_media_files(from_dir, to_dir):\n    \"\"\"\n    Recursively copy all files except markdown and HTML into another directory.\n    \"\"\"\n    for (source_dir, dirnames, filenames) in os.walk(from_dir):\n        relative_path = os.path.relpath(source_dir, from_dir)\n        output_dir = os.path.normpath(os.path.join(to_dir, relative_path))\n\n        for filename in filenames:\n            if not is_markdown_file(filename) and not is_html_file(filename):\n                source_path = os.path.join(source_dir, filename)\n                output_path = os.path.join(output_dir, filename)\n                copy_file(source_path, output_path)\n\n\ndef get_html_path(path):\n    \"\"\"\n    Map a source file path to an output html path.\n\n    Paths like 'index.md' will be converted to 'index.html'\n    Paths like 'about.md' will be converted to 'about/index.html'\n    Paths like 'api-guide/core.md' will be converted to 'api-guide/core/index.html'\n    \"\"\"\n    path = os.path.splitext(path)[0]\n    if os.path.basename(path) == 'index':\n        return path + '.html'\n    return \"/\".join((path, 'index.html'))\n\n\ndef get_url_path(path, use_directory_urls=True):\n    \"\"\"\n    Map a source file path to an output html path.\n\n    Paths like 'index.md' will be converted to '/'\n    Paths like 'about.md' will be converted to '/about/'\n    Paths like 'api-guide/core.md' will be converted to '/api-guide/core/'\n\n    If `use_directory_urls` is `False`, returned URLs will include the a trailing\n    `index.html` rather than just returning the directory path.\n    \"\"\"\n    path = get_html_path(path)\n    url = '/' + path.replace(os.path.sep, '/')\n    if use_directory_urls:\n        return url[:-len('index.html')]\n    return url\n\n\ndef is_homepage(path):\n    return os.path.splitext(path)[0] == 'index'\n\n\ndef is_markdown_file(path):\n    \"\"\"\n    Return True if the given file path is a Markdown file.\n\n    http://superuser.com/questions/249436/file-extension-for-markdown-files\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.markdown',\n        '.mdown',\n        '.mkdn',\n        '.mkd',\n        '.md',\n    ]\n\n\ndef is_css_file(path):\n    \"\"\"\n    Return True if the given file path is a CSS file.\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.css',\n    ]\n\n\ndef is_javascript_file(path):\n    \"\"\"\n    Return True if the given file path is a Javascript file.\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.js',\n        '.javascript'\n    ]\n\n\ndef is_html_file(path):\n    \"\"\"\n    Return True if the given file path is an HTML file.\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.html',\n        '.htm',\n    ]\n\n\ndef create_media_urls(nav, url_list):\n    \"\"\"\n    Return a list of URLs that have been processed correctly for inclusion in a page.\n    \"\"\"\n    final_urls = []\n    for url in url_list:\n        # Allow links to fully qualified URL's\n        parsed = urlparse(url)\n        if parsed.netloc:\n            final_urls.append(url)\n        else:\n            relative_url = '%s/%s' % (nav.url_context.make_relative('/'), url)\n            final_urls.append(relative_url)\n    return final_urls\n", "path": "mkdocs/utils.py"}], "after_files": [{"content": "# coding: utf-8\n\n\"\"\"\nStandalone file utils.\n\nNothing in this module should have an knowledge of config or the layout\nand structure of the site and pages in the site.\n\"\"\"\n\nimport os\nimport shutil\n\nfrom mkdocs.compat import urlparse\n\n\ndef copy_file(source_path, output_path):\n    \"\"\"\n    Copy source_path to output_path, making sure any parent directories exist.\n    \"\"\"\n    output_dir = os.path.dirname(output_path)\n    if not os.path.exists(output_dir):\n        os.makedirs(output_dir)\n    shutil.copy(source_path, output_path)\n\n\ndef write_file(content, output_path):\n    \"\"\"\n    Write content to output_path, making sure any parent directories exist.\n    \"\"\"\n    output_dir = os.path.dirname(output_path)\n    if not os.path.exists(output_dir):\n        os.makedirs(output_dir)\n    open(output_path, 'wb').write(content)\n\n\ndef clean_directory(directory):\n    \"\"\"\n    Remove the content of a directory recursively but not the directory itself.\n    \"\"\"\n    if os.path.exists(directory):\n        for entry in os.listdir(directory):\n            path = os.path.join(directory, entry)\n            if os.path.isdir(path):\n                shutil.rmtree(path, True)\n            else:\n                os.unlink(path)\n\n\ndef copy_media_files(from_dir, to_dir):\n    \"\"\"\n    Recursively copy all files except markdown and HTML into another directory.\n    \"\"\"\n    for (source_dir, dirnames, filenames) in os.walk(from_dir):\n        relative_path = os.path.relpath(source_dir, from_dir)\n        output_dir = os.path.normpath(os.path.join(to_dir, relative_path))\n\n        # Filter filenames starting with a '.'\n        filenames = [f for f in filenames if not f.startswith('.')]\n\n        # Filter the dirnames that start with a '.' and update the list in\n        # place to prevent us walking these.\n        dirnames[:] = [d for d in dirnames if not d.startswith('.')]\n\n        for filename in filenames:\n            if not is_markdown_file(filename) and not is_html_file(filename):\n                source_path = os.path.join(source_dir, filename)\n                output_path = os.path.join(output_dir, filename)\n                copy_file(source_path, output_path)\n\n\ndef get_html_path(path):\n    \"\"\"\n    Map a source file path to an output html path.\n\n    Paths like 'index.md' will be converted to 'index.html'\n    Paths like 'about.md' will be converted to 'about/index.html'\n    Paths like 'api-guide/core.md' will be converted to 'api-guide/core/index.html'\n    \"\"\"\n    path = os.path.splitext(path)[0]\n    if os.path.basename(path) == 'index':\n        return path + '.html'\n    return \"/\".join((path, 'index.html'))\n\n\ndef get_url_path(path, use_directory_urls=True):\n    \"\"\"\n    Map a source file path to an output html path.\n\n    Paths like 'index.md' will be converted to '/'\n    Paths like 'about.md' will be converted to '/about/'\n    Paths like 'api-guide/core.md' will be converted to '/api-guide/core/'\n\n    If `use_directory_urls` is `False`, returned URLs will include the a trailing\n    `index.html` rather than just returning the directory path.\n    \"\"\"\n    path = get_html_path(path)\n    url = '/' + path.replace(os.path.sep, '/')\n    if use_directory_urls:\n        return url[:-len('index.html')]\n    return url\n\n\ndef is_homepage(path):\n    return os.path.splitext(path)[0] == 'index'\n\n\ndef is_markdown_file(path):\n    \"\"\"\n    Return True if the given file path is a Markdown file.\n\n    http://superuser.com/questions/249436/file-extension-for-markdown-files\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.markdown',\n        '.mdown',\n        '.mkdn',\n        '.mkd',\n        '.md',\n    ]\n\n\ndef is_css_file(path):\n    \"\"\"\n    Return True if the given file path is a CSS file.\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.css',\n    ]\n\n\ndef is_javascript_file(path):\n    \"\"\"\n    Return True if the given file path is a Javascript file.\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.js',\n        '.javascript'\n    ]\n\n\ndef is_html_file(path):\n    \"\"\"\n    Return True if the given file path is an HTML file.\n    \"\"\"\n    ext = os.path.splitext(path)[1].lower()\n    return ext in [\n        '.html',\n        '.htm',\n    ]\n\n\ndef create_media_urls(nav, url_list):\n    \"\"\"\n    Return a list of URLs that have been processed correctly for inclusion in a page.\n    \"\"\"\n    final_urls = []\n    for url in url_list:\n        # Allow links to fully qualified URL's\n        parsed = urlparse(url)\n        if parsed.netloc:\n            final_urls.append(url)\n        else:\n            relative_url = '%s/%s' % (nav.url_context.make_relative('/'), url)\n            final_urls.append(relative_url)\n    return final_urls\n", "path": "mkdocs/utils.py"}]}