1414# License for the specific language governing permissions and limitations
1515# under the License.
1616
17- # This hook preserves Change-Id during amend operations where the message
18- # is provided via -m or -F flags (which would otherwise lose the Change-Id).
17+ # This hook preserves Change-Id and Claude-Session-Id during amend operations
18+ # where the message is provided via -m or -F flags (which would otherwise lose
19+ # these trailers).
1920#
2021# Arguments:
2122# $1 - Path to the commit message file
@@ -30,9 +31,9 @@ MSG_FILE="$1"
3031SOURCE=" ${2:- } "
3132
3233# If source is "commit" (from --amend or -c/-C), git already preserves the
33- # original message content including Change-Id , so we don't need to do anything.
34+ # original message content including trailers , so we don't need to do anything.
3435# This hook is specifically for the case where -m or -F is used with --amend,
35- # which sets source to "message" and loses the original Change-Id .
36+ # which sets source to "message" and loses the original trailers .
3637
3738# Only act if we have a message file
3839if test ! -f " $MSG_FILE " ; then
@@ -44,44 +45,74 @@ if ! git rev-parse --verify HEAD >/dev/null 2>&1; then
4445 exit 0
4546fi
4647
47- # Check if the current message already has a Change-Id
48- if grep -q " ^Change-Id: I[0-9a-f]\{40\}$" " $MSG_FILE " ; then
48+ # Function to detect if this is an amend operation with -m flag
49+ is_amend_with_m_flag () {
50+ # Heuristic to detect amend: During --amend, git sets GIT_AUTHOR_DATE to preserve
51+ # the original author date. This date should exactly match HEAD's author date.
52+ # For a regular commit, GIT_AUTHOR_DATE is not set by git.
53+ # We also check that source is "message" (set by git for both -m and -F flags).
54+ if test " $SOURCE " ! = " message" || test -z " $GIT_AUTHOR_DATE " ; then
55+ return 1
56+ fi
57+
58+ # Get HEAD's author date in the same format git uses internally (raw format)
59+ # The raw format is: seconds-since-epoch timezone (e.g., "1234567890 +0000")
60+ HEAD_AUTHOR_DATE_RAW=$( git log -1 --format=%ad --date=raw HEAD 2> /dev/null)
61+ if test -z " $HEAD_AUTHOR_DATE_RAW " ; then
62+ return 1
63+ fi
64+
65+ # Extract epoch from GIT_AUTHOR_DATE (handles various formats)
66+ # During amend, GIT_AUTHOR_DATE is in format: "@epoch tz" (e.g., "@1234567890 +0000")
67+ # Remove the @ prefix if present
68+ GIT_AUTHOR_EPOCH=$( echo " $GIT_AUTHOR_DATE " | cut -d' ' -f1 | tr -d ' @' )
69+ HEAD_AUTHOR_EPOCH=$( echo " $HEAD_AUTHOR_DATE_RAW " | cut -d' ' -f1)
70+
71+ # If the epoch timestamps match, this is likely an amend operation.
72+ # Additional check: the author date should be at least 2 seconds in the past.
73+ # This prevents false positives when commits happen in quick succession
74+ # (e.g., in automated tests or scripts) where timestamps might match by coincidence.
75+ if test " $GIT_AUTHOR_EPOCH " ! = " $HEAD_AUTHOR_EPOCH " ; then
76+ return 1
77+ fi
78+
79+ CURRENT_EPOCH=$( date +%s)
80+ AGE=$(( CURRENT_EPOCH - GIT_AUTHOR_EPOCH))
81+ if test " $AGE " -lt 2; then
82+ return 1
83+ fi
84+
85+ return 0
86+ }
87+
88+ # Only proceed if this is an amend with -m flag
89+ if ! is_amend_with_m_flag; then
4990 exit 0
5091fi
5192
52- # Get Change-Id from HEAD if it exists
53- HEAD_CHANGEID=$( git log -1 --format=%B HEAD 2> /dev/null | grep " ^Change-Id: I[0-9a-f]\{40\}$" | tail -1)
54- if test -z " $HEAD_CHANGEID " ; then
55- exit 0
93+ # Track if we need to add a blank line before trailers
94+ NEED_BLANK_LINE=false
95+
96+ # Preserve Change-Id if missing from current message but present in HEAD
97+ if ! grep -q " ^Change-Id: I[0-9a-f]\{40\}$" " $MSG_FILE " ; then
98+ HEAD_CHANGEID=$( git log -1 --format=%B HEAD 2> /dev/null | grep " ^Change-Id: I[0-9a-f]\{40\}$" | tail -1)
99+ if test -n " $HEAD_CHANGEID " ; then
100+ if test " $NEED_BLANK_LINE " = " false" ; then
101+ echo " " >> " $MSG_FILE "
102+ NEED_BLANK_LINE=true
103+ fi
104+ echo " $HEAD_CHANGEID " >> " $MSG_FILE "
105+ fi
56106fi
57107
58- # Heuristic to detect amend: During --amend, git sets GIT_AUTHOR_DATE to preserve
59- # the original author date. This date should exactly match HEAD's author date.
60- # For a regular commit, GIT_AUTHOR_DATE is not set by git.
61- # We also check that source is "message" (set by git for both -m and -F flags).
62- if test " $SOURCE " = " message" && test -n " $GIT_AUTHOR_DATE " ; then
63- # Get HEAD's author date in the same format git uses internally (raw format)
64- # The raw format is: seconds-since-epoch timezone (e.g., "1234567890 +0000")
65- HEAD_AUTHOR_DATE_RAW=$( git log -1 --format=%ad --date=raw HEAD 2> /dev/null)
66- if test -n " $HEAD_AUTHOR_DATE_RAW " ; then
67- # Extract epoch from GIT_AUTHOR_DATE (handles various formats)
68- # During amend, GIT_AUTHOR_DATE is in format: "@epoch tz" (e.g., "@1234567890 +0000")
69- # Remove the @ prefix if present
70- GIT_AUTHOR_EPOCH=$( echo " $GIT_AUTHOR_DATE " | cut -d' ' -f1 | tr -d ' @' )
71- HEAD_AUTHOR_EPOCH=$( echo " $HEAD_AUTHOR_DATE_RAW " | cut -d' ' -f1)
72-
73- # If the epoch timestamps match, this is likely an amend operation.
74- # Additional check: the author date should be at least 2 seconds in the past.
75- # This prevents false positives when commits happen in quick succession
76- # (e.g., in automated tests or scripts) where timestamps might match by coincidence.
77- if test " $GIT_AUTHOR_EPOCH " = " $HEAD_AUTHOR_EPOCH " ; then
78- CURRENT_EPOCH=$( date +%s)
79- AGE=$(( CURRENT_EPOCH - GIT_AUTHOR_EPOCH))
80- if test " $AGE " -ge 2; then
81- # This looks like an amend with -m flag - preserve the Change-Id
82- echo " " >> " $MSG_FILE "
83- echo " $HEAD_CHANGEID " >> " $MSG_FILE "
84- fi
108+ # Preserve Claude-Session-Id if missing from current message but present in HEAD
109+ if ! grep -q " ^Claude-Session-Id:" " $MSG_FILE " ; then
110+ HEAD_CLAUDE_SESSION_ID=$( git log -1 --format=%B HEAD 2> /dev/null | grep " ^Claude-Session-Id:" | tail -1)
111+ if test -n " $HEAD_CLAUDE_SESSION_ID " ; then
112+ if test " $NEED_BLANK_LINE " = " false" ; then
113+ echo " " >> " $MSG_FILE "
114+ NEED_BLANK_LINE=true
85115 fi
116+ echo " $HEAD_CLAUDE_SESSION_ID " >> " $MSG_FILE "
86117 fi
87118fi
0 commit comments