A console script that allows you to easily update multiple git repositories at once
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

146 rivejä
4.9 KiB

  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2011-2014 Ben Kurtovic <ben.kurtovic@gmail.com>
  4. # See the LICENSE file for details.
  5. from __future__ import print_function
  6. import os
  7. from colorama import Fore, Style
  8. from git import Repo, exc
  9. __all__ = ["update_bookmarks", "update_directories"]
  10. BOLD = Style.BRIGHT
  11. RED = Fore.RED + BOLD
  12. GREEN = Fore.GREEN + BOLD
  13. BLUE = Fore.BLUE + BOLD
  14. RESET = Style.RESET_ALL
  15. INDENT1 = " " * 3
  16. INDENT2 = " " * 7
  17. def _update_repository(repo, rebase=True):
  18. """Update a single git repository by fetching remotes and rebasing/merging.
  19. The specific actions depends on ...
  20. """
  21. print(INDENT1, BOLD + os.path.split(repo.working_dir)[1] + ":")
  22. ref = repo.head.ref.tracking_branch()
  23. if ref:
  24. remote = repo.remotes[ref.remote_name]
  25. # else:
  26. ###
  27. remote.fetch()
  28. if not repo.remotes:
  29. print(INDENT2, RED + "Error:" + RESET, "no remotes configured.")
  30. return
  31. try:
  32. repo = repo.remotes.origin
  33. except AttributeError:
  34. if len(repo.remotes) == 1:
  35. repo = repo.remotes[0]
  36. else:
  37. print(INDENT2, RED + "Error:" + RESET, "ambiguous remotes:",
  38. ", ".join(remote.name for remote in repo.remotes))
  39. #####################################
  40. try:
  41. # Check if there is anything to pull, but don't do it yet:
  42. dry_fetch = _exec_shell("git fetch --dry-run")
  43. except subprocess.CalledProcessError:
  44. print(INDENT2, RED + "Error:" + RESET, "cannot fetch;",
  45. "do you have a remote repository configured correctly?")
  46. return
  47. try:
  48. last_commit = _exec_shell("git log -n 1 --pretty=\"%ar\"")
  49. except subprocess.CalledProcessError:
  50. last_commit = "never" # Couldn't get a log, so no commits
  51. if not dry_fetch: # No new changes to pull
  52. print(INDENT2, BLUE + "No new changes." + RESET,
  53. "Last commit was {0}.".format(last_commit))
  54. else: # Stuff has happened!
  55. print(INDENT2, "There are new changes upstream...")
  56. status = _exec_shell("git status")
  57. if status.endswith("nothing to commit, working directory clean"):
  58. print(INDENT2, GREEN + "Pulling new changes...")
  59. result = _exec_shell("git pull")
  60. if last_commit == "never":
  61. print(INDENT2, "The following changes have been made:")
  62. else:
  63. print(INDENT2, "The following changes have been made since",
  64. last_commit + ":")
  65. print(result)
  66. else:
  67. print(INDENT2, RED + "Warning:" + RESET,
  68. "you have uncommitted changes in this repository!")
  69. print(INDENT2, "Ignoring.")
  70. def _update_subdirectories(path, long_name):
  71. """Update all subdirectories that are git repos in a given directory."""
  72. repos = []
  73. for item in os.listdir(path):
  74. try:
  75. repo = Repo(os.path.join(path, item))
  76. except (exc.InvalidGitRepositoryError, exc.NoSuchPathError):
  77. continue
  78. repos.append(repo)
  79. suffix = "ies" if len(repos) != 1 else "y"
  80. print(long_name[0].upper() + long_name[1:],
  81. "contains {0} git repositor{1}:".format(len(repos), suffix))
  82. for repo in sorted(repos, key=lambda r: os.path.split(r.working_dir)[1]):
  83. _update_repository(repo)
  84. def _update_directory(path, is_bookmark=False):
  85. """Update a particular directory.
  86. Determine whether the directory is a git repo on its own, a directory of
  87. git repositories, or something invalid. If the first, update the single
  88. repository; if the second, update all repositories contained within; if the
  89. third, print an error.
  90. """
  91. dir_type = "bookmark" if is_bookmark else "directory"
  92. long_name = dir_type + ' "' + BOLD + path + RESET + '"'
  93. try:
  94. repo = Repo(path)
  95. except exc.NoSuchPathError:
  96. print(RED + "Error:" + RESET, long_name, "doesn't exist!")
  97. except exc.InvalidGitRepositoryError:
  98. if os.path.isdir(path):
  99. _update_subdirectories(path, long_name)
  100. else:
  101. print(RED + "Error:" + RESET, long_name, "isn't a repository!")
  102. else:
  103. long_name = (dir_type.capitalize() + ' "' + BOLD + repo.working_dir +
  104. RESET + '"')
  105. print(long_name, "is a git repository:")
  106. _update_repository(repo)
  107. def update_bookmarks(bookmarks, current_only=False, rebase=False, merge=False,
  108. verbose=False):
  109. """Loop through and update all bookmarks."""
  110. if bookmarks:
  111. for path, name in bookmarks:
  112. _update_directory(path, is_bookmark=True)
  113. else:
  114. print("You don't have any bookmarks configured! Get help with 'gitup -h'.")
  115. def update_directories(paths, current_only=False, rebase=False, merge=False,
  116. verbose=False):
  117. """Update a list of directories supplied by command arguments."""
  118. for path in paths:
  119. _update_directory(os.path.abspath(path), is_bookmark=False)