git-knife: GUI-редактор метаданных коммитов Git

Сравнение инструментов

Инструмент Удобный GUI Правка сообщения Переупорядочивание / squash / удаление Правка даты автора Правка даты коммитера Правка автора/email Массовая замена (regex)

git-knife

🚧 планируется

GitKraken

⚠️ только amend

⚠️

Sublime Merge

⚠️ amend

Fork

⚠️

SmartGit

⚠️

git-cola

lazygit (TUI)

◐ TUI

⚠️

git-filter-repo (CLI)

через callback

Обозначения: ✅ полноценная поддержка · ⚠️ возможно, но неудобно или ограниченно · ◐ устаревший или терминальный интерфейс · ❌ не поддерживается · 🚧 планируется.

Снимок экрана git-knife

Чистый десктопный графический интерфейс (GUI) для прямого редактирования метаданных коммитов — сообщения, даты автора, даты коммитера, имени и email автора.

Существующие GUI-клиенты (GitKraken, Sublime Merge, Fork, lazygit) хорошо справляются с переименованием и переупорядочиванием коммитов, однако считают даты коммитов практически неизменяемыми и не позволяют редактировать дату коммитера или идентификационные данные автора для произвольных коммитов. Инструменты, которые умеют переписывать эти метаданные (git-filter-repo, трюки с env при git rebase, git commit-tree), лишены графического интерфейса. git-knife закрывает этот пробел.

Инструмент не переизобретает git — он вызывает системный git CLI и пересобирает коммиты через git commit-tree, повторно используя оригинальное дерево каждого коммита, так что содержимое файлов гарантированно остаётся неизменным.

Отполированные GUI-клиенты хорошо справляются с переупорядочиванием и переименованием, но считают даты коммитов — особенно дату коммитера — практически неизменяемыми, и ни один из них не предлагает массовой замены по регулярным выражениям в данных об авторе. Инструменты, способные переписывать эти метаданные, не имеют GUI. git-knife — это пересечение двух миров: удобный GUI, редактирующий каждое поле, пакетно и безопасно.

Текущее состояние (MVP)

  • ✅ Открыть репозиторий и выбрать любую локальную ветку для просмотра и редактирования — по её ref, без переключения, так что рабочее дерево никогда не затрагивается

  • ✅ Редактирование сообщения, имени и email автора/коммитера, даты автора и даты коммитера

  • ✅ Массовый поиск и замена по текстовым полям — дословный или по регулярному выражению (удобно для исправления неверного email во всей истории)

  • ✅ Предварительный просмотр всех изменений перед применением

  • ✅ Автоматическое создание резервной ref перед каждой перезаписью и её восстановление в один клик

  • ✅ Предупреждение, если перезапись затронет уже отправленную (pushed) историю

  • ✅ Поддержка подписанных коммитов — помечает их значком, предупреждает о снятии подписей при перезаписи и может заново подписать пересобранные коммиты вашим ключом

  • ✅ Редактирование через merge-коммиты — пересобирает полный граф коммитов, сохраняя всех родителей каждого merge

  • ⛔ Пока не реализовано: переупорядочивание / squash / удаление коммитов, работа со staging, ветками и удалёнными репозиториями

Требования

  • git (2.x)

  • Node.js + pnpm (corepack enable pnpm или npm i -g pnpm)

  • Rust (stable) — установить через https://rustup.rs

  • Системные зависимости Tauri v2 для Linux: webkit2gtk-4.1, libgtk-3, libayatana-appindicator3, librsvg2 (Debian/Ubuntu: sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev)

Запуск (режим разработки)

pnpm install
pnpm tauri dev

Первая сборка cargo загружает и компилирует крейты Tauri — это займёт несколько минут.

Сборка пакета

pnpm tauri build
Примечание

Для упаковки (tauri build) нужны иконки приложения. Они уже добавлены в репозиторий в каталоге src-tauri/icons/; пересоздать их из любого квадратного PNG можно командой pnpm tauri icon path/to/icon.png. Для запуска в режиме разработки иконки не нужны.

Автоматические релизы (GitHub Actions)

Файл .github/workflows/release.yml собирает нативные установщики для macOS, Linux и Windows с помощью tauri-action и прикрепляет их к черновику GitHub Release. Чтобы выпустить релиз, достаточно запушить тег:

git tag v0.1.0
git push origin v0.1.0

Или запустить сборку вручную из вкладки Actions репозитория. Подпись кода пока не настроена, поэтому сборки для macOS и Windows не подписаны — для ранних тестировщиков это приемлемо.

Редактирование истории и отправка изменений

Редактирование коммита

  1. Откройте репозиторий (через «Обзор…» или вставив путь), затем выберите ветку из выпадающего списка — git-knife редактирует её по ref, не переключаясь на неё, так что рабочее дерево и текущий checkout остаются нетронутыми.

  2. Нажмите на любой не-merge коммит, чтобы открыть его редактор.

  3. Измените сообщение, имя/email автора или коммитера, даты. Изменённые строки подсвечиваются; поля дат сохраняют исходное смещение UTC коммита.

  4. Нажмите Review & apply, проверьте предварительный просмотр старых и новых значений и подтвердите изменения.

