Skip to content

Commit

Permalink
Support pathspecs in --cut
Browse files Browse the repository at this point in the history
Sometimes I want to extract a small number of changes from a commit
that touches loads of files. Since the cut mode prompts about every
single file, there is no convenient way to do this.

Teach --cut about pathspec arguments.  This allows to use

	git revise --cut my-commit -- path/to/my/file
	a

to extract to a separate commit all changes in the given file.

In future we could support pathspecs in other subcommands.
  • Loading branch information
krobelus committed May 22, 2023
1 parent 5a10920 commit 0995c3b
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 5 deletions.
6 changes: 4 additions & 2 deletions docs/man.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ SYNOPSIS
========

*git revise* [<options>] [<target>]
*git revise* [<options>] --cut <target> [--] [<pathspec>...]

DESCRIPTION
===========
Expand Down Expand Up @@ -93,8 +94,9 @@ Main modes of operation

.. option:: -c, --cut

Interactively select hunks from <target>. The chosen hunks are split into
a second commit immediately after the target.
Interactively select hunks from <target>, optionally limited by <pathspec>.
The chosen hunks are split into a second commit immediately after the
target.

After splitting is complete, both commits' messages are edited.

Expand Down
5 changes: 4 additions & 1 deletion gitrevise/tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ def build_parser() -> ArgumentParser:
nargs="?",
help="target commit to apply fixups to",
)
parser.add_argument(
"pathspecs", nargs="*", help="make --cut select only from matching files"
)
parser.add_argument("--ref", default="HEAD", help="reference to update")
parser.add_argument(
"--reauthor",
Expand Down Expand Up @@ -201,7 +204,7 @@ def noninteractive(

# If the commit should be cut, prompt the user to perform the cut.
if args.cut:
current = cut_commit(current)
current = cut_commit(current, args.pathspecs)

# Add or remove GPG signatures.
if repo.sign_commits != bool(current.gpgsig):
Expand Down
11 changes: 9 additions & 2 deletions gitrevise/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def update_head(ref: Reference[Commit], new: Commit, expected: Optional[Tree]) -
)


def cut_commit(commit: Commit) -> Commit:
def cut_commit(commit: Commit, pathspecs: Optional[List[str]] = None) -> Commit:
"""Perform a ``cut`` operation on the given commit, and return the
modified commit."""

Expand All @@ -274,7 +274,14 @@ def cut_commit(commit: Commit) -> Commit:

# Run an interactive git-reset to allow picking which pieces of the
# patch should go into the first part.
index.git("reset", "--patch", final_tree.persist().hex(), "--", ".", stdout=None)
index.git(
"reset",
"--patch",
final_tree.persist().hex(),
"--",
*pathspecs if pathspecs else ".",
stdout=None,
)

# Write out the newly created tree.
mid_tree = index.tree()
Expand Down
58 changes: 58 additions & 0 deletions tests/test_cut.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from textwrap import dedent

from gitrevise.odb import Repository

from .conftest import bash, editor_main
Expand Down Expand Up @@ -84,3 +86,59 @@ def test_cut_root(repo: Repository) -> None:

assert new_u != new
assert new_u != prev


def test_cut_pathspec(repo: Repository) -> None:
bash(
"""
echo "Hello, World" >> file1
git add file1
git commit -m "commit 1"
echo "Append f1" >> file1
echo "Make f2" >> file2
git add file1 file2
git commit -m "commit 2"
"""
)

with editor_main(["--cut", "HEAD", "file2"], input=b"y\n") as ed:
with ed.next_file() as f:
assert f.startswith_dedent("[1] commit 2\n")
f.replace_dedent("extracted changes\n")

with ed.next_file() as f:
assert f.startswith_dedent("[2] commit 2\n")
f.replace_dedent("remaining changes\n")

assert (
repo.git("show", "HEAD~", "--format=%s").decode()
== dedent(
"""
extracted changes
diff --git a/file2 b/file2
new file mode 100644
index 0000000..93350fe
--- /dev/null
+++ b/file2
@@ -0,0 +1 @@
+Make f2"""
)[1:]
)

assert (
repo.git("show", "HEAD", "--format=%s").decode()
== dedent(
"""
remaining changes
diff --git a/file1 b/file1
index 3fa0d4b..ada44cf 100644
--- a/file1
+++ b/file1
@@ -1 +1,2 @@
Hello, World
+Append f1"""
)[1:]
)

0 comments on commit 0995c3b

Please sign in to comment.