We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
mkdocs build cleaning removes .git when site_dir points to a parent directory
`mkdocs build --clean` wipes out the project when attempting to split doc development and mkdocs' build output across two git branches (gh-pages, gh-pages-dev) with the following layout:

```
<branch: gh-pages-dev>
$PROJ_ROOT/
|- dev
`  |- doc/
   `- mkdoc.yml  \# NOTE: site_dir=../

<branch: gh-pages>
$PROJ_ROOT/
`- ... \# build output
```

This is so I can both keep everything in the same project and also track the dev/ directory on the dev branch and have the output where it should be on the gh-pages branch. It seems obvious now that this would wipe out everything including the .git/ for the project (glad this was a test). Possibly, it could recursively check `site_dir` for a .git, warn and exit. Or just a disclaimer [here](http://www.mkdocs.org/user-guide/configuration/#build-directories) of this possibility would be enough, so no one else tries this and wipes out their project (and maybe you could recommend to new users how to maintain site development and build output in the same repo).

Thanks,
Kris


--- 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         # Filter filenames starting with a '.'
58         filenames = [f for f in filenames if not f.startswith('.')]
59 
60         # Filter the dirnames that start with a '.' and update the list in
61         # place to prevent us walking these.
62         dirnames[:] = [d for d in dirnames if not d.startswith('.')]
63 
64         for filename in filenames:
65             if not is_markdown_file(filename) and not is_html_file(filename):
66                 source_path = os.path.join(source_dir, filename)
67                 output_path = os.path.join(output_dir, filename)
68                 copy_file(source_path, output_path)
69 
70 
71 def get_html_path(path):
72     """
73     Map a source file path to an output html path.
74 
75     Paths like 'index.md' will be converted to 'index.html'
76     Paths like 'about.md' will be converted to 'about/index.html'
77     Paths like 'api-guide/core.md' will be converted to 'api-guide/core/index.html'
78     """
79     path = os.path.splitext(path)[0]
80     if os.path.basename(path) == 'index':
81         return path + '.html'
82     return "/".join((path, 'index.html'))
83 
84 
85 def get_url_path(path, use_directory_urls=True):
86     """
87     Map a source file path to an output html path.
88 
89     Paths like 'index.md' will be converted to '/'
90     Paths like 'about.md' will be converted to '/about/'
91     Paths like 'api-guide/core.md' will be converted to '/api-guide/core/'
92 
93     If `use_directory_urls` is `False`, returned URLs will include the a trailing
94     `index.html` rather than just returning the directory path.
95     """
96     path = get_html_path(path)
97     url = '/' + path.replace(os.path.sep, '/')
98     if use_directory_urls:
99         return url[:-len('index.html')]
100     return url
101 
102 
103 def is_homepage(path):
104     return os.path.splitext(path)[0] == 'index'
105 
106 
107 def is_markdown_file(path):
108     """
109     Return True if the given file path is a Markdown file.
110 
111     http://superuser.com/questions/249436/file-extension-for-markdown-files
112     """
113     ext = os.path.splitext(path)[1].lower()
114     return ext in [
115         '.markdown',
116         '.mdown',
117         '.mkdn',
118         '.mkd',
119         '.md',
120     ]
121 
122 
123 def is_css_file(path):
124     """
125     Return True if the given file path is a CSS file.
126     """
127     ext = os.path.splitext(path)[1].lower()
128     return ext in [
129         '.css',
130     ]
131 
132 
133 def is_javascript_file(path):
134     """
135     Return True if the given file path is a Javascript file.
136     """
137     ext = os.path.splitext(path)[1].lower()
138     return ext in [
139         '.js',
140         '.javascript'
141     ]
142 
143 
144 def is_html_file(path):
145     """
146     Return True if the given file path is an HTML file.
147     """
148     ext = os.path.splitext(path)[1].lower()
149     return ext in [
150         '.html',
151         '.htm',
152     ]
153 
154 
155 def create_media_urls(nav, url_list):
156     """
157     Return a list of URLs that have been processed correctly for inclusion in a page.
158     """
159     final_urls = []
160     for url in url_list:
161         # Allow links to fully qualified URL's
162         parsed = urlparse(url)
163         if parsed.netloc:
164             final_urls.append(url)
165         else:
166             relative_url = '%s/%s' % (nav.url_context.make_relative('/'), url)
167             final_urls.append(relative_url)
168     return final_urls
169 
170 
171 def create_relative_media_url(nav, url):
172     """
173     For a current page, create a relative url based on the given URL.
174 
175     On index.md (which becomes /index.html):
176         image.png -> ./image.png
177         /image.png -> ./image.png
178 
179     on sub/page.md (which becomes /sub/page/index.html):
180         image.png -> ../image.png
181         /image.png -> ../../image.png
182 
183     """
184 
185     # Allow links to fully qualified URL's
186     parsed = urlparse(url)
187     if parsed.netloc:
188         return url
189 
190     # If the URL we are looking at starts with a /, then it should be
191     # considered as absolute and will be 'relative' to the root.
192     if url.startswith('/'):
193         base = '/'
194         url = url[1:]
195     else:
196         base = nav.url_context.base_path
197 
198     relative_url = '%s/%s' % (nav.url_context.make_relative(base), url)
199 
200     # TODO: Fix this, this is a hack. Relative urls are not being calculated
201     # correctly for images in the same directory as the markdown. I think this
202     # is due to us moving it into a directory with index.html, but I'm not sure
203     if nav.url_context.base_path is not '/' and relative_url.startswith("./"):
204         relative_url = ".%s" % relative_url
205 
206     return relative_url
207
```
--- 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
@@ -37,13 +37,21 @@
     """
     Remove the content of a directory recursively but not the directory itself.
     """
