diff --git a/hgitaly/service/diff.py b/hgitaly/service/diff.py
index 7e77711d64ac8959e7f1e1dc1f22b71f59c2c15c_aGdpdGFseS9zZXJ2aWNlL2RpZmYucHk=..983e393511be21081cdd3c280e5eb6de80b820bf_aGdpdGFseS9zZXJ2aWNlL2RpZmYucHk= 100644
--- a/hgitaly/service/diff.py
+++ b/hgitaly/service/diff.py
@@ -25,6 +25,7 @@
     chunk_stats,
     diff_opts,
 )
+from ..errors import not_implemented
 from ..git import (
     NULL_BLOB_OID,
     EMPTY_TREE_OID,
@@ -51,6 +52,8 @@
     CommitDeltaResponse,
     FindChangedPathsRequest,
     FindChangedPathsResponse,
+    GetPatchIDRequest,
+    GetPatchIDResponse,
     RawDiffRequest,
     RawDiffResponse,
     RawPatchRequest,
@@ -506,6 +509,10 @@
                              for path in changed_paths(repo, *extr)):
             yield FindChangedPathsResponse(paths=paths)
 
+    def GetPatchID(self, request: GetPatchIDRequest,
+                   context) -> GetPatchIDResponse:
+        not_implemented(context, issue=131)  # pragma no cover
+
 
 def fcp_resolve_commit(context, repo, revision):
     ctx = gitlab_revision_changeset(
diff --git a/hgitaly/stub/diff_pb2.py b/hgitaly/stub/diff_pb2.py
index 7e77711d64ac8959e7f1e1dc1f22b71f59c2c15c_aGdpdGFseS9zdHViL2RpZmZfcGIyLnB5..983e393511be21081cdd3c280e5eb6de80b820bf_aGdpdGFseS9zdHViL2RpZmZfcGIyLnB5 100644
--- a/hgitaly/stub/diff_pb2.py
+++ b/hgitaly/stub/diff_pb2.py
@@ -21,7 +21,7 @@
   syntax='proto3',
   serialized_options=b'Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb',
   create_key=_descriptor._internal_create_key,
-  serialized_pb=b'\n\ndiff.proto\x12\x06gitaly\x1a\nlint.proto\x1a\x0cshared.proto\"\xcb\x03\n\x11\x43ommitDiffRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\x12 \n\x18ignore_whitespace_change\x18\x04 \x01(\x08\x12\r\n\x05paths\x18\x05 \x03(\x0c\x12\x16\n\x0e\x63ollapse_diffs\x18\x06 \x01(\x08\x12\x16\n\x0e\x65nforce_limits\x18\x07 \x01(\x08\x12\x11\n\tmax_files\x18\x08 \x01(\x05\x12\x11\n\tmax_lines\x18\t \x01(\x05\x12\x11\n\tmax_bytes\x18\n \x01(\x05\x12\x17\n\x0fmax_patch_bytes\x18\x0e \x01(\x05\x12\x16\n\x0esafe_max_files\x18\x0b \x01(\x05\x12\x16\n\x0esafe_max_lines\x18\x0c \x01(\x05\x12\x16\n\x0esafe_max_bytes\x18\r \x01(\x05\x12\x35\n\tdiff_mode\x18\x0f \x01(\x0e\x32\".gitaly.CommitDiffRequest.DiffMode\"%\n\x08\x44iffMode\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x00\x12\x0c\n\x08WORDDIFF\x10\x01\"\xff\x01\n\x12\x43ommitDiffResponse\x12\x11\n\tfrom_path\x18\x01 \x01(\x0c\x12\x0f\n\x07to_path\x18\x02 \x01(\x0c\x12\x0f\n\x07\x66rom_id\x18\x03 \x01(\t\x12\r\n\x05to_id\x18\x04 \x01(\t\x12\x10\n\x08old_mode\x18\x05 \x01(\x05\x12\x10\n\x08new_mode\x18\x06 \x01(\x05\x12\x0e\n\x06\x62inary\x18\x07 \x01(\x08\x12\x16\n\x0eraw_patch_data\x18\t \x01(\x0c\x12\x14\n\x0c\x65nd_of_patch\x18\n \x01(\x08\x12\x17\n\x0foverflow_marker\x18\x0b \x01(\x08\x12\x11\n\tcollapsed\x18\x0c \x01(\x08\x12\x11\n\ttoo_large\x18\r \x01(\x08J\x04\x08\x08\x10\t\"\x82\x01\n\x12\x43ommitDeltaRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\x12\r\n\x05paths\x18\x04 \x03(\x0c\"u\n\x0b\x43ommitDelta\x12\x11\n\tfrom_path\x18\x01 \x01(\x0c\x12\x0f\n\x07to_path\x18\x02 \x01(\x0c\x12\x0f\n\x07\x66rom_id\x18\x03 \x01(\t\x12\r\n\x05to_id\x18\x04 \x01(\t\x12\x10\n\x08old_mode\x18\x05 \x01(\x05\x12\x10\n\x08new_mode\x18\x06 \x01(\x05\":\n\x13\x43ommitDeltaResponse\x12#\n\x06\x64\x65ltas\x18\x01 \x03(\x0b\x32\x13.gitaly.CommitDelta\"o\n\x0eRawDiffRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\"\x1f\n\x0fRawDiffResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"p\n\x0fRawPatchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\" \n\x10RawPatchResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"q\n\x10\x44iffStatsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\"Q\n\tDiffStats\x12\x0c\n\x04path\x18\x01 \x01(\x0c\x12\x11\n\tadditions\x18\x02 \x01(\x05\x12\x11\n\tdeletions\x18\x03 \x01(\x05\x12\x10\n\x08old_path\x18\x04 \x01(\x0c\"5\n\x11\x44iffStatsResponse\x12 \n\x05stats\x18\x01 \x03(\x0b\x32\x11.gitaly.DiffStats\"\xdc\x03\n\x17\x46indChangedPathsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x13\n\x07\x63ommits\x18\x02 \x03(\tB\x02\x18\x01\x12\x39\n\x08requests\x18\x03 \x03(\x0b\x32\'.gitaly.FindChangedPathsRequest.Request\x1a\xc2\x02\n\x07Request\x12K\n\x0ctree_request\x18\x01 \x01(\x0b\x32\x33.gitaly.FindChangedPathsRequest.Request.TreeRequestH\x00\x12O\n\x0e\x63ommit_request\x18\x02 \x01(\x0b\x32\x35.gitaly.FindChangedPathsRequest.Request.CommitRequestH\x00\x1a\x46\n\x0bTreeRequest\x12\x1a\n\x12left_tree_revision\x18\x01 \x01(\t\x12\x1b\n\x13right_tree_revision\x18\x02 \x01(\t\x1aI\n\rCommitRequest\x12\x17\n\x0f\x63ommit_revision\x18\x01 \x01(\t\x12\x1f\n\x17parent_commit_revisions\x18\x02 \x03(\tB\x06\n\x04type\"?\n\x18\x46indChangedPathsResponse\x12#\n\x05paths\x18\x01 \x03(\x0b\x32\x14.gitaly.ChangedPaths\"\xba\x01\n\x0c\x43hangedPaths\x12\x0c\n\x04path\x18\x01 \x01(\x0c\x12+\n\x06status\x18\x02 \x01(\x0e\x32\x1b.gitaly.ChangedPaths.Status\x12\x10\n\x08old_mode\x18\x03 \x01(\x05\x12\x10\n\x08new_mode\x18\x04 \x01(\x05\"K\n\x06Status\x12\t\n\x05\x41\x44\x44\x45\x44\x10\x00\x12\x0c\n\x08MODIFIED\x10\x01\x12\x0b\n\x07\x44\x45LETED\x10\x02\x12\x0f\n\x0bTYPE_CHANGE\x10\x03\x12\n\n\x06\x43OPIED\x10\x04\x32\xea\x03\n\x0b\x44iffService\x12M\n\nCommitDiff\x12\x19.gitaly.CommitDiffRequest\x1a\x1a.gitaly.CommitDiffResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12P\n\x0b\x43ommitDelta\x12\x1a.gitaly.CommitDeltaRequest\x1a\x1b.gitaly.CommitDeltaResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x44\n\x07RawDiff\x12\x16.gitaly.RawDiffRequest\x1a\x17.gitaly.RawDiffResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12G\n\x08RawPatch\x12\x17.gitaly.RawPatchRequest\x1a\x18.gitaly.RawPatchResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12J\n\tDiffStats\x12\x18.gitaly.DiffStatsRequest\x1a\x19.gitaly.DiffStatsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x10\x46indChangedPaths\x12\x1f.gitaly.FindChangedPathsRequest\x1a .gitaly.FindChangedPathsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3'
+  serialized_pb=b'\n\ndiff.proto\x12\x06gitaly\x1a\nlint.proto\x1a\x0cshared.proto\"\xfb\x04\n\x11\x43ommitDiffRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\x12 \n\x18ignore_whitespace_change\x18\x04 \x01(\x08\x12\r\n\x05paths\x18\x05 \x03(\x0c\x12\x16\n\x0e\x63ollapse_diffs\x18\x06 \x01(\x08\x12\x16\n\x0e\x65nforce_limits\x18\x07 \x01(\x08\x12\x11\n\tmax_files\x18\x08 \x01(\x05\x12\x11\n\tmax_lines\x18\t \x01(\x05\x12\x11\n\tmax_bytes\x18\n \x01(\x05\x12\x17\n\x0fmax_patch_bytes\x18\x0e \x01(\x05\x12\x16\n\x0esafe_max_files\x18\x0b \x01(\x05\x12\x16\n\x0esafe_max_lines\x18\x0c \x01(\x05\x12\x16\n\x0esafe_max_bytes\x18\r \x01(\x05\x12\x35\n\tdiff_mode\x18\x0f \x01(\x0e\x32\".gitaly.CommitDiffRequest.DiffMode\x12h\n\"max_patch_bytes_for_file_extension\x18\x10 \x03(\x0b\x32<.gitaly.CommitDiffRequest.MaxPatchBytesForFileExtensionEntry\x1a\x44\n\"MaxPatchBytesForFileExtensionEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"%\n\x08\x44iffMode\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x00\x12\x0c\n\x08WORDDIFF\x10\x01\"\xff\x01\n\x12\x43ommitDiffResponse\x12\x11\n\tfrom_path\x18\x01 \x01(\x0c\x12\x0f\n\x07to_path\x18\x02 \x01(\x0c\x12\x0f\n\x07\x66rom_id\x18\x03 \x01(\t\x12\r\n\x05to_id\x18\x04 \x01(\t\x12\x10\n\x08old_mode\x18\x05 \x01(\x05\x12\x10\n\x08new_mode\x18\x06 \x01(\x05\x12\x0e\n\x06\x62inary\x18\x07 \x01(\x08\x12\x16\n\x0eraw_patch_data\x18\t \x01(\x0c\x12\x14\n\x0c\x65nd_of_patch\x18\n \x01(\x08\x12\x17\n\x0foverflow_marker\x18\x0b \x01(\x08\x12\x11\n\tcollapsed\x18\x0c \x01(\x08\x12\x11\n\ttoo_large\x18\r \x01(\x08J\x04\x08\x08\x10\t\"\x82\x01\n\x12\x43ommitDeltaRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\x12\r\n\x05paths\x18\x04 \x03(\x0c\"u\n\x0b\x43ommitDelta\x12\x11\n\tfrom_path\x18\x01 \x01(\x0c\x12\x0f\n\x07to_path\x18\x02 \x01(\x0c\x12\x0f\n\x07\x66rom_id\x18\x03 \x01(\t\x12\r\n\x05to_id\x18\x04 \x01(\t\x12\x10\n\x08old_mode\x18\x05 \x01(\x05\x12\x10\n\x08new_mode\x18\x06 \x01(\x05\":\n\x13\x43ommitDeltaResponse\x12#\n\x06\x64\x65ltas\x18\x01 \x03(\x0b\x32\x13.gitaly.CommitDelta\"o\n\x0eRawDiffRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\"\x1f\n\x0fRawDiffResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"p\n\x0fRawPatchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\" \n\x10RawPatchResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"q\n\x10\x44iffStatsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\"Q\n\tDiffStats\x12\x0c\n\x04path\x18\x01 \x01(\x0c\x12\x11\n\tadditions\x18\x02 \x01(\x05\x12\x11\n\tdeletions\x18\x03 \x01(\x05\x12\x10\n\x08old_path\x18\x04 \x01(\x0c\"5\n\x11\x44iffStatsResponse\x12 \n\x05stats\x18\x01 \x03(\x0b\x32\x11.gitaly.DiffStats\"\xdc\x03\n\x17\x46indChangedPathsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x13\n\x07\x63ommits\x18\x02 \x03(\tB\x02\x18\x01\x12\x39\n\x08requests\x18\x03 \x03(\x0b\x32\'.gitaly.FindChangedPathsRequest.Request\x1a\xc2\x02\n\x07Request\x12K\n\x0ctree_request\x18\x01 \x01(\x0b\x32\x33.gitaly.FindChangedPathsRequest.Request.TreeRequestH\x00\x12O\n\x0e\x63ommit_request\x18\x02 \x01(\x0b\x32\x35.gitaly.FindChangedPathsRequest.Request.CommitRequestH\x00\x1a\x46\n\x0bTreeRequest\x12\x1a\n\x12left_tree_revision\x18\x01 \x01(\t\x12\x1b\n\x13right_tree_revision\x18\x02 \x01(\t\x1aI\n\rCommitRequest\x12\x17\n\x0f\x63ommit_revision\x18\x01 \x01(\t\x12\x1f\n\x17parent_commit_revisions\x18\x02 \x03(\tB\x06\n\x04type\"?\n\x18\x46indChangedPathsResponse\x12#\n\x05paths\x18\x01 \x03(\x0b\x32\x14.gitaly.ChangedPaths\"\xba\x01\n\x0c\x43hangedPaths\x12\x0c\n\x04path\x18\x01 \x01(\x0c\x12+\n\x06status\x18\x02 \x01(\x0e\x32\x1b.gitaly.ChangedPaths.Status\x12\x10\n\x08old_mode\x18\x03 \x01(\x05\x12\x10\n\x08new_mode\x18\x04 \x01(\x05\"K\n\x06Status\x12\t\n\x05\x41\x44\x44\x45\x44\x10\x00\x12\x0c\n\x08MODIFIED\x10\x01\x12\x0b\n\x07\x44\x45LETED\x10\x02\x12\x0f\n\x0bTYPE_CHANGE\x10\x03\x12\n\n\x06\x43OPIED\x10\x04\"m\n\x11GetPatchIDRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x14\n\x0cold_revision\x18\x02 \x01(\x0c\x12\x14\n\x0cnew_revision\x18\x03 \x01(\x0c\"&\n\x12GetPatchIDResponse\x12\x10\n\x08patch_id\x18\x01 \x01(\t2\xb7\x04\n\x0b\x44iffService\x12M\n\nCommitDiff\x12\x19.gitaly.CommitDiffRequest\x1a\x1a.gitaly.CommitDiffResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12P\n\x0b\x43ommitDelta\x12\x1a.gitaly.CommitDeltaRequest\x1a\x1b.gitaly.CommitDeltaResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x44\n\x07RawDiff\x12\x16.gitaly.RawDiffRequest\x1a\x17.gitaly.RawDiffResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12G\n\x08RawPatch\x12\x17.gitaly.RawPatchRequest\x1a\x18.gitaly.RawPatchResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12J\n\tDiffStats\x12\x18.gitaly.DiffStatsRequest\x1a\x19.gitaly.DiffStatsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x10\x46indChangedPaths\x12\x1f.gitaly.FindChangedPathsRequest\x1a .gitaly.FindChangedPathsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12K\n\nGetPatchID\x12\x19.gitaly.GetPatchIDRequest\x1a\x1a.gitaly.GetPatchIDResponse\"\x06\xfa\x97(\x02\x08\x02\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3'
   ,
   dependencies=[lint__pb2.DESCRIPTOR,shared__pb2.DESCRIPTOR,])
 
