Skip to content

Commit

Permalink
Allow for pass-through arguments to git machete diff and `git mache…
Browse files Browse the repository at this point in the history
…te log`
  • Loading branch information
PawelLipski committed Aug 17, 2024
1 parent fab9e18 commit 79a2b87
Show file tree
Hide file tree
Showing 14 changed files with 115 additions and 49 deletions.
4 changes: 4 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Release notes

## New in git-machete 3.28.0

- added: ability to specify pass-through flags in `diff` and `log`, for example `git machete diff -- file.txt`, `git machete log -- --patch` (partly contributed by @tdyas)

## New in git-machete 3.27.0

- added: git config key `http.sslVerify` is honored when connecting to GitHub and GitLab APIs (suggested by @scamden)
Expand Down
11 changes: 11 additions & 0 deletions ci/checks/prohibit-fork-point-in-git-context.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash

set -e -o pipefail -u

file=git_machete/git_operations.py
if git grep -n 'fork.point' $file; then
echo
echo "The above lines in $file refer to 'fork point'."
echo "$file should be oblivious to git-machete-specific concepts like fork point, please rename or move the code"
exit 1
fi
1 change: 1 addition & 0 deletions ci/checks/run-all-checks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enforce-shell-scripts-pass-shellcheck.sh
prohibit-bash-usages-from-python.sh
prohibit-deploy-step-in-circleci.sh
prohibit-exempli-gratia-in-rst.sh
prohibit-fork-point-in-git-context.sh
prohibit-id-est-in-rst.sh
prohibit-double-backticks-in-python.sh
prohibit-markdown-links-in-rst.sh
Expand Down
20 changes: 11 additions & 9 deletions docs/man/git-machete.1
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "GIT-MACHETE" "1" "Aug 08, 2024" "" "git-machete"
.TH "GIT-MACHETE" "1" "Aug 17, 2024" "" "git-machete"
.SH NAME
git-machete \- git-machete 3.27.0
git-machete \- git-machete 3.28.0
.sp
git machete is a robust tool that \fBsimplifies your git workflows\fP\&.
.sp
Expand Down Expand Up @@ -627,7 +627,7 @@ Don\(aqt ask for confirmation.
.INDENT 3.5
.sp
.EX
git machete d[iff] [\-s|\-\-stat] [<branch>]
git machete d[iff] [\-s|\-\-stat] [<branch>] [\-\- <pass\-through\-arguments>]
.EE
.UNINDENT
.UNINDENT
Expand All @@ -639,11 +639,9 @@ See help for \fI\%fork\-point\fP for more details on the meaning of \fIfork poin
Note: the branch in question does not need to occur in the branch layout file.
.sp
\fBOptions:\fP
.INDENT 0.0
.TP
.B \-s\fP,\fB \-\-stat
Makes \fBgit machete diff\fP pass \fB\-\-stat\fP option to \fBgit diff\fP, so that only summary (diffstat) is printed.
.UNINDENT
.sp
\-\- <pass\-through\-arguments> Arguments to pass directly to the underlying \fBgit diff\fP, for example \fBgit machete diff \-\- \-\-name\-only\fP\&.
\-s, \-\-stat Makes \fBgit machete diff\fP pass \fB\-\-stat\fP option to \fBgit diff\fP, so that only summary (diffstat) is printed.
.SH DISCOVER
.sp
\fBUsage:\fP
Expand Down Expand Up @@ -1490,7 +1488,7 @@ This command is generally not meant for a day\-to\-day use, it\(aqs mostly neede
.INDENT 3.5
.sp
.EX
git machete l[og] [<branch>]
git machete l[og] [<branch>] [\-\- <pass\-through\-arguments>]
.EE
.UNINDENT
.UNINDENT
Expand All @@ -1499,6 +1497,10 @@ Runs \fBgit log\fP for the range of commits from tip of the given branch (or cur
See help for \fI\%fork\-point\fP for more details on meaning of the \fIfork point\fP\&.
.sp
Note: the branch in question does not need to occur in the branch layout file.
.sp
\fBOptions:\fP
.sp
\-\- <pass\-through\-arguments> Arguments to pass directly to the underlying \fBgit log\fP, for example \fBgit machete log \-\- \-\-patch\fP\&.
.SH REAPPLY
.sp
\fBUsage:\fP
Expand Down
5 changes: 3 additions & 2 deletions docs/source/cli/diff.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ diff

.. code-block:: shell
git machete d[iff] [-s|--stat] [<branch>]
git machete d[iff] [-s|--stat] [<branch>] [-- <pass-through-arguments>]
Runs ``git diff`` of the given branch tip against its fork point or, if none specified,
of the current working tree against the fork point of the currently checked out branch.
Expand All @@ -16,4 +16,5 @@ Note: the branch in question does not need to occur in the branch layout file.

**Options:**

-s, --stat Makes ``git machete diff`` pass ``--stat`` option to ``git diff``, so that only summary (diffstat) is printed.
-- <pass-through-arguments> Arguments to pass directly to the underlying ``git diff``, for example ``git machete diff -- --name-only``.
-s, --stat Makes ``git machete diff`` pass ``--stat`` option to ``git diff``, so that only summary (diffstat) is printed.
6 changes: 5 additions & 1 deletion docs/source/cli/log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ log

.. code-block:: shell
git machete l[og] [<branch>]
git machete l[og] [<branch>] [-- <pass-through-arguments>]
Runs ``git log`` for the range of commits from tip of the given branch (or current branch, if none specified) back to its fork point.
See help for :ref:`fork-point` for more details on meaning of the *fork point*.

Note: the branch in question does not need to occur in the branch layout file.

**Options:**

-- <pass-through-arguments> Arguments to pass directly to the underlying ``git log``, for example ``git machete log -- --patch``.
2 changes: 1 addition & 1 deletion git_machete/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '3.27.0'
__version__ = '3.28.0'
17 changes: 13 additions & 4 deletions git_machete/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3

import argparse
import itertools
import os
import pkgutil
import re
Expand Down Expand Up @@ -567,8 +568,10 @@ def launch(orig_args: List[str]) -> None:
cli_opts = git_machete.options.CommandLineOptions()
git = GitContext()

direct_args = list(itertools.takewhile(lambda arg: arg != "--", orig_args))
pass_through_args = list(itertools.dropwhile(lambda arg: arg != "--", orig_args))
cli_parser: argparse.ArgumentParser = create_cli_parser()
parsed_cli: argparse.Namespace = cli_parser.parse_args(orig_args)
parsed_cli: argparse.Namespace = cli_parser.parse_args(direct_args)
parsed_cli_as_dict: Dict[str, Any] = vars(parsed_cli)

# Let's set up options like debug/verbose before we first start reading `git config`.
Expand All @@ -577,12 +580,18 @@ def launch(orig_args: List[str]) -> None:
update_cli_options_using_parsed_args(cli_opts, parsed_cli)
cli_opts.validate()

if not orig_args:
if not direct_args:
print(get_help_description(display_help_topics=False))
sys.exit(ExitCode.ARGUMENT_ERROR)

cmd = parsed_cli.command

if cmd not in ("d", "diff", "l", "log") and pass_through_args:
print(fmt("Extra arguments after `--` are only allowed after `diff` and `log`"))
sys.exit(ExitCode.ARGUMENT_ERROR)
if pass_through_args and pass_through_args[0] == "--":
pass_through_args = pass_through_args[1:]

if cmd == "completion":
completion_shell = parsed_cli.shell

Expand Down Expand Up @@ -670,7 +679,7 @@ def print_completion_resource(name: str) -> None:
elif cmd in {"diff", alias_by_command["diff"]}:
machete_client.read_branch_layout_file(perform_interactive_slide_out=should_perform_interactive_slide_out)
diff_branch = get_local_branch_short_name_from_arg(cli_opts.opt_branch) if (cli_opts.opt_branch is not None) else None
machete_client.diff(branch=diff_branch, opt_stat=cli_opts.opt_stat)
machete_client.display_diff(branch=diff_branch, opt_stat=cli_opts.opt_stat, extra_git_diff_args=pass_through_args)
elif cmd == "discover":
machete_client.read_branch_layout_file(perform_interactive_slide_out=should_perform_interactive_slide_out)
machete_client.discover_tree(
Expand Down Expand Up @@ -822,7 +831,7 @@ def strip_remote_name(remote_branch: RemoteBranchShortName) -> LocalBranchShortN
elif cmd in {"log", alias_by_command["log"]}:
machete_client.read_branch_layout_file(perform_interactive_slide_out=should_perform_interactive_slide_out)
branch = get_local_branch_short_name_from_arg_or_current_branch(cli_opts.opt_branch, git)
machete_client.log(branch)
machete_client.display_log(branch, extra_git_log_args=pass_through_args)
elif cmd == "reapply":
machete_client.read_branch_layout_file(perform_interactive_slide_out=should_perform_interactive_slide_out)
git.expect_no_operation_in_progress()
Expand Down
13 changes: 5 additions & 8 deletions git_machete/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1421,19 +1421,16 @@ def fork_point_or_none(self, branch: LocalBranchShortName, use_overrides: bool)
except MacheteException:
return None

def diff(self, *, branch: Optional[LocalBranchShortName], opt_stat: bool) -> None:
def display_diff(self, *, branch: Optional[LocalBranchShortName], opt_stat: bool, extra_git_diff_args: List[str]) -> None:
diff_branch = branch or self.__git.get_current_branch()
fork_point = self.fork_point(diff_branch, use_overrides=True)

self.__git.display_diff(
# In case no param has been supplied, we want to diff against the current working directory, not the current branch.
branch=branch,
fork_point=fork_point,
format_with_stat=opt_stat)
self.__git.display_diff(branch=branch, against=fork_point, opt_stat=opt_stat, extra_git_diff_args=extra_git_diff_args)

def log(self, branch: LocalBranchShortName) -> None:
def display_log(self, branch: LocalBranchShortName, extra_git_log_args: List[str]) -> None:
fork_point = self.fork_point(branch, use_overrides=True)
self.__git.display_branch_history_from_fork_point(branch.full_name(), fork_point)
self.__git.display_log_between(from_inclusive=branch.full_name(), until_exclusive=fork_point,
extra_git_log_args=extra_git_log_args)

def down(self, branch: LocalBranchShortName, pick_mode: bool) -> List[LocalBranchShortName]:
self.expect_in_managed_branches(branch)
Expand Down
13 changes: 9 additions & 4 deletions git_machete/generated_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@
""",
"diff": """
<b>Usage:</b><b>
git machete d[iff] [-s|--stat] [<branch>]</b>
git machete d[iff] [-s|--stat] [<branch>] [-- <pass-through-arguments>]</b>
Runs `git diff` of the given branch tip against its fork point or, if none specified,
of the current working tree against the fork point of the currently checked out branch.
Expand All @@ -384,8 +384,9 @@
Note: the branch in question does not need to occur in the branch layout file.
<b>Options:</b>
<b>-s</b>, <b>--stat</b>
Makes `git machete diff` pass `--stat` option to `git diff`, so that only summary (diffstat) is printed.
-- <pass-through-arguments> Arguments to pass directly to the underlying `git diff`, for example `git machete diff -- --name-only`.
-s, --stat Makes `git machete diff` pass `--stat` option to `git diff`, so that only summary (diffstat) is printed.
""",
"discover": """
<b>Usage:</b><b>
Expand Down Expand Up @@ -1020,12 +1021,16 @@
""",
"log": """
<b>Usage:</b><b>
git machete l[og] [<branch>]</b>
git machete l[og] [<branch>] [-- <pass-through-arguments>]</b>
Runs `git log` for the range of commits from tip of the given branch (or current branch, if none specified) back to its fork point.
See help for `fork-point` for more details on meaning of the fork point.
Note: the branch in question does not need to occur in the branch layout file.
<b>Options:</b>
-- <pass-through-arguments> Arguments to pass directly to the underlying `git log`, for example `git machete log -- --patch`.
""",
"reapply": """
<b>Usage:</b><b>
Expand Down
17 changes: 11 additions & 6 deletions git_machete/git_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -1048,8 +1048,9 @@ def get_commit_data(self, commit: AnyRevision, pattern: GitFormatPatterns) -> st

return self._popen_git("log", "-1", f"--format={pattern.value}", commit).stdout.strip()

def display_branch_history_from_fork_point(self, branch: LocalBranchFullName, fork_point: FullCommitHash) -> int:
return self._run_git("log", f"^{fork_point}", branch, flush_caches=False)
def display_log_between(self, from_inclusive: LocalBranchFullName,
until_exclusive: FullCommitHash, extra_git_log_args: List[str]) -> int:
return self._run_git("log", f"^{until_exclusive}", from_inclusive, *extra_git_log_args, flush_caches=False)

def commit_tree_with_given_parent_and_message_and_env(
self, parent_revision: AnyRevision, msg: str, env: Dict[str, str]) -> FullCommitHash:
Expand All @@ -1064,14 +1065,18 @@ def delete_branch(self, branch_name: LocalBranchShortName, force: bool) -> int:
def delete_remote_branch(self, branch_name: RemoteBranchShortName) -> int:
return self._run_git('branch', '-d', '-r', branch_name, flush_caches=True)

def display_diff(self, fork_point: AnyRevision, format_with_stat: bool, branch: Optional[LocalBranchShortName] = None) -> int:
def display_diff(self, branch: Optional[LocalBranchShortName], against: AnyRevision,
opt_stat: bool, extra_git_diff_args: List[str]) -> int:
params = []
if format_with_stat:
if opt_stat:
params.append("--stat")
params.append(fork_point)
params.append(against)
if branch:
params.append(branch.full_name())
params.append("--")
if extra_git_diff_args:
params += extra_git_diff_args
else:
params.append("--")

return self._run_git("diff", *params, flush_caches=False)

Expand Down
10 changes: 6 additions & 4 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@


class TestCLI(BaseTest):
def test_aliases(self) -> None:
"""
Verify that each command alias is unique
"""
def test_aliases_unique(self) -> None:
assert len(alias_by_command.values()) == len(set(alias_by_command.values()))

def test_main(self, mocker: MockerFixture) -> None:
Expand All @@ -23,6 +20,11 @@ def test_main(self, mocker: MockerFixture) -> None:
main()
assert ExitCode.ARGUMENT_ERROR == e.value.code

with pytest.raises(SystemExit) as e:
self.patch_symbol(mocker, "sys.argv", ["", "status", "--", "--patch"])
main()
assert ExitCode.ARGUMENT_ERROR == e.value.code

os.chdir(mkdtemp())

with pytest.raises(SystemExit) as e:
Expand Down
13 changes: 12 additions & 1 deletion tests/test_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,18 @@ def test_diff(self, mocker: MockerFixture) -> None:
assert_success(["diff", "refs/heads/develop"], expected_status_output)

assert_success(
["diff", "--stat", "refs/heads/develop"],
["diff", "--stat", "refs/heads/develop", "--"],
"develop_file_name.txt | 1 +\n"
"1 file changed, 1 insertion(+)\n"
)

assert_success(
["diff", "--", "--name-only"],
"develop_file_name.txt\n"
"file_name.txt\n"
)

assert_success(
["diff", "develop", "--", "--name-only"],
"develop_file_name.txt\n"
)
32 changes: 23 additions & 9 deletions tests/test_log.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
from pytest_mock import MockerFixture

from .base_test import BaseTest
from .mockers import launch_command, mock__run_cmd_and_forward_stdout
from .mockers import (assert_success, fixed_author_and_committer_date_in_past,
launch_command, mock__run_cmd_and_forward_stdout)


class TestLog(BaseTest):

def test_log(self, mocker: MockerFixture) -> None:
self.patch_symbol(mocker, 'git_machete.utils._run_cmd', mock__run_cmd_and_forward_stdout)

self.repo_sandbox.new_branch('root')
self.repo_sandbox.commit()
roots_only_commit_hash = self.repo_sandbox.get_current_commit_hash()
with fixed_author_and_committer_date_in_past():
self.repo_sandbox.new_branch('root')
self.repo_sandbox.commit()
roots_only_commit_hash = self.repo_sandbox.get_current_commit_hash()

self.repo_sandbox.new_branch('child')
self.repo_sandbox.commit()
child_first_commit_hash = self.repo_sandbox.get_current_commit_hash()
self.repo_sandbox.commit()
child_second_commit_hash = self.repo_sandbox.get_current_commit_hash()
self.repo_sandbox.new_branch('child')
self.repo_sandbox.commit()
child_first_commit_hash = self.repo_sandbox.get_current_commit_hash()
self.repo_sandbox.commit()
child_second_commit_hash = self.repo_sandbox.get_current_commit_hash()

log_contents = [launch_command('log'), launch_command('log', 'child'), launch_command('log', 'refs/heads/child')]

Expand All @@ -30,3 +32,15 @@ def test_log(self, mocker: MockerFixture) -> None:
assert all(roots_only_commit_hash not in log_content for log_content in log_contents), \
("Verify that commits from parent branch are not visible when "
"executing `git machete log`.")

assert_success(
["log", "--", "--oneline"],
"47d565d Some commit message.\n"
"dcd2db5 Some commit message.\n"
)

assert_success(
["log", "child", "--", "--oneline"],
"47d565d Some commit message.\n"
"dcd2db5 Some commit message.\n"
)

0 comments on commit 79a2b87

Please sign in to comment.