diff --git a/rbtools/clients/git.py b/rbtools/clients/git.py
index 6d9c115b328da67be83b15f522eb06e3e3635099..d075f86a18091094980fdfe9650e3e6b95a11b4a 100644
--- a/rbtools/clients/git.py
+++ b/rbtools/clients/git.py
@@ -971,8 +971,10 @@ class GitClient(SCMClient):
         """
         base_path = b''
         diff_data = b''
-        filename = b''
+        old_filename = b''
+        new_filename = b''
         p4rev = b''
+        is_full_rename = False
 
         # Find which depot changelist we're based on
         log = self._execute([self.git, 'log', merge_base],
@@ -993,34 +995,132 @@ class GitClient(SCMClient):
 
         for i, line in enumerate(diff_lines):
             if line.startswith(b'diff '):
-                # Grab the filename and then filter this out.
                 # This will be in the format of:
                 #    diff --git a/path/to/file b/path/to/file
-                filename = line.split(b' ')[2].strip()
+                #
+                # Filter this out. We can't extract any file names from this
+                # line as they may contain spaces and we can't therefore easily
+                # split the line.
+                old_filename = b''
+                new_filename = b''
+                is_full_rename = False
             elif (line.startswith(b'index ') or
                   line.startswith(b'new file mode ')):
-                # Filter this out
+                # Filter this out.
                 pass
-            elif (line.startswith(b'--- ') and i + 1 < len(diff_lines) and
+            elif (line.startswith(b'similarity index 100%') and
+                  i + 2 < len(diff_lines) and
+                  diff_lines[i + 1].startswith(b'rename from') and
+                  diff_lines[i + 2].startswith(b'rename to')):
+                # The file was renamed without any file lines changing.
+                # We have to special-case this and generate a perforce-specific
+                # line in the same way that perforce.py does.
+
+                # At this point, the current line and the next 2 lines look
+                # like this:
+                #
+                # similarity index 100%
+                # rename from <old filename>
+                # rename to <new filename>
+                #
+                # We parse out the old and new filenames and output the
+                # following:
+                #
+                # === <old depot path>#<revision> ==MV== <new depot path> ===
+                #
+                # Followed by an empty line. We then skip the following 2 lines
+                # which would otherwise print "Move from: ..." and "Move to:
+                # ...".
+                old_filename = diff_lines[i + 1].split(b' ', 2)[2].strip()
+                new_filename = diff_lines[i + 2].split(b' ', 2)[2].strip()
+
+                p4path = force_unicode(base_path + old_filename + b'@' + p4rev)
+                data = self._execute(['p4', 'files', p4path],
+                                     ignore_errors=True,
+                                     results_unicode=False)
+                m = re.search(br'^%s%s#(\d+).*$' % (re.escape(base_path),
+                                                    re.escape(old_filename)),
+                              data, re.M)
+                if m:
+                    file_version = m.group(1).strip()
+                else:
+                    file_version = b'1'
+
+                diff_data += b'==== %s%s#%s ==MV== %s%s ====\n\n' % (
+                    base_path,
+                    old_filename,
+                    file_version,
+                    base_path,
+                    new_filename)
+
+                is_full_rename = True
+            elif line.startswith(b'similarity index'):
+                # Filter this out.
+                pass
+            elif line.startswith(b'rename from'):
+                # For perforce diffs where a file was renamed and modified, we
+                # specify "Moved from: <depotpath>" along with the usual diff
+                # markers.
+                from_filename = line.split(b' ', 2)[2].strip()
+                if not is_full_rename:
+                    diff_data += b'Moved from: %s%s\n' % (base_path,
+                                                          from_filename)
+            elif line.startswith(b'rename to'):
+                # For perforce diffs where a file was renamed and modified, we
+                # specify "Moved to: <depotpath>" along with the usual diff
+                # markers.
+                to_filename = line.split(b' ', 2)[2].strip()
+                if not is_full_rename:
+                    diff_data += b'Moved to: %s%s\n' % (base_path,
+                                                        to_filename)
+            elif (not old_filename and
+                  line.startswith(b'--- ') and i + 1 < len(diff_lines) and
                   diff_lines[i + 1].startswith(b'+++ ')):
-                p4path = force_unicode(base_path + filename + b'@' + p4rev)
+
+                # At this point in parsing the current line and the next line
+                # look like this:
+                #
+                # --- <old filename><optional tab character>
+                # +++ <new filename><optional tab character>
+                #
+                # The tab character is present precisely when old or new
+                # filename (respectively) contain whitespace.
+                #
+                # So we take the section 4 characters from the start (i.e.
+                # after --- or +++) and split on tab, taking the first part.
+                old_filename = line[4:].split(b'\t', 1)[0].strip()
+                new_filename = diff_lines[i + 1][4:].split(b'\t', 1)[0].strip()
+
+                # Perforce diffs require that the "new file" and "old file"
+                # match the original filename in the case of adds and deletes.
+                if new_filename == b'/dev/null':
+                    # The file was deleted, use the old filename when writing
+                    # out the +++ line.
+                    new_filename = old_filename
+                elif old_filename == b'/dev/null':
+                    # The file is new, use the new filename in the --- line.
+                    old_filename = new_filename
+
+                p4path = force_unicode(base_path + old_filename + b'@' + p4rev)
                 data = self._execute(['p4', 'files', p4path],
                                      ignore_errors=True,
                                      results_unicode=False)
                 m = re.search(br'^%s%s#(\d+).*$' % (re.escape(base_path),
-                                                    re.escape(filename)),
+                                                    re.escape(old_filename)),
                               data, re.M)
                 if m:
                     file_version = m.group(1).strip()
                 else:
                     file_version = b'1'
 
-                diff_data += b'--- %s%s\t%s%s#%s\n' % (base_path, filename,
-                                                       base_path, filename,
+                diff_data += b'--- %s%s\t%s%s#%s\n' % (base_path,
+                                                       old_filename,
+                                                       base_path,
+                                                       old_filename,
                                                        file_version)
             elif line.startswith(b'+++ '):
                 # TODO: add a real timestamp
-                diff_data += b'+++ %s%s\t%s\n' % (base_path, filename,
+                diff_data += b'+++ %s%s\t%s\n' % (base_path, new_filename,
                                                   b'TIMESTAMP')
             else:
                 diff_data += line