@@ -47,8 +47,8 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=471,
-  serialized_end=508,
+  serialized_start=647,
+  serialized_end=684,
 )
 _sym_db.RegisterEnumDescriptor(_COMMITDIFFREQUEST_DIFFMODE)
 
@@ -87,9 +87,9 @@
   ],
   containing_type=None,
   serialized_options=None,
-  serialized_start=2283,
-  serialized_end=2358,
+  serialized_start=2459,
+  serialized_end=2534,
 )
 _sym_db.RegisterEnumDescriptor(_CHANGEDPATHS_STATUS)
 
 
@@ -92,7 +92,45 @@
 )
 _sym_db.RegisterEnumDescriptor(_CHANGEDPATHS_STATUS)
 
 
+_COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY = _descriptor.Descriptor(
+  name='MaxPatchBytesForFileExtensionEntry',
+  full_name='gitaly.CommitDiffRequest.MaxPatchBytesForFileExtensionEntry',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='key', full_name='gitaly.CommitDiffRequest.MaxPatchBytesForFileExtensionEntry.key', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='value', full_name='gitaly.CommitDiffRequest.MaxPatchBytesForFileExtensionEntry.value', index=1,
+      number=2, type=5, cpp_type=1, label=1,
+      has_default_value=False, default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=b'8\001',
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=577,
+  serialized_end=645,
+)
+
 _COMMITDIFFREQUEST = _descriptor.Descriptor(
   name='CommitDiffRequest',
   full_name='gitaly.CommitDiffRequest',
@@ -206,6 +244,13 @@
       message_type=None, enum_type=None, containing_type=None,
       is_extension=False, extension_scope=None,
       serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='max_patch_bytes_for_file_extension', full_name='gitaly.CommitDiffRequest.max_patch_bytes_for_file_extension', index=15,
+      number=16, type=11, cpp_type=10, label=3,
+      has_default_value=False, default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
   ],
   extensions=[
   ],
