- Getting started with git
- Basic git workflow
- Create your own repository
- Remote Repositories
- Working with branches
- Pull or Merge Requests
- User Experience
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:
git clone URI
Git supports different protocols, typically you use one of the below:
# clone for GitLab, GitHub etc. via HTTPS git clone https://github.com/ansible/ansible.git # if you want to commit to a repo, it is often more efficient to use SSH git clone email@example.com:ansible/ansible.git
When you work in your local repository:
# review current status git status # after editing a file, save and commit git add path/to/file git commit -m "implemented new feature A" # you can combine the two previous commands if you only modified an existing file git commit -m "fixed bug #123 by verifying input data" -a # delete a file from the repository git rm path/to/file # and commit the change git 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
# only fetch latest changes, but do not merge them! git fetch # 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! git fetch --all # get latest changes from remote and merge them locally git pull # push changes to remote git 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:
# history of all changes git log # git more details about a specific commit git show <commit> # show differences git diff <commit> # roll back previous change git checkout <commit> # switch back to last commit git 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:
# create a work directory mkdir my_new_project && cd my_new_project # initialize repository git init # 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.
# add a new repository git remote add <name> <URI> # get a list of all remotes currently configured git remote -v # remove a remote repository git 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?).
# create a new branch from the current one git checkout -b <new branch> # switch between branches git checkout <old branch> # get a list of branches git branch # add -a to see also remote branches git branch -a # or add -v for more details git branch -v # or combine them git 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
# stash local changes without committing them git stash # switch to the branch you actually wanted to apply the change git checkout <branch> # apply the stashed changes again git stash apply # 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:
# differences between branches git diff <branch> # sometimes the reversed output is more useful git diff -R >branch> # just find the list of modified files git 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).
# switch to the target branch, e.g. master git checkout master # merge changes from the other branch git merge <branch> # 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 git checkout -p <branch> # merge a specific file from the other branch git 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.
# merge with master or other branch git merge <branch> # assume a conflict happens, solve it with your favorite editor vi file/with/conflict # add the files to your next commit git add files/with/conflict git 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.
git branch -d <branch> # or, if there are uncommitted changes you don't want to keep git branch -D <branch> # if you need to delete the branch on a remote repository, you can do that as well # this examples assumes your remote is called "origin" git 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:
# make sure master is up to date and optionally review changes git checkout master git pull # switch back to your branch git checkout <branch> # and merge all changes from master git merge <master> # or, review them while merging git checkout -p master # pull and merge in one command git pull <remote> <branch> # push your merged branch git 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.
# clean orphaned remote branches git remote prune <remote> # find local branches which no longer exist on the remote git branch -v # delete those local branches which no longer exist on the remote git branch -d <branch> # if the branch was not fully merged and you know what you're doing git branch -D <branch> # you can do this in one command git 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:
[alias] co = checkout br = branch ci = commit st = status 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.
git ci -m "commit a change" # is the same as git commit -m "commit a change" # this works with longer aliases as well git pr # is the same as git 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.