Browse Source

More work on GitPython integration.

tags/v0.2
Ben Kurtovic 10 years ago
parent
commit
8b07934369
2 changed files with 70 additions and 43 deletions
  1. +3
    -3
      gitup/script.py
  2. +67
    -40
      gitup/update.py

+ 3
- 3
gitup/script.py View File

@@ -41,7 +41,7 @@ def main():
rebase_or_merge.add_argument(
'-r', '--rebase', action="store_true", help="""always rebase upstream
branches instead of following `pull.rebase` and `branch.<name>.rebase`
in git config (like `git pull --rebase`)""")
in git config (like `git pull --rebase=preserve`)""")
rebase_or_merge.add_argument(
'-m', '--merge', action="store_true", help="""like --rebase, but merge
instead""")
@@ -82,10 +82,10 @@ def main():
list_bookmarks()
acted = True
if args.directories_to_update:
update_directories(args.directories_to_update, *update_args)
update_directories(args.directories_to_update, update_args)
acted = True
if args.update or not acted:
update_bookmarks(get_bookmarks(), *update_args)
update_bookmarks(get_bookmarks(), update_args)

def run():
"""Thin wrapper for main() that catches KeyboardInterrupts."""


+ 67
- 40
gitup/update.py View File

@@ -20,46 +20,74 @@ RESET = Style.RESET_ALL

INDENT1 = " " * 3
INDENT2 = " " * 7
ERROR = RED + "Error:" + RESET

def _update_repository(repo, rebase=True):
def _read_config(repo, attr):
"""Read an attribute from git config."""
try:
return repo.git.config("--get", attr)
except exc.GitCommandError:
return None

def _update_repository(repo, current_only=False, rebase=False, merge=False,
verbose=False):
"""Update a single git repository by fetching remotes and rebasing/merging.

The specific actions depends on ...
The specific actions depend on the arguments given. We will fetch all
remotes if *current_only* is ``False``, or only the remote tracked by the
current branch if ``True``. By default, we will merge unless
``pull.rebase`` or ``branch.<name>.rebase`` is set in config; *rebase* will
cause us to always rebase with ``--preserve-merges``, and *merge* will
cause us to always merge. If *verbose* is set, additional information is
printed out for the user.
"""
def _update_branch(branch):
"""Update a single branch."""
print(INDENT2, "Updating branch:", branch, end=" ")
upstream = branch.tracking_branch()
if not upstream:
print("Branch is not tracking any remote.")
continue
c_attr = "branch.{0}.rebase".format(branch.name)
if not merge and (rebase or repo_rebase or _read_config(repo, c_attr)):
### TODO: rebase
else:
### TODO: merge

print(INDENT1, BOLD + os.path.split(repo.working_dir)[1] + ":")

ref = repo.head.ref.tracking_branch()
if ref:
remote = repo.remotes[ref.remote_name]
# else:
###
active = repo.active_branch
if current_only:
ref = active.tracking_branch()
if not ref:
print(INDENT2, ERROR, "no remote tracked by current branch.")
return
remotes = [repo.remotes[ref.remote_name]]
else:
remotes = repo.remotes

remote.fetch()
for remote in remotes:
print(INDENT2, "Fetching remote:", remote.name)
remote.fetch() # TODO: show progress

if not repo.remotes:
print(INDENT2, RED + "Error:" + RESET, "no remotes configured.")
return
try:
repo = repo.remotes.origin
except AttributeError:
if len(repo.remotes) == 1:
repo = repo.remotes[0]
else:
print(INDENT2, RED + "Error:" + RESET, "ambiguous remotes:",
", ".join(remote.name for remote in repo.remotes))
repo_rebase = _read_config(repo, "pull.rebase")

_update_branch(active)
branches = set(repo.heads) - {active}
if branches:
stashed = repo.git.stash("--all") != "No local changes to save"
try:
for branch in sorted(branches, key=lambda b: b.name):
branch.checkout()
_update_branch(branch)
finally:
active.checkout()
if stashed:
repo.git.stash("pop")

#####################################

try:
# Check if there is anything to pull, but don't do it yet:
dry_fetch = _exec_shell("git fetch --dry-run")
except subprocess.CalledProcessError:
print(INDENT2, RED + "Error:" + RESET, "cannot fetch;",
"do you have a remote repository configured correctly?")
return

try:
last_commit = _exec_shell("git log -n 1 --pretty=\"%ar\"")
except subprocess.CalledProcessError:
last_commit = "never" # Couldn't get a log, so no commits
@@ -87,7 +115,7 @@ def _update_repository(repo, rebase=True):
"you have uncommitted changes in this repository!")
print(INDENT2, "Ignoring.")

def _update_subdirectories(path, long_name):
def _update_subdirectories(path, long_name, update_args):
"""Update all subdirectories that are git repos in a given directory."""
repos = []
for item in os.listdir(path):
@@ -101,9 +129,9 @@ def _update_subdirectories(path, long_name):
print(long_name[0].upper() + long_name[1:],
"contains {0} git repositor{1}:".format(len(repos), suffix))
for repo in sorted(repos, key=lambda r: os.path.split(r.working_dir)[1]):
_update_repository(repo)
_update_repository(repo, *update_args)

def _update_directory(path, is_bookmark=False):
def _update_directory(path, update_args, is_bookmark=False):
"""Update a particular directory.

Determine whether the directory is a git repo on its own, a directory of
@@ -117,29 +145,28 @@ def _update_directory(path, is_bookmark=False):
try:
repo = Repo(path)
except exc.NoSuchPathError:
print(RED + "Error:" + RESET, long_name, "doesn't exist!")
print(ERROR, long_name, "doesn't exist!")
except exc.InvalidGitRepositoryError:
if os.path.isdir(path):
_update_subdirectories(path, long_name)
_update_subdirectories(path, long_name, update_args)
else:
print(RED + "Error:" + RESET, long_name, "isn't a repository!")
print(ERROR, long_name, "isn't a repository!")
else:
long_name = (dir_type.capitalize() + ' "' + BOLD + repo.working_dir +
RESET + '"')
print(long_name, "is a git repository:")
_update_repository(repo)
_update_repository(repo, *update_args)

def update_bookmarks(bookmarks, current_only=False, rebase=False, merge=False,
verbose=False):
def update_bookmarks(bookmarks, update_args):
"""Loop through and update all bookmarks."""
if bookmarks:
for path, name in bookmarks:
_update_directory(path, is_bookmark=True)
_update_directory(path, update_args, is_bookmark=True)
else:
print("You don't have any bookmarks configured! Get help with 'gitup -h'.")

def update_directories(paths, current_only=False, rebase=False, merge=False,
verbose=False):
def update_directories(paths, update_args):
"""Update a list of directories supplied by command arguments."""
for path in paths:
_update_directory(os.path.abspath(path), is_bookmark=False)
full_path = os.path.abspath(path)
_update_directory(full_path, update_args, is_bookmark=False)

Loading…
Cancel
Save