@@ -209,7 +254,7 @@
   ],
   extensions=[
   ],
-  nested_types=[],
+  nested_types=[_COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY, ],
   enum_types=[
     _COMMITDIFFREQUEST_DIFFMODE,
   ],
@@ -220,7 +265,7 @@
   oneofs=[
   ],
   serialized_start=49,
-  serialized_end=508,
+  serialized_end=684,
 )
 
 
@@ -328,8 +373,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=511,
-  serialized_end=766,
+  serialized_start=687,
+  serialized_end=942,
 )
 
 
@@ -381,8 +426,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=769,
-  serialized_end=899,
+  serialized_start=945,
+  serialized_end=1075,
 )
 
 
@@ -448,8 +493,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=901,
-  serialized_end=1018,
+  serialized_start=1077,
+  serialized_end=1194,
 )
 
 
@@ -480,8 +525,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1020,
-  serialized_end=1078,
+  serialized_start=1196,
+  serialized_end=1254,
 )
 
 
@@ -526,8 +571,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1080,
-  serialized_end=1191,
+  serialized_start=1256,
+  serialized_end=1367,
 )
 
 
@@ -558,8 +603,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1193,
-  serialized_end=1224,
+  serialized_start=1369,
+  serialized_end=1400,
 )
 
 
