diff --git a/CHANGELOG b/CHANGELOG index afa840b..10cfe52 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ v0.3.1 (unreleased): +- Added a `--prune` flag to delete remote-tracking branches that no longer + exist on their remote after fetching. - Fixed a bug related to Python 3 compatibility. v0.3 (released June 7, 2015): diff --git a/README.md b/README.md index 0d4e9da..bfc125a 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,10 @@ upstreams configured. It will always skip branches where this is not possible (e.g. dirty working directory or a merge/rebase is required). Pass `--fetch-only` (or `-f`) to only fetch remotes. +After fetching, gitup will _keep_ remote-tracking branches that no longer exist +upstream. Pass `--prune` (or `-p`) to delete them, or set `fetch.prune` or +`remote..prune` in git config to do this by default. + For a full list of all command arguments and abbreviations: gitup --help diff --git a/gitup/script.py b/gitup/script.py index d353412..d4bb3b9 100644 --- a/gitup/script.py +++ b/gitup/script.py @@ -41,6 +41,9 @@ def main(): group_u.add_argument( '-f', '--fetch-only', action="store_true", help="only fetch remotes, don't try to fast-forward any branches") + group_u.add_argument( + '-p', '--prune', action="store_true", help="""after fetching, delete + remote-tracking branches that no longer exist on their remote""") group_b.add_argument( '-a', '--add', dest="bookmarks_to_add", nargs="+", metavar="path", @@ -66,7 +69,7 @@ def main(): color_init(autoreset=True) args = parser.parse_args() - update_args = args.current_only, args.fetch_only + update_args = args.current_only, args.fetch_only, args.prune print(Style.BRIGHT + "gitup" + Style.RESET_ALL + ": the git-repo-updater") print() diff --git a/gitup/update.py b/gitup/update.py index a121a67..80a5f04 100644 --- a/gitup/update.py +++ b/gitup/update.py @@ -53,12 +53,13 @@ class _ProgressMonitor(RemoteProgress): print(str(cur_count), end=end) -def _fetch_remotes(remotes): +def _fetch_remotes(remotes, prune): """Fetch a list of remotes, displaying progress info along the way.""" def _get_name(ref): """Return the local name of a remote or tag reference.""" return ref.remote_head if isinstance(ref, RemoteRef) else ref.name + # TODO: missing branch deleted (via --prune): info = [("NEW_HEAD", "new branch", "new branches"), ("NEW_TAG", "new tag", "new tags"), ("FAST_FORWARD", "branch update", "branch updates")] @@ -72,7 +73,7 @@ def _fetch_remotes(remotes): continue try: - results = remote.fetch(progress=_ProgressMonitor()) + results = remote.fetch(progress=_ProgressMonitor(), prune=prune) except exc.GitCommandError as err: msg = err.command[0].replace("Error when fetching: ", "") if not msg.endswith("."): @@ -101,12 +102,16 @@ def _update_branch(repo, branch, is_active=False): if not upstream: print(YELLOW + "skipped:", "no upstream is tracked.") return - try: - branch.commit, upstream.commit + branch.commit except ValueError: print(YELLOW + "skipped:", "branch has no revisions.") return + try: + upstream.commit + except ValueError: + print(YELLOW + "skipped:", "upstream does not exist.") + return base = repo.git.merge_base(branch.commit, upstream.commit) if repo.commit(base) == upstream.commit: @@ -133,13 +138,15 @@ def _update_branch(repo, branch, is_active=False): repo.git.branch(branch.name, upstream.name, force=True) print(GREEN + "done", end=".\n") -def _update_repository(repo, current_only=False, fetch_only=False): +def _update_repository(repo, current_only, fetch_only, prune): """Update a single git repository by fetching remotes and rebasing/merging. 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``. If *fetch_only* is ``False``, we will also update all fast-forwardable branches that are tracking valid upstreams. + If *prune* is ``True``, remote-tracking branches that no longer exist on + their remote after fetching will be deleted. """ print(INDENT1, BOLD + os.path.split(repo.working_dir)[1] + ":") @@ -163,7 +170,7 @@ def _update_repository(repo, current_only=False, fetch_only=False): if not remotes: print(INDENT2, ERROR, "no remotes configured to fetch.") return - _fetch_remotes(remotes) + _fetch_remotes(remotes, prune) if not fetch_only: for branch in sorted(repo.heads, key=lambda b: b.name):