#!/usr/bin/env zsh # this is a git merge driver that magically fixes conflicts in the ChangeLog # file (for simple additions at least). useful for back-porting # # to use, add this to your .git/config: # # [merge "zsh-merge-changelog"] # name = merge the zsh changelog somewhat reasonably # driver = Util/zsh-merge-changelog %O %A %B %L %P # # and add this to your .git/info/attributes: # # /ChangeLog merge=zsh-merge-changelog # # note: currently the ChangeLog is still updated even when the rest of the merge # would be a no-op # # original script written by Mikachu emulate -L zsh -o extended_glob -o warn_create_global eputs() { [[ $1 == (-|--) ]] && shift print -rlu2 - "${ZSH_ARGZERO:t}: $1" "${@[2,-1]}" } main() { local tmp=${TMPDIR:-/tmp}/${ZSH_ARGZERO:t}.$$.$RANDOM local diff line ctx_after header data datb idx color local -a out orig diff=$( git diff --no-index -U200 -- $1 $3 ) for line in ${${(f)diff}[5,-1]}; do case $line in @@*) ;; ' '*) (( $#out )) && ctx_after=1 # commit header from context (entry added under existing header) (( ! $#out )) && [[ $line == ' '<->-<->-<->* ]] && header=$line[2,-1] ;; +*) (( ctx_after )) && { eputs 'unable to handle non-consecutive addition' return 1 } [[ -n $header ]] && { out+=( $header '' ) header= } out+=( "$line[2,-1]" ) ;; -*) eputs 'unable to handle deletion' return 1 ;; *) eputs 'unexpected line in diff:' $line return 1 ;; esac done (( $#out )) || { eputs 'no changed lines found' return 1 } [[ $out[1] == <->-<->-<->* && $out[2] == '' ]] || { eputs 'commit header not found' return 1 } trap "rm -f -- ${(q+)tmp}" EXIT HUP INT orig=( "${(@f)"$( < $2 )"}" ) data=${(M)orig[1]##<->-<->-<->} [[ -n $data ]] || { eputs 'failed to get latest date in original change log' return 1 } datb=${(M)out[1]##<->-<->-<->} # new entry later than last -- just prepend if [[ $datb > $data ]]; then print -rl - "${(@)out}" "${(@)orig}" > $tmp || return # header already present in file -- re-use it. this always inserts above the # existing entries, so it might not be the same order it was in originally. # but it's fine elif [[ -n ${(M)orig:#$out[1]} ]]; then idx=$orig[(ie)$out[1]] print -rl - \ "${(@)orig[1,idx]}" \ "${(@)out[2,-1]}" \ "${(@)orig[idx+2,-1]}" \ > $tmp || return # insert in the middle somewhere else for (( idx = 1; idx <= $#orig; idx++ )); do data=${(M)orig[idx]##<->-<->-<->} [[ -n $data && $datb > $data ]] || continue print -rl - \ "${(@)orig[1,idx-1]}" \ "${(@)out}" \ "${(@)orig[idx,-1]}" \ > $tmp || return break done fi [[ -t 2 ]] && color=--color=always out=( "${(@f)"$( git diff --no-index $color -U4 -- $2 $tmp )"}" ) out=( "${(@)out[3,-1]}" ) out[1]=${out[1]/a\/[^[:cntrl:]]##/a/$5} out[2]=${out[2]/b\/[^[:cntrl:]]##/b/$5} eputs 'fixed ChangeLog entry:' "${(F)out}" [[ -n $ZMC_FAIL ]] && return 1 # for testing cp -- $tmp $2 } main "$@"