@@ -604,8 +649,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1226,
-  serialized_end=1338,
+  serialized_start=1402,
+  serialized_end=1514,
 )
 
 
@@ -636,8 +681,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1340,
-  serialized_end=1372,
+  serialized_start=1516,
+  serialized_end=1548,
 )
 
 
@@ -682,8 +727,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1374,
-  serialized_end=1487,
+  serialized_start=1550,
+  serialized_end=1663,
 )
 
 
@@ -735,8 +780,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1489,
-  serialized_end=1570,
+  serialized_start=1665,
+  serialized_end=1746,
 )
 
 
@@ -767,8 +812,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1572,
-  serialized_end=1625,
+  serialized_start=1748,
+  serialized_end=1801,
 )
 
 
@@ -806,8 +851,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1951,
-  serialized_end=2021,
+  serialized_start=2127,
+  serialized_end=2197,
 )
 
 _FINDCHANGEDPATHSREQUEST_REQUEST_COMMITREQUEST = _descriptor.Descriptor(
@@ -844,8 +889,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2023,
-  serialized_end=2096,
+  serialized_start=2199,
+  serialized_end=2272,
 )
 
 _FINDCHANGEDPATHSREQUEST_REQUEST = _descriptor.Descriptor(
@@ -887,8 +932,8 @@
       create_key=_descriptor._internal_create_key,
     fields=[]),
   ],
