It has been a while that I have been working with GIT, mostly on github and I noticed I kept returning to this one note in a text file that used as an external memory when ever I needed to clone a new Github repo and start working on it. So about time to transform this into a sharable blog post. Especially working on a windows system can be tricky to get it working how it should. (for some reason some eployers keep insisting me to work on windows ;-) )
I will dicuss the following things here:
- What is Git
- Setup Git for Github
- Additional tools
- Generation of SSH keys
- Basic operations and commands
- Best practises
- Ammend your PRs
- If all else fails …Fuckit!
- The Better Best practises
- Branch you work
- Working with branches
- For the Git Pros!
What is Git
straight from Wikipeadia:
Git is a distributed version-control system for tracking changes in source code during software development. It is designed for coordinating work among programmers, but it can be used to track changes in any set of files. Its goals include speed, data integrity, and support for distributed, non-linear workflows.
For me since I have been tracking, storing ans sharing several project on Github it is the de-facto standard to sync and keep versions for my projects.
Setup Git for Github
I install the following:
- Chocolatey - a Windows package manager
- git.install - Git for Windows
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force
iwr https://chocolatey.org/install.ps1 -UseBasicParsing | iex
choco install git.install -y
Aditional tools
Just to improve your working experience a little I also install another Console Emulator which work nicely with multiple tabs etcetera. And to finish it of I use some customisation to get my
I install the following:
- ConEmu - Terminal Emulator for Windows
- posh-git - PowerShell functions for working with Git
choco install conemu -y
Install-PackageProvider NuGet -MinimumVersion '2.8.5.201' -Force
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module -Name 'posh-git'
For detail on how to customise your prompt proper read this https://hodgkins.io/ultimate-powershell-prompt-and-git-setup.
Generation of SSH keys
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\Program Files\Git\usr\bin", "Machine")
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\Program Files\Git\bin", "Machine")
mkdir $env:USERPROFILE\.ssh
ssh-keygen -t rsa-sha2-512 -b 4096 -C "[email protected]" -f $env:USERPROFILE\.ssh\id_rsa
Get-Content $env:USERPROFILE\.ssh\id_rsa.pub | clip
If you have executed the above you now have your key ready to insert into Github in your clipboard. Open up your GitHub settings and choose ‘SSH and GPG’ keys on the left.
Now you can start using the Key from you some usefull comands:
Get-Service -Name ssh-agent | Set-Service -StartupType Manual
Start-Service ssh-agent
Add-SshKey $env:USERPROFILE\.ssh\id_rsa
# List ssh keys
ssh-add -l
# Remove all ssh keys
ssh-add -D
# Test ssh connection to GitHub
ssh -T [email protected]
You might want to avoid a chatty ssh login (banners, disclaimers etc.) on a server like this:
New-Item -Path $env:USERPROFILE\.ssh\ -Name "configs" -ItemType "file" -Value "Host git.host_name.tld`r`nLogLevel QUIET"
Basic operations and commands
Initial Setup
Edit the global Global Configuration file
git config --global user.name "Firstname Lastname"
git config --global user.email [email protected]
git config --global credential.helper cache
git config --global push.default matching
or use <git config –global -e> and edit the file manualy
To donwload a repo and make the settings correct
git clone [email protected]:user_name/repo_name.git
cd repo_name
git remote add upstream [email protected]:original_repo/repo_name.git
git remote -v
Rebase before making changes
When useful: You need to update your clone/fork BEFORE making changes, or AFTER committing changes to master to make sure you are working in the latest version.
# Grabs the latest changes from the upstream master
git fetch upstream master
# Puts your changed work on top of the previously fetched work
git rebase upstream/master
# Force pushes the change to your own GitHub repo
git push
( Or Fuckit if you feel lazy )
Best practises
Amend your PRs
Commit an additional change (before commit is merged) – only works if you want to add all files in your local repos When useful: You have just sent a pull request, but want to commit an additional pull request (in case you forgot something, or the merger points out another detail or error).
# Add all changed files
git add -A
# Check what you added if needed
git status
# Commit the changes to existing commit, don't change commit name.
git commit --amend --no-edit
# Force push to your repo
git push -f
Keep in mind that the default behaviour when amending is that you actualy add it also to any Pull Request that you amend the change to. This is usefull of course when ever there is a 4-eyes review with some minor changes requested from the reviewer. Just amend and the chnages are squashed into the already existing PR.
If all else fails …Fuckit!
You can create aliasses with the following commands
git config --global alias.hist "log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short"
git config --global alias.fuckit ‘!git fetch upstream && git checkout master && git reset --hard upstream/master && git push origin master’.
These are just examples but I do often start with working on a repo bu hard flushing any diffs between my for fork & localmaster and the original upstream. Just use and you are ready to start working from hete on.
The Better Best practises
The above “Best practises” work fine especially when working with small teams and low level of commits. But especially when working with a large team and high frequency of changes especialy on the same files. Things can get tricky and a git push -f
can make things worse and create confilict for you fellow engeneers or developers. Because you actually can force push / flush some one else his or her changes.
Instead use --force-with-lease
if you have to. It is hardly a perfect solution, but it is preferable to its blind, wrecking ball cousin. Using git push --force-with-lease
will check that the remote branch is in the state that we expect before pushing.
Create some aliases if you like to prevent you having to type such a long command often
git config --global alias.fpush ‘push --force-with-lease’
git config --global alias.fp ‘push --force-with-lease’
git config --global alias.pf ‘push --force-with-lease’
Branch you work
Using branches has 2 big advantages. If you work proper with branches you can avoid having to forced pushing your code. The other advantage is of course that you can work on seperate issues and features at the same time and also have clean working master branch where you can fetch the latest chnages form the upstream into. This way you can always start to work clean on the next issue without interferance with a ongoing improvement cycle that otherwise first needs to be finished.
# checkout and create a branch
git checkout -b story_4134
# Same as
git branch story_4134 | git checkout story_4134
# You can work on the branch
git commit -a -m '[story_4134_1] Create new thing your working on'
Now comes the interesting part you get interupted and need to work on a hotfix:
# checkout back to master
git checkout master
# collect latest change the issue might just be in something just changed
git fetch upstream master
# start wokring on your hotfix again in a branch
git checkout -b hotfix_20200309_1
# You found the issue updated files now commit it and push
git commit -a -m '[HF_20200309_1] Fix a broken thing'
git push
# now move back to the master and merge the hotfix and remove the branch
git checkout master
git merge hotfix_20200309_1
git branch -d hotfix_20200309_1
Form here you can continue to work on you improvement:
git checkout story_4134
git commit -a -m '[story_4134_2] Create new thing your working on '
For the Git PROs
Resolving Conflicts
Copy paste code to desktop as backup, otherwise code is lost after resetting.
# Fetch the latest changes from the upstream master
git fetch upstream master
# Hard reset
git reset --hard upstream/master
# Force push to your repo
git push --force-with-lease
it can happen that you have some files in your clone, but in the master they’re gone which results in commits that won’t disappear. What you can do is stash the commits and clear them. (only use this when there is no other solution) Do these steps to get them removed
git add .
git stash
git stash clear
git pull -r upstream master
git push --force-with-lease
Polish your CLI
Like mentioned before a good alternate resource: https://hodgkins.io/ultimate-powershell-prompt-and-git-setup.
# Creates profile if doesn't exist then edits it
if (!(Test-Path -Path $PROFILE)){ New-Item -Path $PROFILE -ItemType File } ; ise $PROFILE
I like using the following config :
# Import module from previous step
Import-Module -Name posh-git
function Test-Administrator {
$user = [Security.Principal.WindowsIdentity]::GetCurrent();
(New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}
function prompt {
$realLASTEXITCODE = $LASTEXITCODE
if (Test-Administrator) { # Use different username if elevated
Write-Host "(Elevated) " -NoNewline -ForegroundColor White
}
Write-Host "$ENV:USERNAME@" -NoNewline -ForegroundColor DarkYellow
Write-Host "$ENV:COMPUTERNAME" -NoNewline -ForegroundColor Magenta
if ($s -ne $null) { # color for PSSessions
Write-Host " (`$s: " -NoNewline -ForegroundColor DarkGray
Write-Host "$($s.Name)" -NoNewline -ForegroundColor Yellow
Write-Host ") " -NoNewline -ForegroundColor DarkGray
}
Write-Host " : " -NoNewline -ForegroundColor DarkGray
Write-Host $($(Get-Location) -replace ($env:USERPROFILE).Replace('\','\\'), "~") -NoNewline -ForegroundColor Blue
Write-Host " : " -NoNewline -ForegroundColor DarkGray
Write-Host (Get-Date -Format G) -NoNewline -ForegroundColor DarkMagenta
Write-Host " : " -NoNewline -ForegroundColor DarkGray
$global:LASTEXITCODE = $realLASTEXITCODE
Write-VcsStatus
Write-Host ""
return "> "
}