diff --git a/revup/amend.py b/revup/amend.py index 1e891f5..1593c48 100644 --- a/revup/amend.py +++ b/revup/amend.py @@ -229,10 +229,13 @@ async def main(args: argparse.Namespace, git_ctx: git.Git) -> int: """ async def get_has_unstaged() -> bool: + # Not converted to plumbing (diff-files/diff-index). This compares the + # worktree, where diff-index returns 1 on a stale mtime even with no content + # change, so it would report spurious unstaged changes. return args.all and await git_ctx.git_return_code("diff", "--no-renames", "--quiet") != 0 has_staged, has_unstaged = await asyncio.gather( - git_ctx.git_return_code("diff", "--cached", "--no-renames", "--quiet"), + git_ctx.git_return_code("diff-index", "--cached", "--no-renames", "--quiet", "HEAD"), get_has_unstaged(), ) @@ -266,7 +269,7 @@ async def get_has_unstaged() -> bool: if args.last_touched: staged_files_output = await git_ctx.git_stdout( - "diff", "--cached", "--name-only", "--no-renames" + "diff-index", "--cached", "-r", "--name-only", "--no-renames", "HEAD" ) if not staged_files_output: return 0 @@ -338,7 +341,7 @@ async def get_has_unstaged() -> bool: await get_topic_summary(topics) if args.parse_topics else "", stack[0].commit_msg, ( - await git_ctx.git_stdout("--no-pager", "diff", "--cached", "--stat", "--no-color") + await git_ctx.git_stdout("diff-index", "--cached", "-r", "-M", "HEAD", "--stat") if has_diff else "" ), @@ -346,7 +349,7 @@ async def get_has_unstaged() -> bool: "" if args.insert else await git_ctx.git_stdout( - "--no-pager", "diff", commit + "~", commit, "--stat", "--no-color" + "diff-tree", "-r", "-M", commit + "~", commit, "--stat" ) ), ) diff --git a/revup/git.py b/revup/git.py index cd78188..b6984df 100644 --- a/revup/git.py +++ b/revup/git.py @@ -525,9 +525,13 @@ async def get_best_base_branch( ret = candidates[0] if len(candidates) == 1: return ret - current_branch = (await self.git("branch", "--show-current"))[1] + # symbolic-ref errors (rc != 0) on a detached HEAD; treat that as no branch. + ret_code, branch_out = await self.git( + "symbolic-ref", "-q", "--short", "HEAD", raiseonerror=False + ) + current_branch = branch_out if ret_code == 0 else None for c in candidates: - if c == f"{self.remote_name}/{current_branch}": + if current_branch is not None and c == f"{self.remote_name}/{current_branch}": ret = c break elif c == f"{self.remote_name}/{self.main_branch}": @@ -640,7 +644,9 @@ async def get_diff_summary( Return the summary of the diff (files and lines changed) """ return ( - await self.git_stdout("diff", "--shortstat", parent, commit, no_config=True) + await self.git_stdout( + "diff-tree", "-r", "-M", "--shortstat", parent, commit, no_config=True + ) ).rstrip() async def merge_tree_commit( @@ -689,7 +695,7 @@ async def dump_conflict_markers(self, tree: GitTreeHash, path: str) -> None: """ groups: List[List[int]] = [] conflict_depth = 0 - lines = (await self.git_stdout("show", f"{tree}:{path}")).split("\n") + lines = (await self.git_stdout("cat-file", "-p", f"{tree}:{path}")).split("\n") for lineno, line in enumerate(lines): if line.startswith("<" * 7): if conflict_depth == 0: