diff --git a/core/commands/pull.py b/core/commands/pull.py index 5a6b6f404..db6a2ba15 100644 --- a/core/commands/pull.py +++ b/core/commands/pull.py @@ -1,9 +1,12 @@ -import sublime -from sublime_plugin import WindowCommand - -from ..git_command import GitCommand from ...common import util from ..ui_mixins.quick_panel import show_branch_panel +from GitSavvy.core.base_commands import Args, GsCommand, GsWindowCommand, Kont +from GitSavvy.core.fns import flatten, unique +from GitSavvy.core.runtime import on_worker +from GitSavvy.core import store + +from typing import Callable, List, Optional, Sequence +from ..git_mixins.branches import Branch __all__ = ( @@ -12,13 +15,14 @@ ) -class GsPullBase(WindowCommand, GitCommand): +class GsPullBase(GsWindowCommand): def do_pull(self, remote, remote_branch, rebase): + # type: (str, str, Optional[bool]) -> None """ Perform `git pull remote branch`. """ self.window.status_message("Starting pull...") - output = self.pull(remote=remote, remote_branch=remote_branch, rebase=rebase).strip() + output = self.pull(remote, remote_branch, rebase).strip() self.window.status_message( output if output == "Already up to date." else "Pull complete." ) @@ -30,41 +34,54 @@ class gs_pull(GsPullBase): Pull from remote tracking branch if it is found. Otherwise, use GsPullFromBranchCommand. """ - def run(self, rebase=False): - self.rebase = rebase - sublime.set_timeout_async(self.run_async) - - def run_async(self): - rebase = self.rebase - if not rebase: - # honor the `pull.rebase` config implicitly - pull_rebase = self.git("config", "pull.rebase", throw_on_error=False) - if pull_rebase and pull_rebase.strip() == "true": - rebase = True + @on_worker + def run(self, rebase=None): upstream = self.get_upstream_for_active_branch() if upstream: - self.do_pull(remote=upstream.remote, remote_branch=upstream.branch, rebase=rebase) + self.do_pull(upstream.remote, upstream.branch, rebase) else: self.window.run_command("gs_pull_from_branch", {"rebase": rebase}) +def ask_for_branch(self, args, done): + # type: (GsCommand, Args, Kont) -> None + last_used_branch = store.current_state(self.repo_path).get("last_branch_used_to_pull_from") + + def _done(branch): + store.update_state(self.repo_path, {"last_branch_used_to_pull_from": branch}) + done(branch) + + show_branch_panel( + _done, + ask_remote_first=False, + ignore_current_branch=True, + selected_branch=last_used_branch + ) + + class gs_pull_from_branch(GsPullBase): """ - Through a series of panels, allow the user to pull from a remote branch. + Through a series of panels, allow the user to pull from a branch. """ + defaults = { + "branch": ask_for_branch + } - def run(self, rebase=False): - self.rebase = rebase - sublime.set_timeout_async(self.run_async) - - def run_async(self): - show_branch_panel( - self.on_branch_selection, - ask_remote_first=True + @on_worker + def run(self, branch, rebase=None): + # type: (str, bool) -> None + sources: Sequence[Callable[[], List[Branch]]] = ( + # Typically, `ask_for_branch`s `show_branch_panel` has just called + # `get_branches` so the cached value in the store should be fresh + # and good to go. + lambda: store.current_state(self.repo_path).get("branches", []), + self.get_branches, ) - - def on_branch_selection(self, branch): - selected_remote, selected_remote_branch = branch.split("/", 1) - - sublime.set_timeout_async( - lambda: self.do_pull(selected_remote, selected_remote_branch, self.rebase)) + branches = unique(flatten(getter() for getter in sources)) + for branch_ in branches: + if branch_.canonical_name == branch: + self.do_pull(branch_.remote or ".", branch_.name, rebase) + break + else: + self.window.status_message( + f"fatal: the name '{branch}' is not in the list of the current branches") diff --git a/core/git_mixins/remotes.py b/core/git_mixins/remotes.py index 81267150a..a6d0a4c2f 100644 --- a/core/git_mixins/remotes.py +++ b/core/git_mixins/remotes.py @@ -2,6 +2,7 @@ from GitSavvy.core.git_command import BranchesMixin, _GitCommand from GitSavvy.core.fns import filter_ +from GitSavvy.core.utils import yes_no_switch from GitSavvy.core import store @@ -65,14 +66,14 @@ def fetch(self, remote=None, refspec=None, prune=True, local_branch=None, remote refspec or None, ) - def pull(self, remote=None, remote_branch=None, rebase=False): + def pull(self, remote=None, remote_branch=None, rebase=None): """ Pull from the specified remote and branch if provided, otherwise perform default `git pull`. """ return self.git( "pull", - "--rebase" if rebase else None, + yes_no_switch("--rebase", rebase), remote if remote else None, remote_branch if remote and remote_branch else None ) diff --git a/core/store.py b/core/store.py index f8ce7a6fc..ccdc2fc35 100644 --- a/core/store.py +++ b/core/store.py @@ -29,6 +29,7 @@ "remotes": Dict[str, str], "local_tags": TagList, "last_branches": Deque[Optional[str]], + "last_branch_used_to_pull_from": Optional[str], "last_local_branch_for_rebase": Optional[str], "last_remote_used": Optional[str], "last_remote_used_for_push": Optional[str],