From 508e80765cc439f6258204f91ec523da5c56f1c0 Mon Sep 17 00:00:00 2001 From: Zach Grant Date: Sun, 12 Oct 2025 13:12:02 -0500 Subject: [PATCH] Add revup reset command implementation - Add reset.py module with main reset functionality - Add hard_reset() method to Git class in git.py - Register reset command in revup.py parser and command handling - Add documentation in docs/reset.md The reset command performs 'git reset --hard @{u}' to reset the current branch to match its upstream tracking branch. Motivation: When working with revup across multiple computers (specifically important when working remotely with limited internet) it is often needed to reset your local branch to what has been pushed by another computer before continuing development. This adds a quick shortcut for doing that. Of course you can run the git command directly, or create an alias, but that requires extra setup when using temporary machines such as Coder instances frequently. This packages it neatly with revup. topic: add-reset branches: main reviewers: --- docs/reset.md | 37 +++++++++++++++++++++++++++++++++++++ revup/git.py | 7 +++++++ revup/reset.py | 33 +++++++++++++++++++++++++++++++++ revup/revup.py | 12 ++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 docs/reset.md create mode 100644 revup/reset.py diff --git a/docs/reset.md b/docs/reset.md new file mode 100644 index 0000000..dec36eb --- /dev/null +++ b/docs/reset.md @@ -0,0 +1,37 @@ +# NAME + +reset - reset current branch to upstream + +# SYNOPSIS + +**revup reset** [**--help**] + +# DESCRIPTION + +The `revup reset` command performs a hard reset of the current branch to match its upstream tracking branch. This is equivalent to running `git reset --hard @{u}`. + +This command is useful when you want to discard all local changes and commits on the current branch and sync it exactly with the upstream version. + +# OPTIONS + +**--help**, **-h** +: Show help message and exit + +# EXAMPLES + +Reset the current branch to match upstream: + +``` +revup reset +``` + +# NOTES + +- The command will fail if the current branch doesn't have an upstream tracking branch configured +- This operation discards all local changes and commits, so use with caution +- All uncommitted or unpushed changes will be lost permanently +- The working directory will be updated to match the upstream state + +# SEE ALSO + +**revup-upload**(1), **revup-restack**(1), **revup-amend**(1) diff --git a/revup/git.py b/revup/git.py index 9bf049b..b56a70a 100644 --- a/revup/git.py +++ b/revup/git.py @@ -796,6 +796,13 @@ async def soft_reset(self, new_commit: GitCommitHash, env: Dict) -> None: # TODO: only strictly needs to drop entries for HEAD self.clear_cache() + async def hard_reset(self, new_commit: str, env: Optional[Dict[str, str]] = None) -> None: + """ + Perform a hard reset to the given commit. + """ + await self.git("reset", "--hard", new_commit, env=env or {}) + self.clear_cache() + async def credential(self, **kwargs: str) -> str: cred = Credential(self, description=kwargs) await cred.fill() diff --git a/revup/reset.py b/revup/reset.py new file mode 100644 index 0000000..afd6bf6 --- /dev/null +++ b/revup/reset.py @@ -0,0 +1,33 @@ +import argparse + +from rich import get_console + +from revup import git + + +async def main(_: argparse.Namespace, git_ctx: git.Git) -> int: + """ + Handles the "reset" command. + Resets the current branch to match the upstream tracking branch. + """ + # Get the current branch + current_branch = await git_ctx.git_stdout("branch", "--show-current") + if not current_branch: + raise RuntimeError("Not on a branch") + + # Get the upstream tracking branch + upstream_ref = "@{u}" + + with get_console().status(f"Resetting {current_branch} to {upstream_ref}..."): + try: + # Verify the upstream exists + await git_ctx.git_stdout("rev-parse", "--verify", upstream_ref) + + # Perform the hard reset + await git_ctx.hard_reset(upstream_ref) + + print(f"Successfully reset {current_branch} to {upstream_ref}") + return 0 + except RuntimeError as e: + print(f"Error: {str(e)}") + return 1 diff --git a/revup/revup.py b/revup/revup.py index eac4415..b36ef36 100755 --- a/revup/revup.py +++ b/revup/revup.py @@ -200,6 +200,10 @@ async def main() -> int: "cherry-pick", add_help=False, ) + reset_parser = subparsers.add_parser( + "reset", + add_help=False, + ) amend_parser = subparsers.add_parser("amend", aliases=["commit"], add_help=False) config_parser = subparsers.add_parser( "config", @@ -214,6 +218,7 @@ async def main() -> int: revup_parser, amend_parser, cherry_pick_parser, + reset_parser, restack_parser, upload_parser, ] @@ -267,6 +272,8 @@ async def main() -> int: cherry_pick_parser.add_argument("branch", nargs=1) cherry_pick_parser.add_argument("--base-branch", "-b") + reset_parser.add_argument("--help", "-h", action=HelpAction, nargs=0) + config_parser.add_argument("--help", "-h", action=HelpAction, nargs=0) config_parser.add_argument("flag", nargs=1) config_parser.add_argument("value", nargs="?") @@ -389,6 +396,11 @@ async def main() -> int: return await restack.main(args=args, git_ctx=git_ctx) + elif args.cmd == "reset": + from revup import reset + + return await reset.main(args, git_ctx) + async with github_connection(args=args, git_ctx=git_ctx, conf=conf) as ( github_ep, repo_info,