Chris.luChris.lu header image, displaying an 80s style landscape and sunset

git

two super heros pointing at each other, it represents two versions of a file getting compared in a git diff

git is an open-source version control system used for tracking changes in source code during software development. Git gives every developer a local copy of a project. After a developer has made his changes, they create a new commit and then push it to a central repository. Other developers can then pull that commit from the central repository into their local copy. Git makes branching (creating a separate line of development) and merging (combining changes from different branches) easy.

Installation

on Windows

Go to git-scm.com/download/win and click on Click here to download which will automatically download the latest (64bit) windows version

Double-click on the exe file when the download has finished to start the installation.

You will get asked a bunch of stuff. I usually keep the default settings but feel free to change the default values to fit your needs.

on Linux

If you are on a distribution (like Fedora or CentOS) that comes with dnf, then use this command:

sudo dnf install git-all

For distributions (like Debian or Ubuntu) that come with apt, then use this command:

sudo apt install git-all

on macOS

If you have the Xcode command line tools installed on your machine, then you already have git.

You can check if it is already installed using this command:

git --version

If it is not yet installed, you can visit git-scm.com/download/mac to see all the options. My favorite way of installing git is via brew using the following command:

brew install git

check what version is installed

Use the following command in your VSCode terminal (or favorite command line tool):

git --version

initialize git

To initialize a git project locally, you first need to use the following command:

git init

If you already have a GitHub repository (I will use GitHub, but you could use any other Git cloud service, like GitLab or Bitbucket if you prefer those services), and you have a local repository, but both are not linked, then this is what you need to do

