Git Updates for Windows, PowerShell and WSL Ubuntu

Git released new versions of their version control software last month and documented here is my experience installing version 2.18.0 64-bit Git for Windows and version 2.18.0 built from the source on WSL Ubuntu.

After installing version 2.18.0 for Windows, I was puzzled when all of the files were showing as modified directly after cloning a repository. When files are showing as modified, this can sometimes be caused by different file line endings such as LF or CRLF. Since I use git across Linux, OS X and Windows, I always configure with git config core.autocrlf input so there is no line ending conversion when files are checked out. When committing files, CRLF will be converted to LF. For cross-platform projects, this is the recommended setting on Unix. Line ending differences were not an issue and I suspect either file permission changes or the cache rebuild when upgrading the new Windows Git was what caused my issue. Here is what I did to fix it.

First, I used git rm –cached to unstage the files. Then I used git reset --hard to write both the index and working directory from git’s data.

# Unstage / remove all files from the index
git rm --cached -r .

# Discard all uncommitted changes
git reset --hard

To provide some context, below are relevant screen captures from my Git for Windows installation setup.

Git 2.18.0 Setup | Adjusting your PATH environment
Adjusting your PATH environment to Use Git from the Windows Command Prompt
Git 2.18.0 Setup | Choosing HTTPS transport backend
Choosing HTTPS transport backend to Use the OpenSSL library
Git 2.18.0 Setup | Configure the line ending conversion
Configure the line ending conversion to checkout as-is, commit UNIX-style line endings
Git 2.18.0 Setup | Configure the terminal emulator to use with Git Bash
Configure terminal emulator to use with Git Bash > Use MinTTY
Git 2.18.0 Setup | Configure extra options
Configure extra options
  • Here are some commands to view various configuration settings.
    git config --list --show-origin (list configuration files and settings)
    git config --list --local (current repository)
    git config --list --global
    git config --list --system

PowerShell

Prerequisite, Git for Windows with the PATH environment set to Use Git from the Windows Command Prompt.

I recommend installing the posh-git PowerShell environment for Git. This integrates Git for Windows with PowerShell to provide tab-completion and a modified prompt to indicate what branch you are in and other useful info. For installation instructions and more, view the projects README.md

SSH

To connect to your Git repos with SSH, An OpenSSH client is installed by default with Windows 10 version 1803 (Windows 10 April 2018 Update). This makes it possibe to now use SSH commands in PowerShell or the Comand prompt without the need for third party SSH Agent plugins.

Windows 10 Settings | SSH Client
Settings | Manage Optional Features | SSH Client

To see all of the available client tools, inspect the C:\Windows\System32\OpenSSH installation folder.

  • OpenSSH
    • scp.exe
    • sftp.exe
    • sftp-server.exe
    • ssh.exe
    • ssh-add.exe
    • ssh-agent.exe
    • sshd.exe
    • sshd_config_default
    • ssh-keygen.exe
    • ssh-keyscan.exe
    • ssh-shellhost.exe

Ubuntu

These steps are done from within the WSL Ubuntu terminal that is available from the Windows Store.

# get the installed version
git --version

For me, on a recently updated Ubuntu 16.04, the Git version was 2.7.4, which is from March of 2016, over two years ago. To install the latest version, we need to build Git from the source code.

Install dependencies to build from the source.

sudu apt get-update

sudo apt -y install make libssl-dev libghc-zlib-dev libcurl4-gnutls-dev libexpat1-dev gettext unzip

Clone or download the latest stable release tag from github.com/git/git/tree/master, for example, version 2.18.0: github.com/git/git/tree/v2.18.0.

git clone https://github.com/git/git.git git-source

Compile and install git from the source. e.g.,

cd git-source

make prefix=/usr/local all

sudo make prefix=/usr/local install

Verify

git --version

# optional:
# remove the source files after installation
cd ../
rm -rf git-source

