{"thread":{"id":"43327","subject":"Re: For all you darcs lovers: git-hunk-commit","startedAt":"2006-12-05T18:48:49Z","lastAt":"2006-12-08T15:37:30Z","messageCount":5,"participants":["Han-Wen Nienhuys","Johannes Schindelin","Matthias Kestenholz"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"298584","messageId":"Pine.LNX.4.63.0612051936480.28348@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"43327","inReplyTo":null,"subject":"For all you darcs lovers: git-hunk-commit","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-12-05T18:48:49Z","receivedAt":"2006-12-05T18:48:49Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nI was inspired by Han-Wen. This script allows you to commit selected hunks \nfrom the current modifications.\n\nIt has two modes: darcs mode (--darcs) and normal mode (without \narguments).\n\nIn darcs mode, all hunks are presented one by one, and you are asked if \nyou want to commit this or not. If you make a mistake: ^C and back to \nstart. I do not really know darcs, so this might not be how it works -- I \ndid not find any good documentation how a \"darcs record\" looks like.\n\nNormal mode shows you the list of modified files, and lets you choose one. \nThen it shows you how many hunks there are, and lets you pick one for \ninspection, after which you are asked if you want it or not.\n\nNormal mode is chattier, but if you know which (of those thousands) hunk \nyou want to commit, it is faster. Besides, it was easier to debug.\n\nNote that this script uses no temporary files, but rather bash array \nvariables.\n\nCiao,\nDscho\n\n\n#!/bin/bash\n\n# Copyright (C) 2006 Johannes E. Schindelin\n# Distributed under the same license as git.\n\n# Use this command to commit just a few hunks of the current output\n# of \"git diff\". For your security, it only works when the index matches\n# HEAD.\n\n# ensure that this is a git repository\n. git-sh-setup\n\n# the index must match the HEAD\nif [ -n \"$(git diff --index --name-only HEAD)\" ]; then\n\techo \"The staging area (AKA index) is already dirty.\"\n\texit 1\nfi\n\n# read the names of all modified files into the array \"modified\"\n\ndeclare -a modified\nfilenr=1\nwhile read -d $'\\0' file; do\n\tmodified[$filenr]=\"$file\"\n\tfilenr=$(($filenr+1))\ndone < <(git ls-files --modified -z)\n\nif [ ${#modified[*]} = 0 ]; then\n\techo \"No modified files.\"\n\texit 1\nfi\n\ndeclare -a hunks\n\n# interactively show the hunks of a file and ask if they should be committed.\n# 1st parameter is the index into the modified file list.\n# 2nd parameter should be \"true\" for darcs mode, empty otherwise.\n#\tDarcs mode means that all hunks are presented one after another.\n#\tNormal mode means user can specify hunks interactively.\n\nselect_hunks () {\n\tlocal index=$1\n\tlocal darcs_mode=$2\n\tlocal filename=${modified[$index]}\n\tlocal -a diff\n\tlocal -a hunk_start\n\tlocal current_hunks=${hunks[$index]}\n\tlocal lineno\n\tlocal hunkno\n\tlocal action\n\tlocal i\n\tlocal active\n\n\tlineno=1\n\thunkno=0\n\twhile read line; do\n\t\tdiff[$lineno]=\"$line\"\n\t\tcase \"$line\" in\n\t\t@@*)\n\t\t\thunk_start[$hunkno]=$lineno\n\t\t\thunkno=$(($hunkno+1))\n\t\t\t;;\n\t\tesac\n\t\tlineno=$(($lineno+1))\n\tdone < <(git diff \"$filename\")\n\n\thunk_start[$hunkno]=$lineno\n\n\taction=\"\"\n\twhile [ \"$action\" != commit -a \"$action\" != abort ]; do\n\t\tcase \"$darcs_mode\" in\n\t\t'')\n\t\t\techo\n\t\t\techo \"Current hunks: ($current_hunks) of $hunkno hunks\"\n\t\t\techo \"To show (and decide on) a hunk type in the number.\"\n\t\t\techo \"To commit the current hunks, say 'commit', else 'abort'.\"\n\t\t\techo\n\t\t\techo -n \"Your choice? \"\n\t\t\tread action\n\t\t\t;;\n\t\t[1-9]*)\n\t\t\tdarcs_mode=$(($darcs_mode+1))\n\t\t\tif [ $darcs_mode -gt $hunkno ]; then\n\t\t\t\taction=commit\n\t\t\telse\n\t\t\t\taction=$darcs_mode\n\t\t\tfi\n\t\t\t;;\n\t\t*)\n\t\t\tdarcs_mode=1\n\t\t\taction=1\n\t\t\t;;\n\t\tesac\n\t\tcase \"$action\" in\n\t\tc) action=commit;;\n\t\tq|a) action=abort;;\n\t\tcommit|abort) ;;\n\t\t[1-9]*)\n\t\t\techo\n\t\t\tfor ((i=${hunk_start[$(($action-1))]}; i<${hunk_start[$action]}; i++)); do\n\t\t\t\tif [ -n \"$darcs_mode\" -a $i = ${hunk_start[0]} ]; then\n\t\t\t\t\techo \"File: $filename\"\n\t\t\t\tfi\n\t\t\t\techo ${diff[$i]}\n\t\t\tdone | less -FS\n\t\t\tactive=$(echo $current_hunks,$action | tr , '\\n' | sort | uniq -u | tr '\\n' , | sed -e \"s/^,//\" -e \"s/,$//\")\n\t\t\tif [ ${#active} -lt ${#current_hunks} ]; then\n\t\t\t\ti=yes\n\t\t\telse\n\t\t\t\ti=no\n\t\t\tfi\n\t\t\techo\n\t\t\twhile [ -n \"$action\" -a \"$action\" != yes -a \"$action\" != no -a -n \"$action\" ]; do\n\t\t\t\techo -n \"Commit this hunk (default is $i)? \"\n\t\t\t\tread action\n\t\t\t\tcase \"$action\" in\n\t\t\t\ty) action=yes;;\n\t\t\t\tn) action=no;;\n\t\t\t\tesac\n\t\t\tdone\n\t\t\tif [ -n \"$action\" -a $i != \"$action\" ]; then\n\t\t\t\tcurrent_hunks=$active\n\t\t\tfi\n\t\t\t;;\n\t\t*) echo \"Unknown command: $action\";;\n\t\tesac\n\tdone\n\n\tif [ \"$action\" = commit ]; then\n\t\thunks[$index]=$current_hunks\n\tfi\n}\n\n# Apply the hunks saved in the array hunks for the specified file.\n# This means that the diff is rewritten to skip the unwanted hunks.\n\napply_hunks () {\n\tlocal index=$1\n\tlocal filename=${modified[$index]}\n\tlocal -a current_hunks\n\tlocal lineno\n\tlocal lineno2\n\tlocal linediff\n\tlocal hunkno\n\tlocal i\n\tlocal active\n\n\ti=0\n\twhile read hunkno; do\n\t\tcurrent_hunks[$i]=$hunkno\n\t\ti=$(($i+1))\n\tdone < <(echo ${hunks[$index]} | tr , '\\n')\n\n\tlinediff=0\n\thunkno=0\n\ti=0\n\tactive=true\n\twhile read line\n\tdo\n\t\tcase \"$line\" in\n\t\t@@*)\n\t\t\thunkno=$(($hunkno+1))\n\t\t\tif [ $hunkno = \"${current_hunks[$i]}\" ]; then\n\t\t\t\tactive=true\n\t\t\t\ti=$(($i+1))\n\t\t\t\tif [ $linediff -ne 0 ]; then\n\t\t\t\t\tlineno=$(echo \"$line\" | sed \"s/^.*+\\([0-9]*\\)[, ].*$/\\1/\")\n\t\t\t\t\tlineno2=$(($lineno+$linediff))\n\t\t\t\t\tline=\"$(echo \"$line\" | sed \"s/+$lineno/+$lineno2/\")\"\n\t\t\t\tfi\n\t\t\telse\n\t\t\t\tactive=\n\t\t\t\tlineno=$(echo \"$line\" | sed -n \"s/^.*-[0-9]*,\\([0-9]*\\) .*$/\\1/p\")\n\t\t\t\tif [ -z \"$lineno\" ]; then\n\t\t\t\t\tlineno=1\n\t\t\t\tfi\n\t\t\t\tlineno2=$(echo \"$line\" | sed -n \"s/^.*+[0-9]*,\\([0-9]*\\) .*$/\\1/p\")\n\t\t\t\tif [ -z \"$lineno2\" ]; then\n\t\t\t\t\tlineno2=1\n\t\t\t\tfi\n\t\t\t\tlinediff=$(($linediff+$lineno-$lineno2))\n\t\t\tfi\n\t\t\t;;\n\t\tesac\n\t\tif [ -n \"$active\" ]; then\n\t\t\techo \"$line\"\n\t\tfi\n\tdone < <(git diff \"$filename\")\n}\n\ndarcs_mode=\ncase \"$1\" in\n--darcs) darcs_mode=true;;\nesac\n\nIFS=''\naction=\ni=\nwhile [ \"$action\" != commit -a \"$action\" != abort ]; do\n\tcase \"$darcs_mode\" in\n\t'')\n\t\techo\n\t\tfor ((i=1; i<$filenr; i++)); do\n\t\t\techo -n \"$i ${modified[$i]}\"\n\t\t\tif [ -n \"${hunks[$i]}\" ]; then\n\t\t\t\techo \" (${hunks[$i]})\"\n\t\t\telse\n\t\t\t\techo\n\t\t\tfi\n\t\tdone | less -FS\n\t\techo\n\t\techo \"To put one or more hunks of a file into the staging area (AKA\"\n\t\techo \"index), type in the number of the file.\"\n\t\techo \"To commit, say 'commit', to abort, say 'abort'.\"\n\t\techo\n\t\techo -n \"Your choice? \"\n\t\tread action\n\t\t;;\n\ttrue)\n\t\tif [ -z \"$i\" ]; then\n\t\t\ti=1\n\t\telse\n\t\t\ti=$(($i+1))\n\t\tfi\n\t\tif [ $i -ge $filenr ]; then\n\t\t\taction=commit\n\t\telse\n\t\t\taction=$i\n\t\tfi\n\t\t;;\n\tesac\n\tcase \"$action\" in\n\tc) action=commit;;\n\tq|a) action=abort;;\n\tcommit|abort) ;;\n\t[0-9]*) select_hunks \"$action\" \"$darcs_mode\";;\n\t*) echo \"Unknown command.\" ;;\n\tesac\ndone\n\nif [ \"$action\" = commit ]; then\n\tfor ((i=1; i<$filenr; i++)); do\n\t\tif [ -n \"${hunks[$i]}\" ]; then\n\t\t\tapply_hunks $i\n\t\tfi\n\tdone | tee a123 | git apply --cached\n\tgit commit\nfi\n\n"},{"id":"294370","messageId":"45760CA3.9060003@xs4all.nl","threadId":"43327","inReplyTo":"Pine.LNX.4.63.0612051936480.28348@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: For all you darcs lovers: git-hunk-commit","fromName":"Han-Wen Nienhuys","fromEmail":"hanwen@xs4all.nl","sentAt":"2006-12-06T00:19:47Z","receivedAt":"2006-12-06T00:19:47Z","isPatch":false,"sender":{"key":"hanwen@google.com","avatar":"https://avatars.githubusercontent.com/u/31547?v=4"},"body":"Johannes Schindelin escreveu:\n> I was inspired by Han-Wen. This script allows you to commit selected hunks \n\nWow!\n\n> In darcs mode, all hunks are presented one by one, and you are asked if \n> you want to commit this or not. If you make a mistake: ^C and back to \n> start. I do not really know darcs, so this might not be how it works -- I \n> did not find any good documentation how a \"darcs record\" looks like.\n\n\nThis is the interactive interface for commits in Darcs. It uses the\nsame interface for pushing and pulling, where I mostly use y/n/a/d but\nsometimes the other letters too.\n\n\n****\nShall I record this change? (1/?)  [ynWsfqadjkc], or ? for help: ?\nHow to use record...\ny: record this patch\nn: don't record it\nw: wait and decide later, defaulting to no\n\ns: don't record the rest of the changes to this file\nf: record the rest of the changes to this file\n\nd: record selected patches, skipping all the remaining patches\na: record all the remaining patches\nq: cancel record\n\nj: skip to next patch\nk: back up to previous patch\nc: calculate number of patches\nh or ?: show this help\n\n<Space>: accept the current default (which is capitalized)\n****\n\n\n\nIf you want to get a feel for it, grab darcs and run\n\n  darcs init\n  echo hello > hello\n  darcs add\n  darcs record\n  \n\nFor a really neat implementation of per-hunk commits, try running\ndarcsum in Emacs\n\n\n> done < <(git ls-files --modified -z)\n\n> \tdone < <(git diff \"$filename\")\n\n> \tdone < <(echo ${hunks[$index]} | tr , '\\n')\n\nam I running the wrong bash? it barf on this. Don't you mean $(echo ... )\n\nFrankly, I am amazed that people write things in bash at all--I vowed never\nto write bash again a couple of years ago.  If you start doing arrays and\ncounting, wouldn't a more high-level language be suitable?\n\n-- \n Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen\n"},{"id":"296998","messageId":"Pine.LNX.4.63.0612060129310.28348@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"43327","inReplyTo":"45760CA3.9060003@xs4all.nl","subject":"Re: For all you darcs lovers: git-hunk-commit","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-12-06T00:36:52Z","receivedAt":"2006-12-06T00:36:52Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Wed, 6 Dec 2006, Han-Wen Nienhuys wrote:\n\n> This is the interactive interface for commits in Darcs. It uses the\n> same interface for pushing and pulling, where I mostly use y/n/a/d but\n> sometimes the other letters too.\n> \n> \n> ****\n> Shall I record this change? (1/?)  [ynWsfqadjkc], or ? for help: ?\n> How to use record...\n> y: record this patch\n> n: don't record it\n> w: wait and decide later, defaulting to no\n> \n> s: don't record the rest of the changes to this file\n> f: record the rest of the changes to this file\n> \n> d: record selected patches, skipping all the remaining patches\n> a: record all the remaining patches\n> q: cancel record\n> \n> j: skip to next patch\n> k: back up to previous patch\n> c: calculate number of patches\n> h or ?: show this help\n> \n> <Space>: accept the current default (which is capitalized)\n> ****\n\nAll but \"y\" and \"n\" are unsupported in hunk-commit.bash... Do you use all \nof these?\n\n> If you want to get a feel for it, grab darcs and run\n\nI already grabbed darcs a long time ago. And run, I did.\n\n> > done < <(git ls-files --modified -z)\n> \n> > \tdone < <(git diff \"$filename\")\n> \n> > \tdone < <(echo ${hunks[$index]} | tr , '\\n')\n> \n> am I running the wrong bash? it barf on this. Don't you mean $(echo ... )\n\nI hoped that I did not use a too new bash. Unfortunately, I seem to have \nbeen wrong. These constructs redirect the output of the command as input \nto the while loop, because\n\n\tbla | while ...; do blub; done\n\nopens a subshell, so that all changes done in \"blub\" are lost as soon as \nthe while loop is finished.\n\n> Frankly, I am amazed that people write things in bash at all--I vowed \n> never to write bash again a couple of years ago.  If you start doing \n> arrays and counting, wouldn't a more high-level language be suitable?\n\nMe, being one of the loudest proponents of C builtins on this list, I \nagree fully.\n\nBut in this case, bash was faster to script and debug, and unless people \nspeak up, saying \"I want that feature badly!\", I do not plan to do \nanything with it.\n\nCiao,\nDscho\n"},{"id":"296783","messageId":"1165568153.21747.11.camel@localhost.localdomain","threadId":"43327","inReplyTo":"Pine.LNX.4.63.0612060129310.28348@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: For all you darcs lovers: git-hunk-commit","fromName":"Matthias Kestenholz","fromEmail":"lists@spinlock.ch","sentAt":"2006-12-08T08:55:53Z","receivedAt":"2006-12-08T08:55:53Z","isPatch":false,"sender":{"key":"lists@spinlock.ch","avatar":null},"body":"Hi,\n\nOn Wed, 2006-12-06 at 01:36 +0100, Johannes Schindelin wrote:\n> But in this case, bash was faster to script and debug, and unless people \n> speak up, saying \"I want that feature badly!\", I do not plan to do \n> anything with it.\n\nThis feature is _very_ handy and I think it would be great if this\nbecame part of the default git distribution.\n\nThanks for writing this tool!\n\nMatthias\n"},{"id":"296748","messageId":"Pine.LNX.4.63.0612081634570.28348@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"43327","inReplyTo":"1165568153.21747.11.camel@localhost.localdomain","subject":"Re: For all you darcs lovers: git-hunk-commit","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-12-08T15:37:30Z","receivedAt":"2006-12-08T15:37:30Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 8 Dec 2006, Matthias Kestenholz wrote:\n\n> On Wed, 2006-12-06 at 01:36 +0100, Johannes Schindelin wrote:\n> > But in this case, bash was faster to script and debug, and unless people \n> > speak up, saying \"I want that feature badly!\", I do not plan to do \n> > anything with it.\n> \n> This feature is _very_ handy and I think it would be great if this\n> became part of the default git distribution.\n\nNote that it requires a relatively new bash version ATM, because of the \n\"while read line; do ...; done < <(cmd)\" construct. I have another version \nwhich substitutes a temporary file for that, but I keep thinking that a \ngraphical tool, such as git-gui, would be more appropriate. BTW I just did \nit in bash, because I wanted to learn about these famous bash arrays.\n\nCiao,\nDscho\n"}]}