git-lfs-advisor-cli 0.1.0__py3-none-any.whl
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.
- get_lfs_advisor_cli/__init__.py +0 -0
- get_lfs_advisor_cli/cli.py +162 -0
- git_lfs_advisor_cli-0.1.0.dist-info/METADATA +90 -0
- git_lfs_advisor_cli-0.1.0.dist-info/RECORD +7 -0
- git_lfs_advisor_cli-0.1.0.dist-info/WHEEL +5 -0
- git_lfs_advisor_cli-0.1.0.dist-info/entry_points.txt +2 -0
- git_lfs_advisor_cli-0.1.0.dist-info/top_level.txt +1 -0
File without changes
|
@@ -0,0 +1,162 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
import configparser
|
4
|
+
import pathlib
|
5
|
+
|
6
|
+
# --- Configuration ---
|
7
|
+
SIZE_LIMIT_MB = 25
|
8
|
+
# A set of common binary file extensions. Add more as needed for your project.
|
9
|
+
BINARY_EXTENSIONS = {
|
10
|
+
# Images
|
11
|
+
'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.svg',
|
12
|
+
# Documents
|
13
|
+
'.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
|
14
|
+
# Archives
|
15
|
+
'.zip', '.rar', '.7z', '.gz', '.tar',
|
16
|
+
# Compiled code and libraries
|
17
|
+
'.exe', '.dll', '.so', '.a', '.lib',
|
18
|
+
# Media
|
19
|
+
'.mp3', '.wav', '.ogg', '.mp4', '.mov', '.avi',
|
20
|
+
# Databases
|
21
|
+
'.db', '.sqlite', '.sqlite3',
|
22
|
+
# Other
|
23
|
+
'.jar', '.bin', '.dat',
|
24
|
+
}
|
25
|
+
# --- End Configuration ---
|
26
|
+
|
27
|
+
|
28
|
+
SIZE_LIMIT_BYTES = SIZE_LIMIT_MB * 1024 * 1024
|
29
|
+
|
30
|
+
|
31
|
+
def is_binary_file(filepath, chunk_size=1024):
|
32
|
+
"""
|
33
|
+
Heuristically determines if a file is binary by checking for null bytes
|
34
|
+
in the first chunk of the file.
|
35
|
+
"""
|
36
|
+
try:
|
37
|
+
with open(filepath, 'rb') as f:
|
38
|
+
return b'\0' in f.read(chunk_size)
|
39
|
+
except IOError:
|
40
|
+
return False # Could not read, assume not binary for safety.
|
41
|
+
|
42
|
+
|
43
|
+
def get_submodule_paths():
|
44
|
+
"""Parses .gitmodules and returns a set of submodule paths."""
|
45
|
+
submodules = set()
|
46
|
+
gitmodules_path = '.gitmodules'
|
47
|
+
if not os.path.exists(gitmodules_path):
|
48
|
+
return submodules
|
49
|
+
|
50
|
+
print("Found .gitmodules, parsing for submodule paths...")
|
51
|
+
config = configparser.ConfigParser()
|
52
|
+
try:
|
53
|
+
config.read(gitmodules_path)
|
54
|
+
for section in config.sections():
|
55
|
+
if config.has_option(section, 'path'):
|
56
|
+
path_str = config.get(section, 'path')
|
57
|
+
# Normalize path for the current OS (e.g., using '\' on Windows)
|
58
|
+
normalized_path = str(pathlib.Path(path_str))
|
59
|
+
submodules.add(normalized_path)
|
60
|
+
except configparser.Error as e:
|
61
|
+
print(f"Warning: Could not parse .gitmodules file: {e}", file=sys.stderr)
|
62
|
+
|
63
|
+
if submodules:
|
64
|
+
print("The following submodule paths will be ignored:")
|
65
|
+
for path in sorted(list(submodules)):
|
66
|
+
print(f" - {path}")
|
67
|
+
return submodules
|
68
|
+
|
69
|
+
|
70
|
+
def scan_repo_files(submodule_paths):
|
71
|
+
"""Walks the repo, yielding file paths to be analyzed."""
|
72
|
+
for root, dirs, files in os.walk('.', topdown=True):
|
73
|
+
if '.git' in dirs:
|
74
|
+
dirs.remove('.git')
|
75
|
+
|
76
|
+
for d in dirs[:]:
|
77
|
+
dir_path = str(pathlib.Path(root) / d)
|
78
|
+
if dir_path in submodule_paths:
|
79
|
+
print(f"Ignoring submodule directory: '{dir_path}'")
|
80
|
+
dirs.remove(d)
|
81
|
+
|
82
|
+
for filename in files:
|
83
|
+
yield os.path.join(root, filename)
|
84
|
+
|
85
|
+
|
86
|
+
def analyze_file(file_path):
|
87
|
+
"""Analyzes a single file and returns an LFS pattern if it matches criteria."""
|
88
|
+
try:
|
89
|
+
normalized_path = str(pathlib.Path(file_path).as_posix())
|
90
|
+
file_size = os.path.getsize(file_path)
|
91
|
+
is_large = file_size > SIZE_LIMIT_BYTES
|
92
|
+
is_bin = False
|
93
|
+
|
94
|
+
if not is_large:
|
95
|
+
_, ext = os.path.splitext(file_path)
|
96
|
+
if ext.lower() in BINARY_EXTENSIONS:
|
97
|
+
is_bin = True
|
98
|
+
else:
|
99
|
+
is_bin = is_binary_file(file_path)
|
100
|
+
|
101
|
+
if is_large or is_bin:
|
102
|
+
if is_large:
|
103
|
+
size_in_mb = file_size / (1024 * 1024)
|
104
|
+
print(f"Found large file: '{normalized_path}' (Size: {size_in_mb:.2f}MB)")
|
105
|
+
else:
|
106
|
+
print(f"Found binary file: '{normalized_path}' (Reason: Binary content)")
|
107
|
+
|
108
|
+
if '.' in os.path.basename(file_path):
|
109
|
+
_, ext = os.path.splitext(file_path)
|
110
|
+
return f"*{ext.lower()}"
|
111
|
+
else:
|
112
|
+
return normalized_path
|
113
|
+
|
114
|
+
except FileNotFoundError:
|
115
|
+
print(f"Warning: Could not access '{file_path}'. Skipping.", file=sys.stderr)
|
116
|
+
|
117
|
+
return None
|
118
|
+
|
119
|
+
|
120
|
+
def print_lfs_suggestions(lfs_patterns):
|
121
|
+
"""Prints the suggested LFS commands based on found patterns."""
|
122
|
+
if not lfs_patterns:
|
123
|
+
print(f"No files found exceeding {SIZE_LIMIT_MB}MB or detected as binary.")
|
124
|
+
return
|
125
|
+
|
126
|
+
print("\n--- Suggested git lfs track commands (for .gitattributes) ---")
|
127
|
+
print("# Run these commands to update your .gitattributes file.")
|
128
|
+
sorted_patterns = sorted(list(lfs_patterns))
|
129
|
+
for pattern in sorted_patterns:
|
130
|
+
print(f'git lfs track "{pattern}"')
|
131
|
+
|
132
|
+
print("\n--- Suggested git lfs migrate command (for rewriting history) ---")
|
133
|
+
include_arg = ",".join(sorted_patterns)
|
134
|
+
print("\n# WARNING: The following commands rewrite the history of your repository.")
|
135
|
+
print("# It is STRONGLY RECOMMENDED to run this on a fresh clone or to backup your repository first.")
|
136
|
+
print("\n# --- Option 1: Migrate ONLY the CURRENT branch (most common) ---")
|
137
|
+
print(f'git lfs migrate import --include="{include_arg}"')
|
138
|
+
print("\n# --- Option 2: Migrate a SPECIFIC branch (e.g., 'main') ---")
|
139
|
+
print(f'# git lfs migrate import --include="{include_arg}" main')
|
140
|
+
print("\n# --- Option 3: Migrate ALL local and remote branches ---")
|
141
|
+
print(f'# git lfs migrate import --include="{include_arg}" --everything')
|
142
|
+
|
143
|
+
|
144
|
+
def main():
|
145
|
+
"""Finds large or binary files and generates .gitattributes LFS rules."""
|
146
|
+
print(f"Scanning for files larger than {SIZE_LIMIT_MB}MB or binary files...")
|
147
|
+
submodule_paths = get_submodule_paths()
|
148
|
+
print("----------------------------------------")
|
149
|
+
|
150
|
+
lfs_patterns = set()
|
151
|
+
for file_path in scan_repo_files(submodule_paths):
|
152
|
+
pattern = analyze_file(file_path)
|
153
|
+
if pattern:
|
154
|
+
lfs_patterns.add(pattern)
|
155
|
+
|
156
|
+
print("----------------------------------------")
|
157
|
+
print("Scan complete.")
|
158
|
+
print_lfs_suggestions(lfs_patterns)
|
159
|
+
|
160
|
+
|
161
|
+
if __name__ == "__main__":
|
162
|
+
main()
|
@@ -0,0 +1,90 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: git-lfs-advisor-cli
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A script to find large/binary files and generate Git LFS commands.
|
5
|
+
Home-page: https://github.com/taicaile/git-lfs-advisor
|
6
|
+
Author: taicaile
|
7
|
+
Author-email:
|
8
|
+
Project-URL: Bug Tracker, https://github.com/taicaile/git-lfs-advisor/issues
|
9
|
+
Project-URL: Source Code, https://github.com/taicaile/git-lfs-advisor
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
12
|
+
Classifier: Operating System :: OS Independent
|
13
|
+
Classifier: Environment :: Console
|
14
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
15
|
+
Requires-Python: >=3.6
|
16
|
+
Description-Content-Type: text/markdown
|
17
|
+
Dynamic: author
|
18
|
+
Dynamic: classifier
|
19
|
+
Dynamic: description
|
20
|
+
Dynamic: description-content-type
|
21
|
+
Dynamic: home-page
|
22
|
+
Dynamic: project-url
|
23
|
+
Dynamic: requires-python
|
24
|
+
Dynamic: summary
|
25
|
+
|
26
|
+
# Git LFS Advisor
|
27
|
+
|
28
|
+
A simple command-line tool to scan a Git repository, find files suitable for Git LFS, and generate the necessary configuration commands.
|
29
|
+
|
30
|
+
This tool helps you quickly set up Git LFS for a new or existing project without manually checking every file.
|
31
|
+
|
32
|
+
## ✨ Features
|
33
|
+
|
34
|
+
- **Repository Scan**: Scans the entire Git repository to find large or binary files.
|
35
|
+
- **Custom Rules**: Define scanning rules based on file size or file extension.
|
36
|
+
- **Command Generation**: Automatically generates `git lfs track` and `git lfs migrate` commands for you to copy and execute.
|
37
|
+
- **Cross-Platform**: Built with Python, it runs on Windows, macOS, and Linux.
|
38
|
+
|
39
|
+
## 📋 What It Does
|
40
|
+
|
41
|
+
1. **Scans** your repository for large files and binary assets
|
42
|
+
2. **Analyzes** file patterns, sizes, and repository structure
|
43
|
+
3. **Recommends** which files should be tracked by Git LFS
|
44
|
+
4. **Generates** `.gitattributes` configuration automatically
|
45
|
+
5. **Provides** migration commands and best practices
|
46
|
+
|
47
|
+
## 🎯 Use Cases
|
48
|
+
|
49
|
+
- Setting up LFS for new repositories
|
50
|
+
- Optimizing existing repositories with large files
|
51
|
+
- Migrating from regular Git to Git LFS
|
52
|
+
- Repository cleanup and size optimization
|
53
|
+
- CI/CD pipeline integration
|
54
|
+
|
55
|
+
## 📊 Example Output
|
56
|
+
|
57
|
+
```txt
|
58
|
+
🔍 Scanning repository...
|
59
|
+
📁 Found 1,247 files (Total: 2.3 GB)
|
60
|
+
|
61
|
+
💡 LFS Recommendations:
|
62
|
+
• *.psd files (127 files, 890 MB) → Track with LFS
|
63
|
+
• *.mp4 files (23 files, 1.2 GB) → Track with LFS
|
64
|
+
• *.zip files (8 files, 156 MB) → Track with LFS
|
65
|
+
|
66
|
+
📝 Generated .gitattributes:
|
67
|
+
*.psd filter=lfs diff=lfs merge=lfs -text
|
68
|
+
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
69
|
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
70
|
+
|
71
|
+
💾 Potential space savings: ~2.1 GB in Git history
|
72
|
+
```
|
73
|
+
|
74
|
+
## 🛠️ Installation
|
75
|
+
|
76
|
+
```bash
|
77
|
+
pip install git-lfs-advisor-cli
|
78
|
+
```
|
79
|
+
|
80
|
+
## 🤝 Contributing
|
81
|
+
|
82
|
+
Contributions are welcome!
|
83
|
+
|
84
|
+
## ⭐ Show Your Support
|
85
|
+
|
86
|
+
If this tool helps you manage your Git LFS setup, please give it a star! ⭐
|
87
|
+
|
88
|
+
---
|
89
|
+
|
90
|
+
**Made with ❤️ for better Git workflows**
|
@@ -0,0 +1,7 @@
|
|
1
|
+
get_lfs_advisor_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
get_lfs_advisor_cli/cli.py,sha256=rTgYaEAdQSpJN3Ooc9vFeWLsmQLYe3eP_qazOW3Vup0,5690
|
3
|
+
git_lfs_advisor_cli-0.1.0.dist-info/METADATA,sha256=kg3s0R_wtr4R_ui9H5icpdXVGyh82uX9Ru2NGUzFCMI,2854
|
4
|
+
git_lfs_advisor_cli-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
5
|
+
git_lfs_advisor_cli-0.1.0.dist-info/entry_points.txt,sha256=YZzhKVbOqvEsDD_crFXeeJpNrw3MX12p0OpZru_0jj8,65
|
6
|
+
git_lfs_advisor_cli-0.1.0.dist-info/top_level.txt,sha256=KNa-t2YpZQLVGU0rxddnP34Jb3cWBAvttoCx0ikjClE,20
|
7
|
+
git_lfs_advisor_cli-0.1.0.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
get_lfs_advisor_cli
|