Home > Hardware and Software, PowerShell, Visual Studio 2008, Windows 7, Windows Server > Using Git (and everything else) through PowerShell

Using Git (and everything else) through PowerShell

August 21, 2009

After a discussion on Stack Overflow a few days ago (and hopefully a useful answer), I got to thinking a bit about how I use PowerShell.  It may be a bit geekish, but PowerShell starts up on Windows startup for me.  The prompt is almost always open on a second monitor–ready for whatever task I may need.

As the SO post mentioned, I also use PowerShell to connect to my Git repositories.  At the office, it has a few more customizations to hashout against our *shudder* SourceSafe */shudder* repositories, but that’s a different post. 

For now, I wanted to walk through how profile script is setup in a bit more detail than the SO post.

Creating a Profile Script

UPDATE: The full source code (plus a few extras) for this article can be found here : http://codepaste.net/53a7z6

A profile script is essentially a “startup” script for your PowerShell environment. 

By default (perhaps a registry key changes this), it’s located in %userprofile%\Documents\WindowsPowerShell and is aptly named Microsoft.PowerShell_Profile.ps1.  The naming convention between “WindowsPowerShell” and “MicrosoftPowerShell” is a bit annoying, but not a big problem.

The file is just plain text, so feel free to use your editor of choice or PowerShell ISE (Windows 7, Windows 2008 R2) for some fancy content highlighting.

What goes in here?

As far as I can tell, the profile is a great place to initialize global customizations:

  • environmental variables,
  • paths,
  • aliases,
  • functions that you don’t want extracted to .ps1 files,
  • customizatons to the console window,
  • and, most importantly, customize the command prompt.

The Console

I use Console2 rather than the standard PowerShell prompt.  Console2 is an amazing open source alternative to the standard console and includes features such as ClearType, multiple tabs, and more.  Check it out.

I also use Live Mesh, so there are a few things that are unnecessary for most users.  Live Mesh is an online syncronization service… so my PowerShell scripts (amongst other things) stay synced between my home and work environments.

My PowerShell Prompt At Startup

Preparing the Environment

My profile script starts off by setting up a few global variables to paths.  I use a quick function to setup the parameters based on the computer I’m currently using. 

# General variables

$computer = get-content env:computername

switch ($computer)

{

    “WORKCOMPUTER_NAME” {

        ReadyEnvironment “E:” “dlongnecker” $computer ; break }

    “HOMECOMPUTER_NAME” {

        ReadyEnvironment “D:” “david” $computer ; break }

    default {

        break; }

}

function ReadyEnvironment (

            [string]$sharedDrive,

            [string]$userName,

            [string]$computerName)

{

    set-variable tools “$sharedDrive\shared_tools” -scope 1

    set-variable scripts “$sharedDrive\shared_scripts” -scope 1

    set-variable rdpDirectory “$sharedDrive\shared_tools\RDP” -scope 1

    set-variable desktop “C:\Users\$userName\DESKTOP” -scope 1

    Write-Host “Setting environment for $computerName” -foregroundcolor cyan

}

Easy enough.  I’m sure I could optimize this a bit more, but it works.  Again, this wouldn’t be necessary on a single computer, but since I use LiveMesh and the same PowerShell profile on multiple computers—this keeps my paths in check.

The second step is to modify the $PATH environmental variable to point to my scripts and Git as well as add a new $HOME variable to satisfy Git’s needs.

# Add Git executables to the mix.

[System.Environment]::SetEnvironmentVariable(“PATH”, $Env:Path + “;” + (Join-Path $tools “\PortableGit-1.6.3.2\bin”), “Process”)

 

# Add our scripts directory in the mix.

[System.Environment]::SetEnvironmentVariable(“PATH”, $Env:Path + “;” + $scripts, “Process”)

 

# Setup Home so that Git doesn’t freak out.

[System.Environment]::SetEnvironmentVariable(“HOME”, (Join-Path $Env:HomeDrive $Env:HomePath), “Process”)

Customizing the Console Prompt

The ‘prompt’ function overrides how the command prompt is generated and allows a great deal of customization.  As I mentioned in the SO post, the inspiration for my Git prompt comes from this blog post.

I’ve added quite a few code comments in here for reference. 

