Skip to content

Commit 0995c3b

Browse files
committed
Support pathspecs in --cut
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.
1 parent 5a10920 commit 0995c3b

File tree

4 files changed

+75
-5
lines changed

4 files changed

+75
-5
lines changed

docs/man.rst

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ SYNOPSIS
1010
========
1111

1212
*git revise* [<options>] [<target>]
13+
*git revise* [<options>] --cut <target> [--] [<pathspec>...]
1314

1415
DESCRIPTION
1516
===========
@@ -93,8 +94,9 @@ Main modes of operation
9394

9495
.. option:: -c, --cut
9596

96-
Interactively select hunks from <target>. The chosen hunks are split into
97-
a second commit immediately after the target.
97+
Interactively select hunks from <target>, optionally limited by <pathspec>.
98+
The chosen hunks are split into a second commit immediately after the
99+
target.
98100

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

gitrevise/tui.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ def build_parser() -> ArgumentParser:
3636
nargs="?",
3737
help="target commit to apply fixups to",
3838
)
39+
parser.add_argument(
40+
"pathspecs", nargs="*", help="make --cut select only from matching files"
41+
)
3942
parser.add_argument("--ref", default="HEAD", help="reference to update")
4043
parser.add_argument(
4144
"--reauthor",
@@ -201,7 +204,7 @@ def noninteractive(
201204

202205
# If the commit should be cut, prompt the user to perform the cut.
203206
if args.cut:
204-
current = cut_commit(current)
207+
current = cut_commit(current, args.pathspecs)
205208

206209
# Add or remove GPG signatures.
207210
if repo.sign_commits != bool(current.gpgsig):

gitrevise/utils.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def update_head(ref: Reference[Commit], new: Commit, expected: Optional[Tree]) -
252252
)
253253

254254

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

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

275275
# Run an interactive git-reset to allow picking which pieces of the
276276
# patch should go into the first part.
277-
index.git("reset", "--patch", final_tree.persist().hex(), "--", ".", stdout=None)
277+
index.git(
278+
"reset",
279+
"--patch",
280+
final_tree.persist().hex(),
281+
"--",
282+
*pathspecs if pathspecs else ".",
283+
stdout=None,
284+
)
278285

279286
# Write out the newly created tree.
280287
mid_tree = index.tree()

tests/test_cut.py

+58
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from textwrap import dedent
2+
13
from gitrevise.odb import Repository
24

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

8587
assert new_u != new
8688
assert new_u != prev
89+
90+
91+
def test_cut_pathspec(repo: Repository) -> None:
92+
bash(
93+
"""
94+
echo "Hello, World" >> file1
95+
git add file1
96+
git commit -m "commit 1"
97+
98+
echo "Append f1" >> file1
99+
echo "Make f2" >> file2
100+
git add file1 file2
101+
git commit -m "commit 2"
102+
"""
103+
)
104+
105+
with editor_main(["--cut", "HEAD", "file2"], input=b"y\n") as ed:
106+
with ed.next_file() as f:
107+
assert f.startswith_dedent("[1] commit 2\n")
108+
f.replace_dedent("extracted changes\n")
109+
110+
with ed.next_file() as f:
111+
assert f.startswith_dedent("[2] commit 2\n")
112+
f.replace_dedent("remaining changes\n")
113+
114+
assert (
115+
repo.git("show", "HEAD~", "--format=%s").decode()
116+
== dedent(
117+
"""
118+
extracted changes
119+
120+
diff --git a/file2 b/file2
121+
new file mode 100644
122+
index 0000000..93350fe
123+
--- /dev/null
124+
+++ b/file2
125+
@@ -0,0 +1 @@
126+
+Make f2"""
127+
)[1:]
128+
)
129+
130+
assert (
131+
repo.git("show", "HEAD", "--format=%s").decode()
132+
== dedent(
133+
"""
134+
remaining changes
135+
136+
diff --git a/file1 b/file1
137+
index 3fa0d4b..ada44cf 100644
138+
--- a/file1
139+
+++ b/file1
140+
@@ -1 +1,2 @@
141+
Hello, World
142+
+Append f1"""
143+
)[1:]
144+
)

0 commit comments

Comments
 (0)