Archive for the ‘git’ Category

My Emacs Magit workflow.

Posted on November 24th, 2012 in emacs, git | No Comments »

I wrote about Magit, the Emacs mode for Git almost two years ago and still use it near-daily since. I love being able to spend most my day within Emacs and not having to drop down to shell to pull or push files. I explained my Magit workflow to a user on Stackoverflow recently, and think it would be helpful to post it here as well for my dear Emacs readers:

Magit screenshot

My flow goes like this.

  1. I start the day at work. I type git diff in command line just to see if I have any uncommitted changes from the previous day (don’t forget to enabled colors!) The reason I do this in command line as apposed to magit is because I’m not in emacs yet.
  2. I either open the uncomitted files in emacs emacs file1 file2 or I open some files I’m about to work on.
  3. I code until I’ve fixed a bug or finished a new feature.
  4. In emacs I type C-c i to open up the Magit status window.
  5. I scroll down to the Changes section and next to each file press tab to see a diff of each changes. I either press s to stage those changes or u to unstage those changes.
  6. Optionally, I can look through diffs code and do the same s and u to stage and unstage sections of the code. Useful if I had some debug code somewhere and want to kill it.
  7. After I’ve confirmed all my changes look good and are staged I type c to open the magit-edit-log. I type my commit message and then type C-c C-c to commit it. Then P to push it. Done!

Note that this sounds like a lot of steps but it becomes quickly natural and the whole process literally takes 30 seconds for me to diff my entire set of changes, stage them, and commit them with a message. All while staying in Emacs. So much easier than dropping down to command line.

Sometimes an error is returned when I do a push via Magit usually caused by new code in the remote repo that I have to pull before I push. In this case F to pull changes then P again to push. Honestly for some reason, instead of pulling through magit, I generally just Ctrl-z in this situation, drop down to shell, git pull, and git push.

And as previously posted, don’t forget to change Magit’s default diff colors!

git hook to reject bad emails on the server.

Posted on February 19th, 2012 in git, node | 2 Comments »

In my git workflow I use git-commit-notifier to email beautiful, color-coded, diff emails out to the dev group anytime there’s a commit. Problem is, if a new engineer didn’t set his git author email properly that email will get silently rejected from the email group.

I finally got around to creating a git commit hook to reject the commit from the start, and inform the developer to update his or her git author email.

To use, simply create a pre-receive file in your remote repos hooks folder and make it executable.
I wrote this in Node so you’ll need to have Node installed on your server if it’s not there already:

#! /bin/env node
 
var fs = require('fs'),
arguments = fs.readFileSync('/dev/stdin').toString().split(' ');
exec = require('child_process').exec;
var email = 'yourcompany.com';
 
exec('git log -1 ' + arguments[1] + ' --format=%ae', function(err, stdout, stderr){
    if (stdout !== '' && stdout.indexOf(email) == -1){
            console.log('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@');
            console.log('Author email must contain ' + email + '! Your email is currently set to: ' + stdout);
            console.log('Please update by running: git config --global user.email "name@' + email + '"');
            console.log('And then: git commit --amend --reset-author');
            console.log('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@');
            process.exit(1);
        }
        process.exit(0);
});

Setting up and using a git wrapper around SVN with git-svn

Posted on January 27th, 2012 in git, Uncategorized | No Comments »

Note: I wrote this post a long time ago but never got around to posting it. A lot of these steps are applicable to porting an SVN repo to Git as well.

Preface on why I love git

Roughly four years ago I switched to git for version control and it’s changed my development life. While SVN is sufficient to “get the job done” in terms of keeping a history of your commits with a group of people, Git is truly the next evolutionary step up in every way. I could expound a whole article on the joy of git, but many others already have, and this articles not about that. But I will kindly throw in my 0.02 on why I personally love it:

  • It’s fast. Git keeps your whole repo’s history local. So no need to ping your repo server for every command. You can even checkout your codebase from 3 weeks ago or a year ago in under a second.”
  • It works offline. That’s right, no internet. Sync up later.
  • It has useful modern tools. Like git stash and git bisect. Both will save you a lot of time.
  • It’s your third hand. Let’s face it, besides svn being slow, it’s not friendly enough to do more than throw your past commits into an empty hole you will probably never see again. With very little setup, you have beautiful colored output in your logs and diffs with git. And “git log” actually pages by default (while keeping colors) instead of flooding your console with the entire repos history! Want to query something in your history log? What about all commits from your friend Bob in the past 2 weeks?
    git log --date=relative --author=nizam --since="2 weeks ago"

    Bam. Done.

  • Easy repo creation. You don’t have to be an admin to setup a git repo. Just cd into a folder and type “git init”. You just created a new repo. I do this all the time, for example in my folder of todo lists, I use it to track history of my todos. At work someone kept messing up the apache config file, all I had to do was “git init” in /etc/httpd/conf and now I can easily “git diff” new changes that were made and revert / adjust if needed.
  • Many ways to use it. Git is promoted as “decentralized” version control, but it can be an easy drop in replacement for any job SVN can do. Which leads me to…

