1
1
#! /bin/bash
2
2
3
- # Script to strip Claude co-author lines from commit messages on current branch
4
- # Usage: ./strip-claude-coauthor.sh [base_branch] [--dry-run]
3
+ # Safe script to strip Claude co-author lines ONLY from commits authored by the current user
4
+ # This version includes additional safety checks to avoid modifying others' commits
5
5
6
6
set -e
7
7
8
+ # Get current user info
9
+ USER_EMAIL=$( git config user.email)
10
+ USER_NAME=$( git config user.name)
11
+
12
+ if [ -z " $USER_EMAIL " ] || [ -z " $USER_NAME " ]; then
13
+ echo " Error: Git user.email and user.name must be configured"
14
+ exit 1
15
+ fi
16
+
17
+ echo " Current user: $USER_NAME <$USER_EMAIL >"
18
+
8
19
# Parse arguments
9
20
DRY_RUN=false
10
21
BASE_BRANCH_ARG=" "
@@ -60,11 +71,9 @@ get_pr_base_branch() {
60
71
61
72
# Determine base branch
62
73
if [ -n " $BASE_BRANCH_ARG " ]; then
63
- # Use provided base branch
64
74
BASE_BRANCH=" $BASE_BRANCH_ARG "
65
75
echo " Using provided base branch: $BASE_BRANCH "
66
76
elif PR_BASE=$( get_pr_base_branch " $CURRENT_BRANCH " ) ; then
67
- # Use base branch from PR
68
77
BASE_BRANCH=" $PR_BASE "
69
78
echo " Detected PR base branch: $BASE_BRANCH "
70
79
else
90
99
echo " Merge base: $MERGE_BASE "
91
100
echo " Base branch: $BASE_BRANCH "
92
101
93
- # Get current user's email for filtering
94
- CURRENT_USER_EMAIL=$( git config user.email)
95
- if [ -z " $CURRENT_USER_EMAIL " ]; then
96
- echo " Error: Could not determine current user email from git config"
97
- exit 1
98
- fi
99
-
100
- echo " Current user email: $CURRENT_USER_EMAIL "
102
+ # Get all commits on current branch (excluding merge commits)
103
+ ALL_COMMITS=$( git rev-list --no-merges $MERGE_BASE ..$CURRENT_BRANCH )
101
104
102
- # Check if there are any commits to rewrite
103
- TOTAL_COMMIT_COUNT=$( git rev-list --count $MERGE_BASE ..$CURRENT_BRANCH )
104
- USER_COMMIT_COUNT=$( git rev-list --count --author=" $CURRENT_USER_EMAIL " --no-merges $MERGE_BASE ..$CURRENT_BRANCH )
105
-
106
- if [ " $USER_COMMIT_COUNT " -eq 0 ]; then
107
- echo " No commits by you to rewrite on current branch"
105
+ if [ -z " $ALL_COMMITS " ]; then
106
+ echo " No commits to process on current branch"
108
107
exit 0
109
108
fi
110
109
111
- echo " Found $TOTAL_COMMIT_COUNT total commits on branch, $USER_COMMIT_COUNT are yours"
110
+ TOTAL_COMMITS=$( echo " $ALL_COMMITS " | wc -l)
111
+ echo " Found $TOTAL_COMMITS total non-merge commits on branch"
112
112
113
- # Show detailed commit information for current user only
113
+ # Filter to only YOUR commits
114
114
echo " "
115
- echo " === YOUR COMMITS TO BE MODIFIED ==="
116
- git log --oneline --no-merges --author=" $CURRENT_USER_EMAIL " $MERGE_BASE ..$CURRENT_BRANCH
115
+ echo " === FILTERING TO YOUR COMMITS ONLY ==="
116
+ YOUR_COMMITS=" "
117
+ YOUR_COMMIT_COUNT=0
118
+
119
+ while IFS= read -r commit_hash; do
120
+ if [ -z " $commit_hash " ]; then continue ; fi
121
+
122
+ # Get commit author email and name
123
+ commit_author_email=$( git log --format=" %ae" -n 1 " $commit_hash " )
124
+ commit_author_name=$( git log --format=" %an" -n 1 " $commit_hash " )
125
+
126
+ # Only include commits authored by current user
127
+ if [ " $commit_author_email " = " $USER_EMAIL " ] && [ " $commit_author_name " = " $USER_NAME " ]; then
128
+ YOUR_COMMITS=" $YOUR_COMMITS$commit_hash " $' \n '
129
+ YOUR_COMMIT_COUNT=$(( YOUR_COMMIT_COUNT + 1 ))
130
+ echo " ✓ $commit_hash $( git log --format=%s -n 1 " $commit_hash " ) "
131
+ else
132
+ echo " ✗ $commit_hash $( git log --format=%s -n 1 " $commit_hash " ) [Author: $commit_author_name <$commit_author_email >] - SKIPPED"
133
+ fi
134
+ done <<< " $ALL_COMMITS"
117
135
118
- # Check which of YOUR commits actually contain Claude co-author lines
136
+ if [ $YOUR_COMMIT_COUNT -eq 0 ]; then
137
+ echo " No commits authored by you found on this branch"
138
+ exit 0
139
+ fi
140
+
141
+ # Check which of YOUR commits contain Claude co-author lines
119
142
echo " "
120
143
echo " === YOUR COMMITS WITH CLAUDE CO-AUTHOR LINES ==="
121
- CLAUDE_COMMITS=0
144
+ CLAUDE_COMMITS=" "
145
+ CLAUDE_COMMIT_COUNT=0
146
+
122
147
while IFS= read -r commit_hash; do
123
- # Only process commits authored by current user
124
- commit_author_email=$( git log --format=%ae -n 1 " $commit_hash " )
125
- if [ " $commit_author_email " = " $CURRENT_USER_EMAIL " ]; then
126
- commit_msg=$( git log --format=%B -n 1 " $commit_hash " )
127
- if echo " $commit_msg " | grep -q -E " (🤖 Generated with \[Claude Code\]|Co-Authored-By: Claude|Co-authored-by: Claude)" ; then
128
- echo " $commit_hash $( git log --format=%s -n 1 " $commit_hash " ) "
129
- CLAUDE_COMMITS=$(( CLAUDE_COMMITS + 1 ))
130
- fi
148
+ if [ -z " $commit_hash " ]; then continue ; fi
149
+
150
+ commit_msg=$( git log --format=%B -n 1 " $commit_hash " )
151
+ if echo " $commit_msg " | grep -q -E " (🤖 Generated with \\ [Claude Code\\ ]|Co-Authored-By: Claude|Co-authored-by: Claude)" ; then
152
+ CLAUDE_COMMITS=" $CLAUDE_COMMITS$commit_hash " $' \n '
153
+ CLAUDE_COMMIT_COUNT=$(( CLAUDE_COMMIT_COUNT + 1 ))
154
+ echo " 📝 $commit_hash $( git log --format=%s -n 1 " $commit_hash " ) "
131
155
fi
132
- done < <( git rev-list --no-merges $MERGE_BASE .. $CURRENT_BRANCH )
156
+ done <<< " $YOUR_COMMITS "
133
157
134
158
echo " "
135
- echo " === SUMMARY ==="
159
+ echo " === SAFETY SUMMARY ==="
160
+ echo " Current user: $USER_NAME <$USER_EMAIL >"
136
161
echo " Current branch: $CURRENT_BRANCH "
137
162
echo " Base branch: $BASE_BRANCH "
138
- echo " Merge base: $MERGE_BASE "
139
- echo " Total commits on branch: $TOTAL_COMMIT_COUNT "
140
- echo " Your commits on branch: $USER_COMMIT_COUNT "
141
- echo " Your commits with Claude co-author lines: $CLAUDE_COMMITS "
163
+ echo " Total commits on branch: $TOTAL_COMMITS "
164
+ echo " YOUR commits on branch: $YOUR_COMMIT_COUNT "
165
+ echo " YOUR commits with Claude co-author: $CLAUDE_COMMIT_COUNT "
166
+ echo " Other authors' commits: $(( TOTAL_COMMITS - YOUR_COMMIT_COUNT)) (will be PRESERVED)"
167
+
168
+ if [ $CLAUDE_COMMIT_COUNT -eq 0 ]; then
169
+ echo " No commits authored by you contain Claude co-author lines"
170
+ exit 0
171
+ fi
142
172
143
173
if [ " $DRY_RUN " = true ]; then
144
174
echo " "
@@ -147,6 +177,16 @@ if [ "$DRY_RUN" = true ]; then
147
177
exit 0
148
178
fi
149
179
180
+ echo " "
181
+ echo " ⚠️ WARNING: This will rewrite git history for commits authored by you only"
182
+ echo " Other authors' commits will be preserved unchanged"
183
+ read -p " Are you sure you want to proceed? (y/N): " -n 1 -r
184
+ echo
185
+ if [[ ! " $REPLY " =~ ^[Yy]$ ]]; then
186
+ echo " Aborted"
187
+ exit 1
188
+ fi
189
+
150
190
# Check for unstaged changes
151
191
if ! git diff-index --quiet HEAD --; then
152
192
echo " Stashing unstaged changes..."
@@ -162,27 +202,36 @@ if git show-ref --verify --quiet refs/original/refs/heads/$CURRENT_BRANCH; then
162
202
git update-ref -d refs/original/refs/heads/$CURRENT_BRANCH
163
203
fi
164
204
165
- # Run filter-branch to strip Claude co-author lines from YOUR commits only
166
- echo " Rewriting commit messages for your commits only..."
167
- FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --msg-filter '
168
- # Get the commit author email
169
- COMMIT_AUTHOR=$(git log --format="%ae" -n 1 $GIT_COMMIT)
205
+ # Create a safer filter that only modifies commits by the current user
206
+ echo " Rewriting commit messages for YOUR commits only..."
207
+ FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --msg-filter "
208
+ # Get current commit hash from environment
209
+ commit_author_email=\$ (git log --format='%ae' -n 1 \$ GIT_COMMIT 2>/dev/null || echo '')
210
+ commit_author_name=\$ (git log --format='%an' -n 1 \$ GIT_COMMIT 2>/dev/null || echo '')
170
211
171
- # Only modify commits by the current user
172
- if [ "$COMMIT_AUTHOR" = "' " $CURRENT_USER_EMAIL " ' " ]; then
173
- sed "/🤖 Generated with \\[Claude Code\\]/d; /Co-Authored-By: Claude/d; /Co-authored-by: Claude/d"
212
+ # Only modify commits by current user
213
+ if [ \"\$ commit_author_email\" = \" $USER_EMAIL \" ] && [ \"\$ commit_author_name\" = \" $USER_NAME \" ]; then
214
+ # Strip Claude co-author lines for current user's commits
215
+ sed '/🤖 Generated with \\\\ [Claude Code\\\\ ]/d; /Co-Authored-By: Claude/d; /Co-authored-by: Claude/d'
174
216
else
175
- # Pass through other commits unchanged
217
+ # Preserve other authors' commit messages unchanged
176
218
cat
177
219
fi
178
- ' $MERGE_BASE ..$CURRENT_BRANCH
220
+ " $MERGE_BASE ..$CURRENT_BRANCH
179
221
180
- echo " Successfully stripped Claude co-author lines from your commits only"
222
+ echo " Successfully processed $YOUR_COMMIT_COUNT of your commits (out of $TOTAL_COMMITS total)"
223
+ echo " Stripped Claude co-author lines from $CLAUDE_COMMIT_COUNT commits"
181
224
182
225
# Restore stashed changes if any
183
226
if [ " $STASHED " = true ]; then
184
227
echo " Restoring stashed changes..."
185
228
git stash pop
186
229
fi
187
230
188
- echo " Done! Use 'git push --force-with-lease origin $CURRENT_BRANCH ' to update remote"
231
+ echo " "
232
+ echo " ✅ Done! Git history rewritten safely:"
233
+ echo " - Only YOUR commits were modified"
234
+ echo " - Other authors' commits were preserved unchanged"
235
+ echo " - Merge commits were not touched"
236
+ echo " "
237
+ echo " Use 'git push --force-with-lease origin $CURRENT_BRANCH ' to update remote"
0 commit comments