A Git Gud Guide
This guide is targeted towards people who have already used
git and have some basic knowledge of how it works and which commands exists and what they do. The main purpose is to provide an overview into the good practices behind the OpenSource community.
First things first. This guide assumes some general/basic knowledge regarding
git. It was created by Linus Torvalds (creator of the Linux Kernel) and the source code is available here.
Documentation and other (more specific) guides can be found everywhere on the internet but mainly on Git SCM.
For starters Git is a “version control” tool. For the purpose of this guide I hope you know what this means. And more importantly I hope you understand why it’s sensible to use Git for software projects (and with the introduction of Git LargeFileStorage, design/media projects).
What Git basically allows you to do is create “snapshots” of your project (in a smart way, not by redundantly keeping the full files) by saving a “tree” of your “changes”.
Before going any further I’ll have to ask you to check your git version and make sure you have an up to date version. (type
git version in your terminal). Another important aspect I recommend to everyone is using Git from your terminal for most work. There are many GUI clients and even IDEs come with Git capabilities but more than often these are cumbersome and lead to annoying and rage inducing moments. What I advise is the following:
- Have a terminal open at all times
- Use Git from the terminal for everything
- Except rebasing, for that I use VSCodes highlighting with manual rebasing
Pick a provider
- Owned now by Microsoft (this proved to be productive for Github’s evolution)
- Free unlimited private and public repos
- Plenty of integrations trough the “Apps Marketplace”
- Good interface for managing merges, projects, and pretty much everything
- Nice GUI
- Big community and social aspects
- By far the most popular of all three
- “Gists” hosting (kinda like PasteBin)
- GitHub pages and Wikis, allows you to create static websites for your projects using Jekyll and even hosting a personal website under
- Use to be better than GitHub simply because of the free unlimited private repos, but now GitHub has that too
- Better projects organisation using folders and groups
- Amazing CI integration
- Can create “private” projects viewable only by other GitLab users (not sure why you’d do this)
- Can create Kubernetes clusters for your projects
- Pretty much better than GitHub in terms of GUI and what it offers, but it lacks the social aspects
- I mean? It’s ok.
It’s not a life or death choice to pick a provider, you can actually use how many you wish. This can be achieved by setting up multiple remotes. For example:
# this can be your main remote git remote add origin "github_project_uri" # this can your other remotes git remote add gitlab "gitlab_project_uri" git remote add bitbucket "bitbucket_project_uri" # now after commiting your files, you can do # this to push to your GitHub remote git push # and then, the following for GitLab and BitBucket git push gitlab master git push bitbucket master
You can create a file
~/.gitconfig. I will provide my own configuration below:
[alias] co = checkout ci = commit st = status br = branch hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short type = cat-file -t dump = cat-file -p undo = reset --soft HEAD^ [core] autocrlf = false safecrlf = true [push] default = simple [branch] autosetuprebase = always [color] ui = auto branch = auto diff = auto status = auto [color "branch"] current = yellow reverse local = yellow remote = green [color "diff"] meta = yellow bold frag = magenta bold old = red bold new = green bold [color "status"] added = yellow changed = green untracked = cyan [user] email = [email protected] name = Jon DOe signingkey = XXXXXXXX [filter "lfs"] clean = git-lfs clean -- %f smudge = git-lfs smudge -- %f process = git-lfs filter-process required = true
signingkey is optional if you want your commits to be signed by your GPG/PGP key in order for other to know and trust the source of your commits. We’ll discuss this later.
Also I have some shell aliases for git. You can come up with other names that are more natural for you.
# GIT alias gpush='git push' alias gpull='git pull' alias gstat='git status' alias gdiff='git-diff' alias glog='git log' alias gls='git-ls-files' alias ggraph='git log --pretty=format:"%h %s" --graph' alias gitc='git commit -S -m' alias gitp='git commit --amend -C HEAD'
You probably used Git with HTTPS remotes at some point, or maybe you still are. There are also SSH remotes. What this means is that you don’t have to insert your username or password every single time you want to do something privileged. With SSH you simply use your
ssh-agent to provide authentication via public-private key. Discussing this in depth would go beyond the guides propose. Follow these instructions here or search for other.
I usually start my project on the website of the provider before creating any files locally. For the sake of keeping this guide more focused on Git than GitHub/GitLab/Bitbucket/etc, I will use GitHub as an example.
Name & description
After this point you’ll be asked to name your project (pick something nice), I usually see a mix of preference between the naming style. I don’t believe there is a right one, but just keep in mind people will use the name to clone and find your project, so keep it short, simple, nice and relevant. Use the project description for a more detailed explanation.
I like to associate my project naming convention with the language syntax convention, but most of the time I just end up using
lowercase-with-hypens or simply
lowercase single word.
Another thing you’ll be asked is if you want the repo to be private or public.
Note that all these things can be later changed, including the name of the repo. For example if you had
github.com/username/som-project you can rename it in the repo’s settings to
github.com/username/awesome-project or even something completely different. GitHub will keep the previous URL pointing to your newly name repo (this will change if you create another repo with the initial name).
- Do people care? Maybe.
- Do companies care? Maybe.
- Should you put a LICENSE on your project? Yes.
A LICENSE tells the people who want to use/modify/distribute/etc your project how to handle it and which steps are necessary. There many OpenSource LICENSEs out there, which range from permissive to restrictive.
If you aren’t sure which license to pick for a specific project, use the following website: Choose a License.
Some other “interesting” licenses worth mentioning:
I find it very important to keep a nice and clean README file. Whenever somebody visits your repository this will be the first thing they’ll see. First impressions matter. Sometimes I avoid potentially interesting projects due to the lack of a README and documentation.
If your project has no README then for somebody who is not familiar with your project, all they can see is a bunch of files and nothing else.
A good README should provide the following information (not necessarily in this order):
- The reason behind your project, and what it “brings to the table”
- An introduction and description
- Installation instructions
- Download links
- Usage instructions
- Contribution guides
- Features list, TODO list
If you are unsure how to write your README check out some popular projects on GitHub.
README files come in all flavours (formats). The most common I believe is “MarkDown” (if you don’t know what Markdown is) but there are other version. I recommend avoiding TXT, and even sticking to Markdown as it’s supported everywhere (all my blog posts are written in Markdown :) ).
If you browsed OpenSource projects before you might have seen “badges” on people’s READMEs.
It’s usually nice to have badges to help improve the image of your project, badges can include different information such as: build status, code health, testing coverage, etc.
Try NOT to over encumber your README file with badges as it may end up looking tacky. The example above could do without the Ethereum address and hits counter.
Most services which provide badges will give you the “code” you need to insert into your README file based on it’s format. If you want to know more or generate your own badges, check this out: Shields.io.
When creating your repo on GitHub you’ll be asked to select a programming language for the
.gitignore file. They have some very good templates that require little to no changes.
If you don’t know by now, the
.gitignore file (or files, you can have multiple scattered around your project) tells git which files to ignore when
git add .... For example you want to ignore common OS misc files (.DS_Store), you want to ignore caches (pycache), binary files (something.o, main.pyc), config files (_config.json) and other misc files/directories.
The gitignore pattern format can be used to ignore multiple files at once
*.png will tell git to not commit any file ending in
.png. A more in depth explanation of the patter can be found here.
Now you should be welcomed by a screen like this (assuming you didn’t create any README, LICENSE or Gitignore file from within the web GUI, if you did you will have the project files view but can still obtain the remote URI, same steps apply below):
At this point you should copy the remote URI. If you decided to improve your life and use SSH then copy (
[email protected]:thee-engineer/_remove_me_later.git) if you still want the painful HTTPS (
With the remote URI in your clipboard, go to your terminal and type:
git clone [email protected]:thee-engineer/_remove_me_later.git cd _remove_me_later git status
And should see the following (or a single Initial commit containing the files generated above by the web interface).
On branch master No commits yet nothing to commit (create/copy files and use "git add" to track)
The things they don’t want you to know
A not so popular “meta-git file” is the
.gitattriubtes file. It allows some interesting configuration towards how files are treated and interpreted (Git Attributes, more in depth documentation).
For example you can tell the git diff algorithm how to treat different file types based on their extension.
*.docx diff=word *.png diff=exif
You can tell git which files to commit using LFS.
*.pdf filter=lfs diff=lfs merge=lfs -text
You can tell websites like GitHub which languages to consider different extensions as.
GitHub allows the creation of a
.github directory in which you can include 2 interesting and useful files.
When someone will open a new issue on your project, they will get whatever you wrote inside
.github/ISSUE_TEMPLATE.md as their starting template.
Having a template like this helps with managing and sorting issues on a large project.
This is the template I use:
<!--- Provide a general summary of the issue in the Title above --> ## Expected Behavior <!--- If you're describing a bug, tell us what should happen --> <!--- If you're suggesting a change/improvement, tell us how it should work --> ## Current Behavior <!--- If describing a bug, tell us what happens instead of the expected behavior --> <!--- If suggesting a change/improvement, explain the difference from current behavior --> ## Possible Solution <!--- Not obligatory, but suggest a fix/reason for the bug, --> <!--- or ideas how to implement the addition or change --> ## Steps to Reproduce (for bugs) <!--- Provide a link to a live example, or an unambiguous set of steps to --> <!--- reproduce this bug. Include code to reproduce, if relevant --> 1. 2. 3. 4. ## Context <!--- How has this issue affected you? What are you trying to accomplish? --> <!--- Providing context helps us come up with a solution that is most useful in the real world --> ## Your Environment <!--- Include as many relevant details about the environment you experienced the bug in --> * Version used: * Browser Name and version: * Operating System and version (desktop or mobile): * Link to your project:
Is the other file, which as the name says a template for Pull Requests. Below is the template I use:
<!--- Provide a general summary of your changes in the Title above --> ## Description <!--- Describe your changes in detail --> ## Motivation and Context <!--- Why is this change required? What problem does it solve? --> <!--- If it fixes an open issue, please link to the issue here. --> ## How Has This Been Tested? <!--- Please describe in detail how you tested your changes. --> <!--- Include details of your testing environment, tests ran to see how --> <!--- your change affects other areas of the code, etc. --> ## Screenshots (if appropriate): ## Types of changes <!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) ## Checklist: <!--- Go over all the following points, and put an `x` in all the boxes that apply. --> <!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! --> - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly.
This will mainly depend on the language and software you’re using, but a general folder I recommend people to have is
/docs/. GitHub will read
/docs/README.md if you don’t have a
/README.md. I usually put all documentation and related assets inside
/docs/. Another nice aspect of the
/docs/ directory is the GithubPages support. You can place your
.md (or web files) inside
/docs/ and then enable GithubPages on
/docs/ directory. Allowing you to create a nice project docs website.
When creating a repo on GitHub, it will auto-create some default Issues Labels (most of which are very good to have). You should have a look over them to get an idea of what might be missing or what might not be needed. I find colours are quite important (red for bugs, blue for enhancements, yellow for todo, (ノಠ益ಠ)ノ彡┻━┻ for when you had enough).
A very important and widely used issue label is
help wanted (darkish green). It will allow people to search for projects (on your providers website or third party websites) which require help with different things. This is one of the best things in the OpenSource community, use it.
Milestones allow you to sort/organise/group your issues into milestones. Telling your users and contributors what to expect and where the project is heading. A milestone can be a planned version of your software, or a very big feature which consists of multiple smaller blocks. Milestones can even have deadlines.
Do you like Kanban boards? Then this is for you. It helps you organise message, issues and pretty much anything into separate board. This includes some level of automation for simple Kanban layouts.
You can assign “releases” (behind the scenes tags will be used) to mark a certain checkpoint in your git history as a Release or Pre-Release. This tells people that the marked version should work as a binary. Releases are normally accompanied by binaries.
A good versioning scheme is
2 represents the major version and
1 the minor version. Some people prefer a
v2.1.3 but frankly, tomayto, tomahto.
CI - Continuous Integration
CI allows you to setup an automatic pipeline where every time (or as often or not you wish it to be) you can have your code executed by a remote machine under certain environments. A good provider of such service is Travis CI - Test and Deploy with Confidence. They will have tutorials on setting up different configuration depending on the language and software you are using.
For example you might be working on a macOS machine on a Go project. You have certain environment settings which might influence the execution and compilation of your program. Distributing this without testing under foreign conditions might result in Linux/Windows users not being able to execute your program.
CI helps you avoid this by customising the pipeline to the point where your code gets tested after being published. The code can be tested under a clean environment, under different software version (eg testing Go 1.6 all the way to the latest version), testing your program to see if it compiles and runs under other operating systems.
Below is an example of my Travis-CI config file for Cryptor.
language: go os: - linux - osx matrix: allow_failures: - os: osx go: - tip before_install: - go get github.com/mattn/goveralls - go get github.com/wadey/gocovmerge - go get -v ./... script: - make testall - cp build/report.out coverage.txt after_success: - $GOPATH/bin/goveralls -coverprofile=build/report.out -service=travis-ci - bash <(curl -s https://codecov.io/bash) - make clean
Each section of this config file is better documented on the Travis-CI website. What you can take from here is the fact that my code has some prerequisites which are installed before executing the test-suite (on the latest Go version, under Linux and macOS) and after a successful test, the code goes to a coverage third party service.
This is subjective and it’s up to you. You decide when it’s the appropriate time and moment to create a new commit. This could mean:
- Committing every time you implement something new
- Committing each component individually
- Committing a days worth of work
- Committing every N amount of time
What I find nice is not pushing all the time after each and every commit especially if you are about to create a couple more commits.
Try to keep your commit messages clean, relevant to the changes made. Start your messages with an uppercase letter and don’t be afraid to use multiple sentences but beware to limit your subject to 50 chars and wrap your body at 72 chars. What this means is you can use multiple commit “messages” for a single commit.
Try and keep your subjects in one sentence and DO NOT end it with a period.
git commit -m "This is the subject" -m "Followed by the body/description of this commit"
Merge branch 'prototype` Revert "Remove old package" Merge pull request #42 from example/master Add support for third party service
A more well structured and in-depth guide to commit etiquette: How to Write a Git Commit Message.