-  serialized_start=1782,
-  serialized_end=2104,
+  serialized_start=1958,
+  serialized_end=2280,
 )
 
 _FINDCHANGEDPATHSREQUEST = _descriptor.Descriptor(
@@ -932,8 +977,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=1628,
-  serialized_end=2104,
+  serialized_start=1804,
+  serialized_end=2280,
 )
 
 
@@ -964,8 +1009,8 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2106,
-  serialized_end=2169,
+  serialized_start=2282,
+  serialized_end=2345,
 )
 
 
@@ -1018,7 +1063,7 @@
   extension_ranges=[],
   oneofs=[
   ],
-  serialized_start=2172,
-  serialized_end=2358,
+  serialized_start=2348,
+  serialized_end=2534,
 )
 
@@ -1023,4 +1068,83 @@
 )
 
+
+_GETPATCHIDREQUEST = _descriptor.Descriptor(
+  name='GetPatchIDRequest',
+  full_name='gitaly.GetPatchIDRequest',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='repository', full_name='gitaly.GetPatchIDRequest.repository', index=0,
+      number=1, type=11, cpp_type=10, label=1,
+      has_default_value=False, default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=b'\230\306,\001', file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='old_revision', full_name='gitaly.GetPatchIDRequest.old_revision', index=1,
+      number=2, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+    _descriptor.FieldDescriptor(
+      name='new_revision', full_name='gitaly.GetPatchIDRequest.new_revision', index=2,
+      number=3, type=12, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"",
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2536,
+  serialized_end=2645,
+)
+
+
+_GETPATCHIDRESPONSE = _descriptor.Descriptor(
+  name='GetPatchIDResponse',
+  full_name='gitaly.GetPatchIDResponse',
+  filename=None,
+  file=DESCRIPTOR,
+  containing_type=None,
+  create_key=_descriptor._internal_create_key,
+  fields=[
+    _descriptor.FieldDescriptor(
+      name='patch_id', full_name='gitaly.GetPatchIDResponse.patch_id', index=0,
+      number=1, type=9, cpp_type=9, label=1,
+      has_default_value=False, default_value=b"".decode('utf-8'),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      serialized_options=None, file=DESCRIPTOR,  create_key=_descriptor._internal_create_key),
+  ],
+  extensions=[
+  ],
+  nested_types=[],
+  enum_types=[
+  ],
+  serialized_options=None,
+  is_extendable=False,
+  syntax='proto3',
+  extension_ranges=[],
+  oneofs=[
+  ],
+  serialized_start=2647,
+  serialized_end=2685,
+)
+
+_COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY.containing_type = _COMMITDIFFREQUEST
 _COMMITDIFFREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY
 _COMMITDIFFREQUEST.fields_by_name['diff_mode'].enum_type = _COMMITDIFFREQUEST_DIFFMODE
@@ -1025,5 +1149,6 @@
 _COMMITDIFFREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY
 _COMMITDIFFREQUEST.fields_by_name['diff_mode'].enum_type = _COMMITDIFFREQUEST_DIFFMODE
+_COMMITDIFFREQUEST.fields_by_name['max_patch_bytes_for_file_extension'].message_type = _COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY
 _COMMITDIFFREQUEST_DIFFMODE.containing_type = _COMMITDIFFREQUEST
 _COMMITDELTAREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY
 _COMMITDELTARESPONSE.fields_by_name['deltas'].message_type = _COMMITDELTA
@@ -1047,6 +1172,7 @@
 _FINDCHANGEDPATHSRESPONSE.fields_by_name['paths'].message_type = _CHANGEDPATHS
 _CHANGEDPATHS.fields_by_name['status'].enum_type = _CHANGEDPATHS_STATUS
 _CHANGEDPATHS_STATUS.containing_type = _CHANGEDPATHS
+_GETPATCHIDREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY
 DESCRIPTOR.message_types_by_name['CommitDiffRequest'] = _COMMITDIFFREQUEST
 DESCRIPTOR.message_types_by_name['CommitDiffResponse'] = _COMMITDIFFRESPONSE
 DESCRIPTOR.message_types_by_name['CommitDeltaRequest'] = _COMMITDELTAREQUEST
@@ -1062,6 +1188,8 @@
 DESCRIPTOR.message_types_by_name['FindChangedPathsRequest'] = _FINDCHANGEDPATHSREQUEST
 DESCRIPTOR.message_types_by_name['FindChangedPathsResponse'] = _FINDCHANGEDPATHSRESPONSE
 DESCRIPTOR.message_types_by_name['ChangedPaths'] = _CHANGEDPATHS
+DESCRIPTOR.message_types_by_name['GetPatchIDRequest'] = _GETPATCHIDREQUEST
+DESCRIPTOR.message_types_by_name['GetPatchIDResponse'] = _GETPATCHIDRESPONSE
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 CommitDiffRequest = _reflection.GeneratedProtocolMessageType('CommitDiffRequest', (_message.Message,), {
@@ -1065,8 +1193,15 @@
 _sym_db.RegisterFileDescriptor(DESCRIPTOR)
 
 CommitDiffRequest = _reflection.GeneratedProtocolMessageType('CommitDiffRequest', (_message.Message,), {
+
+  'MaxPatchBytesForFileExtensionEntry' : _reflection.GeneratedProtocolMessageType('MaxPatchBytesForFileExtensionEntry', (_message.Message,), {
+    'DESCRIPTOR' : _COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY,
+    '__module__' : 'diff_pb2'
+    # @@protoc_insertion_point(class_scope:gitaly.CommitDiffRequest.MaxPatchBytesForFileExtensionEntry)
+    })
+  ,
   'DESCRIPTOR' : _COMMITDIFFREQUEST,
   '__module__' : 'diff_pb2'
   # @@protoc_insertion_point(class_scope:gitaly.CommitDiffRequest)
   })
 _sym_db.RegisterMessage(CommitDiffRequest)
@@ -1068,8 +1203,9 @@
   'DESCRIPTOR' : _COMMITDIFFREQUEST,
   '__module__' : 'diff_pb2'
   # @@protoc_insertion_point(class_scope:gitaly.CommitDiffRequest)
   })
 _sym_db.RegisterMessage(CommitDiffRequest)
+_sym_db.RegisterMessage(CommitDiffRequest.MaxPatchBytesForFileExtensionEntry)
 
 CommitDiffResponse = _reflection.GeneratedProtocolMessageType('CommitDiffResponse', (_message.Message,), {
   'DESCRIPTOR' : _COMMITDIFFRESPONSE,
@@ -1193,5 +1329,19 @@
   })
 _sym_db.RegisterMessage(ChangedPaths)
 
+GetPatchIDRequest = _reflection.GeneratedProtocolMessageType('GetPatchIDRequest', (_message.Message,), {
+  'DESCRIPTOR' : _GETPATCHIDREQUEST,
+  '__module__' : 'diff_pb2'
+  # @@protoc_insertion_point(class_scope:gitaly.GetPatchIDRequest)
+  })
+_sym_db.RegisterMessage(GetPatchIDRequest)
+
+GetPatchIDResponse = _reflection.GeneratedProtocolMessageType('GetPatchIDResponse', (_message.Message,), {
+  'DESCRIPTOR' : _GETPATCHIDRESPONSE,
+  '__module__' : 'diff_pb2'
+  # @@protoc_insertion_point(class_scope:gitaly.GetPatchIDResponse)
+  })
+_sym_db.RegisterMessage(GetPatchIDResponse)
+
 
 DESCRIPTOR._options = None
@@ -1196,5 +1346,6 @@
 
 DESCRIPTOR._options = None
+_COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY._options = None
 _COMMITDIFFREQUEST.fields_by_name['repository']._options = None
 _COMMITDELTAREQUEST.fields_by_name['repository']._options = None
 _RAWDIFFREQUEST.fields_by_name['repository']._options = None
@@ -1202,6 +1353,7 @@
 _DIFFSTATSREQUEST.fields_by_name['repository']._options = None
 _FINDCHANGEDPATHSREQUEST.fields_by_name['repository']._options = None
 _FINDCHANGEDPATHSREQUEST.fields_by_name['commits']._options = None
+_GETPATCHIDREQUEST.fields_by_name['repository']._options = None
 
 _DIFFSERVICE = _descriptor.ServiceDescriptor(
   name='DiffService',
@@ -1210,8 +1362,8 @@
   index=0,
   serialized_options=None,
   create_key=_descriptor._internal_create_key,
-  serialized_start=2361,
-  serialized_end=2851,
+  serialized_start=2688,
+  serialized_end=3255,
   methods=[
   _descriptor.MethodDescriptor(
     name='CommitDiff',
@@ -1273,6 +1425,16 @@
     serialized_options=b'\372\227(\002\010\002',
     create_key=_descriptor._internal_create_key,
   ),
+  _descriptor.MethodDescriptor(
+    name='GetPatchID',
+    full_name='gitaly.DiffService.GetPatchID',
+    index=6,
+    containing_service=None,
+    input_type=_GETPATCHIDREQUEST,
+    output_type=_GETPATCHIDRESPONSE,
+    serialized_options=b'\372\227(\002\010\002',
+    create_key=_descriptor._internal_create_key,
+  ),
 ])
 _sym_db.RegisterServiceDescriptor(_DIFFSERVICE)
 
diff --git a/hgitaly/stub/diff_pb2_grpc.py b/hgitaly/stub/diff_pb2_grpc.py
index 7e77711d64ac8959e7f1e1dc1f22b71f59c2c15c_aGdpdGFseS9zdHViL2RpZmZfcGIyX2dycGMucHk=..983e393511be21081cdd3c280e5eb6de80b820bf_aGdpdGFseS9zdHViL2RpZmZfcGIyX2dycGMucHk= 100644
--- a/hgitaly/stub/diff_pb2_grpc.py
+++ b/hgitaly/stub/diff_pb2_grpc.py
@@ -46,6 +46,11 @@
                 request_serializer=diff__pb2.FindChangedPathsRequest.SerializeToString,
                 response_deserializer=diff__pb2.FindChangedPathsResponse.FromString,
                 )
