Here is a collection of useful commands when working with Git. I have not included everything you can do with Git, but these are the ones I most often use in my day-to-day life. There is a lot more you can do though.
Creating and cloning
The first time you use Git you should set up your user name and email.
Setup a new git repo in the current directory.
Clone a remote git repo to your local machine. If you don't specify (target-folder) it will default to making a new folder with the name of the repo.
Push and pull changes
Check if your code is up to date or if there are uncommitted changes, or to see what branch you're on.
Pull down the latest changes from the server into your local branch.
Fetch all changes from the server but don't update the local branch.
Delete all your uncommitted changes and reset to the last commit on the current branch.
Reset branch to the server's version.
Add all changes and commit, then push to the server.
NOTE: Don’t ever do a "force push", with the -f
flag. The most common case of a push error is when someone else has made changes to that branch on the server and you didn’t have those changes yet when you did your commit. In that case, just do a git pull
to fix your local branch and then git push
again.
If you absolutely have to do a force push (really you shouldn’t though), make sure you tell everyone else who works on this code to reset their branch to the server’s version before making any changes themselves, or else they will just get corrupted as well.
Branches
Create a new branch and then switch to it.
Pull changes from another branch into your current branch.
Pull the latest changes from the server's branch into your local branch.
- Switch to an exact commit, and enter "detached HEAD" mode. In this mode, you are viewing the state of the repo as of a single commit and there is no active branch.
- Turn that commit into it's own branch and exit "detached HEAD" mode.
- Or return to an existing branch and exit "detached HEAD" mode.
Dealing with merge conflicts
The merge
command will ensure your local changes to the branch, if any, are applied "on top" of the newly merged code. You will not lose your changes. This does mean that conflicts can occur, if the same piece of code was changed on your branch as well as the merging-in branch. When this happens, Git will enter a "conflict resolution" mode. The affected files will have sections that look like this:
<<<<<<< HEAD let x = 2 ======= let x = 3 >>>>>>> other-branch
The structure of these conflict blocks looks like this:
- First the
<<<
line marks the start of the conflict. - Next comes the code as it was on your branch.
- Next there’s a separator
=====
. - Then comes the code that is coming in from the merging-in branch.
- Finally the block is ended with
>>> other-branch-name
.
You now have to manually fix the code here. You can remove the entire block and keep the code you want. You can even change code in other places if you like, to ensure everything still works. Do this for all merge conflicts. If you’re using Visual Studio Code, you can easily see all merge conflicts in the Git tab on the left.
Once you’ve fixed all conflicts, you can “resume” the original merge by simply doing the commit:
If you don’t want to fix the conflicts and just want to cancel this merge instead:
Dealing with Windows / Mac / Linux compatibility
Git has built-in support for automatically converting line endings and file permissions, so this may already be fine for you. However, I’ve always had trouble with this, most likely since I use Resilio Sync to sync my work folder between my PC and my MacBook. The first time I use Git on a new machine, I run these commands to ensure there are no issues:
Merging PRs & releases
The usual process used when multiple people are working on a codebase, is to have a master
branch which represents your “production” code, a dev
branch which represents your latest “dev” build, and then individual branches for each PR or change. Usually, when a build is created, you would merge the latest PR branches into dev
and update the version number.
I’ve found that doing this entire process locally works much better and prevents problems with any CI system you might have for auto-deploying builds. Doing it this way allows you to locally test the new version before pushing it up to the server, and you can always revert if a certain PR caused a problem, and do the build again without that PR.
GitHub even has good support for this, meaning that once you do finally push the dev
branch up, it will automatically mark those PRs you merged as “merged”.
One thing to note about Git, is that when you do git fetch
(or git pull
) it downloads a local copy of all remote branches and keeps them up to date locally. These branches are all available with an origin/
prefix (assuming your remote is called origin
). You can use this to pull in PR branches as well for your release, for example if a PR branch is called feature/save-backups
you can now do git fetch
and git merge origin/feature/save-backups
to pull that PR into your local branch.
If you’re using GitHub, it’s a good idea to create a Release tied to the dev
branch after each new release. Besides being a good way of keeping a changelog, it also creates a git tag tied to that exact commit, so you can always go back to the code as it was at that moment in time. For example, if you wanted to do a hotfix on an old version of your code:
Forks and remotes
Sometimes you want to work on someone else’s repo, but you don’t have write access or you are just making modifications for your own use. If you’re using GitHub, when you create a “fork” it will copy the repo to your local account, but will keep a reference to the original repo. This is called the upstream repo.
You will now have two remotes on your git repo:
origin
: Your copy of the repo on the server. This is the default remote.upstream
: The original repo.
NOTE: With Git, every remote’s branches are available locally with the remotename/
prefix. A “fork” is simply a repo that has an upstream
remote. At this point, there are three “groups” of branches: The branches on your local machine (no prefix), the branches on your server (origin/
prefix), and the branches on the upstream repo (upstream/
prefix).
Take for example the master
branch. You have "master"
which is your local machine’s copy, you have "origin/master"
which is the branch as it exists on the server, and you have "upstream/master"
which is the branch as it exists on the upstream repo. You can git checkout
or git merge
any of these at any time.
These commands can be used to pull in changes from upstream. This assumes you’re syncing the master
branch.