Skip to content

Make submit work with 'git rebase -i' #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions src/stack_pr/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@

import argparse
import configparser
import contextlib
import json
import logging
import os
Expand Down Expand Up @@ -526,6 +527,24 @@ def draft_bitmask_type(value: str) -> list[bool]:
return [bool(int(bit)) for bit in value]


@contextlib.contextmanager
def maybe_stash_interactive_rebase() -> Iterator[None]:
"""
If the user is in the middle of an interactive rebase, we stash the
rebase state so that we can restore it later. This is useful when
the user is trying to submit only part of their commit history.
"""
if os.path.exists(".git/rebase-merge"):
try:
assert not os.path.exists(".git/rebase-merge-stashed")
os.rename(".git/rebase-merge", ".git/rebase-merge-stashed")
yield
finally:
os.rename(".git/rebase-merge-stashed", ".git/rebase-merge")
else:
yield


# ===----------------------------------------------------------------------=== #
# SUBMIT
# ===----------------------------------------------------------------------=== #
Expand Down Expand Up @@ -1500,13 +1519,14 @@ def main() -> None: # noqa: PLR0912
common_args = deduce_base(common_args)

if args.command in ["submit", "export"]:
command_submit(
common_args,
draft=args.draft,
reviewer=args.reviewer,
keep_body=args.keep_body,
draft_bitmask=args.draft_bitmask,
)
with maybe_stash_interactive_rebase():
command_submit(
common_args,
draft=args.draft,
reviewer=args.reviewer,
keep_body=args.keep_body,
draft_bitmask=args.draft_bitmask,
)
elif args.command == "land":
command_land(common_args)
elif args.command == "abandon":
Expand Down
12 changes: 10 additions & 2 deletions src/stack_pr/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def get_current_branch_name(repo_dir: Path | None = None) -> str:
repo_dir: path to the repo. Defaults to the current working directory.

Returns:
The name of the branch currently checked out, or "HEAD" if the repo is
The name of the branch currently checked out, or a hash if the repo is
in a 'detached HEAD' state

Raises:
Expand All @@ -92,9 +92,17 @@ def get_current_branch_name(repo_dir: Path | None = None) -> str:
"""

try:
return get_command_output(
result = get_command_output(
["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=repo_dir
).strip()
if result == "HEAD":
# Detached HEAD state, return a hash so we can cleanup after ourselves properly, since
# git checkout HEAD
# is a no-op.
result = get_command_output(
["git", "rev-parse", "HEAD"], cwd=repo_dir
).strip()
return result
except subprocess.CalledProcessError as e:
if e.returncode == GIT_NOT_A_REPO_ERROR:
raise GitError("Not inside a valid git repository.") from e
Expand Down
3 changes: 2 additions & 1 deletion src/stack_pr/shell_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def run_shell_command(
raise ValueError("shell support has been removed")
_ = subprocess.list2cmdline(cmd)
if quiet:
kwargs.update({"stdout": subprocess.DEVNULL, "stderr": subprocess.DEVNULL})
# Use pipes so errors result in usable error messages
kwargs.update({"stdout": subprocess.PIPE, "stderr": subprocess.PIPE})
logger.debug("Running: %s", cmd)
return subprocess.run(list(map(str, cmd)), **kwargs, check=check)

Expand Down
Loading