2

I use git and bugs-everywhere in my project. If you don't know the latter, it's a simple text file based issue tracker, i.e. bugs are simply files, and modifying them is done with the command-line tool be. The files themselves are stored in the git repository. The idea of bugs-everywhere is to keep the issue statuses in sync with the code you commit.

What I'd like to achieve: If a programmer commits changes and references the bug in the message he just fixed / feature he implemented (e.g. the message is something like fixed #123), I'd like to mark the issue as done using the corresponding be command. This obviously changes the issue file. I then want these changes to be included in the current commit.

Since I need to parse the commit message, I can't use a pre-commit hook but need to use a commit-msg hook. But I can't find any information whether or not it is possible to change what is being committed but only the message for the commit.

My idea is, in the commit-msg hook, to always reject such commits, but also do another commit which includes the corresponding changes in the issue file. This leaves some open questions:

  • Is it possible to do a commit during a commit-msg hook?
  • Is it possible to reliably find out which files the user wanted to commit originally? (I guess I can simply use the comment lines in the commit message, but aren't they possibly truncated?)

Or is there a different approach you can think of?

Another idea, not really solving the above problem, is to only use the hook to check if the programmer already marked the issue as done. My primary goal is to avoid forgetting to mark the issue as done.

leemes
  • 44,967
  • 21
  • 135
  • 183
  • 2
    As a general rule, it's bad form to modify what's about to be committed in a hook, but not so bad to reject the commit. As for modifying or inspecting the commit, you can look at the index, but with `git commit -a` or `git commit file ...` git uses a different (non-standard) index, so this is a bit perilous. Probably a better way to get "mark issue done and commit result" is to write a script that does those in that order. Then a hook that checks to make sure the marking is correct, aborting the commit if not, can remind the user to use the script, rather than a direct `git commit`. – torek Aug 05 '14 at 15:55
  • @torek Thank you for your honest advice. I guess I go for the other direction: a prepare-commit-msg hook inserts "fixed #123" notes if the issue file was changed in that way (detected using git diff). The user sees this immediately in his commit message editor. Then maybe, but I guess it's not necessary, check in the commit-msg hook that issues and message are matching. – leemes Aug 05 '14 at 16:04
  • The `prepare-commit-msg` hook runs *before* you get a chance to edit the commit message, so it's fine to fuss with the text there: the user gets to see what's going in. Changing it in the commit-msg hook, *after* the user has set it, just seems sort of rude. (I thought, based on your text above, that this is what you were going to do. Of course, it's *your* repo, so it's really up to you.) BTW, inspecting the index in the hook itself is safe enough, just remember that `$GIT_INDEX_FILE` may point to an alternative file (if you're inclined to fuss with it). – torek Aug 05 '14 at 18:05

1 Answers1

1

As discussed in the comments, it's not really recommended to configure the workflow like that.

As an alternative, I went for the other way around: when a commit includes a change to an issue file, mention the bug in the prepared commit message.

I implemented this mechanism using the prepare-commit-msg hook which I'll describe here step by step:

  • First, I list all currently fixed bugs according to the files in the current working directory, and get their UUID:

    fixedbugs="`be list -x --status fixed | sed -n 's#  <uuid>\(.*\)</uuid>#\1#p'`"
    
  • For each of them, I check the following two things: Has the bug already been fixed in HEAD? Is the issue file itself staged for commit (to allow partial commits)? This can be checked with a git diff between HEAD and --staged; then finding out if a line "status": "fixed" has been added according to the diff using grep. (Note that here, the hex string 2111156... is the ID of my bugdir, replace with your own):

    for bug in $fixedbugs; do
        if git diff HEAD --staged .be/211156fd-fa49-4e87-878c-7642f7163a4b/bugs/$bug/values | grep '^\+    "status": "fixed",.\?$' > /dev/null; then
            # (do something with $bug, e.g. `be show $bug...`)
        fi
    done
    
  • For each such issue "to be committed as being fixed now" (within the if above), I collect some information and concatenate the text lines to be prepended to the commit message:

    # collect information
    details="`be show -x 211156fd-fa49-4e87-878c-7642f7163a4b/$bug`"
    short="`echo "$details" | sed -n 's#.*<short-name>\(.*\)</short-name>.*#\1#p'`"
    shorter="`echo "$short" | sed 's#211/##'`"   # remove bugdir
    summary="`echo "$details" | sed -n 's#.*<summary>\(.*\)</summary>.*#\1#p'`"
    
    # prepend string in format 'fixed #123: "foo bar is broken"'
    prepend="$prepend`echo fixed \#$shorter: \\\"$summary\\\"`\n"
    
  • At the end of the hook, prepend this string to the prepared commit message:

    tmpfile="`mktemp`
    echo "$prepend" > $tmpfile
    cat "$1" >> $tmpfile
    mv "$tmpfile" "$1"
    

Full hook file is published as a gist at https://gist.github.com/leemes/dd336e5fc88096ad6924

If you have any suggestions for improvement or spot a bug, please comment.

leemes
  • 44,967
  • 21
  • 135
  • 183