With all those advantages, many larger companies haven’t jumped on the git bandwagon. I believe there’s two reasons this is the case.

  • As programmers get more experienced, they generally become more pragmatic (which is generally a good thing.) They adopt a “if it ain’t broke, don’t fix it.” mentality. After all, SVN get’s the job done.
  • There is a bit of a learning curve with git. But there are a ton of good resources for learning it. I recommend getting your hands dirty with Git Immersion if you’re new or would like to learn. I don’t recommend wrapping git around svn as I’m about to show you for a person who’s learning git.

Getting down to business.

In order to use git with an svn repo, you’ll have to run some commands to import that svn repo, commit by commit into a git repo.

1. First, make sure you have a version of git installed with svn bindings. If you type “git svn” and it give you an error, I’d google one of the resources in reinstalling git with svn bindings.

2. We need to keep

# In your existing svn repo, lets grab a list of authors
svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors.txt
# create a new folder
cd ..; mkdir NEWREPO.git;
git svn clone -A ../OLDREPO/authors.txt https://svn/repo/trunk
git svn fetch # this could take a long time as it checks the repo out one rev at a time.
 
# update your working copy:
git-svn rebase
 
# commit your changes to svn server
git-svn dcommit

kudos to:

http://flavio.castelli.name/howto_use_git_with_svn

Great little bash snippet to summarize your daily git commits.

Posted on January 9th, 2012 in bash, git | No Comments »

For general invoicing and hour tracking, I like to post the details of my git commits. Though, I had my own little version of this script, this one posted at stackoverflow was a lot better looking. Posted here for posterity:

function gdaily {
    NEXT=$(date +%F)
    echo "CHANGELOG"
    echo ----------------------
    git log --no-merges --format="%cd" --date=short | sort -u -r | while read DATE ; do
        echo
        echo [$DATE]
        GIT_PAGER=cat git log --no-merges --format=" * %s" --since=$DATE --until=$NEXT
        NEXT=$DATE
    done
}

Which looks like:

[2012-01-07]
 * Refactor list portfolio page css and js.
 * namespace.data include to load fake api data until it is ready. Portfolio list working again.
 * CurrentUser model defaults and code cleanup.

[2012-01-06]
 * Upgrade portfolio call from GET and POST. To be discussed in tomorrow's standup.

Working with git repos on non-standard ports

Posted on March 30th, 2011 in git, ssh | 4 Comments »

Recently due to some SSH attacks I’ve had to change my default SSH port to something non-standard. While I’m not a proponent of security through obscurity, most automated botnets ping random IP addresses on port 22 to see if there’s an SSH daemon listening before relentlessly hammering down on them—it only makes sense to get off of that port. (I’ve obviously hardened my security in other ways as well.)

Since I run my own little version of GitHub (using a combination of Gitolite, git-commit-notifier, and other open-source tools) which I share with friends, I needed to send out a quick email on how to switch up existing checked-out repositories as well as how to clone new ones using this non-standard port. Since I did the research, I thought I might as well post it here, too:

Cloning a git repository on a non-standard port

The git man file says you can specify a port using the traditional git syntax but I couldn’t get it to work for the life of me, It always defaulted to port 22. Since git just uses SSH anyways, here’s the alternative syntax that also works:

old:

git clone git@domain.com:<project name>

new:

git clone ssh://git@domain.com:<port>/<project name>

Switching an existing checked-out repository to use a non-standard port

To prevent having to re-checkout an entire project, simply change the location of master and all will be fine. There’s a way to do this using a git shell command but I prefer to just modify the .git/config file directly, as that’s all the commands does anyways.

old:

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = git@domain.com:<project name>


new:

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = ssh://git@domain.com:<port>/<project name>

Set it and forget it method (.ssh/config)

Instead of doing any of the above, if you’re on a Mac or Linux environment, the config file inside of your ~/.ssh folder can save you from typing long ssh commands. It allows you to create short ssh alias’s that predefines a host, username, port, as well as more advanced functionality like running proxy commands, forwarding your ssh agent, etc. It’s well worth taking a look at. When you set an SSH alias anything that uses SSH (git, rsync, scp, etc) all have access to it.

Add the following lines to your ~/.ssh/config:

Host myrepo
     User git
     Port <port number>
     Hostname <hostname.com>

Now you can do a git clone by doing the following:

git clone myrepo:<project name>

Or in your current checked-out project change the remote “origin” url to:

myrepo:<project name>

It will automatically pick up your username, port, and hostname from your .ssh/config file.