GITHUB Cheat Sheet
Last updated
Last updated
Excerpt
A version control system (VCS) allows you to manage a collection of files and gives access to different versions of these files.
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.
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 VGS to switching between these versions and you can work on different versions of these files in parallel. The different versions are stored in 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 in 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 sever onto their individual computer.
Both approaches have the drawback that they have one single point of failure. In a localized version control systems it is the individual computer and in a centralized version control systems it is the server machine. Both system makes it also harder to work in parallel on different features. To remove the limitations of local and centralized version control systems, distributed version control system have been created.
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 which of the copies is considered to be the central server repository is pure convention.
The following description gives you a very high-level overview of the Git version control system.
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.
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 an 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 locally 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.
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.
Git allows you to 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.
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 their 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.
This description uses the term repository to talk about a non-bare repository. If it talks about a bare repository, 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 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 online option followed by the command.
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 hyphen. The following two commands are equivalent.
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.
You can also use graphical tools.
See GUI Clients 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.
The git config
command allows you to configure your Git settings. These settings can be system wide, user or repository specific.
A more specific setting overwrites values in the previous level. A setting for the repository overrides the user setting and a user setting overrides a system wide setting.
5.1.1. 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 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.
5.1.3. 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.
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.
If your are using Git in a version below 2.0 you should also execute the following command.
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.
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.
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.
If you want Git to automatically save your uncommited 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.
Before Git v2.6 git pull --rebase
didn't respected this setting.
The following commands enables color highlighting for Git in the console.
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.
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.
To query your Git settings, execute the following command:
If you want to query the global settings you can use the following command.
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
For example, the following .gitignore
file tells Git to ignore the bin
and target
directories and all files ending with a ~.
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.
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.
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) for details.
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.
The global .gitignore
file is only locally available.
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.
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.
To use Git you can to configure your user name and the email for Git usage.
Configure your user and email for Git via the following command.
Another commmon setting is to configure Git to use rebase during the pull operation.
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.
In this exercise, you learn how to use the Git command line to work with Git. To ensure that you have a repository available, you start by creating a local Git repository via the command line.
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.
The following commands create an empty directory which is used later in this exercise to contain the working tree and the Git repository.
You now create a new local repository. Use the git init
command to create a Git repository in the current directory. Git does not care whether you start with an empty directory or if it contains already files.
All files inside the repository folder, excluding the .git
folder, are the working tree.
Create a few new files in your directory. For example, the following commands create a few files in a bash shell.
View the status of your repository via the following command.
The output looks similar to the following listing.
Inform git that all new files should be added to the Git repository with the git stage
command.
Afterwards run the git status
command again to see the current status. The following listing shows the output of this command.
Adjust an existing file.
Validate that the new changes are not yet staged.
Add the new changes to the staging area.
Use the git status
command again to see that all changes are staged.
Commit the staged changes to your Git repository.
Git also offers a mode that lets you choose interactively which changes you want to commit. After you quit the mode you will be asked to provide a commit message in your $EDITOR.
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.
You see an output similar to the following.
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.
Delete a file. Stage the deletion for the next commit with the git stage .
command.
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.
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 delete file by checking out the last version before the current commit (HEAD~1).
Checkout the status and commit the file again.
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.
If you use git status
command to see that there are no changes left in the working directory.
Use this command carefully. The git reset
command deletes the changes of tracked files (file known to Git) in the working tree and it is not possible to restore this deletion via Git.
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.
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 based their work already on the existing commit. If that would be the case, they would need to migrate their work based on the new commit.
Create the following .gitignore
file in the root of your Git directory to ignore the specified directory and file.
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.
It is good practice to commit the .gitignore
file into the Git repository. Use the following commands for this.
Git allows that you can 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 point to another remote repository that can hosted on the Internet, locally or on the network.
You can specify properties for the remove, 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 typically 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.
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.
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.
Converting a normal Git repository to a bare repository is not directly support 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 others 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.
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 the port 9148 which might be blocked by firewalls.
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.
Alternatively you could clone the same repository via the http
protocol.
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.
To rename an existing remote repository use the git remote rename
command. This is demonstrated by the following listing.
If you create a Git repository from scratch with the git init
command, the origin remote is not created automatically.
HTTP as Git protocol proxy support in Git 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.
For secured SSL encrypted communication you should use the SSH or HTTPS protocol in order to guarantee security.
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.
The following listing configures the proxy via Git config settings.
Git is able to store different proxy configurations for different domains, see core.gitProxy
in Git config manpage.
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.
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.
To see the existing definitions of the remote repositories, use the following command.
To see the details of the remotes, e.g., the URL use the following command.
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 aslo only push a change to a remote repository which results in a fast-forward merge.
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.
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.
Execute the following commands to create a bare repository based on your existing Git repository.
Clone your bare repository and checkout a working tree in a new directory via the following commands.
Make some changes in one of your non-bare local repositories and push them to your bare repository via the following commands.
To test the git pull
in your example Git repositories, switch to 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.
You can pull in the changes in your first example repository with the following commands.
Git allows you to create branches, i.e. 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 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.
The git branch
command lists all local branches. The currently active branch is marked with *
.
If you want to see all branches (including remote-tracking branches), use the -a
for the git branch
command.
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.
You can create a new branch via the git branch [newname]
command. This command allows 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.
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.
To create a branch and to switch to it at the same time you can use the git checkout
command with the -b
parameter.
Renaming a branch can be done with the following command.
To delete a branch which is not needed anymore, you can use the following command. You may get an error message that there are uncommited changes if you did the previous examples step by step. Use force delete (uppercase -D
) to delete it anyway.
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
This way you can decide which branches you want to push to other repositories and which should be local branches.
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.
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 that you lose 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.
To see the difference between two branches you can use the following command.
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.
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:
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.
To see the commit the tag points to, you can use:
You could also use the following command (and define a alias for that):
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.
You can also create tags for a certain commit id.
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.
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.
By default the git push
command does not transfer tags to remote repositories. You explicitly have to push the tag with the following command.
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.
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.
Git allows to list the commits between any reference; this includes tags.
This allows to create a release log, for example via the following commands.
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 severals files, only the directory is shown.
The following commands create some changes in your Git repository.
Make some changes in your working tree
Now use the status command.
The output of the command looks like the following listing.
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 path can be a file or directory git diff [path]
.
The following example code demonstrate the usage of the git diff
command.
Make some changes in your working tree
Use the git diff command
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 commits references
4
shows the differences introduced in the working tree compared with the staging area for [file_reference]
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.
1
shows the history of commits starting from the HEAD~10 commit
2
shows the history of commits starting from the COMMIT_REF commit
The following gives an overview of useful parameters for the git log
command.
1
--oneline
- fits the output of the git log
command in one line. --online
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.
To see changes in a file you can use the -p
option in the git log
command.
1
- shows the list of commits for this file
2
- the -p
parameter triggers that the diffs of each commit is shown
3
- --follow
allow include renames in the log output
You can use the --pretty
parameter to configure the output.
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.
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=<pattern>
and --grep-reflog=<pattern>
option.
For example the following command instructs the log command to list all commits which contain the word "workspace" in their commit message.
1
Greps in commit message for "workspace", oneline parameter included for better readability of the output
There is also the --invert-grep=<pattern>
option. When this option is used, git log lists the commits that don't match the specified pattern.
You can use the --author=<pattern>
or --committer=<pattern>
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".
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.
The following code snippet demonstrates the usage of the git blame
command.
The git blame
command can also ignore whitespace changes with the -w
parameter.
Gitk can be used to visualize the history of a repository of 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
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 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.
This command also allows you to see the commits done by a certain author or committer.
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.
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".
The following commands will save a stash and reapply them after some changes.
It is also possible to keep a list of stashes.
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.
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.
The following commands demonstrate the usage of the git clean
command.
If you have a tracked file in Git, you can always recreate the file content based on the staging area or based on a previous commit. You can also remove staged changes from the staging area to avoid that these changes are included in the next commit. This chapter explains you how you can do this.
Staging area, remove staged changes You can use the git reset [paths]
command to remove staged changes from the staging area. This means that git reset [paths]
is the opposite of git add [paths]
. It avoids that the changes are included in the next commit. The changes are still available in the working tree, e.g., you will not lose your changes and 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.
The output of git status
command should look similar to the following.
Remove the changes from the staging area with the following command.
Use the git status
command to see the result.
The git reset
behaves differently depending on the options you provide.
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.
Changes in the working tree which are not staged can be undone with 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.
For example, you can restore the content of a directory called data
with the following command.
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 delete directory.
The additional commit pointer parameter instructs the git checkout
command to reset the working tree and to also remove the staged changes.
When you have added the changes of a file to the staging area, you can also revert the changes in the staging area base on the last commit.
Sometimes you want to change the commit your branch pointer is pointing to. The git reset
command allows you to manually set the current HEAD pointer (and its associated branch) to a specified commit. This is for example useful to undo a particular change or to build up a different commit history.
All commits which were originally pointed to by the HEAD pointer and the commit pointed to by HEAD after the reset, are reseted, e.g., not directly visible anymore from the current HEAD and branch pointer.
Via parameters you can decide what you happen to the 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. As a reminder, the working tree contains the files and the staging area contains the changes which are marked to be included in the next commit. Depending on the specified parameters the git reset
command performs the following:
If you specify the --soft
parameter, the git reset
command moves the HEAD pointer. Changes in the working tree will be left unchanged and all changes which were commited included in commits which are reseted are staged.
If you specify the --mixed
parameter (the default), the git reset
command moves the HEAD pointer and resets the staging area to the new HEAD. Any file change between the original commit and the one you reset to shows up as modifications (or untracked files) in your working tree. Use this option to remove commits but keep all the work you have done. You can do additional changes, stage changes and commit again. This way you can build up a different commit history.
If you specify the --hard
parameter, the git reset
command moves the HEAD pointer and 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.
Via parameters you can define if the staging area and the working tree is updated. 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.
The git reset --hard
command makes the working tree exactly match HEAD.
If you have tracked files with modifications, you lose these changes with the above command.
The reset command does not delete untracked files. If you also want to delete them, use the git reflog
command.
git reset, squash commits As a soft reset does not remove your change to your files and index, you can use the git reset --soft
command to squash several commits into one commit.
As the staging area is not changed with a soft reset, you keep it in the desired state for your new commit. This means that all the file changes from the commits which were reseted are still part of the staging area.
The interactive rebase adds more flexibility to squashing commits and allows to use the existing commit messages.
The git show
command allows 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 the current directory use: ./pom.xml
The following commands demonstrate that. You can also make a copy of the file.
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 command.
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.
git revert You can revert commits via the git revert
command. This command reverts the changes of a commit.
Such commits are useful to document that a change was withdrawn.
git checkout, based on commit ID
You can check out arbitrary revisions of your file system via the git checkout command followed by the commit ID. This command will reset your complete working tree to the status described by this commit.
The commit ID is shown if you enter the git log
command.
The following command shows the log.
The following listing shows an example output of a Git log command.
To checkout a specific commit you can use the following command.
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.
If you checkout a commit or a tag, 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. After you checkout a branch you cannot see the commit you did in detached head mode in the git log
command.
To find such commits you can use the git reflog
command.
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.
The git reflog
command also list commits which you have removed.
There are multiple reflogs: one per branch and one for HEAD. For branches use the git reflog [branch]
command and for HEAD use the git reflog
or the git reflog HEAD
command.
The following example shows how you can use git reflog to reset the current local branch to a commit which isn't reachable from the current branch anymore.
Your local Git repository contains references to the state of the branches on the remote repositories to which it is connected. These local references are called remote-tracking branches.
You can see your remote-tracking branches with the following command.
To update remote-tracking branches without changing local branches you use the git fetch
command.
It is safe to delete a remote branch in your local Git repository, this does not affect a remote repository. The next time you run the git fetch
command, the remote branch is recreated. You can use the following command for that.
To delete the branch in a remote repository use the following command.
Branches can track another branch. This is called to have an upstream branch and such branches can be referred to as tracking branches.
Tracking branches allow you to use the git pull
and git push
command directly without specifying the branch and repository.
If you clone a Git repository, your local master branch is created as a tracking branch for the master branch of the origin repository (short: origin/master ) by Git.
You create new tracking branches by specifying the remote branch during the creation of a branch. The following example demonstrates that.
Instead of using the git checkout
command you can also use the git branch
command.
The --no-track
allows you to specify that you do not want to track a branch. You can explicitly add a tracking branch with the git branch -u
command later.
To see the tracking branches for a remote repository (short: remote) you can use the following command.
An example output of this might look as follows.
The git fetch
command updates your remote-tracking branches, i.e., it updates the local copy of branches stored in a remote repository. The following command updates the remote-tracking branches from the repository called origin.
The fetch command only updates the remote-tracking branches and none of the local branches. It also does not change the working tree of the Git repository. Therefore, you can run the git fetch
command at any point in time.
After reviewing the changes in the remote tracking branchm you can merge the changes into your local branches or rebase your local branches onto the remote-tracking branch.
Alternatively you can also use the git cherry-pick commit_id
command to take over only selected commits.
The git fetch
command updates only the remote-tracking branches for one remote repository. In case you want to update the remote-tracking branches of all your remote repositories you can use the following command.
The following code shows a few options how you can compare your branches.
The above commands show the changes introduced in HEAD compared to origin. If you want to see the changes in origin compared to HEAD, you can switch the arguments or use the -R
parameter.
You can rebase your current local branch onto a remote-tracking branch. The following commands demonstrate that.
The git pull
command performs a git fetch
and git merge
(or git rebase
based on your Git settings). The git fetch
does not perform any operations on your local branches. You can always run the fetch command and review the incoming changes.
Git allows you to combine the changes which were created on two different branches. One way to achieve this is merging, which is described in this chapter. You can merge based on branches, tags or commits. Other ways are using rebase or cherry-pick.
This part explains how to merge changes between two different branches under the assumption that no merging conflicts happen. Solving conflicts is covered in What is a conflict during a merge operation?.
If the commits which are merged are direct successors of the HEAD pointer of the current branch, Git performs a so-called fast forward merge. This fast forward merge only moves the HEAD pointer of the current branch to the tip of the branch which is being merged.
This process is depicted in the following diagram. The first picture assumes that master is checked out and that you want to merge the changes of the branch labeled "branch 1" into your "master" branch. Each commit points to its predecessor (parent).
After the fast-forward merge the HEAD points to the master branch pointing to "Commit 3". The "branch 1" branch points to the same commit.
If commits are merged which are not direct predecessors of the current branch, Git performs a so-called three-way-merge between the latest commits of the two branches, based on the most recent common predecessor of both.
As a result a so-called merge commit is created on the current branch. It combines the respective changes from the two branches being merged. This commit points to both of its predecessors.
If multiple common predecessors exist, Git uses recursion to create a virtual common predecessor. For this Git creates a merged tree of the common ancestors and uses that as the reference for the 3-way merge. This is called the recursive merge strategy and is the default merge strategy.
If a fast-forward merge is not possible, Git uses a merge strategy. The default strategy called recursive merge strategy was described in Merge commit.
The Git command line tooling also supports the octopus merge strategy for merges of multiple references. With this operation it can merge multiple branches at once.
The subtree
option is useful when you want to merge in another project into a sub-directory of your current project. It is rarely used and you should prefer the usage of Git submodules. See Git Submodules for more information.
The ours
strategy merges a branch without looking at the changes introduced in this branch. This keeps the history of the merged branch but ignores the changes introduced in this branch.
You can use the ours merge strategy to document that you have integrated a branch and decided to ignore all changes from this branch.
The git merge
command performs a merge. You can merge changes from one branch to the current active one via the following command.
The -s
parameter allows you to specify other merge strategies. This is demonstrated with the following command.
For example, you can specify the ours strategy in which the result of the merge is always that of the current branch head, effectively ignoring all changes from all other branches. This is demonstrated with the following command.
Be careful if you use the ours merge strategy, it ignores everything from the branch which is merged.
The usage of the octopus merge strategy is triggered if you specify more than one reference to merge.
The recursive merge strategy (default) allows you to specify flags with the -X
parameter. For example you can specify here the ours
option. This option forces conflicting changes to be auto-resolved by favoring the local version. Changes from the other branch that do not conflict with our local version are reflected to the merge result. For a binary file, the entire contents are taken from the local version.
The ours
option for the recursive merge strategy should not be confused with the ours merge strategy.
A similar option to ours
is the theirs
option. This option prefers the version from the branch which is merged.
Both options are demonstrated in the following example code.
Another useful option is the ignore-space-change
parameter which ignores whitespace changes.
For more information about the merge strategies and options see Git merge manpage.
If you prefer to have merge commits even for situations in which Git could perform a fast-forward merge you can use the git merge --no-ff
command.
The --no-ff
parameter can make sense if you want to record in the history at which time you merged from a maintenance branch to the master branch.
When pulling from a remote repository, prefer doing a rebase to a merge. This will help to keep the history easier to read. A merge commit can be helpful to document that functionality was developed in parallel.
You can use Git to rebase one branch on another one. As described, the merge
command combines the changes of two branches. If you rebase a branch called A onto another, the git
command takes the changes introduced by the commits of branch A and applies them based on the HEAD of the other branch. After this operation the changes in the other branch are also available in branch A.
The process is displayed in the following picture. We want to rebase the branch called branch_1
onto master.
Running the rebase command creates a new commit with the changes of the branch on top of the master branch.
Performing a rebase does not create a merge commit. The final result for the source code is the same as with merge but the commit history is cleaner; the history appears to be linear.
Rebase can be used to forward-port a feature branch in the local Git repository onto the changes of the master branch. This ensures that your feature is close to the tip of the upstream branch until it is finally published.
If you rewrite more than one commit by rebasing, you may have to solve conflicts per commit. In this case the merge operations might be simpler to be performed because you only have to solve merge conflicts once.
Also, if your policy requires that all commits result in correct software you have to test all the rewritten commits since they are "rewritten" by the rebase algorithm. Since merge/rebase/cherry-pick are purely text-based and do not understand the semantics of these texts they can end up with logically incorrect results. Hence, it might be more efficient to merge a long feature branch into upstream instead of rebasing it since you only have to review and test the merge commit.
You can use the rebase command to change your Git repository history commits. This is called interactive rebase, see ? for information about this feature.
You should avoid using the Git rebase operation for changes which have been published in other Git repositories. The Git rebase operation creates new commit objects, this may confuse other developers using the existing commit objects.
Assume that a user has a local feature branch and wants to push it to a branch on the remote repository. However, the branch has evolved and therefore pushing is not possible. Now it is good practice to fetch the latest state of the branch from the remote repository. Afterwards you rebase the local feature branch onto the remote tracking branch. This avoids an unnecessary merge commit. This rebasing of a local feature branch is also useful to incorporate the latest changes from remote into the local development, even if the user does not want to push right away.
Rebasing and amending commits is safe as long as you do not push any of the changes involved in the rebase. For example, when you cloned a repository and worked in this local repository. Rebasing is a great way to keep the history clean before contributing back your modifications.
In case you want to rewrite history for changes you have shared with others you need to use the -f
parameter in your git push
command and subsequently your colleagues have to use fetch -f to fetch the rewritten commits.
The following demonstrates how to perform a rebase operation.
Git allows you to edit your commit history with a functionality called interactive rebase
. For example, you can combine several commits into one commit, reorder or skip commits and edit the commit message.
This is useful as it allows the user to rewrite some commit history (cleaning it up) before pushing the changes to a remote repository.
Interactive rebase allows you to quickly edit a series of commits using the following actions:
Table 3. Interactive rebase actions
Action
Description
pick
includes the selected commit, moving pick entries enables reordering of commits
skip
removes a commit
edit
amends the commit
squash
combines the changes of the commit with the previous commit and combines their commit messages
fixup
squashes the changes of a commit into the previous commit discarding the squashed commit's message
reword
similar to pick but allows modifying the commit message
The setup for the rebase is called the rebase plan. Based on this plan, the actual interactive rebase can be executed.
It is safe to use interactive rebase as long as the commits have not been pushed to another repository. As the interactive rebase creates new commit objects, other developers might be confused if you rebase already published changes.
The following commands create several commits which will be used for the interactive rebase.
We want to combine the last seven commits. You can do this interactively via the following command.
This command opens your editor of choice and lets you configure the rebase operation by defining which commits to pick, squash or fixup.
The following listing shows an example of the selection. We pick the last commit, squash 5 commits and fix the sixth commit. The listing uses the long format of the commands (for example fixup
instead of the short form f
) for better readability.
The git cherry-pick
command allows you to select the patch which was introduced with an individual commit and apply this patch on another branch. The patch is captured as a new commit on the other branch.
This way you can select individual changes from one branch and transfer them to another branch.
The new commit does not point back to its original commit so do not use cherry-pick blindly since you may end up with several copies of the same change. Most often cherry-pick is either used locally (to emulate an interactive rebase) or to port individual bug fixes done on a development branch into maintenance branches.
In the following example you create a new branch and commit two changes.
You can check the commit history, for example, with the git log --oneline
command.
The following command selects the first commit based on the commit ID and applies its changes to the master branch. This creates a new commit on the master branch.
The cherry-pick
command can be used to change the order of commits. git cherry-pick
also accepts commit ranges for example in the following command.
Commit ranges can be used.
If things go wrong or you change your mind, you can always reset to the previous state using the following command.
Merge conflict A conflict during a merge operation occurs if two commits from different branches have modified the same content and Git cannot automatically determine how both changes should be combined when merging these branches.
This happens for example if the same line in a file has been replaced by two different commits.
If a conflict occurs, Git marks the conflict in the file and the programmer has to resolve the conflict manually.
After resolving it, he adds the file to the staging area and commits the change. These steps are required to finish the merge operation.
Merge conflict LARSSECONDARY"theirs parameter"LARSSECONDARY Merge conflict
LARSSECONDARY"ours parameter"LARSSECONDARY Sometimes if a conflict occurs the developer does not want to solve the conflict. He decides that he wants to keep the original version or the new version of the file.
For this, there is the --theirs
and the --ours
options on the git checkout
command. The first option keeps the version of the file that you merged in, and the second option keeps the version before the merge operation was started.
In the following example you create a conflict during a merge operation.
The following steps create a merge conflict. It assumes that repo1 and repo2 have the same origin repository defined.
As this push would not result in a non-fast-format merge, you receive an error message similar to the following listing.
To solve this, you need to integrate the remote changes into your local repository. In the following listing the git fetch
command gets the changes from the remote repository. The git merge
command tries to integrate it into your local repository.
This creates the conflict and a message similar to the following.
The resulting conflict is displayed in ? and solved in ?
If you use the git pull
command it performs the "fetch and merge" or the "fetch and rebase" command together in one step. Whether merge or rebase is used depends on your Git configuration for the branch. See ? for the global configuration.
Git marks the conflicts in the affected files. In the example from ? one file has a conflict and the file looks like the following listing.
The text above the ======= signs is the conflicting change from your current branch and the text below is the conflicting change from the branch that you are merging in.
In this example you resolve the conflict which was created in ? and apply the change to the Git repository.
To solve the merge conflict you edit the file manually. The following listing shows a possible result.
Afterwards add the affected file to the staging area and commit the result. This creates the merge commit. You can also push the integrated changes now to the remote repository.
Instead of using the -m
option in the above example you can also use the git commit
command without this option. In this case the command opens your default editor with the default commit message about the merged conflicts. It is good practice to use this message.
Alternatively, you could use the git mergetool
command. git mergetool
starts a configurable merge tool that displays the changes in a split screen. Some operating systems may come with a suitable merge tool already installed or configured for Git.
If a conflict occurs during a rebase operation, the rebase operation stops and the developer needs to resolve the conflict. After he has solved the conflicts, the developer instructs Git to continue with the rebase operation.
A conflict during a rebase operation is solved similarly to the way a conflict during a merge operation is solved. The developer edits the conflicts and adds the files to the Git index. Afterwards he continues the rebase operation with the following command.
To see the files which have a rebase conflict use the following command.
You solve such a conflict the same way as you would solve a merge conflict.
You can also skip the commit which creates the conflict.
You can also abort a rebase operation with the following command.
If a file is in conflict, you can instruct Git to take the version from the new commit of the version of commit onto which the new changes are applied. This is sometimes easier than to solve all conflicts manually. For this you can use the git checkout
with the --theirs
or --ours
flag. During the conflict --ours
points to the file in the commit onto which the new commit is placed, i.g., using this skips the new changes for this file.
Therefore to ignore the changes in a commit for a file use the following command.
To take the version of the new commit use the following command.
An alias in Git allows you to create a short form of one or several existing Git commands. For example, you can define an alias which is a short form of your own favorite commands or you can combine several commands with an alias.
The following defines an alias to see the staged changes with the new git staged
command.
Or you can define an alias for a detailed git log
command. The following command defines the git ll
alias.
You can also run external commands. In this case you start the alias definition with a !
character. For example, the following defines the git ac
command which combines git add . -A
and git commit
commands.
When you add a file to your repository, Git LFS replaces its contents with a pointer, and stores the file contents in a local Git LFS cache.
When you push new commits to the server, any Git LFS files referenced by the newly pushed commits are transferred from your local Git LFS cache to the remote Git LFS store tied to your Git repository.
When you checkout a commit that contains Git LFS pointers, they are replaced with files from your local Git LFS cache, or downloaded from the remote Git LFS store.
To use Git LFS, you will need a Git LFS aware host such as Bitbucket Cloud or Bitbucket Server.
Enable it
sudo apt-get install git-lfs git lfs install # initialize the Git LFS project git lfs track "*.iso"
git lfs track "*.png" --lockable git lfs clone - Faster clone git lfs pull - Checkout any missing files
Lock file git lfs lock images/foo.jpg git lfs unlock images/foo.jpg git lfs unlock images/foo.jpg --force β Someone elses lock
Using it:
git bisect The git bisect
command allows you to run a binary search through the commit history to identify the commit which introduced an issue. You specify a range of commits and a script that the bisect
command uses to identify whether a commit is good or bad.
This script must return 0 if the condition is fulfilled and non-zero if the condition is not fulfilled.
Create a new Git repository, create the text1.txt
file and commit it to the repository. Do a few more changes, remove the file and again do a few more changes.
We use a simple shell script which checks the existence of a file. Ensure that this file is executable.
Afterwards use the git bisect
command to find the bad commit. First you use the git bisect start
command to define a commit known to be bad (showing the problem) and a commit known to be good (not showing the problem).
Afterwards run the bisect command using the shell script.
The above commands serve as an example. The existence of a file can be easier verified with the git bisect
command: git bisect run test -f test1.txt
The git filter-branch
command allows you to rewrite the Git commit history. This can be done for selected branches and you can apply custom filters on each revision. This creates different hashes for all modified commits. This implies that you get new IDs for all commits based on any rewritten commit.
The command allows you to filter for several values, e.g., the author, the message, etc. For details please see the git-filter-branch manual page
Using the filter-branch
command is dangerous as it changes the Git repository. It changes the commit IDs and reacting on such a change requires explicit action from the developer, e.g., trying to rebase the stale local branch onto the corresponding rewritten remote-tracking branch.
For example, you can use git filter-branch
if you want to remove a file which contains a password from the Git history. Or you want to remove huge binary files from the history. To completely remove such files, you need to run the filter-branch
command on all branches.
The following command extracts a directory from a Git repository and retains all commits for this subfolder.
The following command replaces the email address of one author from all commits.
A patch is a text file that contains changes to other text files in a standarized format. A patch created with the git format-patch
command includes meta-information about the commit (committer, date, commit message, etc) and also contains the changes introduced in binary data in the commit.
This file can be sent to someone else and the receiver can use it to apply the changes to his local repository. The metadata is preserved.
Alternatively you could create a diff file with the git diff
command, but this diff file does not contain the metadata information.
The following example creates a branch, changes several files and creates a commit recording these changes.
The next example creates a patch for these changes.
To apply this patch to your master branch in a different clone of the repository, switch to it and use the git apply
command.
Afterwards you can commit the changes introduced by the patches and delete the patch file.
Use the git am
command to apply and commit the changes in a single step. To apply and commit all patch files in the directory use, for example, the git am *.patch
command. You specify the order in which the patches are applied by specifying them on the command line.
You can specify the commit ID and the number of patches which should be created. For example, to create a patch for selected commits based on the HEAD pointer you can use the following commands.
Git provides commit hooks, e.g., programs which can be executed at a pre-defined point during the work with the repository. For example, you can ensure that the commit message has a certain format or trigger an action after a push to the server.
These programs are usually scripts and can be written in any language, e.g., as shell scripts or in Perl, Python etc. You can also implement a hook, for example, in C and use the resulting executables. Git calls the scripts based on a naming convention.
Git provides hooks for the client and for the server side. On the server side you can use the pre-receive
and post-receive
script to check the input or to trigger actions after the commit. The usage of a server commit hook requires that you have access to the server. Hosting providers like GitHub or Bitbucket do not offer this access.
If you create a new Git repository, Git creates example scripts in the .git/hooks
directory. The example scripts end with .sample
. To activate them make them executable and remove the .sample
from the filename.
Not all Git server implementations support server side commit hooks. Local hooks in the local repository can be removed by the developer.
Every time a developer presses return on the keyboard an invisible character called a line ending is inserted. Unfortunately, different operating systems handle line endings differently.
Linux and Mac use different line endings than Windows. Windows uses a carriage-return and a linefeed character (CRLF), while Linux and Mac only uses a linefeed character (LF). This becomes a problem if developers use different operating system to commit changes to a Git repository.
To avoid commits because of line ending differences in your Git repository you should configure all clients to write the same line ending to the Git repository.
On Windows systems you can tell Git to convert line endings during a checkout to CRLF and to convert them back to LF during commit. Use the following setting for this.
On Linux and Mac you can tell Git to convert CRLF to LF with the following setting.
You can also configure the line ending handling per repository by adding a special .gitattributes
file to the root folder of your Git repository. If this file is committed to the repository, it overrides the core.autocrlf
setting of the individual developer.
In this file you can configure Git to auto detect the line endings.
To convert Subversion projects to Git you can use a RubyGem called svn2git. This tool relies on git svn
internally and handles most of the trouble.
To install it (on Ubuntu) simply type:
Let's say you have a repository called
http://svn.example.com/repo
with the default layout (trunk, branches, tags) and already prepared a local git repository where you want to put everything. Then navigate to your git directory and use the following commands:
The parameter --verbose
adds detailed output to the commandline so you can see what is going on including potential errors. The second svn2git --rebase
command aligns your new git repository with the svn import. You are now ready to push to the web and get forked! If your svn layout deviates from the standard or other problems occur, seek svn2git --help
for documentation on additional parameters.
The usage of symlinks requires that the operating system used by the developers supports them.
Git as version control system can handle symlinks.
If the symlink points to a file, then Git stores the path information it is symlinking to, and the file type. This is similar to a symlink to a directory; Git does not store the contents under the symlinked directory.
This tutorial is part of a series about the Git version control system. See the other tutorials for more information.
Conceptually a commit object (short:commit) represents a version of all files tracked in the repository at the time the commit was created. Commits know their parent(s) and this way capture the version history of the repository.
This commit object is addressable via a hash ( SHA-1 checksum ). This hash is calculated based on the content of the files, the content of the directories, the complete history of up to the new commit, the committer, the commit message, and several other factors.
This means that Git is safe, you cannot manipulate a file or the commit message in the Git repository without Git noticing that corresponding hash does not fit anymore to the content.
The commit object points to the individual files in this commit via a tree object. The files are stored in the Git repository as blob objects and might be packed by Git for better performance and more compact storage. Blobs are addressed via their SHA-1 hash.
Packing involves storing changes as deltas, compression and storage of many objects in a single pack file. Pack files are accompanied by one or multiple index files which speedup access to individual objects stored in these packs.
A commit object is depicted in the following picture.
The above picture is simplified. Tree objects point to other tree objects and file blobs. Objects which didn't change between commits are reused by multiple commits.
A Git commit object is identified by its hash (SHA-1 checksum). SHA-1 produces a 160-bit (20-byte) hash value. A SHA-1 hash value is typically rendered as a hexadecimal number, 40 digits long.
In a typical Git repository you need fewer characters to uniquely identify a commit object. This short form is called the abbreviated commit hash or abbreviated hash. Sometimes it is also called the shortened SHA-1 or abbreviated SHA-1.
Several commands, e.g., the git log
command can be instructed to use the shortened SHA-1 for their output.
Each commit has zero or more direct predecessor commits. The first commit has zero parents, merge commits have two or more parents, most commits have one parent.
In Git you frequently want to refer to certain commits. For example, you want to tell Git to show you all changes which were done in the last three commits. Or you want to see the differences introduced between two different branches.
Git allows addressing commits via commit reference for this purpose.
A commit reference can be a simple reference (simple ref), in this case it points directly to a commit. This is the case for a commit hash or a tag. A commit reference can also be symbolic reference (symbolic ref, symref). In this case it points to another reference (either simple or symbolic). For example HEAD is a symbolic ref for a branch, if it points to a branch. HEAD points to the branch pointer and the branch pointer points to a commit.
[reference]~1 describes the first predecessor of the commit object accessed via [reference]. [reference]~2 is the first predecessor of the first predecessor of the [reference] commit. [reference]~3 is the first predecessor of the first predecessor of the first predecessor of the [reference] commit, etc.
[reference]~ is an abbreviation for [reference]~1.
For example, you can use the HEAD~1 or HEAD~ reference to access the first parent of the commit to which the HEAD pointer currently points.
[reference]^1 also describes the first predecessor of the commit object accessed via [reference].
For example HEAD^ is the same as HEAD~ and is the same as HEAD~3.
The difference is that [reference]^2 describes the second parent of a commit. A merge commit typically has two predecessors. HEAD^3 means βthe third parent of a merge' and in most cases this won't exist (merges are generally between two commits, though more is possible).
[reference]^ is an abbreviation for [reference]^1.
You can also specify ranges of commits. This is useful for certain Git commands, for example, for seeing the changes between a series of commits.
The double dot operator allows you to select all commits which are reachable from a commit c2 but not from commit c1. The syntax for this is c1..c2
. A commit A is reachable from another commit B if A is a direct or indirect parent of B.
Think of c1..c2 as all commits as of c1 (not including c1) until commit c2.
For example, you can ask Git to show all commits which happened between HEAD and HEAD~4.
This also works for branches. To list all commits which are in the master branch but not in the testing branch, use the following command.
You can also list all commits which are in the testing but not in the master branch.
The triple dot operator allows you to select all commits which are reachable either from commit c1 or commit c2 but not from both of them.
This is useful to show all commits in two branches which have not yet been combined.