- Use Azure Bastion as a jump host for RDP and SSH - Tue, Apr 18 2023
- Azure Virtual Desktop: Getting started - Fri, Apr 14 2023
- Understanding Azure service accounts - Fri, Mar 31 2023
Windows systems administrators who’ve embraced Windows PowerShell have almost universally also adopted the Git source code management (SCM) technology. Git is free open-source software (FOSS) that does one thing and one thing well: tracks changes to source code files.
Even if you work in a team of one, you can still get a lot out of Git. If nothing else, distributed version control systems such as Git give you protected access to your source code from any computer. When I got into IT, the developers I worked with used centralized SCM tools such as Microsoft Visual SourceSafe (now Team Foundation Server). The weakness of centralized SCM solutions is that you had a single point of failure.
By contrast, with Git, all developers have a full copy of a tracked repository. Team members can pull changes from other team members’ repos and/or push changes to a central repo.
Enough preliminary—I want this to be a “quick and dirty” setup guide for those of you who knew you’d have to learn Git eventually but successfully put off the task until today. Let’s get started!
Installing Git for Windows
For starters, forget about mSysgit or the Posh-Git project—we finally have a full-featured Git client for Windows. You can download the software from either of the following websites:
I’ll walk you through the important installation dialog box choices and give you suggestions.
Particularly, Git for Windows includes useful extensions, as shown in the following dialog box. The Git Bash environment is particularly cool; it’s a Cygwin-like wrapper that allows you to run Linux Bash commands. (Let’s face it, Git was historically a Linux program. In fact, the inventor of Linux, Linus Torvalds, also invented Git.)
Git for Windows includes useful shell extensions
Speaking of Git Bash, I’d recommend that you integrate the Git environment with the Windows console. And, yes, in case you wondered, the integration applies to both Cmd.exe and PowerShell.exe.
Integrating Git Bash with the Windows console
One of the most important choices in Git for Windows is to allow the installer to add the Git tools to your system search path. This way, you can call Git from your PowerShell sessions no matter where your prompt is in the file system.
Make sure to add Git to your search path
You may or may not know that Windows and Linux use different line-end escape characters. Your safest bet here is to choose to checkout Windows and commit UNIX line endings. This makes your PowerShell script code easily portable between Windows and, say, OS X systems.
Specifying line endings
Setting up your development environment
I’m running Windows PowerShell v5 RTM on a Windows 8.1 workstation.
PS C:\Users\Tim> $PSVersionTable.PSVersion Major Minor Build Revision ----- ----- ----- -------- 5 0 10586 51
Let’s say that we plan to create a big function that will assemble common system configuration information for a given computer. Because we want to see our revision history, as well as make the code available to other developers, we’ll use Git to track our script files.
I created a folder named get-sysinfo inside my home folder, and a file named get-sysinfo.ps1 within the folder.
Open your new script file in the Windows PowerShell ISE and add the following code:
# Get installed .NET Frameworks Write-Host 'Installed .NET Framework Components' -ForegroundColor Yellow Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse | Get-ItemProperty -Name Version,Release -ErrorAction 0 | Where-Object { $_.PSChildName -match '^(?!S)\p{L}'} | Select-Object -Property @{N='.NET Component';E={$_.PSChildName}}, @{N='Version';E={$_.Version}} | Sort-Object -Property Version -Descending | Format-Table -AutoSize
We’re almost ready to instruct Git to start tracking our project.
Configuring Git
Git tracks source code changes by (a) creating a unique hash value for each commit, and (b) associating each commit with a user identity. Open a fresh, elevated PowerShell console and let’s identify ourselves to Git. Run the following commands, substituting your e-mail address and personal name:
git config –-global user.email “tim@4sysops.com” git config –-global user.name “Tim Warner”
Tracking changes with Git
Open a new elevated PowerShell prompt and use cd or Set-Location to switch to the Get-sysinfo folder. Next, run git init:
PS C:\Users\Tim\get-sysinfo> git init Initialized empty Git repository in C:/Users/Tim/get-sysinfo/.git/
Git creates the .git hidden directory to perform the metadata and change tracking. We run git status to see how our new repository looks now:
PS C:\Users\Tim\get-sysinfo> git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) get-sysinfo.ps1 nothing added to commit but untracked files present (use "git add" to track
What git status tells us is that we have one file in the folder (get-sysinfo.ps1), but at present the file isn’t tracked. Let’s use git add to change that situation, and then git status to verify:
PS C:\Users\Tim\get-sysinfo> git add .\get-sysinfo.ps1 PS C:\Users\Tim\get-sysinfo> git status On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: get-sysinfo.ps1 PS C:\Users\Tim\get-sysinfo>
Note that our script is tracked and staged for commit, but we still haven’t performed the commit that instructs Git to snapshot the file’s content. We use (as logic dictates) git commit for that. The -m switch is highly recommended because any comment we can include that describes the commit will be helpful to you and to other project developers. The “clean” message returned by git status tells me that our repo is up to date.
PS C:\Users\Tim\get-sysinfo> git commit -m "Added file to repository." [master (root-commit) d7f2307] Added file to repository. 1 file changed, 8 insertions(+) create mode 100644 get-sysinfo.ps1 PS C:\Users\Tim\get-sysinfo> git status On branch master nothing to commit, working directory clean PS C:\Users\Tim\get-sysinfo>
Comparing changes
Re-open the get-sysinfo.ps1 script and modify it into a simple function as shown below:
function Get-DotNetVersion { Clear-Host Write-Host 'Installed .NET Framework Components' -ForegroundColor Yellow Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse | Get-ItemProperty -Name Version,Release -ErrorAction 0 | Where-Object { $_.PSChildName -match '^(?!S)\p{L}'} | Select-Object -Property @{N='.NET Component';E={$_.PSChildName}}, @{N='Version';E={$_.Version}} | Sort-Object -Property Version -Descending | Format-Table -AutoSize } Get-DotNetVersion
Run git status and Git will inform you that the get-sysinfo.ps1 file has changed. No surprise there. We can run git diff HEAD to compare changes between the current file and the state of the file at last commit. Forgive the wonky color formatting in the Git console; we can customize that, of course, but we’ll need to cover that in a future article:
PS C:\Users\Tim\get-sysinfo> git diff head diff --git a/get-sysinfo.ps1 b/get-sysinfo.ps1 index f69865c..6d4b03f 100644 --- a/get-sysinfo.ps1 +++ b/get-sysinfo.ps1 @@ -1,8 +1,12 @@ -<U+FEFF># Get installed .NET Frameworks -Write-Host 'Installed .NET Framework Components' -ForegroundColor Yellow -Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse | -Get-ItemProperty -Name Version,Release -ErrorAction 0 | -Where-Object { $_.PSChildName -match '^(?!S)\p{L}'} | -Select-Object -Property @{N='.NET Component';E={$_.PSChildName}}, @{N='Version' ;E={$_.Version}} | -Sort-Object -Property Version -Descending | -Format-Table -AutoSize \ No newline at end of file +<U+FEFF>function Get-DotNetVersion +{ + Clear-Host + Write-Host 'Installed .NET Framework Components' -ForegroundColor Yellow + Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP' -Recurse | + Get-ItemProperty -Name Version,Release -ErrorAction 0 | + Where-Object { $_.PSChildName -match '^(?!S)\p{L}'} | + Select-Object -Property @{N='.NET Component';E={$_.PSChildName}}, @{N='Vers ion';E={$_.Version}} | + Sort-Object -Property Version -Descending | + Format-Table -AutoSize +} PS C:\Users\Tim\get-sysinfo>
To be sure, the previous output isn’t the easiest to parse. You should check out some of the myriad Git GUI front-ends to make file comparisons easier:
- Git Gui
- Atlassian Source Tree
- GitHub Desktop
Finally, we’ll add the file to our commit “stage” and make a second commit. The dot shortcut adds all files in the present working directory to the staged area:
git add . Git commit -m “Changed the static code into a function.”
Pushing our project to GitHub
We have plenty of cloud-based public Git repositories available to us (Atlassian Bitbucket springs to mind), but my favorite by far is GitHub. Go there and create a free user account. You can host as many public repositories as you want for free. If you need private repos, then you’ll have to pay for a site subscription.
From your GitHub home page, click New repository and deploy a new repo to host our get-sysinfo project.
Creating a new public Git repository
Do you see the highlighted options in the above screen capture? Normally it’s fine to let GitHub create preliminary documentation and whatnot in your public cloud repo. But, in this case, we’re going to push content from our local computer and we don’t want conflicts.
On the next page, you’ll see instructions for adding README and LICENSE files. We’re concerned with our repository .git URL; copy that to the clipboard to prepare ourselves for the next step.
Copying our repo URL
We run git remote add to add a remote repository. We can then run git remote -v to verify:
PS C:\Users\Tim\get-sysinfo> git remote add origin https://github.com/timothywarner/get-sysinfo.git PS C:\Users\Tim\get-sysinfo> git remote -v origin https://github.com/timothywarner/get-sysinfo.git (fetch) origin https://github.com/timothywarner/get-sysinfo.git (push) PS C:\Users\Tim\get-sysinfo>
We use git push to upload our full local repository to the empty one waiting in the GitHub cloud:
PS C:\Users\Tim\get-sysinfo> git push origin master Username for 'https://github.com': tim@4sysops.com Password for 'https://tim@4sysops.com@github.com': Counting objects: 6, done. Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 863 bytes | 0 bytes/s, done. Total 6 (delta 1), reused 0 (delta 0) To https://github.com/timothywarner/get-sysinfo.git * [new branch] master -> master PS C:\Users\Tim\get-sysinfo>
We’ll finish by going back to GitHub and refreshing our repo page. Done and done!
Now our repo lives in the cloud and on our local computer.
Next steps
If you’re the curious sort like I am, then you probably have all sorts of questions:
- How can I download the GitHub repo to another computer?
- If I make changes directly on GitHub, how can I synchronize those changes with my local repo (and vice versa?)
- How do I remove Git revision tracking for a file?
- How do branches work?
- What’s a pull request?
Those are outstanding questions because we literally barely scratched the surface of what’s possible with Git. Let us know in the comments what coverage you’d like to see from us at 4sysops in the future.
In the meantime, I’ll leave you with a few key documentation resources to help you on your Git/PowerShell journey:
- Git official documentation
- GitHub official documentation
- Code School Try Git! Interactive course (free)