Getting started with git
This is just a list of useful commands and practices I learned over time while using git.
Basic git workflow
The following chapters are the simple commands to get you started.
Clone a repository
Create a local clone:
1git clone URI
Git supports different protocols, typically you use one of the below:
1# clone for GitLab, GitHub etc. via HTTPS 2git clone https://github.com/ansible/ansible.git 3# if you want to commit to a repo, it is often more efficient to use SSH 4git clone firstname.lastname@example.org:ansible/ansible.git
When you work in your local repository:
1# review current status 2git status 3# after editing a file, save and commit 4git add path/to/file 5git commit -m "implemented new feature A" 6# you can combine the two previous commands if you only modified an existing file 7git commit -m "fixed bug #123 by verifying input data" -a 8# delete a file from the repository 9git rm path/to/file 10# and commit the change 11git commit -m "delete path/to/file since it's obsolete"
This was only saving your change locally and did not (yet) push it to your remote! You can do many changes without pushing to your remote, depending on your work style and collaboration mode.
Some people get annoyed about the fact that
git commit asks them for a commit message every time and start using messages like “minor change”, “fix”, “updated README”. It’s natural and understandable that people get annoyed and feel forced to write messages. It feels interrupting and you just want to get things done and don’t to waste time thinking about good commit messages.
Commit messages should be short and precise. They should describe the change in as few words as possible. If you ever try to go back in your
git log to find a certain change and you can only see “minor fix”, it can become incredible hard to find the commit you’re looking for. So do your future self a favor, pause a second and write something useful.
describe the change: why was it needed? what was the problem you try to fix?
be as short as possible, no need for epic descriptions
no redundant information, e.g. the commit already contains the information about which file was modified, there is typically no need to repeat that in the commit message (no “updated README”)
Pull updates and push changes
Until now, you only worked on your local repository - typically you want to interact with a remote server like GitLab, GitHub or others, for collaboration.
1# only fetch latest changes, but do not merge them! 2git fetch 3# get all changes in all remote branches - particularly helpful if you want to see what others changed in their branches - but does not merge them! 4git fetch --all 5# get latest changes from remote and merge them locally 6git pull 7# push changes to remote 8git push
Note: If the remote has a newer version of the branch than your local repository, a
git push will give you an error message. In this case run
git pull again to fetch and merge the latest changes from the remote repository.
Git keeps all commits and you can review them with
git log. You can also see more details:
1# history of all changes 2git log 3# git more details about a specific commit 4git show <commit> 5# show differences 6git diff <commit> 7# roll back previous change 8git checkout <commit> 9# switch back to last commit 10git checkout HEAD
Create your own repository
I recommend to always use git - even if you’re not sure yet you want to keep your work. Creating a git repository is just one simple command and therefore comes with very little cost:
1# create a work directory 2mkdir my_new_project && cd my_new_project 3# initialize repository 4git init 5# you're done! You just created a git repository!
Now you can do local edits, revert changes, do diffs and when you’re done, add a remote repository later. If you realize it was all in vain, you can just delete the entire directory.
Since git is a decentralized software management tool you can add and remove remote repositories at any point in time and you can use multiple remotes as well.
1# add a new repository 2git remote add <name> <URI> 3# get a list of all remotes currently configured 4git remote -v 5# remove a remote repository 6git remote remove <name>
All git commands like pull, push, diff etc. support different remotes, so you can easily compare their different states and decide where to pull or push changes to/from. I find it difficult at times to work with too many remotes, and seem to get lost in what’s where, so I would personally suggest not to stress this concept too much…
Working with branches
Git loves branches. It’s always a good idea to create a new branch before you implement a new feature (remember the old days when you created script-v1.sh, script-v2.sh, script-20200802.sh and lost track which script has which change?).
1# create a new branch from the current one 2git checkout -b <new branch> 3# switch between branches 4git checkout <old branch> 5# get a list of branches 6git branch 7# add -a to see also remote branches 8git branch -a 9# or add -v for more details 10git branch -v 11# or combine them 12git branch -av
Sometimes you have a local change which you want to keep but not yet commit. Or you accidentally started to work in the wrong branch. Instead of copying your local changes to /tmp or similar hacks, you can use
1# stash local changes without committing them 2git stash 3# switch to the branch you actually wanted to apply the change 4git checkout <branch> 5# apply the stashed changes again 6git stash apply 7# note until this point everything just happened in your working directory and nothing was committed or pushed
You can also work with different stashes by assigning names, check
git stash -h for more details.
Sometimes there are many changes you need to identify them. I find it useful to do the following list of commands:
1# differences between branches 2git diff <branch> 3# sometimes the reversed output is more useful 4git diff -R >branch> 5# just find the list of modified files 6git diff -R <branch> --name-only
After you finished your work in the new branch, you want to merge it back to master (or any other branch).
1# switch to the target branch, e.g. master 2git checkout master 3# merge changes from the other branch 4git merge <branch> 5# sometimes you want to review changes and apply them individually, this will use the editor specified in the EDITOR environment variable if you want to edit the changes 6git checkout -p <branch> 7# merge a specific file from the other branch 8git checkout <branch> -- path/to/file
When merging branches conflicts often occur. While git is quite clever in solving many of them automatically, you will still have some which will require manual fixes.
1# merge with master or other branch 2git merge <branch> 3# assume a conflict happens, solve it with your favorite editor 4vi file/with/conflict 5# add the files to your next commit 6git add files/with/conflict 7git commit -m "solving conflict" # or other meaningful commit message
Delete and cleanup
After your work is complete and has been merged, you can delete the local branch.
1git branch -d <branch> 2# or, if there are uncommitted changes you don't want to keep 3git branch -D <branch> 4# if you need to delete the branch on a remote repository, you can do that as well 5# this examples assumes your remote is called "origin" 6git push origin -d <branch>
Use check the chapter Cleaning your local directory.
Pull or Merge Requests
Git makes it easy to work with branches to keep track of new features, bug fixes, releases etc. To simplify collaboration in projects Merge Requests (GitLab) and Pull Requests (GitHub) can be used. These are not features of git, but capabilities provided by the respective platform. Specially when you’re new to git it can be difficult to differentiate between pure git functionality and these additional features.
Merge or Pull Requests are a good way to collaborate on new features or code changes. My typical workflow looks like this:
make sure your local repository is up to date by running
create a local branch to start development (
git checkout -b <new branch>)
make your changes, commit them and continue the typical workflow as described in basic git workflow
push the local branch to the remote (
git push, doing this the first time, you will probably see a message the remote branch does not yet exist and how you fix that, e.g.
git push -u origin local-branch)
you will see a link which will create the Merge or Pull Request - you can also navigate to the Web UI and create it from there
fill out the details, mark it as a draft or WIP (Work in Progress) - this will make sure nobody “accidentally” merges the branch until it’s ready
continue working on your branch (you can still push new changes to the same PR/MR, no need to delete it and create a new one!)
when you feel it’s ready, remove the draft or WIP flag
collaborate and discuss the proposed changes with your peers, push additional changes when needed
merge the changes
delete the branch created for this MR/PR
Merge from master
When working with MR/PR your branch might fall behind and new changes from master need to be merged into your branch:
1# make sure master is up to date and optionally review changes 2git checkout master 3git pull 4# switch back to your branch 5git checkout <branch> 6# and merge all changes from master 7git merge <master> 8# or, review them while merging 9git checkout -p master 10# pull and merge in one command 11git pull <remote> <branch> 12# push your merged branch 13git push
Clean up merged branches
If you create a lot of branches to work on changes, you probably want to clean them up, after they got merged.
1# clean orphaned remote branches 2git remote prune <remote> 3# find local branches which no longer exist on the remote 4git branch -v 5# delete those local branches which no longer exist on the remote 6git branch -d <branch> 7# if the branch was not fully merged and you know what you're doing 8git branch -D <branch> 9# you can do this in one command 10git branch -d `git branch -vv | grep gone | cut -f3 -d' '`
In this section I’m listing some tweaks I learned which make git easier to use.
Unlike some other tools, git doesn’t allow you to shorten commands. For example, in
svn you were allowed to shorten commands like “cummit” to “ci”. I got used to that and defined some aliases which bring back this comfort.
Create or edit your
~/.gitconfig configuration file like this:
1[alias] 2 co = checkout 3 br = branch 4 ci = commit 5 st = status 6 pr = remote prune origin
After saving these changes you can type
git ci instead of
git commit - the rest of the command line remains the same.
1git ci -m "commit a change" 2# is the same as 3git commit -m "commit a change" 4# this works with longer aliases as well 5git pr 6# is the same as 7git remote prune origin
A very powerful feature which builds on top of SCM are pipelines. In GitLab CI/CD has been integrated for a long time and GitHub recently introduced the concept of Actions. There are many other tools like Jenkins, Travis etc.
There are a few articles on CI/CD on this blog as well.