---
title: Git - Tutorial
source: https://www.vogella.com/tutorials/Git/article.html
tags:
- IT/Development/Git
- IT/Tools/Shell
---
> [!note]
> This tutorial explains the usage of the distributed version control system Git via the command line. The examples were done on Linux (Ubuntu), but should also work on other operating systems like Microsoft Windows.
## Introduction into version control systems
### What is a version control system?
A version control system (VCS) allows you to manage a collection of files and gives access to different versions of these files.
The VCS allows you to capture the content and structure of your files at a certain point in time. You can use the VCS to switch between these versions and you can work on different versions of these files in parallel. The different versions are stored in a storage system which is typically called a *repository*. The process of creating different versions (snapshots) in the repository is depicted in the following graphic.

In this example, your repository contains two versions, one with three files and another version with four files, two one them in the same state as in the first version, one modified one and another new one.
VCS are very good at tracking changes in text files. For example, you may track changes in HTML code or Java source code. If is also possible to use VCS for other file types but VCS are not that efficient to trace changes in binary files.
A localized version control system keeps local copies of the files. This approach can be as simple as creating a manual copy of the relevant files.
A centralized version control system provides a server software component which stores and manages the different versions of the files. A developer can copy (checkout) a certain version from the central server onto their individual computer.
Both approaches have the drawback that they have one single point of failure. In a localized version control system it is the individual computer and in a centralized version control system it is the server machine. Both systems also make it harder to work in parallel on different features. To remove the limitations of local and centralized version control systems, distributed version control systems have been created.
### Distributed version control systems
In a distributed version control system each user has a complete local copy of a repository on his individual computer. The user can copy an existing repository. This copying process is typically called *cloning* and the resulting repository can be referred to as a *clone*.
Every clone contains the full history of the collection of files and a cloned repository has the same functionality as the original repository.
Every repository can exchange versions of the files with other repositories by transporting these changes. This is typically done via a repository running on a server which is, unlike the local machine of a developer, always online. Typically, there is a central server for keeping a repository but each cloned repository is a full copy of this repository. The decision regarding which of the copies is considered to be the central server repository is pure convention.

## Introduction into Git
The following description gives you a very high-level overview of the Git version control system.
### What is Git?
*Git* is the leading distributed version control system.
Git originates from the Linux kernel development and was founded in 2005 by Linus Torvalds. Nowadays it is used by many popular open source projects, e.g., Visual Studio Code from Microsoft, Android from Google or the Eclipse developer teams, as well as many commercial organizations.
The core of Git was originally written in the programming language *C*, but Git has also been re-implemented in other languages, e.g., Java, Ruby and Python.
### Git repositories and working trees
A Git repository manages a collection of files in a certain directory. A Git repository is file based, i.e., all versions of the managed files are stored on the file system.
A Git repository can be designed to be used on a server or for a user:
- *bare repositories* are supposed to be used on a server for sharing changes coming from different developers. Such repositories do not allow the user to modify local files and to create new versions for the repository based on these modifications.
- *non-bare repositories* target the user. They allow you to create new changes through modification of files and to create new versions in the repository. This is the default type which is created if you do not specify any parameter during the clone operation.
A *local non-bare Git repository* is typically called *local repository*.
Git allows the user to synchronize the local repository with other (remote) repositories.
Users with sufficient authorization can send new versions of their local repository to the remote repositories via the *push* operation. They can also integrate changes from other repositories into their local repository via the *fetch* and *pull* operation.
Every local repository has a *working tree*. The files in the working tree may be new or based on a certain version from the repository. The user can change and create files or delete them.
After doing changes in the working tree, the user can capture new versions of the files in the Git repository. Or the user can restore files to a state already captured by Git.
### Adding a new version of the files to a Git repository
After modifying files in your *working tree* you need to perform two steps to add them to your local repository.
- mark the desired file changes as relevant for the next commit; this operation is called `staging`
- instruct Git to create a new version of the managed files via the commit operation, the new created version is called *commit*.
This process is depicted in the following graphic.