git-knife переписывает только вашу локальную ветку. Он не обращается к удалённому репозиторию и не делает push за вас — отправка всегда остаётся на ваше усмотрение.

Массовый поиск и замена

Нажмите Bulk find & replace над таблицей коммитов, чтобы изменить текст сразу во многих коммитах:

  • Выберите целевые поля (сообщение, имя/email автора или коммитера — в любой комбинации).

  • Введите текст в поля Find / Replace. Включите Regex для поиска по шаблону с обратными ссылками $1 или оставьте выключенным для дословного поиска. По умолчанию включён режим Case-sensitive.

  • Панель в реальном времени показывает количество совпадающих коммитов и замен. Нажмите Stage edits, чтобы превратить их в подсвеченные строки, затем используйте Review & apply как обычно.

Пример — перенести все коммиты со старого email на новый: выберите Author email + Committer email, в поле поиска введите old@example.com, в поле замены — new@example.com. Merge-коммиты также затрагиваются, а последовательные проходы применяются поверх предыдущих.

Отправка перезаписанной истории

Редактирование коммита меняет его хеш и хеши всех последующих коммитов, поэтому локальная ветка и удалённая расходятся. Обычный git push будет отклонён как non-fast-forward. Выполните push с lease (проверкой):

git push --force-with-lease origin <branch>

--force-with-lease отклоняет push, если удалённая ветка изменилась с момента последнего fetch, — это защищает от случайного затирания коммитов коллег. Предпочитайте эту опцию обычному --force, который пропускает такую проверку.

Примечание

git-knife показывает предупреждение «rewrites pushed history», если редактирование затрагивает коммиты, уже существующие в upstream. По возможности редактируйте только неотправленные коммиты — перезапись общей истории заставляет всех остальных заново синхронизироваться.

После перезаписи общей истории

У всех, кто уже получил старые коммиты, теперь расходящаяся история. Каждый из них синхронизирует локальную ветку с новым состоянием удалённой:

git fetch origin
git reset --hard origin/<branch>   # удаляет только локальные коммиты — сначала скоординируйтесь

Отмена перезаписи

  • В приложении: панель Backups восстанавливает состояние ветки до перезаписи одним нажатием.

  • Из командной строки: каждое применение сохраняет резервную ref —

git for-each-ref refs/knife-backup      # найти tip до перезаписи
git reset --hard <backup-ref-or-hash>   # вернуть ветку назад

git reflog также содержит старый tip. Если force-push уже был выполнен, восстановите ветку локально, а затем снова выполните git push --force-with-lease.

Подписанные коммиты

Перезапись коммита меняет его хеш, что делает недействительной любую GPG/SSH-подпись на нём (это вызывало обоснованную обеспокоенность на HN). git-knife обнаруживает подписанные коммиты по заголовку gpgsig в их raw-данных — независимо от верификации, так что SSH-подписи определяются даже без настроенного allowedSignersFile — и:

  • помечает их значком signed в таблице,

  • предупреждает в панели применения о том, сколько подписанных коммитов потеряют подпись,

  • предлагает переключатель re-sign, который заново подписывает пересобранные коммиты вашим настроенным ключом (user.signingkey / gpg.format). Если re-sign включён, но ключ не настроен, применение безопасно завершается с ошибкой, не затронув ни одной ref.

Примечание о сигнатуре (прозрачность)

По умолчанию git-knife прикрепляет небольшую явную заметку к каждому перезаписанному tip-коммиту в отдельной notes ref, не затрагивая обычные заметки:

git notes --ref=git-knife show <commit>   # прочитать заметку
git for-each-ref refs/notes/git-knife      # редактировался ли этот репозиторий через git-knife?

В обычном git log она невидима (отдельная ref), но полностью доступна для обнаружения — никакого скрытого кодирования. Отключить её можно в любой момент через флажок 🔪 signature note в приложении (настройка сохраняется). Чтобы полностью удалить заметки из репозитория:

git update-ref -d refs/notes/git-knife

Как это работает

  • src-tauri/src/git.rs — единственное место, где запускается git.

  • commits.rsopen_repo, list_commits (разбор с разделителями NUL/record-separator).

  • rewrite.rspreview_edits + apply_edits: пересобирает цепочку от самого раннего изменённого коммита до tip через commit-tree, затем сохраняет резервную ref и перемещает ветку с compare-and-swap по старому tip.

  • backup.rs — выводит список refs/knife-backup/* и восстанавливает через git reset --hard.

Стратегия перезаписи проверяется на уровне git скриптом scratchpad/verify_engine.sh (воспроизводит точный процесс commit-tree и убеждается, что diff содержимого пуст).

Безопасность

Каждое применение создаёт refs/knife-backup/<branch>/<epoch>, указывающую на старый tip, прежде чем что-либо изменить. Ничто не удаляется принудительно; восстановление всегда доступно из панели Backups.

© 2026 meganuke