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
Just to improve your working experience a little I also install another Console Emulator
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 '184.108.40.206' -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]
Basic operations and commands
Edit the global Global Configuration file
git config --global user.name "Firtname Lastname" git config --global user.email [email protected] git config --global credential.helper cache git config --global push.default matching
To donwload a repo and make the settings correct
git clone https://github.com/user.name/repo_name.git cd repo_name git remote add upstream https://github.com/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 )
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.
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.
--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
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