A Foolish Manifesto

fREWdiculous!

Stop accidentally committing all with git

One of the things that annoys me a lot when using git is if I go through a lot of work to stage some changes, probably using `git add -p` to stage parts of files, and then from muscle memory I type `git ci -am ‘lolol I dummy’`. If you didn’t know the -a says commit everything, so then of my painstaking staging is gone.

Well, on Thursday I finally fixed this problem. I wrote the following, very basic, git wrapper. All it does is:

  • Find all aliases for commit
  • Check if the current command is a commit or commit alias
  • Check if the current arguments have -a or –all
  • Check if there are staged modifications
  • And if all of those conditions are true, it prompts the user to ensure that they actually want to commit all.

I’m fairly happy with the alias detection; the only thing it should also do is introspect the arguments in the values of the alias as well as the current command. I don’t have any aliases like that, but if I wanted to make this a canned solution that would be a must.

The arguments detection is actually very dumb. It wouldn’t work if you did `git ci -m ‘Foo’ -a`. I’m ok with that because this is to battle my own muscle memory and I would never type that. But it is definitely a spot for improvement.

The staged checking I am very happy with. It only checks for staged modifications. So if you add a new file or delete a file and then do `git ci -am “station”` it will happily go on it’s way, which I like.

Anyway, here’s the script. To install it just put it somewhere in your path as wrap-git (I use ~/bin) and alias git=wrap-git

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/env perl

use strict;
use warnings;

my %aliases = map { split(/\n/, $_, 2) }
   split /\0/,
   `git config -z --get-regexp alias\\.`;

