Permalink
Browse files

initial commit

  • Loading branch information...
bartman committed Nov 4, 2009
0 parents commit 9d9ae1b21671bde67182d02814568134e8f70184
Showing with 360 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +90 −0 README
  3. +268 −0 git-wip
@@ -0,0 +1,2 @@
+*.swp
+*~
90 README
@@ -0,0 +1,90 @@
+# About
+
+git-wip is a script that will manage Work In Progress (or WIP) branches.
+WIP branches are mostly throw away but identify points of development
+between commits. The intent is to tie this script into your editor so
+that each time you save your file, the git-wip script captures that
+state in git. git-wip also helps you return back to a previous state of
+development.
+
+Latest git-wip can be obtained from [github.com](http://github.com/bartman/git-wip)
+git-wip was written by [Bart Trojanowski](mailto:bart@jukie.net)
+
+# WIP branches
+
+Wip branches are named after the branch that is being worked on, but are
+prefixed with 'wip/'. For example if you are working on a branch named
+'feature' then the git-wip script will only manipulate the 'wip/feature'
+branch.
+
+When you run git-wip for the first time, it will capture all changes to
+tracked files and all untracked (but not ignored) files, create a
+commit, and make a new wip/*topic* branch point to it.
+
+ --- * --- * --- * <-- topic
+ \
+ * <-- wip/topic
+
+The next invocation of git-wip after a commit is made will continue to
+evolve the work from the last wip/*topic* point.
+
+ --- * --- * --- * <-- topic
+ \
+ *
+ \
+ * <-- wip/topic
+
+Whne git-wip is invoked after a commit is made, the state of the
+wip/*topic* branch will be reset back to your *topic* branch and the new
+changes to the working tree will be caputred on a new commit.
+
+ --- * --- * --- * --- * <-- topic
+ \ \
+ * * <-- wip/topic
+ \
+ *
+
+While the old wip/*topic* work is no longer accessible directly, it can
+alwasy be recovered from git-reflog. In the above example you could use
+`wip/topic@{1}` to access the dangling references.
+
+# git-wip command
+
+The git-wip command can be invoked in several differnet ways.
+
+* `git wip`
+
+ In this mode, git-wip will create a new commit on the wip/*topic*
+ branch (creating it if needed) as described above.
+
+* `git wip save "description"`
+
+ Similar to `git wip`, but allows for a custom commit message.
+
+* `git wip log`
+
+ Show the list of the work that leads upto the last WIP commit. This
+ is similar to invoking:
+
+ `git log --stat wip/$branch...$(git merge-base wip/$branch $branch)`
+
+# editor hooking
+
+To use git-wip effectively, you should tie it into your editor so you
+don't have to remember to run git-wip manually.
+
+To add git-wip support to vim add the following to your `.vimrc`. Doing
+so will make it be invoked after every `:w` operation.
+
+ augroup git-wip
+ autocmd!
+ autocmd BufWritePost * :silent !git wip --editor -- "%"
+ augroup END
+
+The `--editor` option puts git-wip into a special mode that will make it
+more quiet and not report errors if there were no changes made to the
+file.
+
+
+
+<!-- vim: set ft=mkd -->
268 git-wip
@@ -0,0 +1,268 @@
+#!/bin/sh
+#
+# Copyright Bart Trojanowski <bart@jukie.net>
+#
+# git-wip is a script that will manage Work In Progress (or WIP) branches.
+# WIP branches are mostly throw away but identify points of development
+# between commits. The intent is to tie this script into your editor so
+# that each time you save your file, the git-wip script captures that
+# state in git. git-wip also helps you return back to a previous state of
+# development.
+#
+# See also http://github.com/bartman/git-wip
+#
+
+USAGE='[ info | save <message> | log | delete ] [ --editor | --untracked ] [ [--] <file>... ]'
+LONG_USAGE="Manage Work In Progress branches
+
+Commands:
+
+ git wip - create a new WIP commit
+ git wip save <message> - create a new WIP commit with custom message
+ git wip info [<branch>] - brief WIP info
+ git wip log [<branch>] - show changes on the WIP branch
+ git wip delete [<branch>] - delete a WIP branch
+
+Options:
+
+ --editor - be less verbose, assume called from an editor
+ --untracked - capture also untracked files
+ --ignored - capture also ignored files
+"
+
+SUBDIRECTORY_OK=Yes
+OPTIONS_SPEC=
+. git-sh-setup || . $(git --exec-path)/git-sh-setup || ( echo "git wip needs git to run." ; exit 1 )
+require_work_tree
+
+TMP="$GIT_DIR/.git-wip.$$"
+trap 'rm -f "$TMP-*"' 0
+
+WIP_INDEX="$TMP-INDEX"
+
+WIP_PREFIX=refs/wip/
+WIP_COMMAND=
+WIP_MESSAGE=WIP
+EDITOR_MODE=false
+LS_FILES_EXTRA=
+
+dbg() {
+ if test -n "$WIP_DEBUG"
+ then
+ printf '# %s\n' "$*"
+ fi
+}
+
+cleanup () {
+ rm -f "$TMP-*"
+}
+
+get_work_branch () {
+ ref=$(git symbolic-ref -q HEAD) \
+ || die "git-wip requires a branch"
+
+
+ branch=${ref#refs/heads/}
+ if [ $branch = $ref ] ; then
+ die "git-wip requires a local branch"
+ fi
+
+ echo $branch
+}
+
+get_wip_branch () {
+ return 0
+}
+
+find_changes () {
+ git ls-files --exclude-standard -m $LS_FILES_EXTRA
+}
+
+check_files () {
+ local files=$@
+
+ for f in $files
+ do
+ [ -f "$f" -o -d "$f" ] || die "$f: No such file or directory."
+ done
+}
+
+do_save () {
+ local msg=$1 ; shift
+ local files=$@
+
+ if test ${#files} -eq 0
+ then
+ files=$(find_changes)
+ else
+ check_files $files
+ fi
+
+ dbg "msg=$msg"
+ dbg "files=$files"
+
+ local work_branch=$(get_work_branch)
+ local wip_branch=$WIP_PREFIX$work_branch
+
+ dbg "work_branch=$work_branch"
+ dbg "wip_branch=$wip_branch"
+
+ # enable reflog
+ mkdir -p "$GIT_DIR/logs/$WIP_PREFIX"
+ : >>"$GIT_DIR/logs/$wip_branch"
+
+ if ! work_last=$(git rev-parse --verify $work_branch)
+ then
+ die "'$work_branch' branch has no commits."
+ fi
+
+ dbg "work_last=$work_last"
+
+ if wip_last=$(git rev-parse --quiet --verify $wip_branch)
+ then
+ base=$(git merge-base $wip_last $work_last) \
+ || die "'work_branch' and '$wip_branch' are unrelated."
+
+ if [ $base = $work_last ] ; then
+ wip_parent=$wip_last
+ else
+ wip_parent=$work_last
+ fi
+ else
+ wip_parent=$work_last
+ fi
+
+ dbg "wip_parent=$wip_parent"
+
+ new_tree=$( ( rm -f $WIP_INDEX \
+ && cp -p .git/index $WIP_INDEX \
+ && export GIT_INDEX_FILE=WIP_INDEX \
+ && git read-tree -m $wip_parent \
+ && git add $files \
+ && git write-tree \
+ && rm -f "$WIP_INDEX" )
+ ) || die "Cannot save the current worktree state."
+
+ dbg "new_tree=$new_tree"
+
+ if git diff-tree --exit-code --quiet $new_tree $wip_parent ; then
+ say "no changes"
+ $EDITOR_MODE && exit 0
+ exit 1
+ fi
+
+ dbg "... has changes"
+
+ new_wip=$(printf '%s\n' "$msg" | git commit-tree $new_tree -p $wip_parent) \
+ || die "Cannot record working tree state"
+
+ dbg "new_wip=$new_wip"
+
+ git update-ref -m "git-wip: $msg" $wip_branch $new_wip
+
+ dbg "SUCCESS"
+}
+
+do_info () {
+ local branch=$1
+
+ die "info not implemented"
+}
+
+do_log () {
+ local branch=$1
+
+ die "log not implemented"
+}
+
+do_delete () {
+ local branch=$1
+
+ die "delete not implemented"
+}
+
+do_help () {
+ local rc=$1
+
+ cat <<END
+Usage: git wip $USAGE
+
+$LONG_USAGE
+END
+ exit $rc
+}
+
+
+if test $# -eq 0
+then
+ dbg "no arguments"
+
+ do_save "WIP"
+ exit $?
+fi
+
+case "$1" in
+save)
+ WIP_COMMAND=$1
+ shift
+ if [ -n "$1" ]
+ then
+ WIP_MESSAGE=$1
+ shift
+ fi
+ ;;
+info|log|delete)
+ WIP_COMMAND=$1
+ shift
+ ;;
+help)
+ do_help 0
+ ;;
+--*)
+ ;;
+*)
+ [ -f "$1" ] || die "Unknow command '$1'."
+ ;;
+esac
+
+while test $# != 0
+do
+ case "$1" in
+ --editor)
+ EDITOR_MODE=true
+ ;;
+
+ --untracked|--ignored)
+ LS_FILES_EXTRA="$LS_FILES_EXTRA $1"
+ ;;
+
+ --)
+ shift
+ break
+ ;;
+ *)
+ [ -f "$1" ] && break
+ die "Unknow option '$1'."
+ ;;
+ esac
+ shift
+done
+
+case $WIP_COMMAND in
+save)
+ do_save "$WIP_MESSAGE" $@
+ ;;
+info)
+ do_info $@
+ ;;
+log)
+ do_log $@
+ ;;
+delete)
+ do_delete $@
+ ;;
+*)
+ usage
+ exit 1
+ ;;
+esac

0 comments on commit 9d9ae1b

Please sign in to comment.