dmbarreiro: Comes from issue #1274 
asottile: > Comes from issue #1274

note that if you put "Closes #1274" in your PR description this'll get automatically linked *and* github will auto-close the issue upon merging!
asottile: I ran the hooks and moved the test (the `run` tests do some isolated `environ` management so it doesn't get forwarded to the hook executables as a normal run would)
diff --git a/pre_commit/commands/run.py b/pre_commit/commands/run.py
index 6690bdd..95f8ab4 100644
--- a/pre_commit/commands/run.py
+++ b/pre_commit/commands/run.py
@@ -312,6 +312,10 @@ def run(
         environ['PRE_COMMIT_ORIGIN'] = args.origin
         environ['PRE_COMMIT_SOURCE'] = args.source
 
+    if args.remote_name and args.remote_url:
+        environ['PRE_COMMIT_REMOTE_NAME'] = args.remote_name
+        environ['PRE_COMMIT_REMOTE_URL'] = args.remote_url
+
     with contextlib.ExitStack() as exit_stack:
         if stash:
             exit_stack.enter_context(staged_files_only(store.directory))
diff --git a/pre_commit/main.py b/pre_commit/main.py
index d96b35f..e65d8ae 100644
--- a/pre_commit/main.py
+++ b/pre_commit/main.py
@@ -101,6 +101,10 @@ def _add_run_options(parser: argparse.ArgumentParser) -> None:
         '--commit-msg-filename',
         help='Filename to check when running during `commit-msg`',
     )
+    parser.add_argument(
+        '--remote-name', help='Remote name used by `git push`.',
+    )
+    parser.add_argument('--remote-url', help='Remote url used by `git push`.')
     parser.add_argument(
         '--hook-stage', choices=C.STAGES, default='commit',
         help='The stage during which the hook is fired.  One of %(choices)s',
diff --git a/pre_commit/resources/hook-tmpl b/pre_commit/resources/hook-tmpl
index 213d16e..573335a 100755
--- a/pre_commit/resources/hook-tmpl
+++ b/pre_commit/resources/hook-tmpl
@@ -120,7 +120,8 @@ def _rev_exists(rev: str) -> bool:
 
 
 def _pre_push(stdin: bytes) -> Tuple[str, ...]:
-    remote = sys.argv[1]
+    remote_name = sys.argv[1]
+    remote_url = sys.argv[2]
 
     opts: Tuple[str, ...] = ()
     for line in stdin.decode().splitlines():
@@ -133,7 +134,7 @@ def _pre_push(stdin: bytes) -> Tuple[str, ...]:
             # ancestors not found in remote
             ancestors = subprocess.check_output((
                 'git', 'rev-list', local_sha, '--topo-order', '--reverse',
-                '--not', f'--remotes={remote}',
+                '--not', f'--remotes={remote_name}',
             )).decode().strip()
             if not ancestors:
                 continue
@@ -150,7 +151,9 @@ def _pre_push(stdin: bytes) -> Tuple[str, ...]:
                     opts = ('--origin', local_sha, '--source', source)
 
     if opts:
-        return opts
+        return (
+            *opts, '--remote-name', remote_name, '--remote-url', remote_url,
+        )
     else:
         # An attempt to push an empty changeset
         raise EarlyExit()

Pre-push hook checks only when pushing to certain remote
I have two remotes configured in my repository (`origin` and `upstream`) and I want my pre-push hook to fire and do the configured checks only when we push to `upstream`, bypassing all checks when we push to remote `origin`. Is this possible without using git `--no-verify` option?
I was checking for ways to obtain the remote from `pre-commit`as a parameter and pass it to my local hook to bypass the checks in case remote doesn't match `upstream` but I haven't been very successful. Any ideas on how to do this?

Thank you so much for all the great work you are doing with this project.
diff --git a/testing/util.py b/testing/util.py
index 0c2cc6a..ce3206e 100644
--- a/testing/util.py
+++ b/testing/util.py
@@ -67,6 +67,8 @@ def run_opts(
         hook=None,
         origin='',
         source='',
+        remote_name='',
+        remote_url='',
         hook_stage='commit',
         show_diff_on_failure=False,
         commit_msg_filename='',
@@ -81,6 +83,8 @@ def run_opts(
         hook=hook,
         origin=origin,
         source=source,
+        remote_name=remote_name,
+        remote_url=remote_url,
         hook_stage=hook_stage,
         show_diff_on_failure=show_diff_on_failure,
         commit_msg_filename=commit_msg_filename,
diff --git a/tests/commands/install_uninstall_test.py b/tests/commands/install_uninstall_test.py
index 562293d..984ae74 100644
--- a/tests/commands/install_uninstall_test.py
+++ b/tests/commands/install_uninstall_test.py
@@ -15,6 +15,7 @@ from pre_commit.parse_shebang import find_executable
 from pre_commit.util import cmd_output
 from pre_commit.util import make_executable
 from pre_commit.util import resource_text
+from testing.fixtures import add_config_to_repo
 from testing.fixtures import git_dir
 from testing.fixtures import make_consuming_repo
 from testing.fixtures import remove_config_from_repo
@@ -512,9 +513,9 @@ def test_installed_from_venv(tempdir_factory, store):
         assert NORMAL_PRE_COMMIT_RUN.match(output)
 
 
-def _get_push_output(tempdir_factory, opts=()):
+def _get_push_output(tempdir_factory, remote='origin', opts=()):
     return cmd_output_mocked_pre_commit_home(
-        'git', 'push', 'origin', 'HEAD:new_branch', *opts,
+        'git', 'push', remote, 'HEAD:new_branch', *opts,
         tempdir_factory=tempdir_factory,
         retcode=None,
     )[:2]
@@ -589,6 +590,33 @@ def test_pre_push_new_upstream(tempdir_factory, store):
         assert 'Passed' in output
 
 
+def test_pre_push_environment_variables(tempdir_factory, store):
+    config = {
+        'repo': 'local',
+        'hooks': [
+            {
+                'id': 'print-remote-info',
+                'name': 'print remote info',
+                'entry': 'bash -c "echo remote: $PRE_COMMIT_REMOTE_NAME"',
+                'language': 'system',
+                'verbose': True,
+            },
+        ],
+    }
+
+    upstream = git_dir(tempdir_factory)
+    clone = tempdir_factory.get()
+    cmd_output('git', 'clone', upstream, clone)
+    add_config_to_repo(clone, config)
+    with cwd(clone):
+        install(C.CONFIG_FILE, store, hook_types=['pre-push'])
+
+        cmd_output('git', 'remote', 'rename', 'origin', 'origin2')
+        retc, output = _get_push_output(tempdir_factory, remote='origin2')
+        assert retc == 0
+        assert '\nremote: origin2\n' in output
+
+
 def test_pre_push_integration_empty_push(tempdir_factory, store):
     upstream = make_consuming_repo(tempdir_factory, 'script_hooks_repo')
     path = tempdir_factory.get()
diff --git a/tests/commands/run_test.py b/tests/commands/run_test.py
index d2e2f23..87eef2e 100644
--- a/tests/commands/run_test.py
+++ b/tests/commands/run_test.py
@@ -456,8 +456,11 @@ def test_origin_source_error_msg_error(
     assert b'Specify both --origin and --source.' in printed
 
 
-def test_origin_source_both_ok(cap_out, store, repo_with_passing_hook):
-    args = run_opts(origin='master', source='master')
+def test_all_push_options_ok(cap_out, store, repo_with_passing_hook):
+    args = run_opts(
+        origin='master', source='master',
+        remote_name='origin', remote_url='https://example.com/repo',
+    )
     ret, printed = _do_run(cap_out, store, repo_with_passing_hook, args)
     assert ret == 0
     assert b'Specify both --origin and --source.' not in printed

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest
3.7
requirements-dev.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
aspy.yaml==1.3.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
cfgv==3.3.1
coverage==7.2.7
distlib==0.3.9
exceptiongroup==1.2.2
filelock==3.12.2
identify==2.5.24
importlib-metadata==6.7.0
iniconfig==2.0.0
nodeenv==1.9.1
packaging==24.0
platformdirs==4.0.0
pluggy==1.2.0
-e git+https://github.com/pre-commit/pre-commit.git@b66d28964ba919171c51691f67b7292f0792c78e#egg=pre_commit
pytest==7.4.4
pytest-env==1.0.1
PyYAML==6.0.1
toml==0.10.2
tomli==2.0.1
typing_extensions==4.7.1
virtualenv==20.26.6
zipp==3.15.0

name: pre-commit
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - aspy-yaml==1.3.0
      - cfgv==3.3.1
      - coverage==7.2.7
      - distlib==0.3.9
      - exceptiongroup==1.2.2
      - filelock==3.12.2
      - identify==2.5.24
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - nodeenv==1.9.1
      - packaging==24.0
      - platformdirs==4.0.0
      - pluggy==1.2.0
      - pytest==7.4.4
      - pytest-env==1.0.1
      - pyyaml==6.0.1
      - toml==0.10.2
      - tomli==2.0.1
      - typing-extensions==4.7.1
      - virtualenv==20.26.6
      - zipp==3.15.0
prefix: /opt/conda/envs/pre-commit

tests/commands/install_uninstall_test.py::test_pre_push_environment_variables
tests/commands/install_uninstall_test.py::test_install_in_submodule_and_run tests/commands/install_uninstall_test.py::test_environment_not_sourced tests/commands/install_uninstall_test.py::test_pre_merge_commit_integration
tests/commands/install_uninstall_test.py::test_is_not_script tests/commands/install_uninstall_test.py::test_is_script tests/commands/install_uninstall_test.py::test_is_previous_pre_commit tests/commands/install_uninstall_test.py::test_shebang_windows tests/commands/install_uninstall_test.py::test_shebang_posix_not_on_path tests/commands/install_uninstall_test.py::test_shebang_posix_on_path tests/commands/install_uninstall_test.py::test_install_pre_commit tests/commands/install_uninstall_test.py::test_install_hooks_directory_not_present tests/commands/install_uninstall_test.py::test_install_multiple_hooks_at_once tests/commands/install_uninstall_test.py::test_install_refuses_core_hookspath tests/commands/install_uninstall_test.py::test_install_hooks_dead_symlink tests/commands/install_uninstall_test.py::test_uninstall_does_not_blow_up_when_not_there tests/commands/install_uninstall_test.py::test_uninstall tests/commands/install_uninstall_test.py::test_install_pre_commit_and_run tests/commands/install_uninstall_test.py::test_install_pre_commit_and_run_custom_path tests/commands/install_uninstall_test.py::test_install_in_worktree_and_run tests/commands/install_uninstall_test.py::test_commit_am tests/commands/install_uninstall_test.py::test_unicode_merge_commit_message tests/commands/install_uninstall_test.py::test_install_idempotent tests/commands/install_uninstall_test.py::test_failing_hooks_returns_nonzero tests/commands/install_uninstall_test.py::test_install_existing_hooks_no_overwrite tests/commands/install_uninstall_test.py::test_legacy_overwriting_legacy_hook tests/commands/install_uninstall_test.py::test_install_existing_hook_no_overwrite_idempotent tests/commands/install_uninstall_test.py::test_failing_existing_hook_returns_1 tests/commands/install_uninstall_test.py::test_install_overwrite_no_existing_hooks tests/commands/install_uninstall_test.py::test_install_overwrite tests/commands/install_uninstall_test.py::test_uninstall_restores_legacy_hooks tests/commands/install_uninstall_test.py::test_replace_old_commit_script tests/commands/install_uninstall_test.py::test_uninstall_doesnt_remove_not_our_hooks tests/commands/install_uninstall_test.py::test_installs_hooks_with_hooks_True tests/commands/install_uninstall_test.py::test_install_hooks_command tests/commands/install_uninstall_test.py::test_installed_from_venv tests/commands/install_uninstall_test.py::test_pre_push_integration_failing tests/commands/install_uninstall_test.py::test_pre_push_integration_accepted tests/commands/install_uninstall_test.py::test_pre_push_force_push_without_fetch tests/commands/install_uninstall_test.py::test_pre_push_new_upstream tests/commands/install_uninstall_test.py::test_pre_push_integration_empty_push tests/commands/install_uninstall_test.py::test_pre_push_legacy tests/commands/install_uninstall_test.py::test_commit_msg_integration_failing tests/commands/install_uninstall_test.py::test_commit_msg_integration_passing tests/commands/install_uninstall_test.py::test_commit_msg_legacy tests/commands/install_uninstall_test.py::test_prepare_commit_msg_integration_failing tests/commands/install_uninstall_test.py::test_prepare_commit_msg_integration_passing tests/commands/install_uninstall_test.py::test_prepare_commit_msg_legacy tests/commands/install_uninstall_test.py::test_install_disallow_missing_config tests/commands/install_uninstall_test.py::test_install_allow_missing_config tests/commands/install_uninstall_test.py::test_install_temporarily_allow_mising_config tests/commands/run_test.py::test_start_msg tests/commands/run_test.py::test_full_msg tests/commands/run_test.py::test_full_msg_with_color tests/commands/run_test.py::test_full_msg_with_postfix tests/commands/run_test.py::test_full_msg_postfix_not_colored tests/commands/run_test.py::test_run_all_hooks_failing tests/commands/run_test.py::test_arbitrary_bytes_hook tests/commands/run_test.py::test_hook_that_modifies_but_returns_zero tests/commands/run_test.py::test_types_hook_repository tests/commands/run_test.py::test_exclude_types_hook_repository tests/commands/run_test.py::test_global_exclude tests/commands/run_test.py::test_global_files tests/commands/run_test.py::test_verbose_duration[1.234-2.0-\n- tests/commands/run_test.py::test_verbose_duration[1.0-1.0-\n- tests/commands/run_test.py::test_show_diff_on_failure[args0-All tests/commands/run_test.py::test_show_diff_on_failure[args1-All tests/commands/run_test.py::test_show_diff_on_failure[args2-reproduce tests/commands/run_test.py::test_run[options0-outputs0-0-True] tests/commands/run_test.py::test_run[options1-outputs1-0-True] tests/commands/run_test.py::test_run[options2-outputs2-0-True] tests/commands/run_test.py::test_run[options3-outputs3-1-True] tests/commands/run_test.py::test_run[options4-outputs4-1-True] tests/commands/run_test.py::test_run[options5-outputs5-0-True] tests/commands/run_test.py::test_run[options6-outputs6-0-True] tests/commands/run_test.py::test_run[options7-outputs7-0-False] tests/commands/run_test.py::test_run_output_logfile tests/commands/run_test.py::test_always_run tests/commands/run_test.py::test_always_run_alt_config tests/commands/run_test.py::test_hook_verbose_enabled tests/commands/run_test.py::test_origin_source_error_msg_error[master-] tests/commands/run_test.py::test_origin_source_error_msg_error[-master] tests/commands/run_test.py::test_all_push_options_ok tests/commands/run_test.py::test_has_unmerged_paths tests/commands/run_test.py::test_merge_conflict tests/commands/run_test.py::test_merge_conflict_modified tests/commands/run_test.py::test_merge_conflict_resolved tests/commands/run_test.py::test_compute_cols[hooks0-80] tests/commands/run_test.py::test_compute_cols[hooks1-81] tests/commands/run_test.py::test_compute_cols[hooks2-82] tests/commands/run_test.py::test_get_skips[environ0-expected_output0] tests/commands/run_test.py::test_get_skips[environ1-expected_output1] tests/commands/run_test.py::test_get_skips[environ2-expected_output2] tests/commands/run_test.py::test_get_skips[environ3-expected_output3] tests/commands/run_test.py::test_get_skips[environ4-expected_output4] tests/commands/run_test.py::test_get_skips[environ5-expected_output5] tests/commands/run_test.py::test_get_skips[environ6-expected_output6] tests/commands/run_test.py::test_skip_hook tests/commands/run_test.py::test_skip_aliased_hook tests/commands/run_test.py::test_hook_id_not_in_non_verbose_output tests/commands/run_test.py::test_hook_id_in_verbose_output tests/commands/run_test.py::test_multiple_hooks_same_id tests/commands/run_test.py::test_aliased_hook_run tests/commands/run_test.py::test_non_ascii_hook_id tests/commands/run_test.py::test_stdout_write_bug_py26 tests/commands/run_test.py::test_lots_of_files tests/commands/run_test.py::test_stages tests/commands/run_test.py::test_commit_msg_hook tests/commands/run_test.py::test_prepare_commit_msg_hook tests/commands/run_test.py::test_local_hook_passes tests/commands/run_test.py::test_local_hook_fails tests/commands/run_test.py::test_meta_hook_passes tests/commands/run_test.py::test_error_with_unstaged_config tests/commands/run_test.py::test_no_unstaged_error_with_all_files_or_files[opts0] tests/commands/run_test.py::test_no_unstaged_error_with_all_files_or_files[opts1] tests/commands/run_test.py::test_files_running_subdir tests/commands/run_test.py::test_pass_filenames[True-hook_args0-foo.py] tests/commands/run_test.py::test_pass_filenames[False-hook_args1-] tests/commands/run_test.py::test_pass_filenames[True-hook_args2-some tests/commands/run_test.py::test_pass_filenames[False-hook_args3-some tests/commands/run_test.py::test_fail_fast tests/commands/run_test.py::test_classifier_removes_dne tests/commands/run_test.py::test_classifier_normalizes_filenames_on_windows_to_forward_slashes tests/commands/run_test.py::test_classifier_does_not_normalize_backslashes_non_windows tests/commands/run_test.py::test_include_exclude_base_case tests/commands/run_test.py::test_matches_broken_symlink tests/commands/run_test.py::test_include_exclude_total_match tests/commands/run_test.py::test_include_exclude_does_search_instead_of_match tests/commands/run_test.py::test_include_exclude_exclude_removes_files tests/commands/run_test.py::test_args_hook_only
pre_commit/main.py pre_commit/resources/hook-tmpl pre_commit/commands/run.py
pre_commit/main.py pre_commit/resources/hook-tmpl pre_commit/commands/run.py