3 # Copyright (C) 2006 Johannes E. Schindelin
4 # Distributed under the same license as git.
6 # Use this command to commit just a few hunks of the current output
7 # of "git diff". For your security, it only works when the index matches
10 # ensure that this is a git repository
11 .
"$(git --exec-path)"/git-sh-setup
13 TMP_FILE
=$GIT_DIR/tmp.$$.txt
15 trap "rm -f $TMP_FILE; exit" 0 1 2 3 15
17 # the index must match the HEAD
18 if [ -n "$(git diff --cached --name-only HEAD)" ]; then
19 echo "The staging area (AKA index) is already dirty."
23 # read the names of all modified files into the array "modified"
27 git ls-files
--modified -z > $TMP_FILE
28 while read -d $
'\0' file; do
29 modified
[$filenr]="$file"
33 if [ ${#modified[*]} = 0 ]; then
34 echo "No modified files."
40 # interactively show the hunks of a file and ask if they should be committed.
41 # 1st parameter is the index into the modified file list.
42 # 2nd parameter should be "true" for darcs mode, empty otherwise.
43 # Darcs mode means that all hunks are presented one after another.
44 # Normal mode means user can specify hunks interactively.
49 local filename
=${modified[$index]}
52 local current_hunks
=${hunks[$index]}
61 git
diff "$filename" > $TMP_FILE
66 hunk_start
[$hunkno]=$lineno
73 hunk_start
[$hunkno]=$lineno
76 while [ "$action" != commit
-a "$action" != abort
]; do
80 echo "Current hunks: ($current_hunks) of $hunkno hunks"
81 echo "To show (and decide on) a hunk type in the number."
82 echo "To commit the current hunks, say 'commit', else 'abort'."
84 echo -n "Your choice? "
88 darcs_mode
=$
(($darcs_mode+1))
89 if [ $darcs_mode -gt $hunkno ]; then
106 for ((i
=${hunk_start[$(($action-1))]}; i
<${hunk_start[$action]}; i
++)); do
107 if [ -n "$darcs_mode" -a $i = ${hunk_start[0]} ]; then
108 echo "File: $filename"
112 active
=$
(echo $current_hunks,$action |
tr , '\n' |
sort |
uniq -u |
tr '\n' , |
sed -e "s/^,//" -e "s/,$//")
113 if [ ${#active} -lt ${#current_hunks} ]; then
119 while [ -n "$action" -a "$action" != yes -a "$action" != no
-a -n "$action" ]; do
120 echo -n "Commit this hunk (default is $i)? "
127 if [ -n "$action" -a $i != "$action" ]; then
128 current_hunks
=$active
131 *) echo "Unknown command: $action";;
135 if [ "$action" = commit
]; then
136 hunks
[$index]=$current_hunks
140 # Apply the hunks saved in the array hunks for the specified file.
141 # This means that the diff is rewritten to skip the unwanted hunks.
145 local filename
=${modified[$index]}
146 local -a current_hunks
155 echo ${hunks[$index]} |
tr , '\n' > $TMP_FILE
156 while read hunkno
; do
157 current_hunks
[$i]=$hunkno
165 git
diff "$filename" > $TMP_FILE
170 hunkno
=$
(($hunkno+1))
171 if [ $hunkno = "${current_hunks[$i]}" ]; then
174 if [ $linediff -ne 0 ]; then
175 lineno
=$
(echo "$line" |
sed "s/^.*+\([0-9]*\)[, ].*$/\1/")
176 lineno2
=$
(($lineno+$linediff))
177 line
="$(echo "$line" | sed "s
/+$lineno/+$lineno2/")"
181 lineno
=$
(echo "$line" |
sed -n "s/^.*-[0-9]*,\([0-9]*\) .*$/\1/p")
182 if [ -z "$lineno" ]; then
185 lineno2
=$
(echo "$line" |
sed -n "s/^.*+[0-9]*,\([0-9]*\) .*$/\1/p")
186 if [ -z "$lineno2" ]; then
189 linediff
=$
(($linediff+$lineno-$lineno2))
193 if [ -n "$active" ]; then
201 --darcs) darcs_mode
=true
;;
207 while [ "$action" != commit
-a "$action" != abort
]; do
208 case "$darcs_mode" in
211 for ((i
=1; i
<$filenr; i
++)); do
212 echo -n "$i ${modified[$i]}"
213 if [ -n "${hunks[$i]}" ]; then
214 echo " (${hunks[$i]})"
220 echo "To put one or more hunks of a file into the staging area (AKA"
221 echo "index), type in the number of the file."
222 echo "To commit, say 'commit', to abort, say 'abort'."
224 echo -n "Your choice? "
233 if [ $i -ge $filenr ]; then
244 [0-9]*) select_hunks
"$action" "$darcs_mode";;
245 *) echo "Unknown command." ;;
249 if [ "$action" = commit
]; then
250 for ((i
=1; i
<$filenr; i
++)); do
251 if [ -n "${hunks[$i]}" ]; then
254 done |
tee a123 | git apply
--cached ||
exit