Release 1.0.6: auto-unignore, macOS fix, --version
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7,6 +7,32 @@
|
||||
|
||||
---
|
||||
|
||||
## [1.0.6] - 2026-07-20
|
||||
|
||||
### Добавлено
|
||||
|
||||
- 🧹 **Автоснятие пути из `.gitignore`** перед регистрацией подмодуля
|
||||
- Удаляются точные правила вида `/path/`, `path/`, `/path`
|
||||
- Если срабатывает более широкое правило — добавляется исключение `!/path/`
|
||||
- 📦 Регистрация **уже существующих** вложенных клонов без повторного `clone`
|
||||
(`gitlink` + `git submodule absorbgitdirs`)
|
||||
- 🏷️ Константа версии `SCRIPT_VERSION` и опции `--version` / `-V`
|
||||
|
||||
### Исправлено
|
||||
|
||||
- 🍎 Совместимость с **macOS/BSD `sed`**: корень `.` больше не попадал в список
|
||||
(раньше `sed -i` без аргумента backup падал тихо, скрипт пытался
|
||||
зарегистрировать `.` и обрывался из‑за `set -e`)
|
||||
- Ошибка одного подмодуля больше не останавливает весь цикл регистрации
|
||||
- Нормализация путей `./foo` → `foo`
|
||||
|
||||
### Документация
|
||||
|
||||
- 📖 Обновлён **README.md**
|
||||
- 📝 Обновлён **CHANGELOG.md**
|
||||
|
||||
---
|
||||
|
||||
## [1.1.0] - 2025-07-19
|
||||
|
||||
### Добавлено
|
||||
@@ -107,6 +133,7 @@
|
||||
|
||||
| Версия | Дата | Изменения |
|
||||
|--------|------|-----------|
|
||||
| **1.0.6** | 2026-07-20 | Автоснятие из `.gitignore`, fix macOS sed, `--version` |
|
||||
| **1.1.0** | 2025-07-19 | Добавлена настройка игнорирования подмодулей |
|
||||
| **1.0.0** | 2025-07-19 | Первый стабильный релиз |
|
||||
| **0.1.0** | 2025-07-19 | Предварительная версия (прототип) |
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Git Management Tools (`git_man`)
|
||||
|
||||
**Версия:** 1.0.6
|
||||
|
||||
Набор скриптов и утилит для управления Git-репозиториями, работы с подмодулями и автоматизации повседневных задач.
|
||||
|
||||
---
|
||||
@@ -12,6 +14,7 @@
|
||||
- [Установка](#установка)
|
||||
- [Использование](#использование)
|
||||
- [Требования](#требования)
|
||||
- [История версий](#история-версий)
|
||||
- [Автор](#автор)
|
||||
- [Лицензия](#лицензия)
|
||||
|
||||
@@ -23,6 +26,7 @@
|
||||
|
||||
Основные задачи:
|
||||
- Автоматическая регистрация вложенных репозиториев как подмодулей
|
||||
- Снятие путей из `.gitignore` при регистрации
|
||||
- Централизованное управление множеством репозиториев
|
||||
- Настройка игнорирования состояния подмодулей в основном репозитории
|
||||
- Автоматизация рутинных операций
|
||||
@@ -34,7 +38,7 @@
|
||||
### `register-submodules.sh`
|
||||
|
||||
**Описание:**
|
||||
Автоматически находит все вложенные Git-репозитории в текущей папке и регистрирует их как подмодули в `.gitmodules`. Поддерживает настройку игнорирования состояния подмодулей.
|
||||
Автоматически находит все вложенные Git-репозитории в текущей папке и регистрирует их как подмодули в `.gitmodules`. Перед регистрацией снимает путь из `.gitignore` (точные правила или исключение `!/path/`). Уже существующие клоны регистрируются без повторного clone. Поддерживает настройку игнорирования состояния подмодулей.
|
||||
|
||||
**Использование:**
|
||||
```bash
|
||||
@@ -46,6 +50,7 @@
|
||||
| Опция | Описание |
|
||||
|-------|----------|
|
||||
| `--help`, `-h` | Показать справку |
|
||||
| `--version`, `-V` | Показать версию скрипта (`1.0.6`) |
|
||||
| `--dry-run` | Только показать, что будет сделано (без изменений) |
|
||||
| `--force`, `-f` | Принудительная перерегистрация подмодулей |
|
||||
| `--ignore=MODE` | Установить режим игнорирования для ВСЕХ подмодулей |
|
||||
@@ -176,6 +181,25 @@ git submodule add https://git.p7net.ru/tools/git_man.git tools/git_man
|
||||
|
||||
---
|
||||
|
||||
## 📌 История версий
|
||||
|
||||
Текущая версия: **1.0.6** (2026-07-20).
|
||||
|
||||
Кратко по релизам — см. [CHANGELOG.md](./CHANGELOG.md).
|
||||
|
||||
| Версия | Дата | Суть |
|
||||
|--------|------|------|
|
||||
| **1.0.6** | 2026-07-20 | Автоснятие из `.gitignore`, fix macOS, `--version` |
|
||||
| **1.1.0** | 2025-07-19 | Настройка `ignore` для подмодулей |
|
||||
| **1.0.0** | 2025-07-19 | Первый стабильный релиз |
|
||||
|
||||
Проверка версии:
|
||||
```bash
|
||||
./register-submodules.sh --version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 👤 Автор
|
||||
|
||||
**Michael BAG**
|
||||
|
||||
+196
-39
@@ -2,14 +2,16 @@
|
||||
# ============================================================
|
||||
# register-submodules.sh - Регистрация всех вложенных репозиториев как подмодулей
|
||||
#
|
||||
# Версия: 1.0.6
|
||||
# Автор: Michael BAG <mk@p7net.ru>
|
||||
# Репозиторий: https://git.p7net.ru/tools/git_man
|
||||
#
|
||||
# Использование:
|
||||
# ./register-submodules.sh [--help] [--dry-run] [--force] [--ignore=all|dirty|untracked|none]
|
||||
# ./register-submodules.sh [--help] [--version] [--dry-run] [--force] [--ignore=all|dirty|untracked|none]
|
||||
#
|
||||
# Опции:
|
||||
# --help, -h Показать эту справку
|
||||
# --version, -V Показать версию скрипта
|
||||
# --dry-run Только показать, что будет сделано (без изменений)
|
||||
# --force, -f Принудительно перерегистрировать подмодули
|
||||
# --ignore=MODE Установить режим игнорирования для всех подмодулей
|
||||
@@ -24,25 +26,33 @@
|
||||
# Описание:
|
||||
# Скрипт находит все вложенные репозитории (папки с .git),
|
||||
# определяет их URL и регистрирует как подмодули в .gitmodules.
|
||||
# Перед регистрацией снимает путь с .gitignore (если он там есть).
|
||||
# Также позволяет настроить игнорирование состояния подмодулей.
|
||||
# ============================================================
|
||||
|
||||
set -e # Остановка при ошибке
|
||||
set -e # Остановка при ошибке (критичные шаги); ошибки регистрации ловятся явно
|
||||
|
||||
SCRIPT_VERSION="1.0.6"
|
||||
|
||||
# ============================================================
|
||||
# Функция показа справки
|
||||
# ============================================================
|
||||
show_help() {
|
||||
cat << 'EOF'
|
||||
cat << EOF
|
||||
============================================================
|
||||
📦 register-submodules.sh - Регистрация вложенных репозиториев
|
||||
📦 register-submodules.sh v${SCRIPT_VERSION} - Регистрация вложенных репозиториев
|
||||
============================================================
|
||||
|
||||
ОПИСАНИЕ:
|
||||
Находит вложенные репозитории (.git), регистрирует их как
|
||||
подмодули. Перед регистрацией сам убирает путь из .gitignore.
|
||||
|
||||
ИСПОЛЬЗОВАНИЕ:
|
||||
./register-submodules.sh [ОПЦИИ]
|
||||
|
||||
ОПЦИИ:
|
||||
--help, -h Показать эту справку
|
||||
--version, -V Показать версию скрипта
|
||||
--dry-run Только показать, что будет сделано (без изменений)
|
||||
--force, -f Принудительно перерегистрировать подмодули
|
||||
(удаляет существующие и создаёт заново)
|
||||
@@ -85,6 +95,11 @@ EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
show_version() {
|
||||
echo "register-submodules.sh ${SCRIPT_VERSION}"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Инициализация переменных
|
||||
# ============================================================
|
||||
@@ -104,6 +119,9 @@ while [[ $# -gt 0 ]]; do
|
||||
--help|-h)
|
||||
show_help
|
||||
;;
|
||||
--version|-V)
|
||||
show_version
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
@@ -214,6 +232,95 @@ fi
|
||||
|
||||
log_success "Окружение проверено"
|
||||
|
||||
# ============================================================
|
||||
# Нормализация пути: ./foo/ -> foo
|
||||
# ============================================================
|
||||
normalize_path() {
|
||||
local path="$1"
|
||||
path="${path#./}"
|
||||
path="${path%/}"
|
||||
printf '%s' "$path"
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Снять путь из .gitignore (точные правила вида /path/, path/, /path)
|
||||
# ============================================================
|
||||
unignore_path_from_gitignore() {
|
||||
local path
|
||||
path=$(normalize_path "$1")
|
||||
local gitignore=".gitignore"
|
||||
|
||||
if [ ! -f "$gitignore" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Не игнорируется — ничего не делаем
|
||||
if ! git check-ignore -q "$path" 2>/dev/null \
|
||||
&& ! git check-ignore -q "$path/" 2>/dev/null \
|
||||
&& ! git check-ignore -q "./$path" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Совпадает ли строка .gitignore с путём (с/без / и комментария в конце)
|
||||
line_matches_path() {
|
||||
local raw="$1"
|
||||
local trimmed="${raw%%#*}"
|
||||
# trim spaces
|
||||
trimmed="${trimmed#"${trimmed%%[![:space:]]*}"}"
|
||||
trimmed="${trimmed%"${trimmed##*[![:space:]]}"}"
|
||||
case "$trimmed" in
|
||||
"/$path"|"/$path/"|"$path"|"$path/"|"./$path"|"./$path/")
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
echo " [DRY-RUN] убрать из .gitignore правила для: $path"
|
||||
local lineno=0
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
lineno=$((lineno + 1))
|
||||
if line_matches_path "$line"; then
|
||||
echo " → $lineno:$line"
|
||||
fi
|
||||
done < "$gitignore"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local tmp
|
||||
tmp=$(mktemp)
|
||||
local removed=0
|
||||
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
if line_matches_path "$line"; then
|
||||
removed=$((removed + 1))
|
||||
continue
|
||||
fi
|
||||
printf '%s\n' "$line"
|
||||
done < "$gitignore" > "$tmp"
|
||||
|
||||
if [ "$removed" -gt 0 ]; then
|
||||
mv "$tmp" "$gitignore"
|
||||
log_success "Убран из .gitignore: $path ($removed правил)"
|
||||
git add -- "$gitignore" 2>/dev/null || true
|
||||
else
|
||||
rm -f "$tmp"
|
||||
# Путь всё ещё игнорируется более широким правилом — добавим исключение
|
||||
if git check-ignore -q "$path" 2>/dev/null || git check-ignore -q "$path/" 2>/dev/null; then
|
||||
log_warning "Широкое правило .gitignore; добавляю исключение: !/$path/"
|
||||
printf '\n# auto-unignore for submodule\n!/%s/\n' "$path" >> "$gitignore"
|
||||
git add -- "$gitignore" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# Если после правок путь всё ещё ignored — для submodule add нужен --force
|
||||
if git check-ignore -q "$path" 2>/dev/null || git check-ignore -q "$path/" 2>/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Функция установки ignore для подмодуля
|
||||
# ============================================================
|
||||
@@ -245,33 +352,82 @@ remove_submodule_ignore() {
|
||||
return $?
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Регистрация уже существующего вложенного репозитория
|
||||
# ============================================================
|
||||
register_existing_repo_as_submodule() {
|
||||
local repo="$1"
|
||||
local url="$2"
|
||||
|
||||
git config -f .gitmodules "submodule.$repo.path" "$repo"
|
||||
git config -f .gitmodules "submodule.$repo.url" "$url"
|
||||
git config "submodule.$repo.url" "$url"
|
||||
git config "submodule.$repo.active" "true"
|
||||
|
||||
if ! git add -f -- .gitmodules "$repo" 2>/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Перенести .git вложенного репо в .git/modules родителя (если доступно)
|
||||
git submodule absorbgitdirs -- "$repo" 2>/dev/null || true
|
||||
return 0
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# Функция регистрации подмодуля
|
||||
# ============================================================
|
||||
register_submodule() {
|
||||
local repo="$1"
|
||||
local repo
|
||||
local url="$2"
|
||||
repo=$(normalize_path "$1")
|
||||
local still_ignored=false
|
||||
|
||||
# Снять путь из .gitignore до регистрации
|
||||
if ! unignore_path_from_gitignore "$repo"; then
|
||||
still_ignored=true
|
||||
log_debug "Путь $repo всё ещё в ignore — будет использован --force"
|
||||
fi
|
||||
|
||||
if [ "$DRY_RUN" = true ]; then
|
||||
echo " [DRY-RUN] git submodule add $url $repo"
|
||||
if [ -e "$repo/.git" ]; then
|
||||
echo " [DRY-RUN] зарегистрировать существующий репозиторий как подмодуль: $repo ← $url"
|
||||
else
|
||||
echo " [DRY-RUN] git submodule add --force $url $repo"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$FORCE" = true ]; then
|
||||
git config --remove-section "submodule.$repo" 2>/dev/null || true
|
||||
git config --file .gitmodules --remove-section "submodule.$repo" 2>/dev/null || true
|
||||
git config -f .gitmodules --remove-section "submodule.$repo" 2>/dev/null || true
|
||||
if [ -d "$repo" ] && [ -z "$(ls -A "$repo" 2>/dev/null)" ]; then
|
||||
rm -rf "$repo"
|
||||
fi
|
||||
fi
|
||||
|
||||
if git config --file .gitmodules --get "submodule.$repo.url" >/dev/null 2>&1; then
|
||||
if [ -f .gitmodules ] && git config -f .gitmodules --get "submodule.$repo.url" >/dev/null 2>&1; then
|
||||
log_debug "Подмодуль $repo уже зарегистрирован"
|
||||
return 2
|
||||
fi
|
||||
|
||||
git submodule add "$url" "$repo" 2>/dev/null
|
||||
return $?
|
||||
|
||||
# Каталог уже клонирован — регистрируем без повторного clone
|
||||
if [ -e "$repo/.git" ]; then
|
||||
if register_existing_repo_as_submodule "$repo" "$url"; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Пустой / отсутствующий путь — обычный submodule add
|
||||
local add_args=()
|
||||
if [ "$still_ignored" = true ] || [ "$FORCE" = true ]; then
|
||||
add_args+=(--force)
|
||||
fi
|
||||
|
||||
if git submodule add "${add_args[@]}" "$url" "$repo" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
@@ -366,8 +522,15 @@ fi
|
||||
log_step "Поиск вложенных репозиториев..."
|
||||
|
||||
TEMP_FILE=$(mktemp)
|
||||
find . -type d -name ".git" -exec dirname {} \; 2>/dev/null | sort > "$TEMP_FILE"
|
||||
sed -i '/^\.$/d' "$TEMP_FILE" 2>/dev/null || true
|
||||
# Исключаем корень «.»; нормализуем ./path → path (portable, без sed -i)
|
||||
find . -type d -name ".git" -exec dirname {} \; 2>/dev/null \
|
||||
| while IFS= read -r p; do
|
||||
[ "$p" = "." ] && continue
|
||||
normalize_path "$p"
|
||||
printf '\n'
|
||||
done \
|
||||
| grep -v '^$' \
|
||||
| sort -u > "$TEMP_FILE"
|
||||
|
||||
if [ ! -s "$TEMP_FILE" ]; then
|
||||
log_warning "Вложенные репозитории не найдены"
|
||||
@@ -381,9 +544,9 @@ log_success "Найдено $TOTAL вложенных репозиториев"
|
||||
if [ "$VERBOSE" = true ]; then
|
||||
echo ""
|
||||
echo -e "${CYAN}📋 Список найденных репозиториев:${NC}"
|
||||
cat "$TEMP_FILE" | while read repo; do
|
||||
while IFS= read -r repo; do
|
||||
echo " 📁 $repo"
|
||||
done
|
||||
done < "$TEMP_FILE"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
@@ -397,43 +560,38 @@ SKIPPED=0
|
||||
ERRORS=0
|
||||
NO_URL=0
|
||||
|
||||
while read repo; do
|
||||
while IFS= read -r repo; do
|
||||
[ -z "$repo" ] && continue
|
||||
repo=$(normalize_path "$repo")
|
||||
|
||||
log_debug "Обработка: $repo"
|
||||
|
||||
if [ -d "$repo" ]; then
|
||||
cd "$repo" 2>/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
log_error "Не удалось перейти в папку: $repo"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
cd - > /dev/null 2>/dev/null || true
|
||||
continue
|
||||
fi
|
||||
|
||||
url=$(git remote get-url origin 2>/dev/null)
|
||||
cd - > /dev/null 2>/dev/null || true
|
||||
|
||||
if [ -z "$url" ]; then
|
||||
if [ "$VERBOSE" = true ] || [ "$QUIET" != true ]; then
|
||||
log_warning "Не удалось определить URL для: $repo (нет remote 'origin')"
|
||||
fi
|
||||
NO_URL=$((NO_URL + 1))
|
||||
continue
|
||||
fi
|
||||
else
|
||||
if [ ! -d "$repo" ]; then
|
||||
log_warning "Папка не существует: $repo"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! url=$(git -C "$repo" remote get-url origin 2>/dev/null); then
|
||||
url=""
|
||||
fi
|
||||
|
||||
if [ -z "$url" ]; then
|
||||
log_warning "Не удалось определить URL для: $repo (нет remote 'origin')"
|
||||
NO_URL=$((NO_URL + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$QUIET" != true ]; then
|
||||
echo -e "${GREEN}➕ Регистрация:${NC} $repo"
|
||||
echo -e " ${CYAN}URL:${NC} $url"
|
||||
fi
|
||||
|
||||
|
||||
# set -e не должен прерывать цикл при ошибке одного подмодуля
|
||||
set +e
|
||||
register_submodule "$repo" "$url"
|
||||
result=$?
|
||||
set -e
|
||||
|
||||
case $result in
|
||||
0)
|
||||
@@ -442,8 +600,7 @@ while read repo; do
|
||||
|
||||
# Если задан режим игнорирования для всех подмодулей
|
||||
if [ -n "$IGNORE_MODE" ]; then
|
||||
set_submodule_ignore "$repo" "$IGNORE_MODE"
|
||||
if [ $? -eq 0 ]; then
|
||||
if set_submodule_ignore "$repo" "$IGNORE_MODE"; then
|
||||
log_debug "Установлен ignore=$IGNORE_MODE для $repo"
|
||||
fi
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user