Go to github.com and create a new repository (if you haven't already created one), by clicking on the "+" icon on the left of your user avatar (in the top right section of the page), then select "new repository".

Then use the following command to link the remote origin to your local git setup (if you have no local repository yet, check out the previous initialze git chapter):

git remote add origin https://github.com/GITHUB_USER_NAME/GITHUB_REPOSITORY_NAME.git

If you are using the git credential manager and have multiple users, then you may want to set the default. To do so, add your DEFAULT_GIT_USER_NAME to the URL like this:

git remote add origin https://DEFAULT_GIT_USER_NAME@github.com/GITHUB_USER_NAME/GITHUB_REPOSITORY_NAME.git

Finally you can verify that your local copy and the remote origin are linked by using the following command:

git remote -v

This should display two links to the origin, one for fetch and another one for push commands

Cloning a repository

To clone one of your repositories (hosted by remote git service like GitHub), first get the HTTPS web URL of the repository, and then use the following command:

git clone https://github.com/GITHUB_USER_NAME/GITHUB_REPOSITORY_NAME.git

If you are using the git credential manager and have multiple users, then you may want to set the default. To do so, add your DEFAULT_GIT_USER_NAME into the URL like this when cloning:

git clone https://DEFAULT_GIT_USER_NAME@github.com/GITHUB_USER_NAME/GITHUB_REPOSITORY_NAME.git

If you have already cloned the repository and want to add or change the default user, then use this command:

git remote set-url origin https://DEFAULT_GIT_USER_NAME@github.com/GITHUB_USER_NAME/GITHUB_REPOSITORY_NAME.git

git fetch vs pull

A fetch will only fetch the changes from the remote repository into your local copy and then stops.

A pull will also fetch the remote changes but then additionally (attempt) to merge, so pull = fetch + merge (a pull will abort if there are conflicts).

So usually after a git fetch you would use the git merge command to also merge the changes. The advantage of NOT doing a pull but use a fetch instead, is that you can still save and commit your local changes before doing using the git merge command.

A pull on the other hand is two commands in one and recommended for when you have no unsaved and uncommited changes in your local copy and just quickly want to fetch + merge the remote changes into your local files.

remote vs upstream

When you create a repository on GitHub (or another git service), then this repository will be your remote repository (also called the origin)

When you do a fork of a repository, then the original repository will be the updtream repository and your fork will be the remote repository

If you have cloned your fork (remote repository) locally and use the following command:

git remote -v

Then will display two links from your local, the first origin is for fetch and the second one is for push commands

So when you use the following command (or if you want to immediatly merge the remote changes with your uncommited changes use git pull instead):

git fetch

You will get the remote changes (if there any)

If you now want to also create a link to the upstream repository (the original one you forked earlier), then use the following command:

git remote add upstream https://github.com/ORIGINAL_REPOSITORY_USER/ORIGINAL_REPOSITORY_NAME.git

If you now use the remote command again, you will see that there are now 4 entries:

git remote -v

You now also have a link to the repository you forked, for fetch and push commands

If there are changes in the repository you forked and you want to fetch those to update your local repository, then you use the fetch command like this:

git fetch upstream

Finally to merge the fetched changes with the code in your local repository, use this command:

git merge upstream/master master

Or if you prefer to do both at once (which is preferred if you have no uncommited changes), use the pull command instead, like this:

git pull upstream

git status

To list the local files that differ from the ones in the remote repository and list files that are not tracked, use the following command:

git status

switch to another branch

To switch to another branch, use the following command:

git checkout BRANCH_NAME

Or you can use the new git switch, like so:

git switch BRANCH_NAME

shortcut to return to the previous branch

There is a shortcut to switch back to the previous branch:

git checkout -

Or using the new switch:

git switch -

Stash your changes before switching

If you want to switch to another branch but have uncommitted changes, then either commit them or stash them away using this command:

git stash

Now, if you want to see the changes that are currently stashed, use this command:

git stash show

Finally, to restore the files, use the following:

git stash apply

Create a new branch

To create a new branch (and stay on the current branch), use the following command:

git branch BRANCH_NAME

To create a new branch and also switch to it, use the checkout command with the -b option, like so:

git checkout -b BRANCH_NAME

Or use the new git switch with the -c option, like so:

git switch -c BRANCH_NAME

renaming a branch

rename a local branch

Renaming a local branch is easy if you haven't pushed the branch yet. Just use the following command in your terminal (command line tool):

git branch --move OLD_BRANCH_NAME NEW_BRANCH_NAME

Renaming a remote branch

To rename a remote branch (a remote branch that has already been pushed), first use the command from the previous chapter to rename it locally.

Then use the following command in your terminal (command line tool) to push it:

git push -u origin NEW_BRANCH_NAME

The -u (alias for --set-upstream-to) option tells the local branch to track changes from the remote branch.

Now, the branch with the new name is also available remotely, but git has copied the branch to rename the old one, meaning the old branch is still present remotely, you work alone on the project skip the next step but if you work with others don't delete the old branch just yet.

At this point, if you work with others on the project now is a good time to let everyone on the team know that you renamed the branch, as they might still have open commits. Tell them to execute the following commands so that they, too, switch to the new branch (those are the commands GitHub recommends after you rename a remote branch on GitHub):

git checkout OLD_BRANCH_NAME
git branch -m NEW_BRANCH_NAME
git fetch origin
git branch -u origin/NEW_BRANCH_NAME

First, they use checkout to switch to the old branch, then they rename their own local branch too, using branch -m command, then they fetch the origin to fetch the ref of all branches in origin, then they need to use the branch -u (which is an alias for set-upstream we used earlier) to tell the local branch to track the origin/NEW_BRANCH_NAME.

If it is the default branch that got renamed, also update origin/HEAD:

git remote set-head origin -a

After the other members of your team have updated their local environment, too, then you can go ahead and delete the old branch using this command:

git push origin --delete OLD_BRANCH_NAME

Update the list of remote branches (locally)

To update/refresh the list of remote branches locally, use this command:

git remote update origin --prune

Get an overview of all local and remote branches

To get an overview of all branches that exist remotely and locally, what local branches track remote branches, ... use this command:

git remote show origin

Delete a local branch

git branch --delete BRANCH_NAME

Windows: git ignorecase configuration option

If you rename a file on Windows and only change the case, for example, you change a file with all small letters to camelCase, then that change will NOT trigger a commit

Usually, something like this will lead to the problem: you are developing on Windows, where filenames are case agnostic, so importing a file on Windows and using all small letters (filename.ext) for a filename uses camelCase (fileName.ext) will NOT cause an error in your local development environment. Everything will be fine until you deploy your code on your staging (testing) environment, where you will probably use a Linux-based operating system. On staging, your import will trigger a file not found error. So now you want to fix your error and update the filename to use only small letters, but after editing the fileName, you realize there is no commit waiting to be done

To tell git to also commit changes where only the case of the filename changed, you have 2 options:

Option 1: Using the config command

In your terminal, go to the root of your repository, then use the following command to change the ignorecase configuration for your current repository:

git config core.ignorecase true

If you want to make that change for all repositories (globally), then add the --global flag to the command:

git config --global core.ignorecase true

Option 2: Edit the configuration file (manually)

Edit the git config in your repository, change ignorecase from true to false, and then save the change

.git/config
[core]
	ignorecase = false