Skip to content

Commit 04dd511

Browse files
improve git search script
1 parent 25ce0b2 commit 04dd511

File tree

1 file changed

+114
-21
lines changed

1 file changed

+114
-21
lines changed

scripts/git_scan.py

Lines changed: 114 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ def search_git_log(repo_path: Path, query: str, ignore_case: bool = False) -> bo
1515
This matches anywhere in the raw `git log` text (authors, dates, subjects, bodies, etc.).
1616
Returns True if a match is found.
1717
"""
18-
cmd = ["git", "-C", str(repo_path), "log", "--all"]
18+
# Use --no-pager to avoid interactive pager, and capture all output
19+
cmd = ["git", "-C", str(repo_path), "--no-pager", "log", "--all"]
1920

2021
try:
2122
result = subprocess.run(cmd, capture_output=True, text=True, check=False)
@@ -28,18 +29,84 @@ def search_git_log(repo_path: Path, query: str, ignore_case: bool = False) -> bo
2829
return False
2930

3031

32+
def find_git_named_dirs(root: Path):
33+
"""Find directories under `root` (only immediate children) whose name contains 'git' (case-insensitive).
34+
35+
This intentionally looks at the root itself and only its direct subdirectories (e.g. `~/git`, `~/git2`, `~/git-repo`).
36+
Returns a list of Path objects (resolved), sorted for stable output.
37+
"""
38+
matches = set()
39+
try:
40+
# include the root itself if it matches
41+
if "git" in root.name.lower():
42+
matches.add(root.resolve())
43+
44+
# look only at immediate children of root (so ~/git, ~/git2, etc.)
45+
try:
46+
for p in root.iterdir():
47+
try:
48+
if p.is_dir() and "git" in p.name.lower():
49+
matches.add(p.resolve())
50+
except Exception:
51+
continue
52+
except Exception:
53+
# Could be permission error when listing root; handle gracefully
54+
pass
55+
56+
except Exception as e:
57+
print(f"Error while scanning directories under {root}: {e}")
58+
59+
return sorted(matches)
60+
61+
3162
def scan_repos(root: Path, query: str, ignore_case: bool = False):
3263
found, not_found = [], []
3364

34-
for path in root.iterdir():
35-
if path.is_dir() and is_git_repo(path):
36-
matched = search_git_log(path, query, ignore_case)
37-
if matched:
38-
print(f"[FOUND] {path.name}")
39-
found.append(path.name)
40-
else:
41-
print(f"[---- ] {path.name}")
42-
not_found.append(path.name)
65+
# First, limit search to folders whose name contains 'git'
66+
git_named_dirs = find_git_named_dirs(root)
67+
if not git_named_dirs:
68+
print(f"No directories with 'git' in the name found under {root}")
69+
return
70+
71+
# Collect git repositories found inside those directories
72+
repos = []
73+
for d in git_named_dirs:
74+
# find .git directories under this folder
75+
try:
76+
for git_dir in d.rglob('.git'):
77+
try:
78+
repo = git_dir.parent.resolve()
79+
repos.append(repo)
80+
except Exception:
81+
continue
82+
except Exception:
83+
# if permission denied or similar, skip this dir
84+
continue
85+
86+
# also include the dir itself if it's a git repo
87+
if is_git_repo(d):
88+
repos.append(d.resolve())
89+
90+
# Deduplicate while preserving order
91+
seen = set()
92+
unique_repos = []
93+
for r in repos:
94+
if r not in seen:
95+
seen.add(r)
96+
unique_repos.append(r)
97+
98+
if not unique_repos:
99+
print(f"No git repositories found inside directories matching 'git' under {root}")
100+
return
101+
102+
for path in unique_repos:
103+
matched = search_git_log(path, query, ignore_case)
104+
if matched:
105+
print(f"[FOUND] {path}")
106+
found.append(path)
107+
else:
108+
print(f"[---- ] {path}")
109+
not_found.append(path)
43110

44111
print("\n==== Summary ====")
45112
print(f"Matched: {len(found)}")
@@ -49,21 +116,46 @@ def scan_repos(root: Path, query: str, ignore_case: bool = False):
49116

50117

51118
def list_repos(root: Path):
52-
repos = [p.name for p in root.iterdir() if p.is_dir() and is_git_repo(p)]
119+
"""List git repositories found under directories whose name contains 'git'."""
120+
git_named_dirs = find_git_named_dirs(root)
121+
if not git_named_dirs:
122+
print(f"No directories with 'git' in the name found under {root}")
123+
return
124+
125+
repos = set()
126+
for d in git_named_dirs:
127+
try:
128+
for git_dir in d.rglob('.git'):
129+
try:
130+
repos.add(git_dir.parent.resolve())
131+
except Exception:
132+
continue
133+
except Exception:
134+
continue
135+
136+
if is_git_repo(d):
137+
repos.add(d.resolve())
138+
139+
repos_list = sorted(repos)
140+
53141
print("Projects under:", root)
54-
for repo in repos:
142+
if not repos_list:
143+
print(" (none found inside matching 'git' folders)")
144+
return
145+
for repo in repos_list:
55146
print(f" - {repo}")
56147

57148

58149
if __name__ == "__main__":
59-
parser = argparse.ArgumentParser(description="Scan git repos for a string in commit logs.")
150+
parser = argparse.ArgumentParser(description="Scan git repos for a string in commit logs. This script limits scan to folders whose name contains 'git' under the given root.")
60151
parser.add_argument("-q", "--query", help="String to search in git logs")
61152
parser.add_argument("-i", "--ignore-case", action="store_true", help="Case-insensitive search")
62-
parser.add_argument("-d", "--dir", type=str, default=".", help="Root directory containing repos")
153+
parser.add_argument("-d", "--dir", type=str, default="~", help="Root directory containing repos (defaults to home)")
63154
parser.add_argument("--list", action="store_true", help="List repos only, no search")
64155

65156
args = parser.parse_args()
66-
root = Path(args.dir).resolve()
157+
root = Path(args.dir).expanduser().resolve()
158+
print(f"Starting search in: {root}")
67159

68160
if args.list:
69161
list_repos(root)
@@ -74,16 +166,17 @@ def list_repos(root: Path):
74166

75167
# Examples:
76168
#
77-
# List all repos:
78-
#
169+
# List all repos (only those under directories with 'git' in their name):
79170
# ./git_scan.py --list
80171
#
81-
#
82172
# Search commit messages for "fix login" (case-insensitive):
83-
#
84173
# ./git_scan.py -q "fix login" -i
85174
#
86-
#
87175
# Search in a different root path:
88-
#
89176
# ./git_scan.py -q "API_KEY" -d /path/to/git/folder
177+
#
178+
# Other example queries:
179+
# $ ~/git/PythonRuns/scripts/git_scan.py -q "user" -i
180+
# $ ~/git/PythonRuns/scripts/git_scan.py -q "@company" -i
181+
182+

0 commit comments

Comments
 (0)