If you need to convert line endings from CRLF to LF for an entire project, in Cygwin, use dos2unix.

Convert line endings from CRLF to LF for all files recursively from the current directory.

find ./ -type f -exec dos2unix {} \;

Customization / Modules

PowerShell modules can enhance functionality and the user interface. In this example, the profile is updated to use git over an SSH connection, readline settings for a bash like experience, custom color output and a custom prompt.

PowerShell Profile

If there is not an existing profile for the current logged in user, create one with the New-Item cmdlet. To check if a profile exists, use Test-Path $profile. $profile is an environmental variable for the path to the CurrentUserCurrentHost profile.

Test-Path $profile

If the test returns false, use the New-Item cmdlet to create the profile script. For example:

New-Item $profile -ItemType File -Force

There should now be a WindowsPowerShell\Microsoft.PowerShell_profile.ps1 file in the Documents folder.

My Customized PowerShell
PowerShell screenshot with the updated profile loaded using the ls command alias to list files.

Custom Prompt

Add these two functions to the top of the Microsoft.PowerShell_profile.ps1 script. The first function checks to see if PowerShell is running with Administrator privileges. This check is used to add (Elevated) to the prompt as needed. The second function, aptly named prompt modifies it’s output.

Microsoft.PowerShell_profile.ps1
function Test-Administrator {
    $user = [Security.Principal.WindowsIdentity]::GetCurrent();
    (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}

function prompt {
    # https://github.com/dahlbyk/posh-git/wiki/Customizing-Your-PowerShell-Prompt
    $origLastExitCode = $LastExitCode
    Write-VcsStatus

    if (Test-Administrator) {  # if elevated
        Write-Host "(Elevated) " -NoNewline -ForegroundColor White
    }

    Write-Host "$env:USERNAME@" -NoNewline -ForegroundColor DarkYellow
    Write-Host "$env:COMPUTERNAME" -NoNewline -ForegroundColor Magenta
    Write-Host ": " -NoNewline -ForegroundColor DarkGray

    $curPath = $ExecutionContext.SessionState.Path.CurrentLocation.Path
    if ($curPath.ToLower().StartsWith($Home.ToLower()))
    {
        $curPath = "~" + $curPath.SubString($Home.Length)
    }

    Write-Host $curPath -NoNewline -ForegroundColor Green

    $LastExitCode = $origLastExitCode
    "`n$('>' * ($nestedPromptLevel + 1)) "
}

PSReadline

Next, Import the PSReadline module that is included with PowerShell 5.x and set some configuration options.

Microsoft.PowerShell_profile.ps1
Import-Module PSReadLine

Set-PSReadLineOption -HistoryNoDuplicates
Set-PSReadLineOption -HistorySearchCursorMovesToEnd
Set-PSReadLineOption -HistorySaveStyle SaveIncrementally
Set-PSReadLineOption -MaximumHistoryCount 4000
# history substring search
Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward

# Tab completion
Set-PSReadlineKeyHandler -Chord 'Shift+Tab' -Function Complete
Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete

SSH Agent

We will use Mark Embling’s ssh-agent-utils Powershell script with functions for starting and managing ssh-agent. Download the ssh-agent-utils.ps1 Gist and place the script into the WindowsPowerShell folder for current logged in user, for example, %UserProfile%\Documents\WindowsPowerShell. In this example, both Microsoft.PowerShell_profile.ps1 and ssh-agent-utils.ps1 should be in the same WindowsPowerShell folder.

Install these modules into the default PSModulePath for the current logged in user, for example, %UserProfile%\Documents\WindowsPowerShell\Modules. PowerShellGet is required, which is included in Windows 10 and WMF 5.

posh-git

The posh-git module integrates Git and PowerShell.

Install-Module posh-git -Scope CurrentUser
  • Check the prerequisites in the posh-git repository to make sure Git is properly configured for use.

Get-ChildItemColor

The Get-ChildItemColor module adds colors to the output of Get-ChildItem cmdlet.

Install-Module Get-ChildItemColor -Scope CurrentUser

Finally, import and setup the remaining modules and load the SSH agent utilities.

Microsoft.PowerShell_profile.ps1
Import-Module Get-ChildItemColor

Set-Alias l Get-ChildItemColor -option AllScope
Set-Alias ls Get-ChildItemColorFormatWide -option AllScope

Import-Module posh-git

$global:GitPromptSettings.BeforeText = '['
$global:GitPromptSettings.AfterText  = '] '

# Update path for SSH (Loaded in PowerShell Profile)
$env:path += ";" + (Get-Item "Env:ProgramFiles").Value + "\Git\bin"
$env:path += ";" + (Get-Item "Env:ProgramFiles").Value + "\Git\usr\bin"

# Load SSH agent utils
. (Resolve-Path ~/Documents/WindowsPowershell/ssh-agent-utils.ps1)

Pop-Location

Add-SshKey

Folders and Files

Here is a tree view of the folders, ssh-agent-utility and profile scripts used in the examples.

  • Documents
    • WindowsPowerShell
      • Modules
        • Get-ChildItemColor
        • posh-git
      • Microsoft.PowerShell_profile.ps1
      • ssh-agent-utils.ps1
Source Code

Resources

Windows PowerShell

A collection of Windows PowerShell resources

Customization / Modules

PowerShell modules can enhance functionality and the user interface. In this example, the profile is updated to use git over an SSH connection, readline settings for a bash like experience, custom color output and a custom prompt.

My Customized PowerShell

Execution Policy

This command sets the PowerShell execution policy.

If you encounter an error such as …

{script path} cannot be loaded.
The file {script path} is not digitally signed.
You cannot run this script on the current system.
For more information about running scripts and setting execution policy,
see about_Execution_Policies at
http://go.microsoft.com/fwlink/?LinkID=135170.

You can set a Bypass execution policy for the current session.

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

Menu Example

This PowerShell script contains a menu to execute various tasks using functions.

UtilityMenuExample.ps1
function ListProcess
{
    Get-Process | Group-Object Company | Sort-Object Count -Descending
}

function ListEnvVars
{
    Get-ChildItem env:
}

function ListEventLog
{
    Get-EventLog -List
}

function Cleanup
{
    Write-Host "Delete files from $env:temp older than 24 hours"
    Get-ChildItem -path $env:temp | where {$_.Lastwritetime -lt (date).addhours(-24)} | remove-item
    <# Clear-RecycleBin #>
    $Shell = New-Object -ComObject Shell.Application
    $RecBin = $Shell.Namespace(0xA)
    $RecBin.Items() | %{Remove-Item $_.Path -Recurse -Confirm:$false}
}

function ShowMenu
{
     param (
           [string]$Title = 'Menu'
     )
     Write-Host "====== $env:USERPROFILE - $Title ======="

     Write-Host "1: List Running Processes"
     Write-Host "2: List Environment Variables"
     Write-Host "3: List Event Log"
     Write-Host "4: Clean Temp and Recycle Bin"
     Write-Host "q: quit"
}

do
{
     ShowMenu
     $input = Read-Host "Please make a selection"
     switch ($input)
     {
        '1' {
            Clear-Host
            ListProcess
        }
        '2' {
            Clear-Host
            ListEnvVars
        }
        '3' {
            Clear-Host
            ListEventLog
        }
        '4' {
            Clear-Host
            Cleanup
        }
        'q' {
            return
        }
     }
     pause
}
until ($input -eq 'q')

Compress-Archive

This example creates a zip file of the Documents folder with a datetime string in the zip filename.

Compress-Archive "$env:USERPROFILE\Documents" "$env:USERPROFILE\Documents_$(get-date -f yyyyMMdd'T'HHmmss).zip"

Setting System Environment Variables

This PowerShell script accepts parameters for setting system environment variables for Java development in Windows.

java.ps1

Resources