|
1 | | -from git.config import SectionConstraint |
2 | | -from git.util import join_path |
3 | | -from git.exc import GitCommandError |
4 | | - |
5 | | -from .symbolic import SymbolicReference |
6 | | -from .reference import Reference |
7 | | - |
8 | | -# typinng --------------------------------------------------- |
9 | | - |
10 | | -from typing import Any, Sequence, Union, TYPE_CHECKING |
11 | | - |
12 | | -from git.types import PathLike, Commit_ish |
13 | | - |
14 | | -if TYPE_CHECKING: |
15 | | - from git.repo import Repo |
16 | | - from git.objects import Commitfrom git.config import GitConfigParser, SectionConstraint |
| 1 | +from git.config import GitConfigParser, SectionConstraint |
17 | 2 | from git.util import join_path |
18 | 3 | from git.exc import GitCommandError |
19 | 4 |
|
@@ -276,250 +261,3 @@ def config_writer(self) -> SectionConstraint[GitConfigParser]: |
276 | 261 | return self._config_parser(read_only=False) |
277 | 262 |
|
278 | 263 | #} END configuration |
279 | | - |
280 | | - from git.refs import RemoteReference |
281 | | - |
282 | | -# ------------------------------------------------------------------- |
283 | | - |
284 | | -__all__ = ["HEAD", "Head"] |
285 | | - |
286 | | - |
287 | | -def strip_quotes(string): |
288 | | - if string.startswith('"') and string.endswith('"'): |
289 | | - return string[1:-1] |
290 | | - return string |
291 | | - |
292 | | - |
293 | | -class HEAD(SymbolicReference): |
294 | | - |
295 | | - """Special case of a Symbolic Reference as it represents the repository's |
296 | | - HEAD reference.""" |
297 | | - _HEAD_NAME = 'HEAD' |
298 | | - _ORIG_HEAD_NAME = 'ORIG_HEAD' |
299 | | - __slots__ = () |
300 | | - |
301 | | - def __init__(self, repo: 'Repo', path: PathLike = _HEAD_NAME): |
302 | | - if path != self._HEAD_NAME: |
303 | | - raise ValueError("HEAD instance must point to %r, got %r" % (self._HEAD_NAME, path)) |
304 | | - super(HEAD, self).__init__(repo, path) |
305 | | - self.commit: 'Commit' |
306 | | - |
307 | | - def orig_head(self) -> SymbolicReference: |
308 | | - """ |
309 | | - :return: SymbolicReference pointing at the ORIG_HEAD, which is maintained |
310 | | - to contain the previous value of HEAD""" |
311 | | - return SymbolicReference(self.repo, self._ORIG_HEAD_NAME) |
312 | | - |
313 | | - def reset(self, commit: Union[Commit_ish, SymbolicReference, str] = 'HEAD', |
314 | | - index: bool = True, working_tree: bool = False, |
315 | | - paths: Union[PathLike, Sequence[PathLike], None] = None, **kwargs: Any) -> 'HEAD': |
316 | | - """Reset our HEAD to the given commit optionally synchronizing |
317 | | - the index and working tree. The reference we refer to will be set to |
318 | | - commit as well. |
319 | | -
|
320 | | - :param commit: |
321 | | - Commit object, Reference Object or string identifying a revision we |
322 | | - should reset HEAD to. |
323 | | -
|
324 | | - :param index: |
325 | | - If True, the index will be set to match the given commit. Otherwise |
326 | | - it will not be touched. |
327 | | -
|
328 | | - :param working_tree: |
329 | | - If True, the working tree will be forcefully adjusted to match the given |
330 | | - commit, possibly overwriting uncommitted changes without warning. |
331 | | - If working_tree is True, index must be true as well |
332 | | -
|
333 | | - :param paths: |
334 | | - Single path or list of paths relative to the git root directory |
335 | | - that are to be reset. This allows to partially reset individual files. |
336 | | -
|
337 | | - :param kwargs: |
338 | | - Additional arguments passed to git-reset. |
339 | | -
|
340 | | - :return: self""" |
341 | | - mode: Union[str, None] |
342 | | - mode = "--soft" |
343 | | - if index: |
344 | | - mode = "--mixed" |
345 | | - |
346 | | - # it appears, some git-versions declare mixed and paths deprecated |
347 | | - # see http://github.com/Byron/GitPython/issues#issue/2 |
348 | | - if paths: |
349 | | - mode = None |
350 | | - # END special case |
351 | | - # END handle index |
352 | | - |
353 | | - if working_tree: |
354 | | - mode = "--hard" |
355 | | - if not index: |
356 | | - raise ValueError("Cannot reset the working tree if the index is not reset as well") |
357 | | - |
358 | | - # END working tree handling |
359 | | - |
360 | | - try: |
361 | | - self.repo.git.reset(mode, commit, '--', paths, **kwargs) |
362 | | - except GitCommandError as e: |
363 | | - # git nowadays may use 1 as status to indicate there are still unstaged |
364 | | - # modifications after the reset |
365 | | - if e.status != 1: |
366 | | - raise |
367 | | - # END handle exception |
368 | | - |
369 | | - return self |
370 | | - |
371 | | - |
372 | | -class Head(Reference): |
373 | | - |
374 | | - """A Head is a named reference to a Commit. Every Head instance contains a name |
375 | | - and a Commit object. |
376 | | -
|
377 | | - Examples:: |
378 | | -
|
379 | | - >>> repo = Repo("/path/to/repo") |
380 | | - >>> head = repo.heads[0] |
381 | | -
|
382 | | - >>> head.name |
383 | | - 'master' |
384 | | -
|
385 | | - >>> head.commit |
386 | | - <git.Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455"> |
387 | | -
|
388 | | - >>> head.commit.hexsha |
389 | | - '1c09f116cbc2cb4100fb6935bb162daa4723f455'""" |
390 | | - _common_path_default = "refs/heads" |
391 | | - k_config_remote = "remote" |
392 | | - k_config_remote_ref = "merge" # branch to merge from remote |
393 | | - |
394 | | - @classmethod |
395 | | - def delete(cls, repo: 'Repo', *heads: 'Head', **kwargs: Any): |
396 | | - """Delete the given heads |
397 | | -
|
398 | | - :param force: |
399 | | - If True, the heads will be deleted even if they are not yet merged into |
400 | | - the main development stream. |
401 | | - Default False""" |
402 | | - force = kwargs.get("force", False) |
403 | | - flag = "-d" |
404 | | - if force: |
405 | | - flag = "-D" |
406 | | - repo.git.branch(flag, *heads) |
407 | | - |
408 | | - def set_tracking_branch(self, remote_reference: 'RemoteReference') -> 'Head': |
409 | | - """ |
410 | | - Configure this branch to track the given remote reference. This will alter |
411 | | - this branch's configuration accordingly. |
412 | | -
|
413 | | - :param remote_reference: The remote reference to track or None to untrack |
414 | | - any references |
415 | | - :return: self""" |
416 | | - from .remote import RemoteReference |
417 | | - if remote_reference is not None and not isinstance(remote_reference, RemoteReference): |
418 | | - raise ValueError("Incorrect parameter type: %r" % remote_reference) |
419 | | - # END handle type |
420 | | - |
421 | | - with self.config_writer() as writer: |
422 | | - if remote_reference is None: |
423 | | - writer.remove_option(self.k_config_remote) |
424 | | - writer.remove_option(self.k_config_remote_ref) |
425 | | - if len(writer.options()) == 0: |
426 | | - writer.remove_section() |
427 | | - else: |
428 | | - writer.set_value(self.k_config_remote, remote_reference.remote_name) |
429 | | - writer.set_value(self.k_config_remote_ref, Head.to_full_path(remote_reference.remote_head)) |
430 | | - |
431 | | - return self |
432 | | - |
433 | | - def tracking_branch(self) -> Union['RemoteReference', None]: |
434 | | - """ |
435 | | - :return: The remote_reference we are tracking, or None if we are |
436 | | - not a tracking branch""" |
437 | | - from .remote import RemoteReference |
438 | | - reader = self.config_reader() |
439 | | - if reader.has_option(self.k_config_remote) and reader.has_option(self.k_config_remote_ref): |
440 | | - ref = Head(self.repo, Head.to_full_path(strip_quotes(reader.get_value(self.k_config_remote_ref)))) |
441 | | - remote_refpath = RemoteReference.to_full_path(join_path(reader.get_value(self.k_config_remote), ref.name)) |
442 | | - return RemoteReference(self.repo, remote_refpath) |
443 | | - # END handle have tracking branch |
444 | | - |
445 | | - # we are not a tracking branch |
446 | | - return None |
447 | | - |
448 | | - def rename(self, new_path: PathLike, force: bool = False) -> 'Head': |
449 | | - """Rename self to a new path |
450 | | -
|
451 | | - :param new_path: |
452 | | - Either a simple name or a path, i.e. new_name or features/new_name. |
453 | | - The prefix refs/heads is implied |
454 | | -
|
455 | | - :param force: |
456 | | - If True, the rename will succeed even if a head with the target name |
457 | | - already exists. |
458 | | -
|
459 | | - :return: self |
460 | | - :note: respects the ref log as git commands are used""" |
461 | | - flag = "-m" |
462 | | - if force: |
463 | | - flag = "-M" |
464 | | - |
465 | | - self.repo.git.branch(flag, self, new_path) |
466 | | - self.path = "%s/%s" % (self._common_path_default, new_path) |
467 | | - return self |
468 | | - |
469 | | - def checkout(self, force: bool = False, **kwargs: Any): |
470 | | - """Checkout this head by setting the HEAD to this reference, by updating the index |
471 | | - to reflect the tree we point to and by updating the working tree to reflect |
472 | | - the latest index. |
473 | | -
|
474 | | - The command will fail if changed working tree files would be overwritten. |
475 | | -
|
476 | | - :param force: |
477 | | - If True, changes to the index and the working tree will be discarded. |
478 | | - If False, GitCommandError will be raised in that situation. |
479 | | -
|
480 | | - :param kwargs: |
481 | | - Additional keyword arguments to be passed to git checkout, i.e. |
482 | | - b='new_branch' to create a new branch at the given spot. |
483 | | -
|
484 | | - :return: |
485 | | - The active branch after the checkout operation, usually self unless |
486 | | - a new branch has been created. |
487 | | - If there is no active branch, as the HEAD is now detached, the HEAD |
488 | | - reference will be returned instead. |
489 | | -
|
490 | | - :note: |
491 | | - By default it is only allowed to checkout heads - everything else |
492 | | - will leave the HEAD detached which is allowed and possible, but remains |
493 | | - a special state that some tools might not be able to handle.""" |
494 | | - kwargs['f'] = force |
495 | | - if kwargs['f'] is False: |
496 | | - kwargs.pop('f') |
497 | | - |
498 | | - self.repo.git.checkout(self, **kwargs) |
499 | | - if self.repo.head.is_detached: |
500 | | - return self.repo.head |
501 | | - return self.repo.active_branch |
502 | | - |
503 | | - #{ Configuration |
504 | | - def _config_parser(self, read_only: bool) -> SectionConstraint: |
505 | | - if read_only: |
506 | | - parser = self.repo.config_reader() |
507 | | - else: |
508 | | - parser = self.repo.config_writer() |
509 | | - # END handle parser instance |
510 | | - |
511 | | - return SectionConstraint(parser, 'branch "%s"' % self.name) |
512 | | - |
513 | | - def config_reader(self) -> SectionConstraint: |
514 | | - """ |
515 | | - :return: A configuration parser instance constrained to only read |
516 | | - this instance's values""" |
517 | | - return self._config_parser(read_only=True) |
518 | | - |
519 | | - def config_writer(self) -> SectionConstraint: |
520 | | - """ |
521 | | - :return: A configuration writer instance with read-and write access |
522 | | - to options of this head""" |
523 | | - return self._config_parser(read_only=False) |
524 | | - |
525 | | - #} END configuration |
0 commit comments