During the stage operation, copies of the specified files are added to a persisted storage called the *staging area* (sometimes it is also called index). This allows you to do further modifications to the same file without including these modifications in the next commit. You can repeat the staging operation until you are satisfied and continue with the commit operation.
The *commit* operation creates a new persistent snapshot called *commit object* (short form: *commit*) of the managed files in the Git repository. A commit object, like all objects in Git, is immutable.
### Alternative versions of files with branches
Git allows you to work on different versions of your files in parallel. For this, Git uses *branches*. A branch allows the user to switch between these versions so that he can work on different changes independently from each other.
For example, if you want to develop a new feature, you can create a branch and make the changes in this branch. This does not affect the state of your files in other branches. For example, you can work independently on a branch called *production* for bugfixes and on another branch called `feature_123` for implementing a new feature.
Branches in Git are local to the repository. A branch created in a local repository does not need to have a counterpart in a remote repository. Local branches can be compared with other local branches and with *remote-tracking* branches. A remote-tracking branch proxies the state of a branch in another remote repository.
Git supports the combination of changes from different branches. The developer can use Git commands to combine the changes at a later point in time.
### Summary of the core Git terminology
The following table summarizes important *Git* terminology. It is intended to be used as a reference, so you can skip this now and return to it if you need clarification.
Table 1. Git terminology
| | |
| --- | --- |
| Term | Definition |
| --- | --- |
| Branch | A *branch* is a named pointer to a commit. Selecting a branch in Git terminology is called *to checkout* a branch. If you are working in a certain branch, the creation of a new commit advances this pointer to the newly created commit.
Each commit knows its parents (predecessors). Successors are retrieved by traversing the commit graph starting from branches or other refs, symbolic references (for example: HEAD) or explicit commit objects. This way a branch defines its own line of descendants in the overall version graph formed by all commits in the repository.
You can create a new branch from an existing one and change the code independently from other branches. One of the branches is the default (typically named *master* ). The default branch is the one for which a local branch is automatically created when cloning the repository. |
| Commit | When you commit your changes into a repository this creates a new *commit object* in the Git repository. This *commit object* uniquely identifies a new revision of the content of the repository.
This revision can be retrieved later, for example, if you want to see the source code of an older version. Each commit object contains the author and the committer. This makes it possible to identify who did the change. The author and committer might be different people. The author did the change and the committer applied the change to the Git repository. This is common for contributions to open source projects. |
| HEAD | *HEAD* is a symbolic reference most often pointing to the currently checked out branch.
Sometimes the *HEAD* points directly to a commit object, this is called *detached HEAD mode*. In that state creation of a commit will not move any branch.
If you switch branches, the *HEAD* pointer points to the branch pointer which in turn points to a commit. If you checkout a specific commit, the *HEAD* points to this commit directly. |
| Index | *Index* is an alternative term for the *staging area*. |
| Repository | A *repository* contains the history, the different versions over time and all different branches and tags. In Git each copy of the repository is a complete repository. If the repository is not a bare repository, it allows you to checkout revisions into your working tree and to capture changes by creating new commits. Bare repositories are only changed by transporting changes from other repositories.
The term *repository* typically refers to a non-bare repository. If a bare repository is referred, this is explicitly mentioned. |
| Revision | Represents a version of the source code. Git implements revisions as *commit objects* (or short *commits* ). These are identified by an SHA-1 hash. |
| Staging area | The *staging area* is the place to store changes in the working tree before the commit. The *staging area* contains a snapshot of the changes in the working tree (changed or new files) relevant to create the next commit and stores their mode (file type, executable bit). |
| Tag | A *tag* points to a commit which uniquely identifies a version of the Git repository. With a tag, you can have a named point to which you can always revert to. You can revert to any point in a Git repository, but tags make it easier. The benefit of tags is to mark the repository for a specific reason, e.g., with a release.
Branches and tags are named pointers, the difference is that branches move when a new commit is created while tags always point to the same commit. Tags can have a timestamp and a message associated with them. |
| URL | A URL in Git determines the location of the repository. Git distinguishes between *fetchurl* for getting new data from other repositories and *pushurl* for pushing data to another repository. |
| Working tree | The *working tree* contains the set of working files for the repository. You can modify the content and commit the changes as new commits to the repository. |
Performing Git operations can be done via the command line or via multiple user interface tools.
### The Git command line tooling
The most common tooling for Git is provided as command line tooling via the `git` command. The examples in this tutorial use the Git command line tooling.
Without any arguments, this command lists its options and the most common commands. You can get help for a certain Git command via the help command inline option followed by the command.
```shell
git help [command to get help for]
```
To see all possible commands, use the `git help --all` command.
| | |
| --- | --- |
| | Git supports for several commands a short and a long version, similar to other Unix commands. The short version uses a single hyphen and the long version uses two hyphens. The following two commands are equivalent.
```
git commit -m "This is a message"
git commit --message "This is a message"
``` |
| | |
| --- | --- |
| | The double hyphens (--) in Git separates out any references or other options from a path (usually file names). For example, HEAD points to the active commit.
Using double hyphens allows you to distinguish between looking at a file called HEAD from a Git commit reference called HEAD.
In case Git can determine the correct parameters and options automatically the double hyphens can be avoided.
```
#
seeing the git log for the HEAD file
git log -- HEAD #
seeing the git log for the HEAD reference
git log HEAD -- #
if there is no HEAD file you can use HEAD as commit reference
git log HEAD
``` |
### Eclipse IDE
The [Eclipse IDE](https://www.eclipse.org/downloads/) provides excellent support for working with Git repositories.

### Visual Studio Code
Also Visual Studio Code provides excellent built-in support for Git.
### Other graphical tools
You can also use graphical tools.
See [GUI Clients](http://git-scm.com/downloads/guis) for an overview of other available tools. Graphical tools like Netbeans or IntelliJ provide also integrated Git tooling but are not covered in this description.
## Installation of the Git command line tooling
### Mac OS
The [Git download page](http://git-scm.com/downloads) provides also native installers for Mac OS X. Git is also installed by default with the Apple Developer Tools on Mac OS X.
### Ubuntu, Debian and derived systems
On Ubuntu and similar systems you can install the Git command line tool via the following command:
### Fedora, Red Hat and derived systems
On Fedora, Red Hat and similar systems you can install the Git command line tool via the following command:
### Other Linux systems
To install Git on other Linux distributions please check the documentation of your distribution. The following listing contains the commands for the most popular ones.
```shell
# Arch Linux
sudo pacman -S git
# Gentoo
sudo emerge -av git
# SUSE
sudo zypper install git
```
## Git configuration
Git requires at least the user name and a valid email to work. [Git settings](https://www.kernel.org/pub/software/scm/git/docs/git-config.html) for all possible settings. This description describes the most important ones.
### Git configuration levels
You configure git via the `git config` command. These settings can be system wide, user or repository specific. A setting for the repository overrides the user setting and a user setting overrides a system wide setting.
#### Git system-wide configuration
You can provide a system wide configuration for your Git settings. A system wide configuration is not very common. Most settings are user specific or repository specific as described in the next chapters.
On a Unix based system, Git uses the `/etc/gitconfig` file for this system-wide configuration. To set this up, ensure you have sufficient rights, i.e. root rights, in your OS and use the `--system` option for the `git config` command.
#### Git user configuration
Git allows you to store user settings in the `.gitconfig` file located in the user home directory. This is also called the *global* Git configuration.
For example Git stores the committer and author of a change in each commit. This and additional information can be stored in the Git user settings.
In each Git repository you can also configure the settings for this repository. User configuration is done if you include the `--global` option in the `git config` command.
#### Repository specific configuration
You can also store repository specific settings in the `.git/config` file of a repository. Use the `--local` or use no flag at all. If neither the `--system` not the `--global` parameter is used, the setting is specific for the current Git repository.
### User credential configuration
You have to configure at least your user and email address to be able to commit to a Git repository because this information is stored in each commit.
```shell
# configure the user which will be used by Git
# this should be not an acronym but your full name
git config --global user.name "Firstname Lastname"
# configure the email address
git config --global user.email "your.email@example.org"
```
### Push configuration
If you are using Git in a version below 2.0 you should also execute the following command.
```
# set default so that only the current branch is pushed
git config --global push.default simple
```
This configures Git so that the `git push` command pushes only the active branch to your Git remote repository. As of Git version 2.0 this is the default and therefore it is good practice to configure this behavior.
You learn about the push command in [Push changes to another repository](#cloneremotes_push).
### Always rebase during pull
By default, Git runs the `git fetch` followed by the `git merge` command if you use the `git pull` command. You can configure git to use `git rebase` instead of `git merge` for the pull command via the following setting.
```shell
# use rebase during pull instead of merge
git config --global pull.rebase true
```
| | |
| --- | --- |
| | This setting helps avoiding merge commits during the pull operation which synchronizes your Git repository with a remote repository. The author of this description always uses this setting for his Git repositories. |
### Allow rebasing with uncommitted changes
If you want Git to automatically save your uncommitted changes before a rebase you can activate autoStash. After the rebase is done your changes will get reapplied. For an explanation of `git stash` please see [Stashing changes in Git](#stash_usage).
```shell
git config --global rebase.autoStash true
```
| | |
| --- | --- |
| | Before Git v2.6 `git pull --rebase` didn’t respected this setting. |
### Color Highlighting
The following commands enables color highlighting for Git in the console.
```shell
git config --global color.ui auto
```
### Setting the default editor
By default Git uses the system default editor which is taken from the *VISUAL* or *EDITOR* environment variables if set. You can configure a different one via the following setting.
```shell
# setup vim as default editor for Git (Linux)
git config --global core.editor vim
```
### Setting the default merge tool
File conflicts might occur in Git during an operation which combines different versions of the same files. In this case the user can directly edit the file to resolve the conflict.
Git allows also to configure a merge tool for solving these conflicts. You have to use third party visual merge tools like tortoisemerge, p4merge, kdiff3 etc. A Google search for these tools help you to install them on your platform. Keep in mind that such tools are not required, you can always edit the files directly in a text editor.
Once you have installed them you can set your selected tool as default merge tool with the following command.
```shell
# setup kdiff3 as default merge tool (Linux)
git config --global merge.tool kdiff3 # to install it under Ubuntu use
sudo apt-get install kdiff3
```
### Query Git settings
To query your Git settings, execute the following command:
If you want to query the global settings you can use the following command.
```shell
git config --global --list
```
## Configure files and directories to ignore
### Ignoring files and directories with a .gitignore file
Git can be configured to ignore certain files and directories for repository operations. This is configured via one or several `.gitignore` files. Typically, this file is located at the root of your Git repository but it can also be located in sub-directories. In the second case the defined rules are only valid for the sub-directory and below.
You can use certain wildcards in this file. `*` matches several characters. More patterns are possible and described under the following URL: [gitignore manpage](https://www.kernel.org/pub/software/scm/git/docs/gitignore.html)
For example, the following `.gitignore` file tells Git to ignore the `bin` and `target` directories and all files ending with a ~.
```shell
# ignore all bin directories
# matches "bin" in any subfolder
bin/ # ignore all target directories
target/ # ignore all files ending with ~
*~
```
You can create the `.gitignore` file in the root directory of the working tree to make it specific for the Git repository.
| | |
| --- | --- |
| | The `.gitignore` file tells Git to ignore the specified files in Git commands. You can still add ignored files to the *staging area* of the Git repository by using the `--force` parameter, i.e. with the `git add --force [paths]` command.
This is useful if you want to add, for example, auto-generated binaries, but you need to have a fine control about the version which is added and want to exclude them from the normal workflow. |
It is good practice to commit the local `.gitignore` file into the Git repository so that everyone who clones this repository have it.
### Stop tracking files based on the .gitignore file
Files that are tracked by Git are not automatically removed if you add them to a `.gitignore` file. Git never ignores files which are already tracked, so changes in the `.gitignore` file only affect new files. If you want to ignore files which are already tracked you need to explicitly remove them.
The following command demonstrates how to remove the `.metadata` directory and the `doNotTrackFile.txt` file from being tracked. This is example code, as you did not commit the corresponding files in your example, the command will not work in your Git repository.
```
#
remove directory .metadata from git repo
git rm -r --cached .metadata #
remove file test.txt from repo
git rm --cached doNotTrackFile.txt
```
Adding a file to the `.gitignore` file does not remove the file from the repository history. If the file should also be removed from the history, have a look at the `git filter-branch` command which allows you to rewrite the commit history. See [Using the git filter branch command (filter-branch)](#filterbranch_definition) for details.
### Global (cross-repository) .gitignore settings
You can also setup a global `.gitignore` file valid for all Git repositories via the `core.excludesfile` setting. The setup of this setting is demonstrated in the following code snippet.
```shell
# Create a ~/.gitignore in your user directory
cd ~/
touch .gitignore # Exclude bin and .metadata directories
echo "bin" >> .gitignore
echo ".metadata" >> .gitignore
echo "*~" >> .gitignore
echo "target/" >> .gitignore
# for Mac
echo ".DS_Store" >> .gitignore
echo "._*" >> .gitignore
# Configure Git to use this file
# as global .gitignore
git config --global core.excludesfile ~/.gitignore
```
The global `.gitignore` file is only locally available.
### Local per-repository ignore rules
You can also create local per-repository rules by editing the `.git/info/exclude` file in your repository. These rules are not committed with the repository so they are not shared with others.
This allows you to exclude, for example, locally generated files.
### Tracking empty directories with Git
Git ignores empty directories, i.e., it does not put them under version control. If you want to track an empty directory in your Git repository, it is a good practice to put a file called `.gitignore` in the directory. As the directory now contains a file, Git includes it into its version control mechanism.
| | |
| --- | --- |
| | The file could be called anything. Some people suggest to call the file `.gitkeep`. One problem with this approach is that `.gitkeep` is unlikely to be ignored by build systems. This may result in the `.gitkeep` file being copied to the output repository, which is typically not desired. |
## Configuration for Git usage via the command line
To use Git you have to configure your user name and email.
Configure your user and email for Git via the following command.
```shell
# configure the user which will be used by Git
# this should be not an acronym but your full name
git config --global user.name "Firstname Lastname"
# configure the email address
git config --global user.email "your.email@example.org"
```
Another commmon setting is to configure Git to use *rebase* during the pull operation.
```shell
# configure new branches to use fetch and rebase during the pull operation
git config --global branch.autosetuprebase always
# always use fetch and rebase during pull
git config --global pull.rebase true
```
| | |
| --- | --- |
| | If you don’t know at this point what the rebase operation or pull operation is, it is fine to leave out these settings, you can still later change these. This description assumes that you set them. |
## Performing a local Git workflow via the command line
In this exercise, use the Git command line to create a local Git repository and commit to it.
Open a command shell for the operations.
| | |
| --- | --- |
| | Some commands are Linux specific, e.g., appending to a file or creating a directory. Substitute these commands with the commands of your operating system. The comments (marked with #) before the commands explain the specific actions. |
### Create a directory
The following commands create an empty directory which is used later in this exercise to contain the working tree and the Git repository.
```shell
# switch to a directory of your choice and afterwards
# create a directory named "repo01" and switch into it
mkdir repo01
cd repo01
# create a new directory
mkdir datafiles
```
### 8.2. Create some files
Use your favorite text editor to create the following files and directory structure in the current folder.
- datafiles/data.txt
- test01
- test02
- test03
You could also create these files via the command line, for example the following commands create these files on Linux via the command line.
```shell
# ensure that you are in your Git Git repository
# create an empty file in a new directory
touch datafiles/data.txt
touch test01
touch test02
touch test03
```
### Create a new Git repository
Use the `git init` command to create a new local Git repository in the created directory. Git does not care whether you start with an empty directory or if it already contains files.
```shell
# initialize the Git repository for the current directory
git init
```
All files inside the repository folder, excluding the `.git` folder, are the *working tree*.
### See the current status of your repository
View the status of your repository via the following command.
The output looks similar to the following listing.
```shell
On branch master
Initial commit
Untracked files:
(use "git add ..." to include in what will be committed) datafiles/
test01
test02
test03
nothing added to commit but untracked files present (use "git add" to track)
```
### Add changes to the staging area
Inform git that all new files should be added to the Git repository with the `git stage` command.
```shell
# add all files to the index of the Git repository
git stage .
# if stage is not available use git add instead, stage was added around 2020 to the git command line
```
Afterwards run the `git status` command again to see the current status. The following listing shows the output of this command.
```shell
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached ..." to unstage)
new file: datafiles/data.txt
new file: test01
new file: test02
new file: test03
```
### Change files that are staged
Adjust an existing file.
```shell
# append a string to the test03 file
echo "foo2" >> test03
```
Validate that the new changes are not yet staged.
```shell
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached ..." to unstage) new file: datafiles/data.txt
new file: test01
new file: test02
new file: test03
Changes not staged for commit: (use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: test03
```
Add the new changes to the staging area.
```shell
# add all files to the index of the Git repository
git stage .
```
Use the `git status` command again to see that all changes are staged.
```shell
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached ..." to unstage) new file: datafiles/data.txt
new file: test01
new file: test02
new file: test03
```
### Commit staged changes to the repository
Commit the staged changes to your Git repository.
```shell
# commit your files to the local repository
git commit -m "Initial commit"
```
### Viewing the commit history
The commit operation, created a new version of your files in the local repository inside the `.git` folder. Run the `git log` command to see the history.
```shell
# show the Git log for the change
git log
```
You see an output similar to the following.
```shell
commit dbbd83bffddb8b9129f37912338011bb82927d0e (HEAD -> master)
Author: Lars Vogel
Date: Mon Feb 8 21:53:12 2021 +0100
Initial commit
```
### Viewing the changes of a commit
Use the `git show` command to see the changes of a commit. If you specify a commit reference as third parameter, this is used to determine the changes, otherwise the *HEAD* reference is used.
### Remove files
Delete a file. Stage the deletion for the next commit with the `git stage .` command.
```shell
# remove the "test03" file
rm test03
# add and commit the removal
git stage .
git commit -m "Removes the test03 file"
```
Alternatively you can use the `git rm` command to delete the file from your working tree and record the deletion of the file in the staging area.
### Revert changes in files in the working tree
Use the `git reset` command (or `git checkout` in older Git command line tools) to reset a tracked file (a file that was once staged or committed) to its latest staged or commit state.
Restore the deleted file by checking out the last version before the current commit (HEAD~1).
```shell
git checkout HEAD~1 -- test03
```
Checkout the status and commit the file again.
```shell
git status
git commit -m "Adding test03 back"
```
You can also replace the content of a file with its last stage version or the version from a certain commit.
In the following example, you reset some changes in your working tree.
```shell
echo "useless data" >> test02
echo "another unwanted file" >> unwantedfile.txt
# see the status
git status
# remove unwanted changes from the working tree
# CAREFUL this deletes the local changes in the tracked file
git restore test02
# unwantedstaged.txt is not tracked by Git simply delete it
rm unwantedfile.txt
```
If you use `git status` command you will see that there are no changes left in the working directory.
```shell
On branch master
nothing to commit, working directory clean
```
Use this command carefully. The `git reset` command deletes the changes of tracked files (files known to Git) in the working tree and it is not possible to restore this deletion via Git.
### Correct the changes of the commit with git amend
The `git commit --amend` command makes it possible to rework the changes of the last commit. It creates a new commit with the adjusted changes.
The amended commit is still available until a clean-up job removes it. But it is not included in the `git log` output hence it does not distract the user.
Assume the last commit message was incorrect as it contained a typo. The following command corrects this via the `--amend` parameter.
```shell
# assuming you have something to commit
git commit -m "message with a tpyo here"
```
```shell
# amend the last commit
git commit --amend -m "More changes - now correct"
```
You should use the `git --amend` command only for commits which have not been pushed to a public branch of another Git repository. The `git --amend` command creates a new commit ID and people may have already based their work on the existing commit. If that would be the case, they would need to migrate their work based on the new commit.
### Ignore files and directories with the .gitignore file
Create the following `.gitignore` file in the root of your Git directory to ignore the specified directory and file.
```shell
cd ~/repo01
touch .gitignore echo ".metadata/" >> .gitignore
echo "doNotTrackFile.txt" >> .gitignore
```
| | |
| --- | --- |
| | The above command creates the file via the command line. A more common approach is to use your favorite text editor to create the file. This editor must save the file as plain text. Editors which do this are for example *gedit* under Ubuntu or *Notepad* under Windows. |
The resulting file looks like the following listing.
```shell
.metadata/
doNotTrackFile.txt
```
### Commit the .gitignore file
It is good practice to commit the `.gitignore` file into the Git repository. Use the following commands for this.
```shell
# add the .gitignore file to the staging area
git stage .gitignore
# ccommit the change
git commit -m "Adds .gitignore file"
```
## Remote repositories
### What are remotes?
Git allows you to synchronize your repository with more than one remote repository.
In the local repository you can address each remote repository by a shortcut. This shortcut is simply called *remote*. Such a *remote* repository points to another remote repository that can be hosted on the Internet, locally or on the network.
You can specify properties for the remote, e.g. URL, branches to fetch or branches to push.
Think of *remotes* as shorter bookmarks for repositories. You can always connect to a remote repository if you know its URL and if you have access to it. Without *remotes* the user would have to type the URL for each and every command which communicates with another repository.
It is possible that users connect their individual repositories directly, but a typical Git workflow involves one or more remote repositories which are used to synchronize the individual repository. Typically the remote repository which is used for synchronization is located on a server which is always available.

A remote repository can also be hosted in the local file system.
### Bare repositories
A remote repository on a server typically does not require a *working tree*. A Git repository without a *working tree* is called a *bare repository*. You can create such a repository with the `--bare` option. The command to create a new empty bare remote repository is displayed below.
```shell
# create a bare repository
git init --bare
```
By convention the name of a bare repository should end with the `.git` extension.
To create a bare Git repository in the Internet you would, for example, connect to your server via the SSH protocol or you use some Git hosting platform, e.g., GitHub.com.
### Convert a Git repository to a bare repository
Converting a normal Git repository to a bare repository is not directly supported by Git.
You can convert it manually by moving the content of the `.git` folder into the root of the repository and by removing all other files from the working tree. Afterwards you need to update the Git repository configuration with the `git config core.bare true` command.
As this is officially not supported, you should prefer cloning a repository with the `--bare` option.
### Cloning a repository
The `git clone` command copies an existing Git repository. This copy is a working Git repository with the complete history of the cloned repository. It can be used completely isolated from the original repository.
Git supports several transport protocols to connect to other Git repositories; the native protocol for Git is also called `git`.
The following command clones an existing repository using the Git protocol. The Git protocol uses port 9148 which might be blocked by firewalls.
```shell
# switch to a new directory
mkdir ~/online
cd ~/online
# clone online repository
git clone git://github.com/vogella/gitbook.git
```
If you have SSH access to a Git repository, you can also use the `ssh` protocol. The name preceding @ is the user name used for the SSH connection.
```shell
# clone online repository
git clone ssh://git@github.com/vogella/gitbook.git
# older syntax
git clone git@github.com:vogella/gitbook.git
```
Alternatively you could clone the same repository via the `http` protocol.
```shell
# the following will clone via HTTP
git clone http://github.com/vogella/gitbook.git
```
### Adding remote repositories
If you clone a repository, Git implicitly creates a *remote* named *origin* by default. The *origin* *remote* links back to the cloned repository.
You can push changes to this repository via `git push` as Git uses `origin` as default. Of course, pushing to a remote repository requires write access to this repository.
You can add more *remotes* via the `git remote add [name] [URL_to_Git_repo]` command. For example, if you cloned the repository from above via the Git protocol, you could add a new remote with the name *github_http* for the http protocol via the following command.
```shell
# add the HTTPS protocol
git remote add github_http https://vogella@github.com/vogella/gitbook.git
```
### Rename remote repositories
To rename an existing remote repository use the `git remote rename` command. This is demonstrated by the following listing.
```shell
# rename the existing remote repository from
# github_http to github_testing
git remote rename github_http github_testing
```
If you create a Git repository from scratch with the `git init` command, the *origin* remote is not created automatically.
### Remote operations via HTTP
It is possible to use the HTTP protocol to clone Git repositories. This is especially helpful if your firewall blocks everything except HTTP or HTTPS.
```shell
git clone http://git.eclipse.org/gitroot/platform/eclipse.platform.ui.git
```
For secured SSL encrypted communication you should use the SSH or HTTPS protocol in order to guarantee security.
### Using a proxy
Git also provides support for HTTP access via a proxy server. The following Git command could, for example, clone a repository via HTTP and a proxy. You can either set the proxy variable in general for all applications or set it only for Git.
The following listing configures the proxy via environment variables.
```shell
# Linux and Mac
export http_proxy=http://proxy:8080
export https_proxy=https://proxy:8443
# Windows
set http_proxy http://proxy:8080
set https_proxy http://proxy:8080
git clone http://git.eclipse.org/gitroot/platform/eclipse.platform.ui.git
```
The following listing configures the proxy via Git config settings.
```shell
# set proxy for git globally
git config --global http.proxy http://proxy:8080
# to check the proxy settings
git config --get http.proxy
# just in case you need to you can also revoke the proxy settings
git config --global --unset http.proxy
```
Git is able to store different proxy configurations for different domains, see `core.gitProxy` in [Git config manpage](http://git-scm.com/docs/git-config).
### Adding a remote repository
You add as many *remotes* to your repository as desired. For this you use the `git remote add` command.
You created a new Git repository from scratch earlier. Use the following command to add a remote to your new bare repository using the *origin* name.
```shell
# add ../remote-repository.git with the name origin
git remote add origin ../remote-repository.git
```
### Synchronizing with remote repositories
You can synchronize your local Git repository with remote repositories. These commands are covered in detail in later sections but the following command demonstrates how you can send changes to your remote repository.
```shell
# do some changes
echo "I added a remote repo" > test02
# commit
git commit -a -m "This is a test for the new remote origin"
# to push use the command:
# git push [target]
# default for [target] is origin
git push origin
```
### Show the existing remotes
To see the existing definitions of the remote repositories, use the following command.
```shell
# show the details of the remote repo called origin
git remote show origin
```
To see the details of the *remotes*, e.g., the URL use the following command.
```shell
# show the existing defined remotes
git remote
# show details about the remotes
git remote -v
```
### Push changes to another repository
The `git push` command allows you to send data to other repositories. By default it sends data from your current branch to the same branch of the remote repository.
By default you can only push to bare repositories (repositories without working tree). You can also only push a change to a remote repository which results in a fast-forward merge.
See [Push changes of a branch to a remote repository](#gitpushbranch) for details on pushing branches or the [Git push manpage](https://www.kernel.org/pub/software/scm/git/docs/git-push.html) for general information.
### Pull changes from a remote repository
The `git pull` command allows you to get the latest changes from another repository for the current branch.
The `git pull` command is actually a shortcut for `git fetch` followed by the `git merge` or the `git rebase` command depending on your configuration. You configured your Git repository so that `git pull` is a fetch followed by a rebase.
## Exercise: Working with a (local) remote repository
You now create a local bare repository based on your existing Git repository. In order to simplify the examples, the Git repository is hosted locally in the filesystem and not on a server in the Internet.
Afterwards you pull from and push to your bare repository to synchronize changes between your repositories.
### Create a bare Git repository via the clone operation
Execute the following commands to create a bare repository based on your existing Git repository.
```shell
# switch to the first repository
cd ~/repo01
# create a new bare repository by cloning the first one
git clone --bare . ../remote-repository.git
# check the content of the git repo, it is similar
# to the .git directory in repo01
# files might be packed in the bare repository
ls ~/remote-repository.git
```
### Exercise: Clone your bare repository
Clone your bare repository and checkout a working tree in a new directory via the following commands.
```shell
# switch to home
cd ~
# make new directory
mkdir repo02
# switch to new directory
cd ~/repo02
# clone
git clone ../remote-repository.git .
```
### Exercise: Using the push command
Make some changes in one of your non-bare local repositories and push them to your bare repository via the following commands.
```shell
# make some changes in the first repository
cd ~/repo01
# make some changes in the file
echo "Hello, hello. Turn your radio on" > test01
echo "Bye, bye. Turn your radio off" > test02
# commit the changes, -a will commit changes for modified files
# but will not add automatically new files
git commit -a -m "Some changes"
# push the changes
git push ../remote-repository.git
```
### Exercise: Using the pull command
To test the `git pull` in your example Git repositories, switch to the other non-bare local repository. Pull in the recent changes from the remote repository. Afterwards make some changes and push them again to your remote repository.
```shell
# switch to second directory
cd ~/repo02
# pull in the latest changes of your remote repository
git pull
# make changes
echo "A change" > test01
# commit the changes
git commit -a -m "A change"
# push changes to remote repository
# origin is automatically created as we cloned original from this repository
git push origin
```
You can pull in the changes in your first example repository with the following commands.
```shell
# switch to the first repository and pull in the changes
cd ~/repo01
git pull ../remote-repository.git/
# check the changes
git status
```
## Using Branches
### What are branches?
Git allows you to create *branches*. Branches are named pointers to commits. You can work on different branches independently from each other. The default branch is most often called *master*.
A branch pointer in Git is 41 bytes large, 40 bytes of characters and an additional new line character. Therefore, the creating of branches in Git is very fast and cheap in terms of resource consumption. Git encourages the usage of branches on a regular basis.
If you decide to work on a branch, you *checkout* (or *switch* to) this branch. This means that Git populates the *working tree* with the version of the files from the commit to which the branch points and moves the *HEAD* pointer to the new branch.
*HEAD* is a symbolic reference usually pointing to the branch which is currently checked out.
### Detached HEAD
If you checkout a commit or a tag directly and not a branch, you are in the so-called *detached HEAD mode*. If you commit changes in this mode, you have no branch which points to this commit.
It is not recommended to create new commits in this mode because such commits would not be visible on a branch and you may not find them easily. Detached HEAD mode is intended to make it easy to view files referred to by a certain commit.
### List available branches
The `git branch` command lists all local branches. The currently active branch is marked with `*`.
```shell
# lists available branches
git branch
```
If you want to see all branches (including remote-tracking branches), use the `-a` for the `git branch` command.
```shell
# lists all branches including the remote branches
git branch -a
```
The `-v` option lists more information about the branches.
In order to list branches in a remote repository use the `git branch -r` command as demonstrated in the following example.
```shell
# lists branches in the remote repositories
git branch -r
```
### Create new branch
You can create a new branch via the `git branch [newname]` command. This command allows you to specify the commit (commit id, tag, remote or local branch) to which the branch pointer original points. If not specified, the commit to which the HEAD reference points is used to create the new branch.
```shell
# syntax: git branch
# in the above is optional
git branch testing
```
### Checkout branch
To start working in a branch you have to *checkout* the branch. If you *checkout* a branch, the HEAD pointer moves to the last commit in this branch and the files in the working tree are set to the state of this commit.
The following commands demonstrate how you switch to the branch called *testing*, perform some changes in this branch and switch back to the branch called *master*.
```shell
# switch to your new branch
git checkout testing
# do some changes
echo "Cool new feature in this branch" > test01
git commit -a -m "new feature"
# switch to the master branch
git checkout master
# check that the content of
# the test01 file is the old one
cat test01
```
To create a branch and to switch to it at the same time you can use the `git checkout` command with the `-b` parameter.
```shell
# create branch and switch to it
git checkout -b bugreport12
# creates a new branch based on the master branch
# without the last commit
git checkout -b mybranch master~1
```
### Rename a branch
Renaming a branch can be done with the following command.
```shell
# rename branch
git branch -m [old_name] [new_name]
```
### Delete a branch
To delete a branch which is not needed anymore, you can use the following command. You may get an error message that there are uncommitted changes if you did the previous examples step by step. Use force delete (uppercase `-D`) to delete it anyway.
```shell
# delete branch testing
git branch -d testing
# git-testforce delete testing
git branch -D testing #
check if branch has been deleted
git branch
```
### Push changes of a branch to a remote repository
You can push the changes in a branch to a remote repository by specifying the target branch. This creates the target branch in the remote repository if it does not yet exist.
If you do not specify the remote repository, the `origin` is used as default
```shell
# push current branch to a branch called "testing" to remote repository
git push origin testing
# switch to the testing branch
git checkout testing
# some changes
echo "News for you" > test01
git commit -a -m "new feature in branch"
# push current HEAD to origin
git push
# make new branch
git branch anewbranch
# some changes
echo "More news for you" >> test01
git commit -a -m "a new commit in a feature branch"
# push anewbranch to the master in the origin
git push origin anewbranch:master
# get the changes into your local master
git checkout master
git pull
```
This way you can decide which branches you want to push to other repositories and which should be local branches.
### Switching branches with untracked files
Untracked files (never added to the staging area) are unrelated to any branch. They exist only in the working tree and are ignored by Git until they are committed to the Git repository. This allows you to create a branch for unstaged and uncommitted changes at any point in time.
### Switching branches with uncommitted changes
Similar to untracked files you can switch branches with unstaged or staged modifications which are not yet committed.
You can switch branches if the modifications do not conflict with the files from the branch.
If Git needs to modify a changed file during the checkout of a branch, the checkout fails with a `checkout conflict` error. This avoids losing changes in your files.
In this case the changes must be committed, reverted or stashed. You can also always create a new branch based on the current HEAD.
### Differences between branches
To see the difference between two branches you can use the following command.
```shell
# shows the differences between
# current head of master and your_branch
git diff master your_branch
```
You can use commit ranges. For example, if you compare a branch called *your_branch* with the *master* branch the following command shows the changes in *your_branch* and *master* since these branches diverged.
```shell
# shows the differences in your
# branch based on the common
# ancestor for both branches
git diff master...your_branch
```
Git has the option to add additional metadata to commits. This can be used to document for example a commit which is used to perform a software release.
This is done via *tags*.
Git supports two different types of tags, lightweight and annotated tags.
A *lightweight tag* is a named pointer to a commit, without any additional information about the tag. An *annotated tag* contains additional meta data:
- the name and email of the person who created the tag
- tagging message similar to a commit message
- the date of the tagging
Annotated tags can also be signed and verified with *GNU Privacy Guard (GPG)*.
You can list the available tags via the following command:
```shell
git tag
# Shows all tags with the commits they point to
git show-ref --tags --abbrev
```
Creating lightweight tags
To create a lightweight tag don’t use the `-m`, `-a` or `-s` option.
Lightweight tags in Git are sometimes used to identify the input for a build.
```shell
# create lightweight tag
git tag 1.7.1
```
To see the commit the tag points to, you can use:
You could also use the following command (and define a alias for that):
```shell
git tag --list --format '%(refname:short) %(objectname:short)'
```
You can create a new annotated tag via the `git tag -a` or the `git tag -m "message"` command. To specify the tag message, use the `-m` parameter. The following command tags the commit to which the current active HEAD points.
```
# create tag
git tag 1.6.1 -m 'Release 1.6.1'
# show the tag
git show 1.6.1
```
You can also create tags for a certain commit id.
```shell
git tag 1.5.1 -m 'version 1.5' [commit id]
```
### Creating signed tags
You can use the option `-s` to create a signed tag. These tags are signed with *GNU Privacy Guard (GPG)* and can also be verified with GPG. For details on this please see the following URL: [Git tag manpage](https://www.kernel.org/pub/software/scm/git/docs/git-tag.html).
### Checkout tags
If you want to use the code associated with the tag, use:
If you checkout a tag, you are in the *detached head mode* and commits created in this mode are harder to find after you checkout a branch again.
### Push tags
By default the `git push` command does not transfer tags to remote repositories. You explicitly have to push the tag with the following command.
```shell
# push a tag or branch called tagname
git push origin [tagname]
# to explicitly push a tag and not a branch
git push origin tag
# push all tags
git push --tags
```
### Delete tags
You can delete tags with the `-d` parameter. This deletes the tag from your local repository. By default Git does not push tag deletions to a remote repository, you have to trigger that explicitly.
The following commands demonstrate how to push a tag deletion.
```shell
# delete tag locally
git tag -d 1.7.0
# delete tag in remote repository
# called origin
git push origin :refs/tags/1.7.0
```
### Search by pattern for a tag
You can use the `-l` parameter in the `git tag` command to search for a pattern in the tag.
### Using tags for software releases
Tags are frequently used to tag a software release. In this case, they are called *release tags*.
Convention is that release tags are labeled based on the \[major\].\[minor\].\[patch\] naming scheme. These release tags follow the semantic versioning of the software release.
- the *patch* version is incremented if (only) backwards compatible bug fixes are introduced
- the *minor* version is incremented if backwards compatible functionality of the user of the public API are introduced
- the *major* version is incremented if incompatible changes are introduced in the public API
For example "1.0.0" or "v1.0.0".
If software build tools like Maven or Gradle are used, the released version should also follow the semantic versioning. In this case the tag is typically the same as the release version.
### Creating of a release log based on tags
Git allows you to list the commits between any reference; this includes tags.
This allows you to create a release log, for example via the following commands.
```shell
# show log between two tags
git log tag1..tag2
# show shortlog between two tags
git shortlog tag1..tag2
```
## Comparing changes
### Listing changed files
The `git status` command shows the current status of your repository and possible actions which you can perform.
It shows which files have changed, which are staged and which are not part of the staging area. It also shows which files have merge conflicts and gives an indication what the user can do with these changes, e.g., add them to the staging area or remove them, etc.
`git status -u` shows all untracked files. Otherwise, if you have a new directory with several files, only the directory is shown.
### Example: Using git status
The following commands create some changes in your Git repository.
Make some changes in your working tree
```shell
# assumes that the test01 and test02 files exist
# and have been committed in the past
echo "This is a new change to the file" > test01
echo "and this is another new change" > test02
# create a new file
ls > newfileanalyzis.txt
```
Now use the status command.
The output of the command looks like the following listing.
```shell
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
# (use "git push" to publish your local commits)
#
# Changes not staged for commit:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: test01
# modified: test02
#
# Untracked files:
# (use "git add ..." to include in what will be committed)
#
# newfileanalyzis.txt
no changes added to commit (use "git add" and/or "git commit -a")
```
### Using git diff
The `git diff` command allows you to compare changes between commits, the staging area and working tree, etc. Via an optional third parameter you can specify a path to filter the displayed changes. The path can be a file or directory `git diff [path]`.
The following example code demonstrates the usage of the `git diff` command.
Make some changes in your working tree
```shell
echo "This is a change" > test01
echo "and this is another change" > test02
```
Use the git diff command
```shell
git diff
(1)
git diff --cached
(2)
git diff COMMIT_REF1 COMMIT_REF2
(3)
git diff -- [file_reference]
(4)
```
| | |
| --- | --- |
| **1** | shows the changes introduced in the working tree compared with the staging area |
| **2** | shows the differences between the staging area and the last commit |
| **3** | shows the differences introduced between two commit references |
| **4** | shows the differences introduced in the working tree compared with the staging area for \[file_reference\] |
## Analyzing the commit history with git log
### Using git log
The `git log` command shows the history of the Git repository. If no commit reference is specified it starts from the commit referred to by the HEAD pointer.
```shell
git log
git log HEAD~10
(1)
git log COMMIT_REF
(2)
```
| | |
| --- | --- |
| **1** | shows the history of commits starting from the HEAD~10 commit |
| **2** | shows the history of commits starting from the COMMIT_REF commit |
### Helpful parameters for git log
The following gives an overview of useful parameters for the `git log` command.
```
git log --oneline
(1)
git log --abbrev-commit
(2)
git log --graph --oneline
(3)
git log --decorate
(4)
```
| | |
| --- | --- |
| **1** | `--oneline` \- fits the output of the `git log` command in one line. `--oneline` is a shorthand for "--pretty=oneline --abbrev-commit" |
| **2** | `--abbrev-commit` \- the log command uses shorter versions of the SHA-1 identifier for a commit object but keeps the SHA-1 unique. This parameter uses 7 characters by default, but you can specify other numbers, e.g., `--abbrev-commit --abbrev=4`. |
| **3** | `graph` \- draws a text-based graphical representation of the branches and the merge history of the Git repository. |
| **4** | decorate - adds symbolic pointers to the log output |
For more options on the `git log` command see the [Git log manpage](https://www.kernel.org/pub/software/scm/git/docs/git-log.html).
### [](#analyzechangesg_changesinafile)[15.3. View the change history of a file](#analyzechangesg_changesinafile)
To see changes in a file you can use the `-p` option in the `git log` command.
```
git log -- [file_reference]
(1)
git log -p -- [file_reference]
(2)
git log --follow -p -- [file_reference]
(3)
```
| | |
| --- | --- |
| **1** | \- shows the list of commits for this file |
| **2** | \- the `-p` parameter shows the diffs of each commit |
| **3** | \- `--follow` includes renames in the log output |
### [](#analyzechanges_output)[15.4. Configuring output format](#analyzechanges_output)
You can use the `--pretty` parameter to configure the output.
```shell
# command must be issued in one line, do not enter the line break
git log --pretty=format:'%Cred%h%Creset %d%Creset %s %Cgreen(%cr) %C(bold blue) %Creset' --abbrev-commit
```
This command creates the output.

Git allows you to create a short form of one or several existing Git commands. You can define an alias for such long commands.
### Filtering based on the commit message via regular expressions
You can filter the output of the `git log` command to commits whose commit message, or reflog entry, respectively, matches the specified regular expression pattern with the `--grep=` and `--grep-reflog=` option.
For example the following command instructs the log command to list all commits which contain the word "workspace" in their commit message.
```
git log --oneline --grep="workspace"
(1)
```
| | |
| --- | --- |
| **1** | Greps in commit message for "workspace", oneline parameter included for better readability of the output |
There is also the `--invert-grep=` option. When this option is used, git log lists the commits that don’t match the specified pattern.
### [](#analyzechanges_user)[15.6. Filtering the log output based on author or committer](#analyzechanges_user)
You can use the `--author=` or `--committer=` to filter the log output by author or committer. You do not need to use the full name, if a substring matches, the commit is included in the log output.
The following command lists all commits with an author name containing the word "Vogel".
See also [git shortlog for release announcements](#gitshortlog).
## Viewing changes with git diff and git show
### See the differences introduced by a commit
To see the changes introduced by a commit use the following command.
### See the difference between two commits
To see the differences introduced between two commits you use the `git diff` command specifying the commits. For example, the following command shows the differences introduced in the last commit.
```shell
# directly between two commits
git diff HEAD~1 HEAD
# using commit ranges
git diff HEAD~1..HEAD
```
### See the files changed by a commit
To see the files which have been changed in a commit use the `git diff-tree` command. The `name-only` tells the command to show only the names of the files.
```shell
git diff-tree --name-only -r
```
## [](#using-the-git-blame-command)[17\. Using the Git blame command](#using-the-git-blame-command)
### [](#git_blame_def)[17.1. Analyzing line changes with git blame](#git_blame_def)
Using the Git log command and filtering the history is a useful tool for inspecting the project history. However, if you look at a particular file and find a bug in a particular line of code you would like to instantly know who was the last person who changed this line of code. Additionally, you would like to know why the developer did that i.e. locate the commit in which the change was done.
In Git, this feature is called *git blame* or *git annotate*. The `git blame` command allows you to see which commit and author modified a file on a per line base. That is very useful to identify the person or the commit which introduced a change.
### [](#git_blame_example)[17.2. Example: git blame](#git_blame_example)
The following code snippet demonstrates the usage of the `git blame` command.
```
# git blame shows the author and commit per
# line of a file
git blame [filename]
# the -L option allows limiting the selection
# for example by line number
# only show line 1 and 2 in git blame
git blame -L 1,2 [filename]
```
The `git blame` command can also ignore whitespace changes with the `-w` parameter.
## Commit history of a repository or certain files
[Gitk](http://git-scm.com/docs/gitk) can be used to visualize the history of a repository or certain files.
In some cases simply using `git blame` is not sufficient in order to see all details of certain changes. You can navigate to the file location in the target git repository and use the `gitk [filename]` command to see all commits of a file in a clear UI.
In this screenshot we can see all commits of the `ShowViewHandler.java` file by using the `gitk ShowViewHandler.java` command:

On Linux you can easily install gitk by using the `sudo apt-get install gitk` command in a terminal.
## git shortlog for release announcements
The `git shortlog` command summarizes the `git log` output. It groups all commits by author and includes the first line of the commit message.
The `-s` option suppresses the commit message and provides a commit count. The `-n` option sorts the output based on the number of commits by author.
```shell
# gives a summary of the changes by author
git shortlog
# compressed summary
# -s summary, provides a commit count summary only
# -n sorted by number instead of name of the author
git shortlog -sn
```
This command also allows you to see the commits done by a certain author or committer.
```shell
# see the commits by the author "Lars Vogel"
git shortlog --author="Lars Vogel"
# see the commits by the author "Lars Vogel"
# restricted by the last years
git shortlog --author="Lars Vogel" --since=2years
# see the number of commits by the author "Lars Vogel"
git shortlog -s --author="Lars Vogel" --since=2years
```
## [](#stash_usage)[20\. Stashing changes in Git](#stash_usage)
### [](#the-git-stash-command)[20.1. The git stash command](#the-git-stash-command)
Git provides the `git stash` command which allows you to record the current state of the working directory and the staging area and to revert to the last committed revision.
This allows you to pull in the latest changes or to develop an urgent fix. Afterwards you can restore the stashed changes, which will reapply the changes to the current version of the source code.
### [](#stash_usage2)[20.2. When to use git stash](#stash_usage2)
In general using the stash command should be the exception in using Git. Typically, you would create new branches for new features and switch between branches. You can also commit frequently in your local Git repository and use interactive rebase to combine these commits later before pushing them to another Git repository.
Even if you prefer not to use branches, you can avoid using the `git stash` command. In this case you commit the changes you want to put aside and amend the commit with the next commit. If you use the approach of creating a commit, you typically put a marker in the commit message to mark it as a draft, e.g., "\[DRAFT\] implement feature x".
### [](#stash_example)[20.3. Example: Using the git stash command](#stash_example)
The following commands will save a stash and reapply them after some changes.
```
#
create a stash with uncommitted changes
git stash #
do changes to the source, e.g., by pulling
#
new changes from a remote repo
#
afterwards, re-apply the stashed changes
#
and delete the stash from the list of stashes
git stash pop
```
It is also possible to keep a list of stashes.
```
#
create a stash with uncommitted changes
git stash save #
see the list of available stashes
git stash list #
result might be something like:
stash@{0}: WIP on master: 273e4a0 Resize issue in Dialog
stash@{1}: WIP on master: 273e4b0 Silly typo in Classname
stash@{2}: WIP on master: 273e4c0 Silly typo in Javadoc #
you can use the ID to apply a stash
git stash apply stash@{0} #
or apply the latest stash and delete it afterwards
git stash pop #
you can also remove a stashed change
#
without applying it
git stash drop stash@{0} #
or delete all stashes
git stash clear
```
### [](#stash_branchexample)[20.4. Create a branch from a stash](#stash_branchexample)
You can also create a branch for your stash if you want to continue to work on the stashed changes in a branch. This can be done with the following command.
```
#
create a new branch from your stack and
#
switch to it
git stash branch newbranchforstash
```
## [](#remove-untracked-files-with-git-clean)[21\. Remove untracked files with git clean](#remove-untracked-files-with-git-clean)
### [](#gitclean_command)[21.1. Removing untracked files](#gitclean_command)
If you have untracked files in your working tree which you want to remove, you can use the `git clean` command.
| | |
| --- | --- |
| | Be careful with this command. All untracked files are removed if you run this command. You will not be able to restore them, as they are not part of your Git repository. |
### [](#gitclean_example)[21.2. Example: Using git clean](#gitclean_example)
The following commands demonstrate the usage of the `git clean` command.
```
#
create a new file with content
echo "this is trash to be deleted" >
test04
#
make a dry-run to see what would happen
#
-n is the same as --dry-run
git clean -n #
delete, -f is required if
#
variable clean.requireForce is not set to false
git clean -f #
use -d flag to delete new directories
#
use -x to delete hidden files, e.g., ".example"
git clean -fdx
```
## [](#undochanges)[22\. Revert uncommitted changes in tracked files](#undochanges)
The content of any file tracked by Git can be restored from the staging area or a commit.
You can unstage changes so that these are not included in the next commit. This chapter explains how you can do this.
### [](#undochanges_reset)[22.1. Remove staged changes from the staging area](#undochanges_reset)
Use the `git reset [paths]` command to remove staged changes from the staging area. This avoids including these changes in the next commit.
This means that `git reset [paths]` is the opposite of `git add [paths]`. The changes are still available in the working tree and you can stage and commit them at a later point.
In the following example you create a new file and change an existing file. Both changes are staged.
```
#
do changes
touch unwantedstaged.txt echo "more.." >> test02
// add changes to staging area
git add unwantedstaged.txt
git add test02 #
see the status
git status
```
The output of the `git status` command should look similar to the following.
```
On branch master
Changes to be committed:
(use "git reset HEAD ..." to unstage) modified: test02
new file: unwantedstaged.txt
```
Remove the changes from the staging area with the following command.
```
#
remove test02 from the staging area
git reset test02 #
remove unwantedstaged.txt from the staging area
git reset unwantedstaged.txt
```
Use the `git status` command to see the result.
```
On branch master
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: test02
Untracked files: (use "git add ..." to include in what will be committed) unwantedstaged.txt
no changes added to commit (use "git add" and/or "git commit -a")
```
The `git reset` behaves differently depending on the options you provide.
### [](#undochanges_checkout)[22.2. Remove changes in the working tree](#undochanges_checkout)
| | |
| --- | --- |
| | Be careful with the following command. It allows you to override the changes in files in your working tree. You will not be able to restore these changes. |
Undesired changes in the working tree which are not staged can be undone with the `git checkout` command. This command resets the file in the working tree to the latest staged version. If there are no staged changes, the latest committed version is used for the restore operation.
```
#
delete a file
rm test01 #
revert the deletion
git checkout -- test01 #
note git checkout test01 also works but using
#
two - ensures that Git understands that test01
#
is a path and not a parameter
#
change a file
echo "override" >
test01
#
restore the file
git checkout -- test01
```
For example, you can restore the contents of a directory called `data` with the following command.
### [](#undochanges_directorydeletion)[22.3. Remove changes in the working tree and the staging area](#undochanges_directorydeletion)
If you want to undo a staged but uncommitted change, you use the `git checkout [commit-pointer] [paths]` command. This version of the command resets the working tree and the staged area.
The following demonstrates the usage of this to restore a deleted directory.
```
#
create a demo directory
mkdir checkoutheaddemo
touch checkoutheaddemo/myfile
git add .
git commit -m "Adds new directory" #
now delete the directory and add the change to
#
the staging area
rm -rf checkoutheaddemo #
Use git add . -A for Git version < 2.0
git add . #
restore the working tree and reset the staging area
git checkout HEAD -- checkoutheaddemo
```
The additional commit pointer parameter instructs the `git checkout` command to reset the working tree and to also remove the staged changes.
### [](#undochanges_indexexisting)[22.4. Remove staging area based on last commit change](#undochanges_indexexisting)
When you have added the changes of a file to the staging area, you can also revert the changes in the staging area based on the last commit.
```
#
some nonsense change
echo "change which should be removed later" >
test01
#
add the file to the staging area
git add test01 #
restores the file based on HEAD in the staging area
git reset HEAD test01
```
## [](#resetcommitsdef)[23\. Moving branch pointers with the Git reset command](#resetcommitsdef)
### [](#using-the-git-reset-command-to-move-branch-pointer-or-the-head-pointer)[23.1. Using the git reset command to move branch pointer or the HEAD pointer](#using-the-git-reset-command-to-move-branch-pointer-or-the-head-pointer)
The `git reset` command allows you to change the commit your HEAD is pointing to (indirectly or directly). This can for example be used to remove an undesired commit.
If a branch is checked out, this branch pointer will move and HEAD is indirectly point to the new commit. If you HEAD points directly to a commit (headless mode) the HEAD pointer will point to the new commit.
For simplification the following will say that the HEAD pointer moves, independent if a branch or a commit is checked out.

The reset command will always move the branch pointer (or the HEAD pointer in case of headless mode) and update the working tree based on the new commit. The following parameters allow you to define will happen to the current changes in the working tree and changes which were included in the commits between the original commit and the commit now referred to by the HEAD pointer.
- soft
- mixed (this is the default if no parameters are defined)
- hard
Depending on the specified parameters the `git reset` command performs the following:
- The HEAD / branch pointer moves to the new commit
- if `--soft` is specified
- changes in the working tree are left unchanged
- the staging areas is not updated (all previous committed changes are staged for the next commit)
- file changes between the original commit and the one you reset to are staged
- if `--mixed` parameter (the default) is used:
- changes in the working tree are left unchanged
- the staging area is set to the new HEAD (the files are not staged)
- file changes between the original commit and the one you reset shows up as modifications (or untracked files) in your working tree.
- if `--hard` parameter is specified:
- resets the staging area and the working tree to the new HEAD. This effectively removes the changes you have done between the original commit and the one you reset to.
Use the `--mixed` or `--soft` option to keep file changes.
These parameters are listed in the following table.
| | | | |
| --- | --- | --- | --- |Table 2. git reset options
| Reset | Branch pointer | Working tree | Staging area |
| soft | Yes | No | No |
| mixed (default) | Yes | No | Yes |
| hard | Yes | Yes | Yes |
The `git reset` command does not remove untracked files. If you have untracked files in your working tree which you want to remove, you can use the `git clean` command.
### [](#resetcommit_path)[23.2. Not moving the HEAD pointer with git reset](#resetcommit_path)
If you specify a path via the `git reset [path]` command, Git does not move the HEAD pointer. It updates the staging area or also the working tree depending on your specified option.
## [](#retrievefiles)[24\. Retrieving files from the history](#retrievefiles)
### [](#retrievefiles_show)[24.1. View file in different revision](#retrievefiles_show)
The `git show` command allows you to see and retrieve files from branches, commits and tags. It allows seeing the status of these files in the selected branch, commit or tag without checking them out into your working tree.
By default, this command addresses a file from the root of the repository, not the current directory. If you want the current directory then you have to use the ./ specifier. For example to address the `pom.xml` file in the current directory use: `./pom.xml`
The following commands demonstrate that. You can also make a copy of the file.
```
#
[reference] can be a branch, tag, HEAD or commit ID
#
[file_path] is the file name including path
git show [reference]:[file_path] #
to make a copy to copiedfile.txt
git show [reference]:[file_path] >
copiedfile.txt
#
assume you have two pom.xml files. One in the root of the Git
#
repository and one in the current working directory
#
address the pom.xml in the git root folder
git show HEAD:pom.xml #
address the pom in the current directory
git show HEAD:./pom.xml
```
### [](#retrievefiles_fromcommit)[24.2. Restore a deleted file in a Git repo](#retrievefiles_fromcommit)
You can checkout a file from the commit. To find the commit which deleted the file you can use the `git log` or the `git ref-list` command as demonstrated by the following commands.
```
#
see history of file
git log --
#
checkout file based on predecessors the last commit which affect it
#
this was the commit which delete the file
git checkout [commit] ^ --
#
alternatively use git rev-list
git rev-list -n 1 HEAD --
#
afterwards, the same checkout based on the predecessors
git checkout [commit] ^ --
```
## [](#retrievefiles_finddeletedfile)[25\. See which commit deleted a file](#retrievefiles_finddeletedfile)
The `git log` command allows you to determine which commit deleted a file. You can use the `--` option in `git log` to see the commit history for a file, even if you have deleted the file.
```
#
see the changes of a file, works even
#
if the file was deleted
git log --full-history -- [file_path] #
limit the output of Git log to the
#
last commit, i.e. the commit which delete the file
#
-1 to see only the last commit
#
use 2 to see the last 2 commits etc
git log --full-history -1 -- [file_path] #
include stat parameter to see
#
some statics, e.g., how many files were
#
deleted
git log --full-history -1 --stat -- [file_path]
```
## [](#revertcommit)[26\. Reverting changes introduced with a certain commit](#revertcommit)
You can undo changes via the `git revert` command. This command compares the changes of the commit compared to its parent and reverts these changes.
This may be necessary if a commit introduced incorrect behavior.
The following command demonstrates the usage of the `git revert` command.
```
#
revert a commit
git revert commit_id
```
## [](#undochanges_checkoutcommits)[27\. Resetting the working tree based on a commit](#undochanges_checkoutcommits)
### [](#undochanges_checkoutcommits1)[27.1. Checkout based on commits and working tree](#undochanges_checkoutcommits1)
You can restore arbitrary revisions of your file system via the git checkout command followed by a commit reference. This command resets the *working tree* to the state described by this commit.
### [](#undochanges_checkoutcommits2)[27.2. Example: Checkout a commit](#undochanges_checkoutcommits2)
To checkout a specific commit you can use the following command.
```
#
checkout the older revision via
git checkout [commit_id] #
based on the example output this could be
git checkout 046474a52e0ba1f1435ad285eae0d8ef19d529bf #
or you can use the abbreviated version
git checkout 046474a5
```
| | |
| --- | --- |
| | If you checkout a commit, you are in the *detached head mode* and commits in this mode are harder to find after you checkout another branch. Before committing it is good practice to create a new branch. |
## [](#recovering-commits-via-the-git-reflog-command)[28\. Recovering commits via the Git reflog command](#recovering-commits-via-the-git-reflog-command)
### [](#findingresettedcommits)[28.1. Finding commits that are no longer visible on a branch](#findingresettedcommits)
Commits are not shown by Git, if they are directly or indirectly referred to be a pointer, like a branch or tag. Certain git commands remove commits from your view, e.g.: * git reset may remove commits from your current branch and therefore these commits vanish from your view * Amending a commit also removes the commit from your view
For example, assume you have two commits A→ B, where B is the commit after A. You reset your branch pointer to A, the `git log` command does not include B anymore.
`git reflog` command allows you to find such commits by showing the HEAD pointer movements.
### [](#git-reflog)[28.2. git reflog](#git-reflog)
Reflog is a mechanism to record the movements of the *HEAD* and the branches references.
The reflog command gives a history of the complete changes of the *HEAD* reference.
```
git reflog #