mirror of
https://github.com/imjasonh/cnotes
synced 2026-07-20 04:58:10 +00:00
Add git notes preservation system with backup/restore functionality
- Added WarnAboutGitNotesLoss hook that warns before destructive git operations - Implemented comprehensive backup/restore system for conversation notes - Added CLI commands: hooks notes backup/restore/list - Configured git to automatically copy notes during rebase operations - Created backup.go with full notes backup and restoration functionality This ensures conversation context is never lost during rebasing, squashing, or other destructive git operations.
This commit is contained in:
parent
d6f6fc5ffe
commit
7b6cdffa8a
4 changed files with 402 additions and 0 deletions
65
internal/handlers/gitrebase.go
Normal file
65
internal/handlers/gitrebase.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/imjasonh/hooks/internal/hooks"
|
||||
)
|
||||
|
||||
func init() {
|
||||
hooks.RegisterHook(hooks.EventPreToolUse, "Bash", WarnAboutGitNotesLoss)
|
||||
}
|
||||
|
||||
// WarnAboutGitNotesLoss warns users about potential git notes loss during destructive operations
|
||||
func WarnAboutGitNotesLoss(ctx context.Context, input hooks.HookInput) (hooks.HookOutput, error) {
|
||||
bashInput, err := input.GetBashInput()
|
||||
if err != nil {
|
||||
return hooks.HookOutput{Decision: "approve"}, nil
|
||||
}
|
||||
|
||||
command := strings.TrimSpace(bashInput.Command)
|
||||
|
||||
// Check for destructive git operations that might lose notes
|
||||
destructiveOperations := []struct {
|
||||
pattern string
|
||||
warning string
|
||||
}{
|
||||
{
|
||||
pattern: "git rebase",
|
||||
warning: "⚠️ Git rebase can lose conversation notes attached to commits. Consider:\n" +
|
||||
" • Run 'git notes --ref=claude-conversations list' to see which commits have notes\n" +
|
||||
" • Use 'git -c notes.rewrite.mode=copy rebase' to preserve notes\n" +
|
||||
" • Or manually backup notes before rebasing with 'git notes --ref=claude-conversations show <commit>'",
|
||||
},
|
||||
{
|
||||
pattern: "git reset --hard",
|
||||
warning: "⚠️ Hard reset will lose commits and their conversation notes permanently.\n" +
|
||||
" • Consider using 'git reset --soft' or 'git reset --mixed' instead\n" +
|
||||
" • Backup important notes first with 'git notes --ref=claude-conversations show <commit>'",
|
||||
},
|
||||
{
|
||||
pattern: "git commit --amend",
|
||||
warning: "⚠️ Amending commits changes their hash and may lose conversation notes.\n" +
|
||||
" • Notes are attached to the original commit hash\n" +
|
||||
" • Consider creating a new commit instead of amending",
|
||||
},
|
||||
}
|
||||
|
||||
for _, op := range destructiveOperations {
|
||||
if strings.Contains(command, op.pattern) {
|
||||
slog.Info("warning user about potential git notes loss",
|
||||
"command", command,
|
||||
"operation", op.pattern)
|
||||
|
||||
return hooks.HookOutput{
|
||||
Decision: "approve", // Don't block, just warn
|
||||
AdditionalContext: fmt.Sprintf("\n%s\n\nDo you want to proceed with this operation?", op.warning),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return hooks.HookOutput{Decision: "approve"}, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue