* For all you darcs lovers: git-hunk-commit
@ 2006-12-05 18:48 Johannes Schindelin
2006-12-06 0:19 ` Han-Wen Nienhuys
0 siblings, 1 reply; 5+ messages in thread
From: Johannes Schindelin @ 2006-12-05 18:48 UTC (permalink / raw)
To: git; +Cc: Han-Wen Nienhuys
[-- Attachment #1: Type: TEXT/PLAIN, Size: 926 bytes --]
Hi,
I was inspired by Han-Wen. This script allows you to commit selected hunks
from the current modifications.
It has two modes: darcs mode (--darcs) and normal mode (without
arguments).
In darcs mode, all hunks are presented one by one, and you are asked if
you want to commit this or not. If you make a mistake: ^C and back to
start. I do not really know darcs, so this might not be how it works -- I
did not find any good documentation how a "darcs record" looks like.
Normal mode shows you the list of modified files, and lets you choose one.
Then it shows you how many hunks there are, and lets you pick one for
inspection, after which you are asked if you want it or not.
Normal mode is chattier, but if you know which (of those thousands) hunk
you want to commit, it is faster. Besides, it was easier to debug.
Note that this script uses no temporary files, but rather bash array
variables.
Ciao,
Dscho
[-- Attachment #2: Type: TEXT/PLAIN, Size: 5604 bytes --]
#!/bin/bash
# Copyright (C) 2006 Johannes E. Schindelin
# Distributed under the same license as git.
# Use this command to commit just a few hunks of the current output
# of "git diff". For your security, it only works when the index matches
# HEAD.
# ensure that this is a git repository
. git-sh-setup
# the index must match the HEAD
if [ -n "$(git diff --index --name-only HEAD)" ]; then
echo "The staging area (AKA index) is already dirty."
exit 1
fi
# read the names of all modified files into the array "modified"
declare -a modified
filenr=1
while read -d $'\0' file; do
modified[$filenr]="$file"
filenr=$(($filenr+1))
done < <(git ls-files --modified -z)
if [ ${#modified[*]} = 0 ]; then
echo "No modified files."
exit 1
fi
declare -a hunks
# interactively show the hunks of a file and ask if they should be committed.
# 1st parameter is the index into the modified file list.
# 2nd parameter should be "true" for darcs mode, empty otherwise.
# Darcs mode means that all hunks are presented one after another.
# Normal mode means user can specify hunks interactively.
select_hunks () {
local index=$1
local darcs_mode=$2
local filename=${modified[$index]}
local -a diff
local -a hunk_start
local current_hunks=${hunks[$index]}
local lineno
local hunkno
local action
local i
local active
lineno=1
hunkno=0
while read line; do
diff[$lineno]="$line"
case "$line" in
@@*)
hunk_start[$hunkno]=$lineno
hunkno=$(($hunkno+1))
;;
esac
lineno=$(($lineno+1))
done < <(git diff "$filename")
hunk_start[$hunkno]=$lineno
action=""
while [ "$action" != commit -a "$action" != abort ]; do
case "$darcs_mode" in
'')
echo
echo "Current hunks: ($current_hunks) of $hunkno hunks"
echo "To show (and decide on) a hunk type in the number."
echo "To commit the current hunks, say 'commit', else 'abort'."
echo
echo -n "Your choice? "
read action
;;
[1-9]*)
darcs_mode=$(($darcs_mode+1))
if [ $darcs_mode -gt $hunkno ]; then
action=commit
else
action=$darcs_mode
fi
;;
*)
darcs_mode=1
action=1
;;
esac
case "$action" in
c) action=commit;;
q|a) action=abort;;
commit|abort) ;;
[1-9]*)
echo
for ((i=${hunk_start[$(($action-1))]}; i<${hunk_start[$action]}; i++)); do
if [ -n "$darcs_mode" -a $i = ${hunk_start[0]} ]; then
echo "File: $filename"
fi
echo ${diff[$i]}
done | less -FS
active=$(echo $current_hunks,$action | tr , '\n' | sort | uniq -u | tr '\n' , | sed -e "s/^,//" -e "s/,$//")
if [ ${#active} -lt ${#current_hunks} ]; then
i=yes
else
i=no
fi
echo
while [ -n "$action" -a "$action" != yes -a "$action" != no -a -n "$action" ]; do
echo -n "Commit this hunk (default is $i)? "
read action
case "$action" in
y) action=yes;;
n) action=no;;
esac
done
if [ -n "$action" -a $i != "$action" ]; then
current_hunks=$active
fi
;;
*) echo "Unknown command: $action";;
esac
done
if [ "$action" = commit ]; then
hunks[$index]=$current_hunks
fi
}
# Apply the hunks saved in the array hunks for the specified file.
# This means that the diff is rewritten to skip the unwanted hunks.
apply_hunks () {
local index=$1
local filename=${modified[$index]}
local -a current_hunks
local lineno
local lineno2
local linediff
local hunkno
local i
local active
i=0
while read hunkno; do
current_hunks[$i]=$hunkno
i=$(($i+1))
done < <(echo ${hunks[$index]} | tr , '\n')
linediff=0
hunkno=0
i=0
active=true
while read line
do
case "$line" in
@@*)
hunkno=$(($hunkno+1))
if [ $hunkno = "${current_hunks[$i]}" ]; then
active=true
i=$(($i+1))
if [ $linediff -ne 0 ]; then
lineno=$(echo "$line" | sed "s/^.*+\([0-9]*\)[, ].*$/\1/")
lineno2=$(($lineno+$linediff))
line="$(echo "$line" | sed "s/+$lineno/+$lineno2/")"
fi
else
active=
lineno=$(echo "$line" | sed -n "s/^.*-[0-9]*,\([0-9]*\) .*$/\1/p")
if [ -z "$lineno" ]; then
lineno=1
fi
lineno2=$(echo "$line" | sed -n "s/^.*+[0-9]*,\([0-9]*\) .*$/\1/p")
if [ -z "$lineno2" ]; then
lineno2=1
fi
linediff=$(($linediff+$lineno-$lineno2))
fi
;;
esac
if [ -n "$active" ]; then
echo "$line"
fi
done < <(git diff "$filename")
}
darcs_mode=
case "$1" in
--darcs) darcs_mode=true;;
esac
IFS=''
action=
i=
while [ "$action" != commit -a "$action" != abort ]; do
case "$darcs_mode" in
'')
echo
for ((i=1; i<$filenr; i++)); do
echo -n "$i ${modified[$i]}"
if [ -n "${hunks[$i]}" ]; then
echo " (${hunks[$i]})"
else
echo
fi
done | less -FS
echo
echo "To put one or more hunks of a file into the staging area (AKA"
echo "index), type in the number of the file."
echo "To commit, say 'commit', to abort, say 'abort'."
echo
echo -n "Your choice? "
read action
;;
true)
if [ -z "$i" ]; then
i=1
else
i=$(($i+1))
fi
if [ $i -ge $filenr ]; then
action=commit
else
action=$i
fi
;;
esac
case "$action" in
c) action=commit;;
q|a) action=abort;;
commit|abort) ;;
[0-9]*) select_hunks "$action" "$darcs_mode";;
*) echo "Unknown command." ;;
esac
done
if [ "$action" = commit ]; then
for ((i=1; i<$filenr; i++)); do
if [ -n "${hunks[$i]}" ]; then
apply_hunks $i
fi
done | tee a123 | git apply --cached
git commit
fi
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: For all you darcs lovers: git-hunk-commit
2006-12-05 18:48 For all you darcs lovers: git-hunk-commit Johannes Schindelin
@ 2006-12-06 0:19 ` Han-Wen Nienhuys
2006-12-06 0:36 ` Johannes Schindelin
0 siblings, 1 reply; 5+ messages in thread
From: Han-Wen Nienhuys @ 2006-12-06 0:19 UTC (permalink / raw)
To: git
Johannes Schindelin escreveu:
> I was inspired by Han-Wen. This script allows you to commit selected hunks
Wow!
> In darcs mode, all hunks are presented one by one, and you are asked if
> you want to commit this or not. If you make a mistake: ^C and back to
> start. I do not really know darcs, so this might not be how it works -- I
> did not find any good documentation how a "darcs record" looks like.
This is the interactive interface for commits in Darcs. It uses the
same interface for pushing and pulling, where I mostly use y/n/a/d but
sometimes the other letters too.
****
Shall I record this change? (1/?) [ynWsfqadjkc], or ? for help: ?
How to use record...
y: record this patch
n: don't record it
w: wait and decide later, defaulting to no
s: don't record the rest of the changes to this file
f: record the rest of the changes to this file
d: record selected patches, skipping all the remaining patches
a: record all the remaining patches
q: cancel record
j: skip to next patch
k: back up to previous patch
c: calculate number of patches
h or ?: show this help
<Space>: accept the current default (which is capitalized)
****
If you want to get a feel for it, grab darcs and run
darcs init
echo hello > hello
darcs add
darcs record
For a really neat implementation of per-hunk commits, try running
darcsum in Emacs
> done < <(git ls-files --modified -z)
> done < <(git diff "$filename")
> done < <(echo ${hunks[$index]} | tr , '\n')
am I running the wrong bash? it barf on this. Don't you mean $(echo ... )
Frankly, I am amazed that people write things in bash at all--I vowed never
to write bash again a couple of years ago. If you start doing arrays and
counting, wouldn't a more high-level language be suitable?
--
Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: For all you darcs lovers: git-hunk-commit
2006-12-06 0:19 ` Han-Wen Nienhuys
@ 2006-12-06 0:36 ` Johannes Schindelin
2006-12-08 8:55 ` Matthias Kestenholz
0 siblings, 1 reply; 5+ messages in thread
From: Johannes Schindelin @ 2006-12-06 0:36 UTC (permalink / raw)
To: Han-Wen Nienhuys; +Cc: git
Hi,
On Wed, 6 Dec 2006, Han-Wen Nienhuys wrote:
> This is the interactive interface for commits in Darcs. It uses the
> same interface for pushing and pulling, where I mostly use y/n/a/d but
> sometimes the other letters too.
>
>
> ****
> Shall I record this change? (1/?) [ynWsfqadjkc], or ? for help: ?
> How to use record...
> y: record this patch
> n: don't record it
> w: wait and decide later, defaulting to no
>
> s: don't record the rest of the changes to this file
> f: record the rest of the changes to this file
>
> d: record selected patches, skipping all the remaining patches
> a: record all the remaining patches
> q: cancel record
>
> j: skip to next patch
> k: back up to previous patch
> c: calculate number of patches
> h or ?: show this help
>
> <Space>: accept the current default (which is capitalized)
> ****
All but "y" and "n" are unsupported in hunk-commit.bash... Do you use all
of these?
> If you want to get a feel for it, grab darcs and run
I already grabbed darcs a long time ago. And run, I did.
> > done < <(git ls-files --modified -z)
>
> > done < <(git diff "$filename")
>
> > done < <(echo ${hunks[$index]} | tr , '\n')
>
> am I running the wrong bash? it barf on this. Don't you mean $(echo ... )
I hoped that I did not use a too new bash. Unfortunately, I seem to have
been wrong. These constructs redirect the output of the command as input
to the while loop, because
bla | while ...; do blub; done
opens a subshell, so that all changes done in "blub" are lost as soon as
the while loop is finished.
> Frankly, I am amazed that people write things in bash at all--I vowed
> never to write bash again a couple of years ago. If you start doing
> arrays and counting, wouldn't a more high-level language be suitable?
Me, being one of the loudest proponents of C builtins on this list, I
agree fully.
But in this case, bash was faster to script and debug, and unless people
speak up, saying "I want that feature badly!", I do not plan to do
anything with it.
Ciao,
Dscho
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: For all you darcs lovers: git-hunk-commit
2006-12-06 0:36 ` Johannes Schindelin
@ 2006-12-08 8:55 ` Matthias Kestenholz
2006-12-08 15:37 ` Johannes Schindelin
0 siblings, 1 reply; 5+ messages in thread
From: Matthias Kestenholz @ 2006-12-08 8:55 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
Hi,
On Wed, 2006-12-06 at 01:36 +0100, Johannes Schindelin wrote:
> But in this case, bash was faster to script and debug, and unless people
> speak up, saying "I want that feature badly!", I do not plan to do
> anything with it.
This feature is _very_ handy and I think it would be great if this
became part of the default git distribution.
Thanks for writing this tool!
Matthias
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: For all you darcs lovers: git-hunk-commit
2006-12-08 8:55 ` Matthias Kestenholz
@ 2006-12-08 15:37 ` Johannes Schindelin
0 siblings, 0 replies; 5+ messages in thread
From: Johannes Schindelin @ 2006-12-08 15:37 UTC (permalink / raw)
To: Matthias Kestenholz; +Cc: git
Hi,
On Fri, 8 Dec 2006, Matthias Kestenholz wrote:
> On Wed, 2006-12-06 at 01:36 +0100, Johannes Schindelin wrote:
> > But in this case, bash was faster to script and debug, and unless people
> > speak up, saying "I want that feature badly!", I do not plan to do
> > anything with it.
>
> This feature is _very_ handy and I think it would be great if this
> became part of the default git distribution.
Note that it requires a relatively new bash version ATM, because of the
"while read line; do ...; done < <(cmd)" construct. I have another version
which substitutes a temporary file for that, but I keep thinking that a
graphical tool, such as git-gui, would be more appropriate. BTW I just did
it in bash, because I wanted to learn about these famous bash arrays.
Ciao,
Dscho
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2006-12-08 15:37 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-05 18:48 For all you darcs lovers: git-hunk-commit Johannes Schindelin
2006-12-06 0:19 ` Han-Wen Nienhuys
2006-12-06 0:36 ` Johannes Schindelin
2006-12-08 8:55 ` Matthias Kestenholz
2006-12-08 15:37 ` Johannes Schindelin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).