git-rexec 1.0.0__tar.gz → 1.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,6 @@
1
+ /coverage.json
2
+ /build
3
+ /dist
4
+ /*.egg-info
5
+ *.pyc
6
+ */__pycache__
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-rexec
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Locate Git repositories and execute commands against them in parallel.
5
5
  Author: James Cherti
6
- License: GPL-3.0-or-later
6
+ License-Expression: GPL-3.0-or-later
7
7
  Project-URL: Homepage, https://github.com/jamescherti/git-rexec
8
8
  Keywords: git,parallel,executor,automation
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
11
10
  Classifier: Operating System :: OS Independent
12
11
  Classifier: Environment :: Console
13
12
  Classifier: Topic :: Software Development :: Version Control :: Git
@@ -19,7 +18,7 @@ Requires-Dist: setproctitle; extra == "extras"
19
18
 
20
19
  # git-rexec: Find Git Repositories and Execute Commands Against Them, either Sequentially or in Parallel
21
20
 
22
- The [git-rexec](https://github.com/jamescherti/git-rexec/) command-line tool that recursively locates Git repositories within a directory and executes commands against them, either sequentially or in parallel.
21
+ The [git-rexec](https://github.com/jamescherti/git-rexec/) command-line tool recursively locates Git repositories within a directory and executes commands against them, either sequentially or in parallel.
23
22
 
24
23
  Here are examples demonstrating how to use `git-rexec`:
25
24
  - Execute `git status -s` across all discovered Git repositories (found by searching recursively under the current working directory) in parallel (`-p` or `--parallel`):
@@ -32,6 +31,12 @@ Here are examples demonstrating how to use `git-rexec`:
32
31
  git-rexec -j 5 --parallel -- git fetch
33
32
  ```
34
33
 
34
+
35
+ - Include sub-repositories (e.g., Git worktrees and submodules) alongside standard Git repositories during discovery (`-s` or `--include-sub-repos`), and execute `git status` against them:
36
+ ```bash
37
+ git-rexec -s -p -- git status
38
+ ```
39
+
35
40
  - Target a specific base directory (`~/projects`) using the `-C` flag to recursively discover repositories within it, while explicitly excluding a specific subfolder (`~/projects/archive`). This example executes `git status -s` in parallel for all discovered repositories except those within the excluded path:
36
41
  ```bash
37
42
  git-rexec -C ~/projects --exclude-dir ~/projects/archive --parallel -- git status -s
@@ -42,15 +47,21 @@ Here are examples demonstrating how to use `git-rexec`:
42
47
  git-rexec --if-exec 'sh -c "test -f README.md"' --parallel -- wc -l README.md
43
48
  ```
44
49
 
50
+ - Print the paths of all discovered Git repositories:
51
+ ```bash
52
+ git-rexec --print
53
+ ```
54
+
45
55
  If this helps your workflow, please support the project by **⭐ starring git-rexec on GitHub** and sharing it on your website, blog, Mastodon, Reddit, X, LinkedIn, or other social media platforms to help more Git users discover its benefits.
46
56
 
47
57
  ## Features
48
58
 
49
59
  - Recursively discover Git repositories starting from a specified root directory.
60
+ - Optional flag to include sub-repositories (e.g., Git worktrees and submodules) in the execution target list.
50
61
  - Execute shell commands across multiple repositories in parallel using worker threads.
51
62
  - Filter target repositories based on the exit code of a conditional check (`--if-exec`).
52
63
  - Exclude specific directories from the search path.
53
- - Optional: Can leverage `fd` for fast directory traversal if installed, falling back to standard Python path resolution otherwise.
64
+ - Export discovered repository paths for integration with other shell tools (using `--print` or `--print0`).
54
65
 
55
66
  ## Installation
56
67
 
@@ -67,7 +78,7 @@ sudo cp git-rexec /usr/local/bin/
67
78
  Install the package directly from the Git repository using `pip`:
68
79
 
69
80
  ```bash
70
- pip install --user git+https://github.com/jamescherti/git-rexec
81
+ pip install --user git-rexec
71
82
  ```
72
83
 
73
84
  ## Dependencies
@@ -75,7 +86,6 @@ pip install --user git+https://github.com/jamescherti/git-rexec
75
86
  ### System Dependencies
76
87
 
77
88
  - `git`: Required for repository validation and execution.
78
- - `fd` (Optional): Highly recommended for faster repository discovery.
79
89
 
80
90
  ### Python Dependencies (Optional)
81
91
 
@@ -86,14 +96,12 @@ You can install the optional Python dependencies via pip:
86
96
 
87
97
  ```bash
88
98
  pip install colorama setproctitle
89
-
90
99
  ```
91
100
 
92
101
  ## Usage
93
102
 
94
103
  ```bash
95
104
  git-rexec [OPTIONS] [exec_cmd ...]
96
-
97
105
  ```
98
106
 
99
107
  *(Assuming the `git-rexec` script is executable and in your PATH.)*
@@ -109,6 +117,7 @@ git-rexec [OPTIONS] [exec_cmd ...]
109
117
  - `-p, --parallel`: Execute the command in parallel using threads.
110
118
  - `-i, --if-exec <command>`: Execute the main command only if this check command returns an exit code of `0`.
111
119
  - `-j, --jobs <int>`: The maximum number of concurrent workers/processors to use for parallel execution. Defaults to the number of CPU cores available.
120
+ - `-s, --include-sub-repos`: Include sub-repositories (e.g., Git worktrees and submodules) in the search target list.
112
121
  - `-h, --help`: Show the help message and exit.
113
122
  - `-q, --quiet`: Quiet mode. Suppresses the informational tracking headers (`[EXEC]` and `[EXEC-P]`) that prefix execution output. In sequential mode, it hides the `[EXEC]` repository delimiter line entirely; in parallel mode (`-p`), it strips the yellow `[EXEC-P]` header track and removes the four-space indentation, printing only the raw, unindented stdout and stderr streams. This flag has no effect when no execution command is supplied, allowing discovered repository paths to print normally.
114
123
 
@@ -1,6 +1,6 @@
1
1
  # git-rexec: Find Git Repositories and Execute Commands Against Them, either Sequentially or in Parallel
2
2
 
3
- The [git-rexec](https://github.com/jamescherti/git-rexec/) command-line tool that recursively locates Git repositories within a directory and executes commands against them, either sequentially or in parallel.
3
+ The [git-rexec](https://github.com/jamescherti/git-rexec/) command-line tool recursively locates Git repositories within a directory and executes commands against them, either sequentially or in parallel.
4
4
 
5
5
  Here are examples demonstrating how to use `git-rexec`:
6
6
  - Execute `git status -s` across all discovered Git repositories (found by searching recursively under the current working directory) in parallel (`-p` or `--parallel`):
@@ -13,6 +13,12 @@ Here are examples demonstrating how to use `git-rexec`:
13
13
  git-rexec -j 5 --parallel -- git fetch
14
14
  ```
15
15
 
16
+
17
+ - Include sub-repositories (e.g., Git worktrees and submodules) alongside standard Git repositories during discovery (`-s` or `--include-sub-repos`), and execute `git status` against them:
18
+ ```bash
19
+ git-rexec -s -p -- git status
20
+ ```
21
+
16
22
  - Target a specific base directory (`~/projects`) using the `-C` flag to recursively discover repositories within it, while explicitly excluding a specific subfolder (`~/projects/archive`). This example executes `git status -s` in parallel for all discovered repositories except those within the excluded path:
17
23
  ```bash
18
24
  git-rexec -C ~/projects --exclude-dir ~/projects/archive --parallel -- git status -s
@@ -23,15 +29,21 @@ Here are examples demonstrating how to use `git-rexec`:
23
29
  git-rexec --if-exec 'sh -c "test -f README.md"' --parallel -- wc -l README.md
24
30
  ```
25
31
 
32
+ - Print the paths of all discovered Git repositories:
33
+ ```bash
34
+ git-rexec --print
35
+ ```
36
+
26
37
  If this helps your workflow, please support the project by **⭐ starring git-rexec on GitHub** and sharing it on your website, blog, Mastodon, Reddit, X, LinkedIn, or other social media platforms to help more Git users discover its benefits.
27
38
 
28
39
  ## Features
29
40
 
30
41
  - Recursively discover Git repositories starting from a specified root directory.
42
+ - Optional flag to include sub-repositories (e.g., Git worktrees and submodules) in the execution target list.
31
43
  - Execute shell commands across multiple repositories in parallel using worker threads.
32
44
  - Filter target repositories based on the exit code of a conditional check (`--if-exec`).
33
45
  - Exclude specific directories from the search path.
34
- - Optional: Can leverage `fd` for fast directory traversal if installed, falling back to standard Python path resolution otherwise.
46
+ - Export discovered repository paths for integration with other shell tools (using `--print` or `--print0`).
35
47
 
36
48
  ## Installation
37
49
 
@@ -48,7 +60,7 @@ sudo cp git-rexec /usr/local/bin/
48
60
  Install the package directly from the Git repository using `pip`:
49
61
 
50
62
  ```bash
51
- pip install --user git+https://github.com/jamescherti/git-rexec
63
+ pip install --user git-rexec
52
64
  ```
53
65
 
54
66
  ## Dependencies
@@ -56,7 +68,6 @@ pip install --user git+https://github.com/jamescherti/git-rexec
56
68
  ### System Dependencies
57
69
 
58
70
  - `git`: Required for repository validation and execution.
59
- - `fd` (Optional): Highly recommended for faster repository discovery.
60
71
 
61
72
  ### Python Dependencies (Optional)
62
73
 
@@ -67,14 +78,12 @@ You can install the optional Python dependencies via pip:
67
78
 
68
79
  ```bash
69
80
  pip install colorama setproctitle
70
-
71
81
  ```
72
82
 
73
83
  ## Usage
74
84
 
75
85
  ```bash
76
86
  git-rexec [OPTIONS] [exec_cmd ...]
77
-
78
87
  ```
79
88
 
80
89
  *(Assuming the `git-rexec` script is executable and in your PATH.)*
@@ -90,6 +99,7 @@ git-rexec [OPTIONS] [exec_cmd ...]
90
99
  - `-p, --parallel`: Execute the command in parallel using threads.
91
100
  - `-i, --if-exec <command>`: Execute the main command only if this check command returns an exit code of `0`.
92
101
  - `-j, --jobs <int>`: The maximum number of concurrent workers/processors to use for parallel execution. Defaults to the number of CPU cores available.
102
+ - `-s, --include-sub-repos`: Include sub-repositories (e.g., Git worktrees and submodules) in the search target list.
93
103
  - `-h, --help`: Show the help message and exit.
94
104
  - `-q, --quiet`: Quiet mode. Suppresses the informational tracking headers (`[EXEC]` and `[EXEC-P]`) that prefix execution output. In sequential mode, it hides the `[EXEC]` repository delimiter line entirely; in parallel mode (`-p`), it strips the yellow `[EXEC-P]` header track and removes the four-space indentation, printing only the raw, unindented stdout and stderr streams. This flag has no effect when no execution command is supplied, allowing discovered repository paths to print normally.
95
105
 
@@ -6,6 +6,7 @@
6
6
  #
7
7
  # Author: James Cherti
8
8
  # URL: https://github.com/jamescherti/git-rexec
9
+ # Version: 1.0.2
9
10
  #
10
11
  # Copyright (C) 2019-2026 James Cherti
11
12
  #
@@ -100,51 +101,95 @@ def git_toplevel(repo_path: Path) -> Optional[Path]:
100
101
  return None
101
102
 
102
103
 
103
- def git_fd_find_repo(path: Path, max_workers: int) -> set[Path]:
104
- """Find all Git repositories in 'path' using fd.
104
+ def git_py_find_repo(root: Path) -> tuple[set[Path], set[Path]]:
105
+ """Recursively find all Git repositories under the root path using Python.
106
+
107
+ :param root: Directory to search under.
108
+ :return: A tuple containing standard repository paths and sub-repository
109
+ paths.
110
+ """
111
+ repos: set[Path] = set()
112
+ sub_repos: set[Path] = set()
113
+
114
+ for dirpath, dirnames, filenames in os.walk(root):
115
+ if ".git" in dirnames:
116
+ repos.add(Path(dirpath).absolute())
117
+ elif ".git" in filenames:
118
+ sub_repos.add(Path(dirpath).absolute())
119
+ else:
120
+ continue
105
121
 
106
- :param path: The root directory to search for Git repositories.
107
- :param max_workers: Maximum number of threads for fd.
108
- :return: set of paths to Git repositories.
122
+ # Clear dirnames to prevent os.walk from descending into
123
+ # subdirectories
124
+ dirnames.clear()
125
+
126
+ return repos, sub_repos
127
+
128
+
129
+ def get_sub_repos(repo_path: Path) -> set[Path]:
130
+ """Extract worktrees and submodules from a Git repository.
131
+
132
+ :param repo_path: The path to the standard repository.
133
+ :return: A set of absolute paths to worktrees and submodules.
109
134
  """
110
- path_str: str = str(path)
135
+ sub_repos: set[Path] = set()
136
+
137
+ # Discover worktrees
138
+ # pylint: disable=too-many-try-statements
111
139
  try:
112
- # Use fd to find .git directories efficiently
113
- proc: subprocess.CompletedProcess[str] = subprocess.run(
114
- [
115
- 'fd', '--type', 'd', '--hidden',
116
- '--no-ignore', '^\\.git$',
117
- '--absolute-path',
118
- '--threads', str(max_workers),
119
- path_str
120
- ],
140
+ wt_proc: subprocess.CompletedProcess[str] = subprocess.run(
141
+ ["git", "-C", str(repo_path), "worktree", "list", "--porcelain"],
121
142
  capture_output=True,
122
143
  text=True,
123
- check=False
144
+ check=True,
124
145
  )
125
- except FileNotFoundError as err:
126
- print(f"Error: {err}", file=sys.stderr)
127
- sys.exit(1)
128
146
 
129
- # Use a set comprehension to remove duplicates and normalize paths
130
- # efficiently
131
- return {
132
- Path(git_dir).parent
133
- for git_dir in proc.stdout.splitlines()
134
- }
147
+ current_wt: Optional[Path] = None
148
+ is_bare: bool = False
135
149
 
150
+ for line in wt_proc.stdout.splitlines():
151
+ line = line.strip()
136
152
 
137
- def git_py_find_repo(root: Path) -> set[Path]:
138
- """Recursively find all Git repositories under the root path using Python.
153
+ # Git porcelain separates blocks with a blank line
154
+ if not line:
155
+ if current_wt and not is_bare \
156
+ and current_wt != repo_path.resolve():
157
+ sub_repos.add(current_wt)
158
+ # Reset state for the next block
159
+ current_wt = None
160
+ is_bare = False
161
+ continue
139
162
 
140
- :param root: Directory to search under.
141
- :return: set of paths to Git repositories.
142
- """
143
- return {
144
- git_dir.absolute().parent
145
- for git_dir in root.rglob(".git")
146
- if git_dir.is_dir()
147
- }
163
+ if line.startswith("worktree "):
164
+ current_wt = Path(line[9:]).resolve()
165
+ elif line == "bare":
166
+ is_bare = True
167
+
168
+ # Process the final block in case the output lacks a trailing newline
169
+ if current_wt and not is_bare and current_wt != repo_path.resolve():
170
+ sub_repos.add(current_wt)
171
+
172
+ except subprocess.CalledProcessError:
173
+ pass
174
+
175
+ # Discover submodules
176
+ try:
177
+ sm_proc: subprocess.CompletedProcess[str] = subprocess.run(
178
+ ["git", "-C", str(repo_path),
179
+ "submodule", "foreach", "--quiet", "pwd"],
180
+ capture_output=True,
181
+ text=True,
182
+ check=True,
183
+ )
184
+
185
+ for line in sm_proc.stdout.splitlines():
186
+ sm_path: Path = Path(line.strip()).resolve()
187
+ sub_repos.add(sm_path)
188
+
189
+ except subprocess.CalledProcessError:
190
+ pass
191
+
192
+ return sub_repos
148
193
 
149
194
 
150
195
  def run_command_get_output(repo_path: Path, cmd_list: list[str],
@@ -242,24 +287,39 @@ def process_repo(repo_path: Path, exec_parallel_cmd: Optional[list[str]],
242
287
 
243
288
  def discover_repos(directory: Path,
244
289
  max_workers: int,
245
- exclude_dirs: list[str]) -> set[Path]:
246
- """Discover Git repositories starting from 'directory' and apply exclusions.
290
+ exclude_dirs: list[str],
291
+ include_sub_repos: bool) -> set[Path]:
292
+ """Discover Git repositories starting from directory and apply exclusions.
247
293
 
248
294
  :param directory: The root directory for search.
249
295
  :param max_workers: Maximum number of threads/workers.
250
296
  :param exclude_dirs: Directories to exclude.
297
+ :param include_sub_repos: Whether to include sub-repositories.
251
298
  :return: A set of repository root paths.
252
299
  """
253
300
  repos: set[Path] = set()
301
+ worktrees: set[Path] = set()
254
302
 
255
303
  # Discover all repositories
256
304
  toplevel: Optional[Path] = git_toplevel(directory)
257
305
  if toplevel:
258
306
  repos = {toplevel}
259
- elif shutil.which("fd"):
260
- repos = git_fd_find_repo(directory, max_workers)
261
307
  else:
262
- repos = git_py_find_repo(directory)
308
+ repos, worktrees = git_py_find_repo(directory)
309
+
310
+ # Extract and append sub-repositories concurrently if requested
311
+ if include_sub_repos:
312
+ sub_repos: set[Path] = set()
313
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
314
+ futures: list[Future[set[Path]]] = [
315
+ executor.submit(get_sub_repos, repo)
316
+ for repo in repos | worktrees
317
+ ]
318
+ for future in as_completed(futures):
319
+ result: set[Path] = future.result()
320
+ sub_repos.update(result)
321
+
322
+ repos.update(sub_repos)
263
323
 
264
324
  # Filter out excluded directories
265
325
  if not exclude_dirs:
@@ -303,7 +363,7 @@ def execute_parallel_tasks(
303
363
  result: Optional[RepoContext] = future.result()
304
364
  if result:
305
365
  results.append(result)
306
- except Exception as exc:
366
+ except (OSError, ValueError) as exc:
307
367
  print(f"Error processing repository {repo_path}: {exc}",
308
368
  file=sys.stderr)
309
369
 
@@ -357,6 +417,25 @@ def parse_args() -> argparse.Namespace:
357
417
  "([EXEC] and [EXEC-P]) that prefix execution output."),
358
418
  default=False
359
419
  )