function prompt {

    Write-Host(“”)

    $status_string = “”

    # check to see if this is a directory containing a symbolic reference,

    # fails (gracefully) on non-git repos.

    $symbolicref = git symbolic-ref HEAD

    if($symbolicref -ne $NULL) {

       

        # if a symbolic reference exists, snag the last bit as our

        # branch name. eg “[master]“

        $status_string += “GIT [" + `

            $symbolicref.substring($symbolicref.LastIndexOf("/") +1) + "] “

       

        # grab the differences in this branch   

        $differences = (git diff-indexname-status HEAD)

       

        # use a regular expression to count up the differences.

        # M`t, A`t, and D`t refer to M {tab}, etc.

        $git_update_count = [regex]::matches($differences, “M`t”).count

        $git_create_count = [regex]::matches($differences, “A`t”).count

        $git_delete_count = [regex]::matches($differences, “D`t”).count

       

        # place those variables into our string.

        $status_string += “c:” + $git_create_count + `

            ” u:” + $git_update_count + `

            ” d:” + $git_delete_count + ” | “

    }

    else {

        # Not in a Git environment, must be PowerShell!

        $status_string = “PS “

    }

   

    # write out the status_string with the approprate color.

    # prompt is done!

    if ($status_string.StartsWith(“GIT”)) {

        Write-Host ($status_string + $(get-location) + “>”) `

            -nonewline -foregroundcolor yellow

    }

    else {

        Write-Host ($status_string + $(get-location) + “>”) `

            -nonewline -foregroundcolor green

    }

    return ” “

 }

The prompts are then color coded, so I can keep track of where I am (as if the really long prompt didn’t give it away).

Prompts

Now, with our prompts and our pathing setup to our Git directory, we have all the advantages of Git—in a stellar PowerShell package.

NOTE: I would like to point out that I use PortableGit, not the installed variety.  Since Git also moves back and forth across my Live Mesh, it seemed more reasonable to use the Portable version.  I don’t believe; however, there would be a difference as long as the \bin directory is referenced.

Setting up Aliases—The Easy Way

Brad Wilson’s implementation of find-to-set-alias is brillant.  Snag the script and get ready for aliasing the easy way.  I keep my most common tools aliased—Visual Studio, PowerShell ISE, and NotePad.  I mean, is there anything else?  (Well, yes, but I have Launchy for that).

Using find-to-set-alias is easy—provide a location, an executable, and an alias name:

find-to-set-alias ‘c:\program files*\Microsoft Visual Studio 9.0\Common7\IDE’ devenv.exe vs

find-to-set-alias ‘c:\windows\system32\WindowsPowerShell\v1.0\’ PowerShell_ISE.exe psise

find-to-set-alias ‘c:\program files*\Notepad2′ Notepad2.exe np

Helpers – Assembly-Info

After getting tired of loading up System.Reflection.Assembly everytime I wanted to see what version of a library I had, I came up with a quick script that dumps out the name of the assembly and the file version.

param(

  $file= $(throw “An assembly file name is required.”)

)

    $fullpath = (Get-Item $file).FullName

    $assembly = [System.Reflection.Assembly]::Loadfile($fullpath)

 

    # Get name, version and display the results

    $name = $assembly.GetName()

    $version =  $name.version

 

    “{0} [{1}]“ -f $name.name, $version

With this, running assembly-info NHibernate.dll returns:

NHibernate [2.1.0.4000]

Nifty.

Taking it a step further, I created a quick function in my profile called ‘aia’ or ‘assembly info all’ that runs assembly-info on all .dlls in the directory.

function aia {

    get-childitem | ?{ $_.extension -eq “.dll” } | %{ ai $_ }

}

Now, in that same directory, I get:

Antlr3.Runtime [3.1.0.39271]
Castle.Core [1.1.0.0]
Castle.DynamicProxy2 [2.1.0.0]
FluentNHibernate [0.1.0.0]
Iesi.Collections [1.0.1.0]
log4net [1.2.10.0]
Microsoft.Practices.ServiceLocation [1.0.0.0]
Moq [4.0.812.4]
MySql.Data [6.0.4.0]
NHibernate.ByteCode.Castle [2.1.0.4000]
NHibernate [2.1.0.4000]
System.Data.SQLite [1.0.60.0]
System.Web.DataVisualization.Design [3.5.0.0]
System.Web.DataVisualization [3.5.0.0]
xunit [1.1.0.1323]

Stellar.

Helpers – Visual Studio “Here”

This was created totally out of laziness.  I have already setup an alias to Visual Studio (‘vs’); however, I didn’t want to type “vs .\projectName.sln”.  That’s a lot.  I mean, look at it. 

So, a quick, and admitted dirty, method to either:

  1. Open the passed solution,
  2. If multiple .sln exist in the directory, open the first one,
  3. If only one .sln exists, open that one.

I don’t often have multiple solution files in the same directory, so #3 is where I wanted to end up.

function vsh {

    param ($param)

   

    if ($param -eq $NULL) {

        “A solution was not specified, opening the first one found.”

        $solutions = get-childitem | ?{ $_.extension -eq “.sln” }

    }

    else {

        “Opening {0} …” -f $param

        vs $param

        break

    }

    if ($solutions.count -gt 1) {

        “Opening {0} …” -f $solutions[0].Name

        vs $solutions[0].Name

    }

    else {

        “Opening {0} …” -f $solutions.Name

        vs $solutions.Name

    }

}

That’s about the gist of it.  The challenge (and fun part) is to keep looking for ways to imrpove common processes using Git.  As those opportunities arise, I’ll toss them out here. :)

UPDATE: The full source code (plus a few extras) for this article can be found here : http://codepaste.net/53a7z6

About these ads
  1. August 21, 2009 at 8:16 pm | #1

    Might want to check the curly-quotes in those code snippets.

  2. August 21, 2009 at 8:29 pm | #2

    Yeah, unfortunately WordPress doesn’t always dump out exactly what I send via BlogJet. Thanks for the heads up! Here’s an update: The full source is now out on codepaste.net: http://codepaste.net/53a7z6

  3. Riku
    October 20, 2009 at 9:43 am | #3

    Leaving out a few lines from your excellent profile script, I have this running with PowerShell 1.0, Console2, and Git (not portable). It seems “gitk” is a shell script (bash) and will not work out of the box with this solution.

    For WinXP (English) users it may be nice to know that the script goes to “C:\Documents and Settings\(Username)\My Documents\WindowsPowerShell\profile.ps1″.

    For all: To make it work with Console2, create a new tab in the “Console Settings” (Edit|Settings|Tabs). Point the “shell” field to your PowerShell executable. Then start the new tab (File|New tab) and enjoy!

    • October 20, 2009 at 9:54 am | #4

      @Riku-

      Thanks for the additional information. As an alternative to gitk, check out QGit (http://bit.ly/yJ3Fa). It works really well via portable and can be easily customized (I’ve just setup an alias).

Comments are closed.
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: