-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmygd
More file actions
213 lines (186 loc) · 7.13 KB
/
Copy pathmygd
File metadata and controls
213 lines (186 loc) · 7.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#!/bin/bash
# 默认值
MAX_DEPTH=99
SHOW_HELP=0
TARGET_DIR="."
DIFF_OPTIONS=""
# 帮助信息
show_help() {
cat << HELP
Usage: $(basename $0) [-d depth] [-o options] [-h] [directory]
显示指定目录下所有 git 仓库的 diff 信息(支持分页和颜色显示)
Options:
-d depth 设置查找 git 仓库的最大深度 (默认: 无限递归)
深度从目标目录开始计数,-d 1 只查找目标目录本身
-o options 传递给 git diff 的选项 (例如: --stat, --name-only 等)
可以传递多个选项,用引号包裹: -o "--stat --summary"
-h 显示此帮助信息
Arguments:
directory 要搜索的目录 (默认: 当前目录 .)
Examples:
$(basename $0) # 查找当前目录下所有 git 仓库的 diff
$(basename $0) components # 查找 components 目录下所有 git 仓库的 diff
$(basename $0) -d 2 . # 只查找当前目录深度 2 以内的 git 仓库
$(basename $0) -o --stat # 只显示统计信息
$(basename $0) -o "--stat --summary" # 显示统计信息和摘要
$(basename $0) -o --name-only apps # 只显示文件名
$(basename $0) -d 1 -o --stat apps # 结合深度和 diff 选项
常用 git diff 选项:
--stat 显示修改统计信息
--name-only 只显示修改的文件名
--name-status 显示文件名和状态(新增/修改/删除)
--summary 显示文件创建、删除、重命名等摘要
--shortstat 简短的统计信息
-w, --ignore-all-space 忽略空白字符
--word-diff 按单词显示差异
注意:
- 输出会自动分页显示(类似 less)
- 使用方向键或 j/k 滚动,q 退出
- 颜色会自动保留
- 支持 git 子模块检查
HELP
}
# 解析参数
while getopts "d:o:h" opt; do
case $opt in
d)
MAX_DEPTH=$OPTARG
# 验证参数是否为数字
if ! [[ "$MAX_DEPTH" =~ ^[0-9]+$ ]]; then
echo "错误: -d 参数必须是正整数" >&2
show_help
exit 1
fi
;;
o)
DIFF_OPTIONS="$OPTARG"
;;
h)
show_help
exit 0
;;
?)
show_help
exit 1
;;
esac
done
# 获取位置参数(目录)
shift $((OPTIND - 1))
if [ $# -gt 0 ]; then
TARGET_DIR="$1"
# 验证目录是否存在
if [ ! -d "$TARGET_DIR" ]; then
echo "错误: 目录 '$TARGET_DIR' 不存在" >&2
exit 1
fi
fi
# 临时文件存储所有 diff 输出
TEMP_OUTPUT=$(mktemp)
trap "rm -f $TEMP_OUTPUT" EXIT
# 处理单个仓库的函数
process_repo() {
local work_tree="$1"
local is_submodule="$2"
(
cd "$work_tree"
# 检查是否有任何改动(工作区、暂存区或未跟踪文件)
has_changes=0
# 检查是否有提交历史
if git rev-parse --verify HEAD >/dev/null 2>&1; then
# 有提交历史,检查各种 diff
if ! git diff-index --quiet HEAD -- 2>/dev/null || \
! git diff --quiet 2>/dev/null || \
! git diff --cached --quiet 2>/dev/null; then
has_changes=1
fi
else
# 新仓库无提交历史,检查是否有暂存的文件
if ! git diff --cached --quiet 2>/dev/null || \
[ -n "$(git ls-files)" ]; then
has_changes=1
fi
fi
# 如果没有任何改动,跳过此仓库
if [ $has_changes -eq 0 ]; then
exit 0
fi
# 格式化标题行(复用原有逻辑)
terminal_width=$(tput cols)
echo_len=$(printf "%d\n" 120 $terminal_width | sort -n | head -1)
# 获取分支名(如果可能)
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "no commits")
# 如果是子模块,添加标记
if [ "$is_submodule" = "true" ]; then
original_str=" $work_tree ($branch) [SUBMODULE] "
else
original_str=" $work_tree ($branch) "
fi
# 计算原始字符串的长度
original_len=${#original_str}
# 计算需要补全的等号字符数
padding_len=$(($echo_len - $original_len))
# 在两侧补全等号字符
printf '\033[1;33m=%.0s' $(seq 1 $((padding_len/2)))
echo -n "$original_str"
printf '=%.0s' $(seq 1 $((padding_len/2)))
[ $((padding_len%2)) -eq 1 ] && printf '=' # 如果需要补全的字符数为奇数,则在右侧再补一个等号
printf '\033[0m'
echo # 换行
# 输出各种 diff(保留颜色)
if git rev-parse --verify HEAD >/dev/null 2>&1; then
# 有提交历史
# 1. 暂存区与 HEAD 的差异
if ! git diff --cached --quiet 2>/dev/null; then
echo -e "\033[1;32m### 暂存区的改动 (staged changes):\033[0m"
git diff --cached --color=always $DIFF_OPTIONS
echo
fi
# 2. 工作区与暂存区的差异(未暂存的改动)
if ! git diff --quiet 2>/dev/null; then
echo -e "\033[1;36m### 工作区的改动 (unstaged changes):\033[0m"
git diff --color=always $DIFF_OPTIONS
echo
fi
else
# 新仓库无提交历史
if ! git diff --cached --quiet 2>/dev/null; then
echo -e "\033[1;32m### 暂存区的新文件 (新仓库):\033[0m"
git diff --cached --color=always $DIFF_OPTIONS
echo
fi
fi
echo # 仓库之间添加空行分隔
)
}
# 查找并处理每个 git 仓库
find "$TARGET_DIR" -maxdepth $MAX_DEPTH -type d -name .git | sort | while read git_dir; do
work_tree=$(dirname "$git_dir")
# 处理主仓库
process_repo "$work_tree" "false"
# 检查并处理子模块
if [ -f "$work_tree/.gitmodules" ]; then
(
cd "$work_tree"
# 获取所有子模块路径
git config --file .gitmodules --get-regexp path | while read key submodule_path; do
# 提取子模块路径(去除 'submodule.xxx.path' 前缀)
submodule_path=$(echo "$submodule_path" | awk '{print $1}')
submodule_full_path="$work_tree/$submodule_path"
# 检查子模块是否已初始化
if [ -d "$submodule_full_path/.git" ] || [ -f "$submodule_full_path/.git" ]; then
process_repo "$submodule_full_path" "true"
fi
done
)
fi
done > "$TEMP_OUTPUT"
# 使用 less 分页显示(保留颜色)
if [ -s "$TEMP_OUTPUT" ]; then
# -R: 保留 ANSI 颜色
# -F: 如果内容少于一屏,直接显示不分页
# -X: 退出后保留输出在终端
less -RFX "$TEMP_OUTPUT"
else
echo "未在任何 git 仓库中发现改动。"
fi