my %commit_aliases = (( commit => 1 ),
   map { s/alias\.//; $_ => 1 }
   grep $aliases{$_} =~ /^commit\b/,
   keys %aliases);

my ($command, @args) = @ARGV;

if ($commit_aliases{$command} && $args[0] =~ /^-a|^--all/) {
   my @staged = grep /^M/, split /\0/, `git status -z`;
   if (@staged) {
      print "There are staged changes, are you sure you want to commit all? (y/N) ";
      chomp(my $answer = <STDIN>);
      if ($answer =~ /^y/i) {
         run_command()
      }
   } else {
      run_command()
   }
} else {
   run_command()
}

sub run_command {
   system 'git', $command, @args;
   exit $? >> 8;
}

One thing I think would be really cool would be to make a WrapGit.pm and wrap-git would just be coderefs passed to WrapGit.pm. I’d love to have full introspection of all git commands and arguments. It would let me do things like keep statistics about how you use git, maybe make a powerful achievement system, make more commands prompt the way this one does. Anyway, I’ll probably do that one of these days when I finish all the other stuff on my list :-)

  • 1 Comment
  • Filed under: Uncategorized
  • Using Cygwin instead of msysGit

    Our main product at work is a Windows product. The reasons are complicated, but the main reason is that that is what our customers seem to want. What this means is that I do some of my development on a virtual machine. For a long time I was just using msysGit. msysGit goes a long way; you have a real bash console, a bunch of standard unix commands, and very good windows integration. On the other hand that’s about all you get. After reading his blog post I spoke with Caelum about getting zsh working with msysgit and he said it was probably just better to use cygwin

    There are a handful of reasons to use cygwin, but the main reason I did was for zsh. If you want to follow my path just get the cywin installer and install at least git and ssh. If you are like me you’ll also want to install zsh.

    A couple other things that are nice to install are screen and mintty. Screen is just great in general and I use it constantly. I should probably do a blog post on just that at some point. mintty solves the constant bother in windows that the console emulator is horrible and can’t be resized sensibly.

    Make sure to follow the instructions in Caelum’s blog post as they are very helpful overall.

    cygwin is certainly not perfect though. First off, it is noticeably slower than the already slow msysgit, which is very disappointing. On top of that the home directory is not the same as the standard windows home directory, which is just obnoxious. For some reason with msysgit I could run the vim installed in program files from the command line, but with cygwin I can’t. I even tried making a symlink but those don’t work with cygwin, even though they are supported by ntfs.

    Either way, it’s nice to have zsh and screen and a real terminal. Hopefully this helps someone out there :-)

  • 1 Comment
  • Filed under: Uncategorized
  • Git aliases for your life

    I only use a handful of git aliases, but the ones I do I really like. First off, the basic ones:

    1
    2
    3
    4
    5
    [alias]
       ci = commit
       co = checkout
       st = status
       br = branch

    Also, another handy tip, as pointed out by a commenter is aliasing g to git (alias g=git) so that after you do the above instead of git ci you can merely do g ci. Neat.

    Those are all very obvious and I’d bet nearly everyone has the first couple. The next ones are more in depth but I totally dig them.

    I use zsh which has a huge number of glob expansions; what that means for me is that often when I try to run a git command it conflicts with the zsh globbing and I end up getting “zsh: no matches for ^foo”. So that’s what my first alias solves:

    1
    alias git='noglob git'

    Once I put that in my .zshrc that problem went away entirely, which is nice.

    I have the same problem with gitk, but also I always want gitk to be backgrounded, since it’s a gui tool. I wrote a tiny wrapper function and an alias to handle that:

    1
    2
    function g_tk() { /usr/bin/env 'gitk' "$@" & }
    alias gitk='noglob g_tk'

    That’s excellent. Now instead of ‘gitk …‘ or ‘gitk … &’ just ‘gitk …’ works.

    Often when running gitk I don’t really want to see the entire history of the project. What I typically want is just what’s in the current branch, but not master. I made the following alias for that:

    1
    alias grr='noglob g_tk ^origin/master HEAD'

    My main repo at work has eight submodules, and updating submodules is really an obnoxiously long command, so I aliased it too:

    1
    alias gosu='git submodule update --init'

    Lastly, I rebase my code regularly onto the latest master, so I made the following alias:

    1
    alias gre='git rebase --root --onto origin/master -i --autosquash'

    Another tiny tool I’ve made for less painful merges is what I call “handymerge” or hm.

    1
    2
    3
    #!/bin/bash

    gitk $(cat .git/MERGE_HEAD) $(cat .git/ORIG_HEAD) "$@" &

    I put that in ~/bin and named it git-hm, so now when I’m merging if I want to look at the commits from both side I just run ‘git hm’. If I just want to see commits to file A I run ‘git hm A’. Pretty cool huh?

  • 2 Comments
  • Filed under: Uncategorized
  • You should be using git grep

    Usually when searching through files I use ack which is an awesome tool indeed.

    Unfortunately, though ack does indeed work on windows, using it on windows is a painful experience. The main two problems are that it’s slow and the color coding doesn’t work.

    I figured I’d try out git grep, with the hope that it might be marginally better. I try my best to at least be familiar with all the git commands, so this is one of those things I had been meaning to do anyway.

    I was in for a pleasant surprise when I found that git-grep’s color coding worked and it is extremely fast. I profiled it on linux and I get about an order of magnitude difference for a simple repo. If you use a repo with submodules the difference is even more visible, though possibly you would actually want to search submodules by default.

    There are two features of ack that I use regularly. The first is that it doesn’t search files it shouldn’t, like .svn and .git. With git grep that is also the case, though it only works with git checkouts (which is all I have at this point.) The second feature is the ability to do –perl or –js or –java or whatever else. This can also be done easily with git grep, and I may make a bash wrapper called git-ack that just gives the interface of ack with the backend of git grep.

    1
    2
      ack frew --js
      git grep frew -- '*.js'

    Sure, it’s marginally longer, but if I do make the wrapper it will just be ‘git ack frew –js’ and given that I have cool shell settings based on the directory I’m in I will set it up such that ‘ack frew –js’ just runs ‘git ack frew –js’

    Also, check out the amazing -p argument for git grep; it uses git’s code parsing to include the function that matches are in.

  • 2 Comments
  • Filed under: Uncategorized
  • My Ideal workflow tool

    1. super fetch:

      • git fetch
      • git fetch –tags
      • git pull –ff-only (all local branches)
      • git reset –hard (specified branches)
    2. pull issues:

      • “rebase” issues from github
      • “rebase” issues from RT
      • “rebase” issues from JIRA
      • sync issues from remote repo
    3. super status:

      • Dirty?
      • Non-Tracking branches? How many?
      • Ahead tracking branches? How many commits total?
      • Unmerged branches?
      • Unreleased master? (no tag)
      • How many issues?

    My last post was about Distributed Issue Tracking. The above is why I’d be so interested in DIT. When I want to code I could sit down, run super fetch, run pull issues, and then run super status.

    super fetch

    super fetch is pretty simple and self explanatory, except for one part, the git pull –ff-only. It uses an idea I got while speaking with mjd. Basically, any branches that track a remote and can be fast-forwarded, should be.

    pull issues

    pull issues uses some as yet unknown tech that imports issues into a git reference (I’d say branch but really I’d rather it not be a head) as well as full, local issue tracking. The idea is that if I want to examine the issues of all of my repos, I don’t want to have to go to a website to see all of them.

    super status

    super status builds upon the ideas explored with genehack’s App::GitGot. Specifically, the status command. It lists some of the information above, and is still totally awesome, just not enough. Without colors, I think I’d format the output something like this:

    Optional the following would be prepended to the list:

    1
    2
    3
    4
    5
    6
    D      dirty?
    !TP    non-tracking branches
    !PC    total unpushed commits
    !MB    total unmerged branches
    !RC    unreleased commits
    I      issues
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    Repository Name                         D !TP !PC  !MB  !RC   I

    ACDRI                                   N   0   0    0    0   0
    Arduino                                 N   0   0    0    0   0
    Catalyst                                N   0   0    0    0   0
    Catalyst-View-CSS-Minifier-XS           N   0   0    0    0   0
    Catalyst-View-JavaScript-Minifier-XS    N   0   0    0    0   0
    Class-Accessor-Grouped                  N   0   0    0    0   0
    Config-ZOMG                             N   0   0    0    0   0
    DBIx-Class                              N   0   0   57    0   0
    DBIx-Class-Candy                        N   0   0    0    0   0
    DBIx-Class-DeploymentHandler            N   0   0    0    0   0

    Repository Name                         D !TP !PC  !MB  !RC   I

    DBIx-Class-Helpers                      Y   0   0    0    0   0
    DBIx-Class-Schema-Auth                  Y   0   0    0    0   0
    DBIx-Exceptions                         N   0   0    0    0   0
    Data-Dumper-Concise                     N   0   0    0    0   0
    Git-Conversion-Book                     N   0   0    0    0   0
    Git-Conversions                         N   0   0    0    0   0
    Harmony                                 N   0   3    0    0   0
    Log-Contextual                          N   0   0    0    0   0
    Log-Sprintf                             N   0   0    0    0   0
    Log-Structured                          N   0   0    0    0   0

    Repository Name                         D !TP !PC  !MB  !RC   I

    Lynx                                    N   0   0    0    0   0
    Lynx-SMS                                N   0   0    0    0   0
    Moo                                     N   0   0    0    0   0

    It would all be optionally color coded. Also, optionally the “good value” (usually zero) would be blank.

    In addition to the output above there will be increasing verbosities to actually list the things being counted etc.

    Anyway, I’m gonna start on the super status tonight, and I figured this would be a nice way to flesh out my thoughts. If anyone is interested in this let me know, I welcome feedback. I’ll probably implement it all in perl, as bash might be tough for something like this.

    Update: I got it mostly working!

    This takes a few commandline options and you can configure the defaults using git’s standard config tool. I probably need to consider the names of the switches and config, as well as write some doc, but it definitely works, which is very neat. Next I’ll probably want to add those verbosity flags, but really, I should deal with all those issues with my repos. I need to figure out how to suppress stuff I don’t care about too…

  • 2 Comments
  • Filed under: Uncategorized
  • Distributed Issue Tracking

    Ever since I heard about SD (Simple Defects) I’ve been enamored with the idea of distributed issue tracking. Unfortunately SD is mostly unmaintained, undocumented, slow, and has lots of deps. I could probably get over the latter two, but the first two are deal breakers.

    Fast forward eighteen months and I saw genehack’s App::GitGot. It’s a little sluggish (1.35s to merely list repos on my SSD) but it’s exciting because it can easily list my repos that are dirty or ahead by X commits. genehack is very receptive to changes, so this gave me an idea. First, what if we also listed how many unmerged brances there were? Next, what about unclosed issues? Obviously both of these ideas require some basic configuration, but it’s totally worth it.

    I figured that step one would be to make a minimalist bug tracker, storing the information in the current git repo. The idea being that if I have a git tracker I can easily keep track of what I have to do next, so I won’t forget what else to do. I’ve been working on it every day a little bit since YAPC and it’s been pretty fun! The only thing is that there are already a few other implementations of what I am doing. I might as well list and evaluate them now.

    git-issues

    First off, it’s implemented in Python, which is an immediate deal breaker, as I don’t have python installed everywhere I have git installed. On top of that it uses XML, which is not exactly easy to parse and modify. Finally it is basically dead, so it’s unlikely to get more features added in the future.

    ticgit

    Implemented in Ruby, which is a problem, just like with git-issues. It is extremely full featured, so if you are working on a Linux system all the time I’d say this is the route to go. Unfortunately it uses rubygems; unless something has significantly changed in the past couple years that means it’s gonna be a little sluggish for a CLI app.

    bugs everywhere

    Again this is a Python app. It seems very full featured like ticgit, so maybe it has the same benefits as ticgit. It seems like it has some really neat features, but I just don’t like the python dep.

    git-case

    This is implemented in bash, so it immediately jumped out at me as something that is going to work anywhere that I have git installed. Unfortunately it is unmaintained for about three years now. I emailed the author to see what’s up, so we’ll have to see what happens there.

    The Dilemma

    So my current dilemma is this: should I start afresh with a Perl app, possibly modelling after or even making it compatible with some of these other apps (be or ticgit) or should I pick up where bart left off with git-case? Before you jump to the former, realize that I don’t want to use any CPAN modules because I want this to be super simple to use anywhere one uses git; that is, all I should dep on is 5.8 and Git.pm (which is mostly useless.)

    Currently I’m leaning towards git-case, maybe with a name change as I probably want to make some backwards incompatible changes. Any ideas? Hopes? Dreams?

  • 2 Comments
  • Filed under: Uncategorized
  • Nicer git remote URLs

    Most open source git repositories that I interact with are hosted at git.shadowcat.co.uk. A few typical repo urls (read/write) hosted here looks like:

    1
    2
    3
    4
      dbsrgits@git.shadowcat.co.uk:DBIx-Class.git
      catagits@git.shadowcat.co.uk:Catalyst-Runtime.git
      p5sagit@git.shadowcat.co.uk:Devel-Declare.git
      gitmo@git.shadowcat.co.uk:Moose.git

    A handy trick is to make a file at ~/.ssh/config with the following in it:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    host catagits
         user catagits
         hostname git.shadowcat.co.uk
         port 22
         identityfile ~/.ssh/id_dsa

    host dbsrgits
         user dbsrgits
         hostname git.shadowcat.co.uk
         port 22
         identityfile ~/.ssh/id_dsa

    host p5sagit
         user p5sagit
         hostname git.shadowcat.co.uk
         port 22
         identityfile ~/.ssh/id_dsa

    host gitmo
         user gitmo
         hostname git.shadowcat.co.uk
         port 22
         identityfile ~/.ssh/id_dsa

    Now that that’s done the repos before are simply:

    1
    2
    3
    4
      dbsrgits:DBIx-Class.git
      catagits:Catalyst-Runtime.git
      p5sagit:Devel-Declare.git
      gitmo:Moose.git

    I actually did that for my work and github stuff too, since I just don’t have the time to type those stupid domains all the time.

    Enjoy!

  • 1 Comment
  • Filed under: Uncategorized
  • Converting repos from Subversion to Git

    I have now converted something like 25 repositories from svn to git. I can fix undetected merges, correctly import tags, and clean up ugly (svk) commit messages.

    With this knowledge I hope to write a small, non-free eBook (7.50 USD I think.) But first I’d like a chance to convert your repository! The more repositories that I convert the more ground the ebook can cover. I’ve converted a number of repos for CPAN modules and I’d love to do more. My first thought was to convert the modules in the Catalyst repo, but sadly I’m not sure which ones I should do.

    So if you are interested in having your repo converted, I am totally willing to do it. All I need from you is an email, comment, ping, etc saying you are interested and I need to you be willing to check the converted repo to ensure that it’s good. I’ve gotten pretty good at this but I’m not perfect and I’m not taking the blame if you miss something :-)

    If you’d like to try your hand at doing this, I put all my conversion scripts online, so feel free to take a peak.

  • 1 Comment
  • Filed under: Uncategorized
  • Git 1.7.5.1 from git on ubuntu

    I really like git. It has an excellent suite of tools bundled with it from the start and it gets lots of updates and active development. Today I was looking at the latest git version (1.7.4) because I was installing it on a new machine and, as usual with new versions of things, I perused the
    release notes. What really caught my eye was this:

    1
    2
     * "git log -G<pattern>" limits the output to commits whose change has
       added or deleted lines that match the given pattern.

    I don’t know about you guys, but I fake that feature 2 or 3 times a month by just doing git log -p | grep foo -C50. It’s not nearly as nice as it catches other things, breaks color, etc. Anyway, I decided that instead of waiting for my already non-standard ubuntu repo to catch up, I’d just build it.

    First, I checked out git with my installed git:

    1
    git clone git://git.kernel.org/pub/scm/git/git.git

    That will take a while, so while that’s going on install

    1
    2
    3
    4
    build-essential
    autoconf
    asciidoc
    libcurl4-openssl-dev

    Note that asciidoc tries to pull in a ton of TeX junk. Don’t let it, you don’t need that at all.

    Once that’s done do something like the following:

    1
    2
    3
    4
    make configure
    ./configure --prefix=/opt
    make -j5 all doc
    sudo make install install-doc install-html

    I used the prefix because I’d rather not install on top of my existing stuff; you might want to install to home. Anyway, after doing that ensure that $prefix/bin is in your path and enjoy a brand new git!

  • 4 Comments
  • Filed under: Uncategorized
  • Catalyst Git Conversion

    Hello All!

    Some of you already know that I am working on converting the Catalyst repository to git. I am happy to announce that I am closing in on completion!

    The current state of the git repo: https://github.com/frioux/Catalyst
    The script to convert it: https://github.com/frioux/Git-Conversions/blob/master/cat-convert

    The only things I know of that we must have before we finalize this conversion is:

    • Is it correct that the svn user rjk is Ronald J Kimball: rjk AT linguist DOT dartmouth DAWT edu ?
    • who is svn user didls?

    Also, if you’d like to help ensure the sanity of the repo it would be great if you looked at it! Here are a few tools I use to try to get a feel for the quality of the final export:

    1
    gitk --all

    Perusing the repo with gitk is good; another great thing to do is to View -> Edit View and click “Strictly sort by date”. This is helpful for finding duplicate commits. Note that there are some commits that look duplicate in this repo but actually aren’t; people decided it would be best to edit multiple branches in a single commit instead of just dealing with that at merge time.

    1
    git shortlog -s

    This will make it clear if I misspelled your name.

    Also looking at blames of files can be handy.

    Hopefully this helps!

    Update: hobbs found confirmation for rjk and identity for didls, so we are good to go assuming no one finds any issues.

    (I hope to have a long blog post soon explaining some of the techniques I used to get this all working. Be prepared though, I’m not as smart as Haarg, so mostly it’s a manual process :-) )

  • 0 Comments
  • Filed under: Uncategorized