-    if os.path.exists(directory):
-        for entry in os.listdir(directory):
-            path = os.path.join(directory, entry)
-            if os.path.isdir(path):
-                shutil.rmtree(path, True)
-            else:
-                os.unlink(path)
+    if not os.path.exists(directory):
+        return
+
+    for entry in os.listdir(directory):
+
+        # Don't remove hidden files from the directory. We never copy files
+        # that are hidden, so we shouldn't delete them either.
+        if entry.startswith('.'):
+            continue
+
+        path = os.path.join(directory, entry)
+        if os.path.isdir(path):
+            shutil.rmtree(path, True)
+        else:
+            os.unlink(path)
 
 
 def copy_media_files(from_dir, to_dir):

{"golden_diff": "diff --git a/mkdocs/utils.py b/mkdocs/utils.py\n--- a/mkdocs/utils.py\n+++ b/mkdocs/utils.py\n@@ -37,13 +37,21 @@\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+    if not os.path.exists(directory):\n+        return\n+\n+    for entry in os.listdir(directory):\n+\n+        # Don't remove hidden files from the directory. We never copy files\n+        # that are hidden, so we shouldn't delete them either.\n+        if entry.startswith('.'):\n+            continue\n+\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 \n def copy_media_files(from_dir, to_dir):\n", "issue": "mkdocs build cleaning removes .git when site_dir points to a parent directory\n`mkdocs build --clean` wipes out the project when attempting to split doc development and mkdocs' build output across two git branches (gh-pages, gh-pages-dev) with the following layout:\n\n```\n<branch: gh-pages-dev>\n$PROJ_ROOT/\n|- dev\n`  |- doc/\n   `- mkdoc.yml  \\# NOTE: site_dir=../\n\n<branch: gh-pages>\n$PROJ_ROOT/\n`- ... \\# build output\n```\n\nThis is so I can both keep everything in the same project and also track the dev/ directory on the dev branch and have the output where it should be on the gh-pages branch. It seems obvious now that this would wipe out everything including the .git/ for the project (glad this was a test). Possibly, it could recursively check `site_dir` for a .git, warn and exit. Or just a disclaimer [here](http://www.mkdocs.org/user-guide/configuration/#build-directories) of this possibility would be enough, so no one else tries this and wipes out their project (and maybe you could recommend to new users how to maintain site development and build output in the same repo).\n\nThanks,\nKris\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        # 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\n\ndef create_relative_media_url(nav, url):\n    \"\"\"\n    For a current page, create a relative url based on the given URL.\n\n    On index.md (which becomes /index.html):\n        image.png -> ./image.png\n        /image.png -> ./image.png\n\n    on sub/page.md (which becomes /sub/page/index.html):\n        image.png -> ../image.png\n        /image.png -> ../../image.png\n\n    \"\"\"\n\n    # Allow links to fully qualified URL's\n    parsed = urlparse(url)\n    if parsed.netloc:\n        return url\n\n    # If the URL we are looking at starts with a /, then it should be\n    # considered as absolute and will be 'relative' to the root.\n    if url.startswith('/'):\n        base = '/'\n        url = url[1:]\n    else:\n        base = nav.url_context.base_path\n\n    relative_url = '%s/%s' % (nav.url_context.make_relative(base), url)\n\n    # TODO: Fix this, this is a hack. Relative urls are not being calculated\n    # correctly for images in the same directory as the markdown. I think this\n    # is due to us moving it into a directory with index.html, but I'm not sure\n    if nav.url_context.base_path is not '/' and relative_url.startswith(\"./\"):\n        relative_url = \".%s\" % relative_url\n\n    return relative_url\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 not os.path.exists(directory):\n        return\n\n    for entry in os.listdir(directory):\n\n        # Don't remove hidden files from the directory. We never copy files\n        # that are hidden, so we shouldn't delete them either.\n        if entry.startswith('.'):\n            continue\n\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\n\ndef create_relative_media_url(nav, url):\n    \"\"\"\n    For a current page, create a relative url based on the given URL.\n\n    On index.md (which becomes /index.html):\n        image.png -> ./image.png\n        /image.png -> ./image.png\n\n    on sub/page.md (which becomes /sub/page/index.html):\n        image.png -> ../image.png\n        /image.png -> ../../image.png\n\n    \"\"\"\n\n    # Allow links to fully qualified URL's\n    parsed = urlparse(url)\n    if parsed.netloc:\n        return url\n\n    # If the URL we are looking at starts with a /, then it should be\n    # considered as absolute and will be 'relative' to the root.\n    if url.startswith('/'):\n        base = '/'\n        url = url[1:]\n    else:\n        base = nav.url_context.base_path\n\n    relative_url = '%s/%s' % (nav.url_context.make_relative(base), url)\n\n    # TODO: Fix this, this is a hack. Relative urls are not being calculated\n    # correctly for images in the same directory as the markdown. I think this\n    # is due to us moving it into a directory with index.html, but I'm not sure\n    if nav.url_context.base_path is not '/' and relative_url.startswith(\"./\"):\n        relative_url = \".%s\" % relative_url\n\n    return relative_url\n", "path": "mkdocs/utils.py"}]}