diff --git a/docs/config/environment.md b/docs/config/environment.md
index 1727977a..c9b1115d 100644
--- a/docs/config/environment.md
+++ b/docs/config/environment.md
@@ -361,12 +361,36 @@ Scripts can also be defined as an array of strings.
     ]
     ```
 
+You can ignore the exit code of commands that start with `-` (a hyphen). For example, the script `error` defined by the following configuration would halt after the second command with `3` as the exit code:
+
+=== ":octicons-file-code-16: pyproject.toml"
+
+    ```toml
+    [tool.hatch.envs.test.scripts]
+    error = [
+      "- exit 1",
+      "exit 3",
+      "exit 0",
+    ]
+    ```
+
+=== ":octicons-file-code-16: hatch.toml"
+
+    ```toml
+    [envs.test.scripts]
+    error = [
+      "- exit 1",
+      "exit 3",
+      "exit 0",
+    ]
+    ```
+
 !!! tip
-    Scripts [inherit](#inheritance) from parent environments just like options.
+    Individual scripts [inherit](#inheritance) from parent environments just like options.
 
 ## Commands
 
-All commands are able to use any defined [scripts](#scripts).
+All commands are able to use any defined [scripts](#scripts). Also like scripts, the exit code of commands that start with a hyphen will be ignored.
 
 ### Pre-install
 
diff --git a/docs/history.md b/docs/history.md
index 427320ec..accdadb2 100644
--- a/docs/history.md
+++ b/docs/history.md
@@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 
 - Add context formatting functionality i.e. the ability to insert values into configuration like environment variables and command line arguments
 - Add `--show-headers` option to the `env run` command to always display headers, even for single environments
+- Similar to `make`, ignore the exit code of executed commands that start with `-` (a hyphen)
 - Update project metadata to reflect the adoption by PyPA
 
 ### [1.0.0](https://github.com/pypa/hatch/releases/tag/hatch-v1.0.0) - 2022-04-28 ### {: #hatch-v1.0.0 }
diff --git a/src/hatch/cli/application.py b/src/hatch/cli/application.py
index ac4e8dda..6601608b 100644
--- a/src/hatch/cli/application.py
+++ b/src/hatch/cli/application.py
@@ -93,6 +93,10 @@ class Application(Terminal):
     def run_shell_commands(self, environment, commands: list[str], show_code_on_error=True):
         with environment.command_context():
             for command in environment.resolve_commands(commands):
+                if command.startswith('-'):
+                    environment.run_shell_command(command[1:].strip())
+                    continue
+
                 process = environment.run_shell_command(command)
                 if process.returncode:
                     if show_code_on_error:

diff --git a/tests/cli/run/test_run.py b/tests/cli/run/test_run.py
index 3a18db1f..2738117c 100644
--- a/tests/cli/run/test_run.py
+++ b/tests/cli/run/test_run.py
@@ -399,6 +399,73 @@ def test_error(hatch, helpers, temp_dir, config_file):
     assert not output_file.is_file()
 
 
+def test_ignore_error(hatch, helpers, temp_dir, config_file):
+    config_file.model.template.plugins['default']['tests'] = False
+    config_file.save()
+
+    project_name = 'My App'
+
+    with temp_dir.as_cwd():
+        result = hatch('new', project_name)
+
+    assert result.exit_code == 0, result.output
+
+    project_path = temp_dir / 'my-app'
+    data_path = temp_dir / 'data'
+    data_path.mkdir()
+
+    project = Project(project_path)
+    helpers.update_project_environment(
+        project,
+        'default',
+        {
+            'skip-install': True,
+            'scripts': {
+                'error': [
+                    '- python -c "import sys;sys.exit(3)"',
+                    'python -c "import pathlib,sys;pathlib.Path(\'test.txt\').write_text(sys.executable)"',
+                ],
+            },
+            **project.config.envs['default'],
+        },
+    )
+
+    with project_path.as_cwd(env_vars={ConfigEnvVars.DATA: str(data_path)}):
+        result = hatch('run', 'error')
+
+    assert result.exit_code == 0
+    assert result.output == helpers.dedent(
+        """
+        Creating environment: default
+        """
+    )
+    output_file = project_path / 'test.txt'
+    assert output_file.is_file()
+
+    env_data_path = data_path / 'env' / 'virtual'
+    assert env_data_path.is_dir()
+
+    storage_dirs = list(env_data_path.iterdir())
+    assert len(storage_dirs) == 1
+
+    storage_path = storage_dirs[0]
+
+    project_part = f'{project_path.name}-'
+    assert storage_path.name.startswith(project_part)
+
+    hash_part = storage_path.name[len(project_part) :]
+    assert len(hash_part) == 8
+
+    env_dirs = list(storage_path.iterdir())
+    assert len(env_dirs) == 1
+
+    env_path = env_dirs[0]
+
+    assert env_path.name == project_path.name
+
+    assert str(env_path) in str(output_file.read_text())
+
+
 def test_matrix_no_environments(hatch, helpers, temp_dir, config_file):
     config_file.model.template.plugins['default']['tests'] = False
     config_file.save()

Option to run all commands in script array even if one fails
[poethepoet](https://github.com/nat-n/poethepoet), for example, allows running all scripts even if any fail.  The result code will be 0 only if all succeeded.  This is nice so that you can always see all errors when running multiple linting commands, for example.  It might be nice if hatch eventually had some more advanced functionality like poethepoet for running scripts, but right now this is the only feature I actually care about.
tests/cli/run/test_run.py::test_ignore_error
tests/cli/run/test_run.py::test_automatic_creation tests/cli/run/test_run.py::test_enter_project_directory tests/cli/run/test_run.py::test_sync_dependencies tests/cli/run/test_run.py::test_scripts tests/cli/run/test_run.py::test_scripts_specific_environment tests/cli/run/test_run.py::test_scripts_no_environment tests/cli/run/test_run.py::test_error tests/cli/run/test_run.py::test_matrix_no_environments tests/cli/run/test_run.py::test_matrix tests/cli/run/test_run.py::test_incompatible_single tests/cli/run/test_run.py::test_incompatible_matrix_full tests/cli/run/test_run.py::test_incompatible_matrix_partial tests/cli/run/test_run.py::test_incompatible_missing_python tests/cli/run/test_run.py::test_env_detection tests/cli/run/test_run.py::test_env_detection_override tests/cli/run/test_run.py::test_matrix_variable_selection_no_command tests/cli/run/test_run.py::test_matrix_variable_selection_duplicate_inclusion tests/cli/run/test_run.py::test_matrix_variable_selection_duplicate_exclusion tests/cli/run/test_run.py::test_matrix_variable_selection_python_alias tests/cli/run/test_run.py::test_matrix_variable_selection_not_matrix tests/cli/run/test_run.py::test_matrix_variable_selection_inclusion tests/cli/run/test_run.py::test_matrix_variable_selection_exclusion tests/cli/run/test_run.py::test_matrix_variable_selection_exclude_all tests/cli/run/test_run.py::test_matrix_variable_selection_include_none tests/cli/run/test_run.py::test_context_formatting_recursion