420
+ parser.add_argument(
421
+ "-s", "--include-sub-repos",
422
+ action="store_true",
423
+ help="Include sub-repositories (e.g., Git worktrees and submodules)",
424
+ default=False
425
+ )
426
+ parser.add_argument(
427
+ "--print",
428
+ action="store_true",
429
+ help="Print the paths (only when no command is provided)",
430
+ default=False
431
+ )
432
+ parser.add_argument(
433
+ "--print0",
434
+ action="store_true",
435
+ help=("Separate the paths with a null character (only when no "
436
+ "command is provided)"),
437
+ default=False
438
+ )
360
439
  parser.add_argument(
361
440
  "exec_cmd",
362
441
  type=str,
@@ -418,6 +497,11 @@ def main() -> None:
418
497
 
419
498
  args: argparse.Namespace = parse_args()
420
499
 
500
+ # Check for empty action
501
+ if not args.exec_cmd and not args.print and not args.print0:
502
+ print("Nothing to do.", file=sys.stderr)
503
+ sys.exit(0)
504
+
421
505
  # Verify that the execution command exists
422
506
  if args.exec_cmd and not shutil.which(args.exec_cmd[0]):
423
507
  print(
@@ -428,7 +512,8 @@ def main() -> None:
428
512
  # Discover Repositories
429
513
  repos: set[Path] = discover_repos(args.directory.absolute(),
430
514
  args.max_workers,
431
- args.exclude_dir)
515
+ args.exclude_dir,
516
+ args.include_sub_repos)
432
517
 
433
518
  # setup background command list if needed
434
519
  exec_parallel_cmd: Optional[list[str]] = None
@@ -499,7 +584,10 @@ def main() -> None:
499
584
 
500
585
  # If no commands were run, just list the repo
501
586
  if not args.exec_cmd:
502
- print(repo_path)
587
+ if args.print0:
588
+ print(repo_path, end="\0")
589
+ elif args.print:
590
+ print(repo_path)
503
591
 
504
592
  # Final Error Summary
505
593
  sys.exit(print_error_summary(execution_errors))
@@ -1,13 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: git-rexec
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Locate Git repositories and execute commands against them in parallel.
5
5
  Author: James Cherti
6
- License: GPL-3.0-or-later
6
+ License-Expression: GPL-3.0-or-later
7
7
  Project-URL: Homepage, https://github.com/jamescherti/git-rexec
8
8
  Keywords: git,parallel,executor,automation
9
9
  Classifier: Programming Language :: Python :: 3
10
- Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
11
10
  Classifier: Operating System :: OS Independent
12
11
  Classifier: Environment :: Console
13
12
  Classifier: Topic :: Software Development :: Version Control :: Git
@@ -19,7 +18,7 @@ Requires-Dist: setproctitle; extra == "extras"
19
18
 
20
19
  # git-rexec: Find Git Repositories and Execute Commands Against Them, either Sequentially or in Parallel
21
20
 
22
- The [git-rexec](https://github.com/jamescherti/git-rexec/) command-line tool that recursively locates Git repositories within a directory and executes commands against them, either sequentially or in parallel.
21
+ The [git-rexec](https://github.com/jamescherti/git-rexec/) command-line tool recursively locates Git repositories within a directory and executes commands against them, either sequentially or in parallel.
23
22
 
24
23
  Here are examples demonstrating how to use `git-rexec`:
25
24
  - Execute `git status -s` across all discovered Git repositories (found by searching recursively under the current working directory) in parallel (`-p` or `--parallel`):
@@ -32,6 +31,12 @@ Here are examples demonstrating how to use `git-rexec`:
32
31
  git-rexec -j 5 --parallel -- git fetch
33
32
  ```
34
33
 
34
+
35
+ - Include sub-repositories (e.g., Git worktrees and submodules) alongside standard Git repositories during discovery (`-s` or `--include-sub-repos`), and execute `git status` against them:
36
+ ```bash
37
+ git-rexec -s -p -- git status
38
+ ```
39
+
35
40
  - Target a specific base directory (`~/projects`) using the `-C` flag to recursively discover repositories within it, while explicitly excluding a specific subfolder (`~/projects/archive`). This example executes `git status -s` in parallel for all discovered repositories except those within the excluded path:
36
41
  ```bash
37
42
  git-rexec -C ~/projects --exclude-dir ~/projects/archive --parallel -- git status -s
@@ -42,15 +47,21 @@ Here are examples demonstrating how to use `git-rexec`:
42
47
  git-rexec --if-exec 'sh -c "test -f README.md"' --parallel -- wc -l README.md
43
48
  ```
44
49
 
50
+ - Print the paths of all discovered Git repositories:
51
+ ```bash
52
+ git-rexec --print
53
+ ```
54
+
45
55
  If this helps your workflow, please support the project by **⭐ starring git-rexec on GitHub** and sharing it on your website, blog, Mastodon, Reddit, X, LinkedIn, or other social media platforms to help more Git users discover its benefits.
46
56
 
47
57
  ## Features
48
58
 
49
59
  - Recursively discover Git repositories starting from a specified root directory.
60
+ - Optional flag to include sub-repositories (e.g., Git worktrees and submodules) in the execution target list.
50
61
  - Execute shell commands across multiple repositories in parallel using worker threads.
51
62
  - Filter target repositories based on the exit code of a conditional check (`--if-exec`).
52
63
  - Exclude specific directories from the search path.
53
- - Optional: Can leverage `fd` for fast directory traversal if installed, falling back to standard Python path resolution otherwise.
64
+ - Export discovered repository paths for integration with other shell tools (using `--print` or `--print0`).
54
65
 
55
66
  ## Installation
56
67
 
@@ -67,7 +78,7 @@ sudo cp git-rexec /usr/local/bin/
67
78
  Install the package directly from the Git repository using `pip`:
68
79
 
69
80
  ```bash
70
- pip install --user git+https://github.com/jamescherti/git-rexec
81
+ pip install --user git-rexec
71
82
  ```
72
83
 
73
84
  ## Dependencies
@@ -75,7 +86,6 @@ pip install --user git+https://github.com/jamescherti/git-rexec
75
86
  ### System Dependencies
76
87
 
77
88
  - `git`: Required for repository validation and execution.
78
- - `fd` (Optional): Highly recommended for faster repository discovery.
79
89
 
80
90
  ### Python Dependencies (Optional)
81
91
 
@@ -86,14 +96,12 @@ You can install the optional Python dependencies via pip:
86
96
 
87
97
  ```bash
88
98
  pip install colorama setproctitle
89
-
90
99
  ```
91
100
 
92
101
  ## Usage
93
102
 
94
103
  ```bash
95
104
  git-rexec [OPTIONS] [exec_cmd ...]
96
-
97
105
  ```
98
106
 
99
107
  *(Assuming the `git-rexec` script is executable and in your PATH.)*
@@ -109,6 +117,7 @@ git-rexec [OPTIONS] [exec_cmd ...]
109
117
  - `-p, --parallel`: Execute the command in parallel using threads.
110
118
  - `-i, --if-exec <command>`: Execute the main command only if this check command returns an exit code of `0`.
111
119
  - `-j, --jobs <int>`: The maximum number of concurrent workers/processors to use for parallel execution. Defaults to the number of CPU cores available.
120
+ - `-s, --include-sub-repos`: Include sub-repositories (e.g., Git worktrees and submodules) in the search target list.
112
121
  - `-h, --help`: Show the help message and exit.
113
122
  - `-q, --quiet`: Quiet mode. Suppresses the informational tracking headers (`[EXEC]` and `[EXEC-P]`) that prefix execution output. In sequential mode, it hides the `[EXEC]` repository delimiter line entirely; in parallel mode (`-p`), it strips the yellow `[EXEC-P]` header track and removes the four-space indentation, printing only the raw, unindented stdout and stderr streams. This flag has no effect when no execution command is supplied, allowing discovered repository paths to print normally.
114
123
 
@@ -1,3 +1,4 @@
1
+ .gitignore
1
2
  README.md
2
3
  git-rexec
3
4
  pyproject.toml
@@ -4,18 +4,17 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "git-rexec"
7
- version = "1.0.0"
7
+ version = "1.0.2"
8
8
  description = "Locate Git repositories and execute commands against them in parallel."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
11
- license = {text = "GPL-3.0-or-later"}
11
+ license = "GPL-3.0-or-later"
12
12
  authors = [
13
13
  {name = "James Cherti"}
14
14
  ]
15
15
  keywords = ["git", "parallel", "executor", "automation"]
16
16
  classifiers = [
17
17
  "Programming Language :: Python :: 3",
18
- "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
19
18
  "Operating System :: OS Independent",
20
19
  "Environment :: Console",
21
20
  "Topic :: Software Development :: Version Control :: Git"
File without changes