@@ -161,15 +161,61 @@ def dereference_recursive(cls, repo: "Repo", ref_path: Union[PathLike, None]) ->
161
161
return hexsha
162
162
# END recursive dereferencing
163
163
164
+ @staticmethod
165
+ def _check_ref_name_valid (ref_path :PathLike )-> None :
166
+ # Based on the rules described in https://git-scm.com/docs/git-check-ref-format/#_description
167
+ previous :Union [str ,None ]= None
168
+ one_before_previous :Union [str ,None ]= None
169
+ for c in str (ref_path ):
170
+ if c in " ~^:?*[\\ " :
171
+ raise ValueError (
172
+ f"Invalid reference '{ ref_path } ': references cannot contain spaces, tildes (~), carets (^),"
173
+ f" colons (:), question marks (?), asterisks (*), open brackets ([) or backslashes (\\ )"
174
+ )
175
+ elif c == "." :
176
+ if previous is None or previous == "/" :
177
+ raise ValueError (
178
+ f"Invalid reference '{ ref_path } ': references cannot start with a period (.) or contain '/.'"
179
+ )
180
+ elif previous == "." :
181
+ raise ValueError (f"Invalid reference '{ ref_path } ': references cannot contain '..'" )
182
+ elif c == "/" :
183
+ if previous == "/" :
184
+ raise ValueError (f"Invalid reference '{ ref_path } ': references cannot contain '//'" )
185
+ elif previous is None :
186
+ raise ValueError (
187
+ f"Invalid reference '{ ref_path } ': references cannot start with forward slashes '/'"
188
+ )
189
+ elif c == "{" and previous == "@" :
190
+ raise ValueError (f"Invalid reference '{ ref_path } ': references cannot contain '@{{'" )
191
+ elif ord (c )< 32 or ord (c )== 127 :
192
+ raise ValueError (f"Invalid reference '{ ref_path } ': references cannot contain ASCII control characters" )
193
+
194
+ one_before_previous = previous
195
+ previous = c
196
+
197
+ if previous == "." :
198
+ raise ValueError (f"Invalid reference '{ ref_path } ': references cannot end with a period (.)" )
199
+ elif previous == "/" :
200
+ raise ValueError (f"Invalid reference '{ ref_path } ': references cannot end with a forward slash (/)" )
201
+ elif previous == "@" and one_before_previous is None :
202
+ raise ValueError (f"Invalid reference '{ ref_path } ': references cannot be '@'" )
203
+ elif any ([component .endswith (".lock" )for component in str (ref_path ).split ("/" )]):
204
+ raise ValueError (
205
+ f"Invalid reference '{ ref_path } ': references cannot have slash-separated components that end with"
206
+ f" '.lock'"
207
+ )
208
+
164
209
@classmethod
165
210
def _get_ref_info_helper (
166
211
cls ,repo :"Repo" ,ref_path :Union [PathLike ,None ]
167
212
)-> Union [Tuple [str ,None ],Tuple [None ,str ]]:
168
213
"""Return: (str(sha), str(target_ref_path)) if available, the sha the file at
169
214
rela_path points to, or None. target_ref_path is the reference we
170
215
point to, or None"""
171
- if ".." in str (ref_path ):
172
- raise ValueError (f"Invalid reference '{ ref_path } '" )
216
+ if ref_path :
217
+ cls ._check_ref_name_valid (ref_path )
218
+
173
219
tokens :Union [None ,List [str ],Tuple [str ,str ]]= None
174
220
repodir = _git_dir (repo ,ref_path )
175
221
try :