+        self.GetPatchID = channel.unary_unary(
+                '/gitaly.DiffService/GetPatchID',
+                request_serializer=diff__pb2.GetPatchIDRequest.SerializeToString,
+                response_deserializer=diff__pb2.GetPatchIDResponse.FromString,
+                )
 
 
 class DiffServiceServicer(object):
@@ -95,6 +100,16 @@
         context.set_details('Method not implemented!')
         raise NotImplementedError('Method not implemented!')
 
+    def GetPatchID(self, request, context):
+        """GetPatchID computes a patch ID for a patch. Patch IDs are a unique ID computed by hashing
+        a patch with some parameters like line numbers ignored. The patch ID can thus be used to compare
+        whether diffs make the same change. Please refer to git-patch-id(1) for further information.
+        If the difference between old and new change is empty then this RPC returns an error.
+        """
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
 
 def add_DiffServiceServicer_to_server(servicer, server):
     rpc_method_handlers = {
@@ -128,6 +143,11 @@
                     request_deserializer=diff__pb2.FindChangedPathsRequest.FromString,
                     response_serializer=diff__pb2.FindChangedPathsResponse.SerializeToString,
             ),
+            'GetPatchID': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetPatchID,
+                    request_deserializer=diff__pb2.GetPatchIDRequest.FromString,
+                    response_serializer=diff__pb2.GetPatchIDResponse.SerializeToString,
+            ),
     }
     generic_handler = grpc.method_handlers_generic_handler(
             'gitaly.DiffService', rpc_method_handlers)
@@ -241,3 +261,20 @@
             diff__pb2.FindChangedPathsResponse.FromString,
             options, channel_credentials,
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def GetPatchID(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/gitaly.DiffService/GetPatchID',
+            diff__pb2.GetPatchIDRequest.SerializeToString,
+            diff__pb2.GetPatchIDResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/hgitaly/stub/repository_pb2_grpc.py b/hgitaly/stub/repository_pb2_grpc.py
index 7e77711d64ac8959e7f1e1dc1f22b71f59c2c15c_aGdpdGFseS9zdHViL3JlcG9zaXRvcnlfcGIyX2dycGMucHk=..983e393511be21081cdd3c280e5eb6de80b820bf_aGdpdGFseS9zdHViL3JlcG9zaXRvcnlfcGIyX2dycGMucHk= 100644
--- a/hgitaly/stub/repository_pb2_grpc.py
+++ b/hgitaly/stub/repository_pb2_grpc.py
@@ -325,7 +325,8 @@
         raise NotImplementedError('Method not implemented!')
 
     def Fsck(self, request, context):
-        """This comment is left unintentionally blank.
+        """Fsck checks the repository for consistency via git-fsck(1). This can be used to check for
+        repository corruption.
         """
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
         context.set_details('Method not implemented!')