Learning Git Ebook
Learning Git Ebook
#git
Table of Contents
About 1
Remarks 2
Versions 2
Examples 4
Clone a repository 5
Sharing code 7
Git Installation 10
Syntax 12
Remarks 12
Examples 12
Chapter 3: Aliases 14
Examples 14
Simple aliases 14
Searching aliases 14
Advanced Aliases 15
Examples 19
Gitflow Workflow 19
Forking Workflow 21
Centralized Workflow 21
GitHub Flow 23
Chapter 5: Archive 25
Syntax 25
Parameters 25
Examples 25
Create archive of git repository based on specific branch, revision, tag or directory 26
Syntax 28
Examples 28
Chapter 7: Blaming 31
Syntax 31
Parameters 31
Remarks 31
Examples 32
Chapter 8: Branching 34
Syntax 34
Parameters 34
Remarks 34
Examples 35
Listing branches 35
Rename a branch 37
Overwrite single file in current working directory with the same from another branch 38
Searching in branches 40
Syntax 41
Parameters 41
Remarks 41
Examples 41
Oneline log 42
Prettier log 43
Log search 44
Filter logs 45
Colorize Logs 46
Examples 50
Introduction 51
Examples 51
Introduction 52
Syntax 52
Parameters 52
Examples 52
Syntax 55
Examples 55
Shallow Clone 55
Regular Clone 55
Clone recursively 56
Introduction 57
Syntax 57
Parameters 57
Examples 58
Amending a commit 58
The basics 60
Shortcuts 60
Sensitive data 61
Syntax 66
Parameters 66
Examples 66
Description 68
Microsoft Windows 68
Setup a proxy 69
.gitconfig-work.config 70
.gitconfig-opensource.config 70
Introduction 72
Examples 72
Usage 72
Examples 74
Examples 75
Examples 76
Introduction 78
Examples 78
Syntax 79
Parameters 79
Examples 79
Clean Interactively 80
Introduction 81
Examples 81
Installing a Hook 81
Syntax 83
Parameters 83
Examples 84
Comparing branches 88
Examples 90
GitHub Desktop 90
Git Kraken 90
SourceTree 90
SmartGit 92
Git Extensions 93
Remarks 94
Examples 94
Install LFS 94
Syntax 96
Parameters 96
Examples 97
Creating a patch 97
Applying patches 98
Syntax 99
Parameters 99
Examples 100
Introduction 103
Examples 103
Remarks 104
Examples 104
Syntax 109
Remarks 109
Examples 109
Composing 109
Syntax 111
Parameters 111
Examples 111
Introduction 114
Syntax 114
Examples 114
Remarks 116
Troubleshooting 116
Examples 117
Remarks 120
Examples 120
Syntax 122
Remarks 122
Examples 122
Commit-msg 122
Post-checkout 123
Post-commit 123
Post-receive 123
Pre-commit 123
Prepare-commit-msg 124
Pre-rebase 124
Pre-receive 124
Update 125
Pre-push 125
Verify Maven build (or other build system) before committing 126
Introduction 128
Examples 128
Examples 128
Ignore files that have already been committed to a Git repository 132
Examples 140
Repo 140
Objects 140
Tree 141
Parent 142
Syntax 145
Parameters 145
Examples 145
Examples 147
SubGit 148
Introduction 151
Syntax 151
Parameters 151
Remarks 151
Examples 151
Introduction 155
Syntax 155
Parameters 155
Remarks 155
Examples 156
Push 156
Explanation 157
Example 158
Example 158
Example 159
Syntax 161
Parameters 161
Remarks 161
Examples 162
On a merge: 163
On a rebase: 163
Summary 166
Assuming: 167
Strategy: 167
Example: 167
Recap 169
Examples 171
With Git, you can (almost) always turn the clock back 172
Chapter 44: Reflog - Restoring commits not shown in git log 174
Remarks 174
Examples 174
Syntax 175
Parameters 175
Examples 175
Examples 177
Syntax 178
Parameters 178
Examples 178
List Commits in master but not in origin/master 178
Examples 179
Syntax 180
Remarks 180
Examples 180
Overview 180
Remarks 182
Examples 182
Remarks 186
Examples 186
Syntax 190
Parameters 190
Remarks 191
Examples 191
Examples 198
Syntax 202
Remarks 202
Examples 202
Examples 204
Delete local branches that have been deleted on the remote 204
Examples 205
Branching 205
Examples 212
Examples 218
Use 218
SYNOPSIS 218
Examples 220
Disable Line Ending Normalization 220
Syntax 221
Examples 221
ls-remote 221
Example 223
Syntax 226
Parameters 226
Remarks 226
Examples 226
Credits 229
About
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: git
It is an unofficial and free Git ebook created for educational purposes. All the content is extracted
from Stack Overflow Documentation, which is written by many hardworking individuals at Stack
Overflow. It is neither affiliated with Stack Overflow nor official Git.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/ 1
Chapter 1: Getting started with Git
Remarks
Git is a free, distributed version control system which allows programmers to keep track of code
changes, via "snapshots" (commits), in its current state. Utilizing commits allows programmers to
test, debug, and create new features collaboratively. All commits are kept in what is known as a
"Git Repository" that can be hosted on your computer, private servers, or open source websites,
such at Github.
Git also allows for users to create new "branches" of the code, which allows different versions of
the code to live alongside each other. This enables scenarios where one branch contains the most
recent stable version, a different branch contains a set of new features being developed, and a yet
another branch contains a different set of features. Git makes the process of creating these
branches, and then subsequently merging them back together, nearly painless.
• Working directory: The area that you will be doing all of your work in (creating, editing,
deleting, and organizing files)
• Staging area: The area where you will list the changes that you have made to the working
directory
• Repository: Where Git permanently stores the changes you have made as different
versions of the project
Git was originally created for managing the Linux kernel source. By making them easier, it
encourages small commits, forking of projects and merging between forks, and having lots of
short-lived branches.
The biggest change for people who are used to CVS or Subversion is that every checkout
contains not only the source tree, but also the whole history of the project. Common operations
like diffing of revisions, checking out older revisions, committing (to your local history), creating a
branch, checking out a different branch, merging branches or patch files can all be done locally
without having to communicate with a central server. Thus the biggest source of latency and
unreliability is removed. Communicating with the "upstream" repository is only needed to get the
latest changes, and to publish your local changes to other developers. This turns what was
previously a technical constraint (whoever has the repository owns the project) into an
organisational choice (your "upstream" is whomever you choose to sync with).
Versions
2.13 2017-05-10
2.12 2017-02-24
https://riptutorial.com/ 2
Version Release Date
2.11.1 2017-02-02
2.11 2016-11-29
2.10.2 2016-10-28
2.10 2016-09-02
2.9 2016-06-13
2.8 2016-03-28
2.7 2015-10-04
2.6 2015-09-28
2.5 2015-07-27
2.4 2015-04-30
2.3 2015-02-05
2.2 2014-11-26
2.1 2014-08-16
2.0 2014-05-28
1.9 2014-02-14
1.8.3 2013-05-24
1.8 2012-10-21
1.7.10 2012-04-06
1.7 2010-02-13
1.6.5 2009-10-10
1.6.3 2009-05-07
1.6 2008-08-17
1.5.3 2007-09-02
1.5 2007-02-14
1.4 2006-06-10
https://riptutorial.com/ 3
Version Release Date
1.3 2006-04-18
1.2 2006-02-12
1.1 2006-01-08
1.0 2005-12-21
0.99 2005-07-11
Examples
Create your first repository, then add and commit files
At the command line, first verify that you have Git installed:
git --version
which git
If nothing is returned, or the command is not recognized, you may have to install Git on your
system by downloading and running the installer. See the Git homepage for exceptionally clear
and easy installation instructions.
After installing Git, configure your username and email address. Do this before making a commit.
Once Git is installed, navigate to the directory you want to place under version control and create
an empty Git repository:
git init
This creates a hidden folder, .git, which contains the plumbing needed for Git to work.
Next, check what files Git will add to your new repository; this step is worth special care:
git status
Review the resulting list of files; you can tell Git which of the files to place into version control
(avoid adding files with confidential information such as passwords, or files that just clutter the
repo):
git add <file/directory name #1> <file/directory name #2> < ... >
https://riptutorial.com/ 4
If all files in the list should be shared with everyone who has access to the repository, a single
command will add everything in your current directory and its subdirectories:
git add .
This will "stage" all files to be added to version control, preparing them to be committed in your
first commit.
For files that you want never under version control, create and populate a file named .gitignore
before running the add command.
Commit all the files that have been added, along with a commit message:
This creates a new commit with the given message. A commit is like a save or snapshot of your
entire project. You can now push, or upload, it to a remote repository, and later you can jump back
to it if necessary.
If you omit the -m parameter, your default editor will open and you can edit and save the commit
message there.
Adding a remote
To add a new remote, use the git remote add command on the terminal, in the directory your
repository is stored at.
NOTE: Before adding the remote you have to create the required repository in your git service,
You'll be able to push/pull commits after adding your remote.
Clone a repository
The git clone command is used to copy an existing Git repository from a server to the local
machine.
https://riptutorial.com/ 5
cd <path where you'd like the clone to create a directory>
git clone https://[email protected]/username/projectname.git
This creates a directory called projectname on the local machine, containing all the files in the
remote Git repository. This includes source files for the project, as well as a .git sub-directory
which contains the entire history and configuration for the project.
Note:
The https version and the ssh version are equivalent. However, some hosting services such as
GitHub recommend that you use https rather than ssh.
If you have cloned a fork (e.g. an open source project on Github) you may not have push access
to the upstream repository, so you need both your fork but be able to fetch the upstream
repository.
$ git remote -v
origin https://github.com/myusername/repo.git (fetch)
origin https://github.com/myusername/repo.git (push)
upstream # this line may or may not be here
If upstream is there already (it is on some Git versions) you need to set the URL (currently it's
empty):
If the upstream is not there, or if you also want to add a friend/colleague's fork (currently they do
not exist):
https://riptutorial.com/ 6
$ git remote add dave https://github.com/dave/repo.git
Sharing code
To share your code you create a repository on a remote server to which you will copy your local
repository.
To minimize the use of space on the remote server you create a bare repository: one which has
only the .git objects and doesn't create a working copy in the filesystem. As a bonus you set this
remote as an upstream server to easily share updates with other programmers.
(Note that ssh: is just one possible way of accessing the remote repository.)
Adding --set-upstream (or -u) created an upstream (tracking) reference which is used by argument-
less Git commands, e.g. git pull.
You need to set who you are *before* creating any commit. That will allow commits to have the
right author name and email associated to them.
It has nothing to do with authentication when pushing to a remote repository (e.g. when
pushing to a remote repository using your GitHub, BitBucket, or GitLab account)
To declare that identity for all repositories, use git config --global
This will store the setting in your user's .gitconfig file: e.g. $HOME/.gitconfig or for Windows,
%USERPROFILE%\.gitconfig.
To declare an identity for a single repository, use git config inside a repo.
This will store the setting inside the individual repository, in the file $GIT_DIR/config. e.g.
/path/to/your/repo/.git/config.
https://riptutorial.com/ 7
cd /path/to/my/repo
git config user.name "Your Login At Work"
git config user.email [email protected]
Settings stored in a repository's config file will take precedence over the global config when you
use that repository.
Tips: if you have different identities (one for open-source project, one at work, one for private
repos, ...), and you don't want to forget to set the right one for each different repos you are working
on:
2.8
• To force git to look for your identity only within a repository's settings, not in the global config:
That way, if you forget to set your user.name and user.email for a given repository and try to make a
commit, you will see:
To get more information about any git command – i.e. details about what the command does,
available options and other documentation – use the --help option or the help command.
For example, to get all available information about the git diff command, use:
Similarly, to get all available information about the status command, use:
If you only want a quick help showing you the meaning of the most used command line flags, use
-h:
git checkout -h
https://riptutorial.com/ 8
Set up SSH for Git
If you are using Windows open Git Bash. If you are using Mac or Linux open your Terminal.
Before you generate an SSH key, you can check to see if you have any existing SSH keys.
$ ls -al ~/.ssh
# Lists all the files in your ~/.ssh directory
Check the directory listing to see if you already have a public SSH key. By default the filenames of
the public keys are one of the following:
id_dsa.pub
id_ecdsa.pub
id_ed25519.pub
id_rsa.pub
If you see an existing public and private key pair listed that you would like to use on your
Bitbucket, GitHub (or similar) account you can copy the contents of the id_*.pub file.
If not, you can create a new public and private key pair with the following command:
$ ssh-keygen
Press the Enter or Return key to accept the default location. Enter and re-enter a passphrase
when prompted, or leave it empty.
Ensure your SSH key is added to the ssh-agent. Start the ssh-agent in the background if it's not
already running:
Add you SSH key to the ssh-agent. Notice that you'll need te replace id_rsa in the command with
the name of your private key file:
$ ssh-add ~/.ssh/id_rsa
If you want to change the upstream of an existing repository from HTTPS to SSH you can run the
following command:
In order to clone a new repository over SSH you can run the following command:
https://riptutorial.com/ 9
Git Installation
Let’s get into using some Git. First things first—you have to install it. You can get it a number of
ways; the two major ones are to install it from source or to install an existing package for your
platform.
If you can, it’s generally useful to install Git from source, because you’ll get the most recent
version. Each version of Git tends to include useful UI enhancements, so getting the latest version
is often the best route if you feel comfortable compiling software from source. It is also the case
that many Linux distributions contain very old packages; so unless you’re on a very up-to-date
distro or are using backports, installing from source may be the best bet.
To install Git, you need to have the following libraries that Git depends on: curl, zlib, openssl,
expat, and libiconv. For example, if you’re on a system that has yum (such as Fedora) or apt-get
(such as a Debian based system), you can use one of these commands to install all of the
dependencies:
When you have all the necessary dependencies, you can go ahead and grab the latest snapshot
from the Git web site:
After this is done, you can also get Git via Git itself for updates:
Installing on Linux
If you want to install Git on Linux via a binary installer, you can generally do so through the basic
package-management tool that comes with your distribution. If you’re on Fedora, you can use
yum:
https://riptutorial.com/ 10
$ apt-get install git
Installing on Mac
There are three easy ways to install Git on a Mac. The easiest is to use the graphical Git installer,
which you can download from the SourceForge page.
http://sourceforge.net/projects/git-osx-installer/
Figure 1-7. Git OS X installer. The other major way is to install Git via MacPorts (
http://www.macports.org). If you have MacPorts installed, install Git via
You don’t have to add all the extras, but you’ll probably want to include +svn in case you ever
have to use Git with Subversion repositories (see Chapter 8).
Homebrew (http://brew.sh/) is another alternative to install Git. If you have Homebrew installed,
install Git via
Installing on Windows
Installing Git on Windows is very easy. The msysGit project has one of the easier installation
procedures. Simply download the installer exe file from the GitHub page, and run it:
http://msysgit.github.io
After it’s installed, you have both a command-line version (including an SSH client that will come in
handy later) and the standard GUI.
Note on Windows usage: you should use Git with the provided msysGit shell (Unix style), it allows
to use the complex lines of command given in this book. If you need, for some reason, to use the
native Windows shell / command line console, you have to use double quotes instead of single
quotes (for parameters with spaces in them) and you must quote the parameters ending with the
circumflex accent (^) if they are last on the line, as it is a continuation symbol in Windows.
https://riptutorial.com/ 11
Chapter 2: .mailmap file: Associating
contributor and email aliases
Syntax
• # Only replace email addresses
<[email protected]> <[email protected]>
• # Replace name by email address
Contributor <[email protected]>
• # Merge multiple aliases under one name and email
# Note this will not associate 'Other <[email protected]>'.
Contributor <[email protected]> <[email protected]> Contributor
<[email protected]>
Remarks
A .mailmap file may be created in any text editor and is just a plain text file containing optional
contributor names, primary email addresses, and their aliases. it has to be placed in the project's
root, next to the .git directory.
Keep in mind that this just modifies the visual output of commands like git shortlog or git log --
use-mailmap. This will not rewrite commit history or prevent commits with varying names and/or
email addresses.
To prevent commits based on information such as email addresses, you should use git hooks
instead.
Examples
Merge contributers by aliases to show commit count in shortlog.
When contributors add to a project from different machines or operating systems, it may happen
that they use different email addresses or names for this, which will fragment contributor lists and
statistics.
Running git shortlog -sn to get a list of contributors and the number of commits by them could
result in the following output:
https://riptutorial.com/ 12
containing email mappings.
All names and email addresses listed in one line will be associated to the first named entity
respectively.
Once this file exists in the project's root, running git shortlog -sn again will result in a condensed
list:
https://riptutorial.com/ 13
Chapter 3: Aliases
Examples
Simple aliases
[alias]
ci = commit
st = status
co = checkout
As with regular git commands, aliases can be used beside arguments. For example:
Searching aliases
To search aliases, add the following to your .gitconfig under [alias]:
aliases = !git config --list | grep ^alias\\. | cut -c 7- | grep -Ei --color \"$1\" "#"
https://riptutorial.com/ 14
• git aliases - show ALL aliases
• git aliases commit - only aliases containing "commit"
Advanced Aliases
Git lets you use non-git commands and full sh shell syntax in your aliases if you prefix them with !.
[alias]
temp = !git add -A && git commit -m "Temp"
The fact that full shell syntax is available in these prefixed aliases also means you can use shell
functions to construct more complex aliases, such as ones which utilize command line arguments:
[alias]
ignore = "!f() { echo $1 >> .gitignore; }; f"
The above alias defines the f function, then runs it with any arguments you pass to the alias. So
running git ignore .tmp/ would add .tmp/ to your .gitignore file.
In fact, this pattern is so useful that Git defines $1, $2, etc. variables for you, so you don't even
have to define a special function for it. (But keep in mind that Git will also append the arguments
anyway, even if you access it via these variables, so you may want to add a dummy command at
the end.)
Note that aliases prefixed with ! in this way are run from the root directory of your git checkout,
even if your current directory is deeper in the tree. This can be a useful way to run a command
from the root without having to cd there explicitly.
[alias]
ignore = "! echo $1 >> .gitignore"
https://riptutorial.com/ 15
watchall = "!git unwatched | xargs -L 1 -I % sh -c 'git watch `echo % | cut -c 2-`'"
[alias]
logp=log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short
Here an explanation of the options and placeholder used in the --pretty format (exhaustive list are
available with git help log )
--branches - show all local branches (by default, only current branch is shown)
%s - commit message
https://riptutorial.com/ 16
%ad - author date (will follow --date directive) (and not commiter date)
Sometimes you need to keep a linear (non-branching) history of your code commits. If you are
working on a branch for a while, this can be tricky if you have to do a regular git pull since that
will record a merge with upstream.
[alias]
up = pull --rebase
This will update with your upstream source, then reapply any work you have not pushed on top of
whatever you pulled down.
To use:
git up
[ alias ]
Shows one line per file, so you can grep (only directories):
Or count:
~$ git ignored | wc -l
199811 # oops, my home directory is getting crowded
Normally, to remove files that are staged to be committed using the git reset commit, reset has a
lot of functions depending on the arguments provided to it. To completely unstage all files staged,
we can make use of git aliases to create a new alias that uses reset but now we do not need to
remember to provide the correct arguments to reset.
Now, any time you want to unstage stages files, type git unstage and you are good to go.
https://riptutorial.com/ 17
Read Aliases online: https://riptutorial.com/git/topic/337/aliases
https://riptutorial.com/ 18
Chapter 4: Analyzing types of workflows
Remarks
Using version control software like Git may be a little scary at first, but its intuitive design
specializing with branching helps make a number of different types of workflows possible. Pick one
that is right for your own development team.
Examples
Gitflow Workflow
Originally proposed by Vincent Driessen, Gitflow is a development workflow using git and several
pre-defined branches. This can seen as a special case of the Feature Branch Workflow.
The idea of this one is to have separate branches reserved for specific parts in development:
• master branch is always the most recent production code. Experimental code does not
belong here.
• develop branch contains all of the latest development. These developmental changes can be
pretty much anything, but larger features are reserved for their own branches. Code here is
always worked on and merged into release before release / deployment.
• hotfix branches are for minor bug fixes, which cannot wait until the next release. hotfix
branches come off of master and are merged back into both master and develop.
• release branches are used to release new development from develop to master. Any last
minute changes, such as bumping version numbers, are done in the release branch, and
then are merged back into master and develop. When deploying a new version, master should
be tagged with the current version number (e.g. using semantic versioning) for future
reference and easy rollback.
• feature branches are reserved for bigger features. These are specifically developed in
designated branches and integrated with develop when finished. Dedicated feature branches
help to separate development and to be able to deploy done features independently from
each other.
https://riptutorial.com/ 19
The original representation of this model:
https://riptutorial.com/ 20
https://riptutorial.com/ 21
branch contains all active development. Contributors will need to be especially sure they pull the
latest changes before continuing development, for this branch will be changing rapidly. Everyone
has access to this repo and can commit changes right to the master branch.
This is the classic version control paradigm, upon which older systems like Subversion and CVS
were built. Softwares that work this way are called Centralized Version Control Systems, or
CVCS's. While Git is capable of working this way, there are notable disadvantages, such as being
required to precede every pull with a merge. It's very possible for a team to work this way, but the
constant merge conflict resolution can end up eating a lot of valuable time.
This is why Linus Torvalds created Git not as a CVCS, but rather as a DVCS, or Distributed
Version Control System, similar to Mercurial. The advantage to this new way of doing things is the
flexibility demonstrated in the other examples on this page.
https://riptutorial.com/ 22
The core idea behind the Feature Branch Workflow is that all feature development should take
place in a dedicated branch instead of the master branch. This encapsulation makes it easy for
multiple developers to work on a particular feature without disturbing the main codebase. It also
means the master branch will never contain broken code, which is a huge advantage for
continuous integration environments.
Encapsulating feature development also makes it possible to leverage pull requests, which are a
way to initiate discussions around a branch. They give other developers the opportunity to sign off
on a feature before it gets integrated into the official project. Or, if you get stuck in the middle of a
feature, you can open a pull request asking for suggestions from your colleagues. The point is, pull
requests make it incredibly easy for your team to comment on each other’s work.
GitHub Flow
Master branch of a specific location (Github, Gitlab, Bitbucket, local server) contains the latest
shippable version. For each new feature/bug fix/architectural change each developer creates a
branch.
Changes happen on that branch and can be discussed in a pull request, code review, etc. Once
accepted they get merged to the master branch.
https://riptutorial.com/ 23
Image courtesy of the GitHub Flow reference
https://riptutorial.com/ 24
Chapter 5: Archive
Syntax
• git archive [--format=<fmt>] [--list] [--prefix=<prefix>/] [<extra>] [-o <file> | --output=<file>] [--
worktree-attributes] [--remote=<repo> [ --exec=<git-upload-archive>]] <tree-ish> [<path>...]
Parameters
Parameter Details
Format of the resulting archive: tar or zip. If this options is not given
--format=<fmt> and the output file is specified, the format is inferred from the filename if
possible. Otherwise, defaults to tar.
-o <file>, --
Write the archive to <file> instead of stdout.
output=<file>
--worktree-
Look for attributes in .gitattributes files in the working tree.
attributes
This can be any options that the archiver backend understands. For zip
<extra> backend, using -0 will store the files without deflating them, while -1
through -9 can be used to adjust compression speed and ratio.
Retrieve a tar archive from a remote repository <repo> rather than the
--remote=<repo>
local repository.
--exec=<git- Used with --remote to specify the path to the <git-upload-archive on the
upload-archive> remote.
Examples
https://riptutorial.com/ 25
Create an archive of git repository with directory prefix
It is considered good practice to use a prefix when creating git archives, so that extraction will
place all files inside a directory. To create an archive of HEAD with a directory prefix:
When extracted all the files will be extracted inside a directory named src-directory-name in the
current directory.
It is also possible to create archives of other items than HEAD, such as branches, commits, tags,
and directories.
Create an archive of files inside a specific sub directory (sub-dir) of revision HEAD:
With git archive it is possible to create compressed archives of a repository, for example for
distributing releases.
This can also be done with (which will use the in-built tar.gz handling):
https://riptutorial.com/ 26
git archive --format tar.gz HEAD > archive-HEAD.tar.gz
Alternatively it is possible to just specify an output file with valid extension and the format and
compression type will be inferred from it:
https://riptutorial.com/ 27
Chapter 6: Bisecting/Finding faulty commits
Syntax
• git bisect <subcommand> <options>
Examples
Binary search (git bisect)
git bisect allows you to find which commit introduced a bug using a binary search.
Start by bisecting a session by providing two commit references: a good commit before the bug,
and a bad commit after the bug. Generally, the bad commit is HEAD.
git starts a binary search: It splits the revision in half and switches the repository to the
intermediate revision. Inspect the code to determine if the revision is good or bad:
git will continue to run the binary search on each remaining subset of bad revisions depending on
your instructions. git will present a single revision that, unless your flags were incorrect, will
represent exactly the revision where the bug was introduced.
Afterwards remember to run git bisect reset to end the bisect session and return to HEAD.
https://riptutorial.com/ 28
If you have a script that can check for the bug, you can automate the process with:
Where [script] is the path to your script and [arguments] is any arguments that should be passed
to your script.
Running this command will automatically run through the binary search, executing git bisect good
or git bisect bad at each step depending on the exit code of your script. Exiting with 0 indicates
good, while exiting with 1-124, 126, or 127 indicates bad. 125 indicates that the script cannot test
that revision (which will trigger a git bisect skip).
Imagine you are on the master branch and something is not working as expected (a regression
was introduced), but you don't know where. All you know is, that is was working in the last release
(which was e.g., tagged or you know the commit hash, lets take old-rel here).
Git has help for you, finding the faulty commit which introduced the regression with a very low
number of steps (binary search).
This will tell git that master is a broken revision (or the first broken version) and old-rel is the last
known version.
Git will now check out a detached head in the middle of both commits. Now, you can do your
testing. Depending on whether it works or not issue
or
. In case this commit cannot be tested, you can easily git reset and test that one, git willl take
care of this.
After a few steps git will output the faulty commit hash.
https://riptutorial.com/ 29
Read Bisecting/Finding faulty commits online: https://riptutorial.com/git/topic/3645/bisecting-
finding-faulty-commits
https://riptutorial.com/ 30
Chapter 7: Blaming
Syntax
• git blame [filename]
• git blame [-f][-e][-w] [filename]
• git blame [-L range] [filename]
Parameters
Parameter Details
Ignore white spaces while making a comparison between child and parent's
-w
version
-L start,end Show only the given line range Example: git blame -L 1,2 [filename]
-p, --
Output for machine consumption
porcelain
In addition to -M, detect lines moved or copied from other files that were
-C
modified in the same commit
Remarks
https://riptutorial.com/ 31
The git blame command is very useful when it comes to know who has made changes to a file on
a per line base.
Examples
Show the commit that last modified a line
git blame <file>
will show the file with each line annotated with the commit that last modified it.
Sometimes repos will have commits that only adjust whitespace, for example fixing indentation or
switching between tabs and spaces. This makes it difficult to find the commit where the code was
actually written.
git blame -w
will ignore whitespace-only changes to find where the line really came from.
• line number
• /regex/
Multiple line ranges can be specified, and overlapping ranges are allowed.
https://riptutorial.com/ 32
// Limits the selection of lines by specified range
git blame -L 1,10 test.c
https://riptutorial.com/ 33
Chapter 8: Branching
Syntax
• git branch [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
• git branch (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
• git branch --unset-upstream [<branchname>]
• git branch (-m | -M) [<oldbranch>] <newbranch>
• git branch (-d | -D) [-r] <branchname>…
• git branch --edit-description [<branchname>]
• git branch [--color[=<when>] | --no-color] [-r | -a] [--list] [-v [--abbrev=<length> | --
no-abbrev]] [--column[=<options>] | --no-column] [(--merged | --no-merged | --contains)
[<commit>]] [--sort=<key>] [--points-at <object>] [<pattern>…]
Parameters
Parameter Details
Delete a branch. The branch must be fully merged in its upstream branch, or in
-d, --delete
HEAD if no upstream was set with --track or --set-upstream
-r, --
List or delete (if used with -d) the remote-tracking branches
remotes
Activate the list mode. git would try to create a branch, use
branch <pattern>
--list
git branch --list <pattern> to list matching branches
If specified branch does not exist yet or if --force has been given, acts exactly
--set-
like --track. Otherwise sets up configuration like --track would when creating
upstream
the branch, except that where branch points to is not changed
Remarks
Every git repository has one or more branches. A branch is a named reference to the HEAD of a
sequence of commits.
A git repo has a current branch (indicated by a * in the list of branch names printed by the git
branch command), Whenever you create a new commit with the git commit command, your new
commit becomes the HEAD of the current branch, and the previous HEAD becomes the parent of
https://riptutorial.com/ 34
the new commit.
A new branch will have the same HEAD as the branch from which it was created until something is
committed to the new branch.
Examples
Listing branches
Git provides multiple commands for listing branches. All commands use the function of git branch,
which will provide a list of a certain branches, depending on which options are put on the
command line. Git will if possible, indicate the currently selected branch with a star next to it.
Goal Command
List remote and local branches git branch -a OR git branch --all
Notes:
• Adding an additional v to -v e.g. $ git branch -avv or $ git branch -vv will print the name of
the upstream branch as well.
• Branches shown in red color are remote branches
Generally, the branch name must not contain spaces and is subject to other specifications listed
here. To switch to an existing branch :
https://riptutorial.com/ 35
git checkout <name>
To create a branch at a point other than the last commit of the current branch (also known as
HEAD), use either of these commands:
The <start-point> can be any revision known to git (e.g. another branch name, commit SHA, or a
symbolic reference such as HEAD or a tag name):
If a given branch name is only found on one remote, you can simply use
which is equivalent to
Sometimes you may need to move several of your recent commits to a new branch. This can be
achieved by branching and "rolling back", like so:
Initial state After git branch <new_name> After git reset --hard HEAD~2
newBranch newBranch
↓ ↓
A-B-C-D-E (HEAD) A-B-C-D-E (HEAD) A-B-C-D-E (HEAD)
↑ ↑ ↑
master master master
https://riptutorial.com/ 36
Delete a branch locally
Deletes the branch named dev if its changes are merged with another branch and will not be lost. If
the dev branch does contain changes that have not yet been merged that would be lost, git branch
-d will fail:
Per the warning message, you can force delete the branch (and lose any unmerged changes in
that branch) by using the -D flag:
There are three ways of creating a new branch feature which tracks the remote branch
origin/feature:
where:
Rename a branch
https://riptutorial.com/ 37
git branch -m branch_you_want_to_rename new_branch_name
Overwrite single file in current working directory with the same from another
branch
The checked out file will overwrite not yet commited changes you did in this file.
This command will check out the file file.example (which is located in the directory path/to/) and
overwrite any changes you might have made to this file.
some-branch can be anything tree-ish known to git (see Revision Selection and gitrevisions for
more details)
You have to add -- before the path if your file could be mistaken for a file (optional otherwise). No
more options can be supplied after the --.
To delete a branch on the origin remote repository, you can use for Git version 1.5.0 and newer
and as of Git version 1.7.0, you can delete a remote branch using
To delete a branch locally. Note that this will not delete the branch if it has any unmerged
changes:
https://riptutorial.com/ 38
git branch -D <branchName>
The first commit made on this new branch will have no parents and it will be the root of
a new history totally disconnected from all the other branches and commits.
source
For example:
As an example, you usually run git push origin master to push your local changes to your online
repository.
Using -u (short for --set-upstream) will set up the tracking information during the push.
By default, git pushes the local branch to a remote branch with the same name. For example, if
you have a local called new-feature, if you push the local branch it will create a remote branch new-
feature as well. If you want to use a different name for the remote branch, append the remote
name after the local branch name, separated by ::
A branch is just a pointer to a commit, so you can freely move it around. To make it so that the
branch is referring to the commit aabbcc, issue the command
Please note that this will overwrite your branch's current commit, and as so, its entire history. You
might loose some work by issuing this command. If that's the case, you can use the reflog to
https://riptutorial.com/ 39
recover the lost commits. It can be advised to perform this command on a new branch instead of
your current one.
However, this command can be particularly useful when rebasing or doing such other large history
modifications.
git checkout -
Searching in branches
To list local and remote branches that contain a specific commit or tag
https://riptutorial.com/ 40
Chapter 9: Browsing the history
Syntax
• git log [options] [revision range] [[--] path...]
Parameters
Parameter Explanation
--use-mailmap Use mail map file (changes user info for committing user)
Show log for specific range of lines in a file, counting from 1. Starts
--L <n,m:file>
from line n, goes to line m. Also shows diff.
-i, --regexp-ignore- Match the regular expression limiting patterns without regard to letter
case case
Remarks
References and up-to-date documentation : git-log official documentation
Examples
"Regular" Git Log
git log
will display all your commits with the author and hash. This will be shown over multiple lines per
commit. (If you wish to show a single line per commit, look at onelineing). Use the q key to exit the
log.
By default, with no arguments, git log lists the commits made in that repository in
reverse chronological order – that is, the most recent commits show up first. As you
can see, this command lists each commit with its SHA-1 checksum, the author’s name
and email, the date written, and the commit message. - source
https://riptutorial.com/ 41
Example (from Free Code Camp repository):
commit 87ef97f59e2a2f4dc425982f76f14a57d0900bcf
Merge: e50ff0d eb8b729
Author: Brian <[email protected]>
Date: Thu Mar 24 15:52:07 2016 -0700
commit eb8b7298d516ea20a4aadb9797c7b6fd5af27ea5
Author: BKinahan <[email protected]>
Date: Thu Mar 24 21:11:36 2016 +0000
commit e50ff0d249705f41f55cd435f317dcfd02590ee7
Merge: 6b01875 2652d04
Author: Mrugesh Mohapatra <[email protected]>
Date: Thu Mar 24 14:26:04 2016 +0530
If you wish to limit your command to last n commits log you can simply pass a parameter. For
example, if you wish to list last 2 commits logs
git log -2
Oneline log
will show all of your commits with only the first part of the hash and the commit message. Each
commit will be in a single line, as the oneline flag suggests.
The oneline option prints each commit on a single line, which is useful if you’re looking
at a lot of commits. - source
Example (from Free Code Camp repository, with the same section of code from the other
example):
If you wish to limit you command to last n commits log you can simply pass a parameter. For
https://riptutorial.com/ 42
example, if you wish to list last 2 commits logs
Prettier log
sample output :
To see the log with changes inline, use the -p or --patch options.
ommit 8ea1452aca481a837d9504f1b2c77ad013367d25
Author: Raymond Chou <[email protected]>
Date: Wed Mar 2 10:35:25 2016 -0800
https://riptutorial.com/ 43
index 1120a00..9bef0ce 100644
--- a/README.md
+++ b/README.md
@@ -134,7 +134,7 @@ the control function threw, but *after* testing the other functions and
readying
the logging. The criteria for matching errors is based on the constructor and
message.
## Asynchronous behaviors
commit d3178a22716cc35b6a2bdd679a7ec24bc8c63ffa
:
Log search
Searches for addition or removal of specific string or the string matching provided REGEXP. In
this case we're looking for addition/removal of the string #define SAMPLES. For example:
or
Searches for changes in lines containing specific string or the string matching provided
REGEXP. For example:
If no parameters are given, a list of all commits made per committer will be shown in chronological
order.
$ git shortlog
Committer 1 (<number_of_commits>):
Commit Message 1
Commit Message 2
...
https://riptutorial.com/ 44
Committer 2 (<number_of_commits>):
Commit Message 1
Commit Message 2
...
To simply see the number of commits and suppress the commit description, pass in the summary
option:
-s
--summary
$ git shortlog -s
<number_of_commits> Committer 1
<number_of_commits> Committer 2
To sort the output by number of commits instead of alphabetically by committer name, pass in the
numbered option:
-n
--numbered
-e
A custom format option can also be provided if you want to display information other than the
commit subject:
--format
This can be any string accepted by the --format option of git log.
Filter logs
As with other commands and flags that accept a date parameter, the allowed date format is as
supported by GNU date (highly flexible).
https://riptutorial.com/ 45
An alias to --after is --since.
commit message
Colorize Logs
The format option allows you to specify your own log output format:
Parameter Details
%d ref names
https://riptutorial.com/ 46
Parameter Details
tree = log --oneline --decorate --source --pretty=format:'"%Cblue %h %Cgreen %ar %Cblue %an
%C(yellow) %d %Creset %s"' --all --graph
example
* 40554ac 3 months ago Alexander Zolotov Merge pull request #95 from
gmandnepr/external_plugins
|\
| * e509f61 3 months ago Ievgen Degtiarenko Documenting new property
| * 46d4cb6 3 months ago Ievgen Degtiarenko Running idea with external plugins
| * 6253da4 3 months ago Ievgen Degtiarenko Resolve external plugin classes
| * 9fdb4e7 3 months ago Ievgen Degtiarenko Keep original artifact name as this may be
important for intellij
| * 22e82e4 3 months ago Ievgen Degtiarenko Declaring external plugin in intellij
section
|/
* bc3d2cb 3 months ago Alexander Zolotov Ignore DTD in plugin.xml
will show the commits that are on foo and not on master. Helpful for seeing
git log master..foo
what commits you've added since branching!
Example:
commit 4ded994d7fc501451fa6e233361887a2365b91d1
Author: Manassés Souza <[email protected]>
Date: Mon Jun 6 21:32:30 2016 -0300
mltracking-poc/.gitignore | 1 +
mltracking-poc/pom.xml | 14 ++++++++++++--
2 files changed, 13 insertions(+), 2 deletions(-)
commit 506fff56190f75bc051248770fb0bcd976e3f9a5
Author: Manassés Souza <[email protected]>
Date: Sat Jun 4 12:35:16 2016 -0300
.gitignore | 42
++++++++++++
https://riptutorial.com/ 47
mltracking-poc/mvnw | 233
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mltracking-poc/mvnw.cmd | 145
+++++++++++++++++++++++++++++++++++++++
mltracking-poc/pom.xml | 74
++++++++++++++++++++
mltracking-poc/src/main/java/br/com/mls/mltracking/MltrackingPocApplication.java | 12
++++
mltracking-poc/src/main/resources/application.properties | 0
mltracking-poc/src/test/java/br/com/mls/mltracking/MltrackingPocApplicationTests.java | 18
+++++
7 files changed, 524 insertions(+)
Example
commit 48c83b3690dfc7b0e622fd220f8f37c26a77c934
Author: Matt Clark <[email protected]>
Date: Wed May 4 18:26:40 2016 -0400
Example:
Will search for removed file string in all logs in all branches.
https://riptutorial.com/ 48
Starting from git 2.4+, the search can be inverted using the --invert-grep option.
Example:
https://riptutorial.com/ 49
Chapter 10: Bundles
Remarks
The key to making this work is to begin by cloning a bundle that starts from the beginning of the
repo history:
Examples
Creating a git bundle on the local machine and using it on another
Sometimes you may want maintain versions of a git repository on machines that have no network
connection. Bundles allow you to package git objects and references in a repository on one
machine and import those into a repository on another.
Somehow transfer the changes_between_tags.bundle file to the remote machine; e.g., via
thumb drive. Once you have it there:
The reverse is also possible. Once you've made changes on the remote repository you can bundle
up the deltas; put the changes on, e.g., a thumb drive, and merge them back into the local
repository so the two can stay in sync without requiring direct git, ssh, rsync, or http protocol
access between the machines.
https://riptutorial.com/ 50
Chapter 11: Change git repository name
Introduction
If you change repository name on the remote side, such as your github or bitbucket, when you
push your exisiting code, you will see error: Fatal error, repository not found**.
Examples
Change local setting
Go to terminal,
cd projectFolder
git remote -v (it will show previous git url)
git remote set-url origin https://[email protected]/username/newName.git
git remote -v (double check, it will show new git url)
git push (do whatever you want.)
https://riptutorial.com/ 51
Chapter 12: Cherry Picking
Introduction
A cherry-pick takes the patch that was introduced in a commit and tries to reapply it on the branch
you’re currently on.
Syntax
• git cherry-pick [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] [-S[key-id]] commit...
• git cherry-pick --continue
• git cherry-pick --quit
• git cherry-pick --abort
Parameters
Parameters Details
With this option, git cherry-pick will let you edit the commit message prior to
-e, --edit
committing.
When recording the commit, append a line that says "(cherry picked from
commit …)" to the original commit message in order to indicate which commit
-x
this change was cherry-picked from. This is done only for cherry picks without
conflicts.
If the current HEAD is the same as the parent of the cherry-pick’ed commit,
--ff
then a fast forward to this commit will be performed.
Forget about the current operation in progress. Can be used to clear the
--quit
sequencer state after a failed cherry-pick or revert.
Examples
Copying a commit from one branch to another
git cherry-pick <commit-hash> will apply the changes made in an existing commit to another
https://riptutorial.com/ 52
branch, while recording a new commit. Essentially, you can copy commits from branch to branch.
We can run
Where the new commit a66b23 has the same content (source diff, commit message) as b886a0 (but
a different parent). Note that cherry-picking will only pick up changes on that commit(b886a0 in this
case) not all the changes in feature branch (for this you will have to either use rebasing or
merging).
git cherry-pick <commit-A>..<commit-B> will place every commit after A and up to and including B
on top of the currently checked-out branch.
git cherry-pick <commit-A>^..<commit-B> will place commit A and every commit up to and including
B on top of the currently checked-out branch.
Before you start the cherry-pick process, you can check if the commit you want to cherry-pick
already exists in the target branch, in which case you don't have to do anything.
git branch --contains <commit> lists local branches that contain the specified commit.
git branch -r --contains <commit> also includes remote tracking branches in the list.
Command git cherry shows the changes which haven't yet been cherry-picked.
Example:
https://riptutorial.com/ 53
git checkout master
git cherry development
+ 492508acab7b454eee8b805f8ba906056eede0ff
- 5ceb5a9077ddb9e78b1e8f24bfc70e674c627949
+ b4459544c000f4d51d1ec23f279d9cdb19c1d32b
+ b6ce3b78e938644a293b2dd2a15b2fecb1b54cd9
The commits that being with + will be the ones that haven't yet cherry-picked into development.
Syntax:
Options:
< upstream > Upstream branch to search for equivalent commits. Defaults to the upstream
branch of HEAD.
https://riptutorial.com/ 54
Chapter 13: Cloning Repositories
Syntax
• git clone [<options>] [--] <repo> [<dir>]
• git clone [--template=<template_directory>] [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror] [-
o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>] [--dissociate] [--
separate-git-dir <git dir>] [--depth <depth>] [--[no-]single-branch] [--recursive | --recurse-
submodules] [--[no-]shallow-submodules] [--jobs <n>] [--] <repository> [<directory>]
Examples
Shallow Clone
Cloning a huge repository (like a project with multiple years of history) might take a long time, or
fail because of the amount of data to be transferred. In cases where you don't need to have the full
history available, you can do a shallow clone:
The above command will fetch just the last commit from the remote repository.
Be aware that you may not be able to resolve merges in a shallow repository. It's often a good
idea to take at least as many commits are you are going to need to backtrack to resolve merges.
For example, to instead get the last 50 commits:
Later, if required, you can the fetch the rest of the repository:
1.8.3
1.8.3
Regular Clone
To download the entire repository including the full history and all branches, type:
https://riptutorial.com/ 55
The example above will place it in a directory with the same name as the repository name.
To clone a specific branch of a repository, type --branch <branch name> before the repository url:
To use the shorthand option for --branch, type -b. This command downloads entire repository and
checks out <branch name>.
To save disk space you can clone history leading only to single branch with:
If --single-branch is not added to the command, history of all branches will be cloned into
[directory]. This can be issue with big repositories.
To later undo --single-branch flag and fetch the rest of repository use command:
Clone recursively
1.6.5
Clones the repository and also clones all submodules. If the submodules themselves contain
additional submodules, Git will also clone those.
If you need to download files with git under a proxy, setting proxy server system-wide couldn't be
enough. You could also try the following:
https://riptutorial.com/ 56
Chapter 14: Committing
Introduction
Commits with Git provide accountability by attributing authors with changes to code. Git offers
multiple features for the specificity and security of commits. This topic explains and demonstrates
proper practices and procedures in committing with Git.
Syntax
• git commit [flags]
Parameters
Parameter Details
--all, -a Commit all changes, including changes that aren't yet staged.
--date Manually set the date that will be associated with the commit.
Commit only the paths specified. This will not commit what
--only
you currently have staged unless told to do so.
-S[keyid], -S --gpg-
Sign commit, GPG-sign commit, countermand commit.gpgSign
sign[=keyid], -S --no-gpg-
configuration variable
sign
https://riptutorial.com/ 57
Examples
Committing without opening an editor
Git will usually open an editor (like vim or emacs) when you run git commit. Pass the -m option to
specify a message from the command line:
Amending a commit
If your latest commit is not published yet (not pushed to an upstream repository) then you can
amend your commit.
This will put the currently staged changes onto the previous commit.
Note: This can also be used to edit an incorrect commit message. It will bring up the default editor
(usually vi / vim / emacs) and allow you to change the prior message.
Amending updates the commit date but leaves the author date untouched. You can tell git to
refresh the information.
https://riptutorial.com/ 58
You can also change the author of the commit with:
Note: Be aware that amending the most recent commit replaces it entirely and the previous
commit is removed from the branch's history. This should be kept in mind when working with
public repositories and on branches with other collaborators.
This means that if the earlier commit had already been pushed, after amending it you will have to
push --force.
Usually, you have to use git add or git rm to add changes to the index before you can git commit
them. Pass the -a or --all option to automatically add every change (to tracked files) to the index,
including removals:
git commit -a
If you would like to also add a commit message you would do:
You don't necessarily need to commit all files at once. Omit the -a or --all flag and specify which
file you want to commit directly:
For directly committing more than one specific file, you can specify one or multiple files, directories
and patterns as well:
git commit path/to/a/file path/to/a/folder/* path/to/b/file -m "your commit message goes here"
Generally speaking, empty commits (or commits with state that is identical to the parent) is an
error.
However, when testing build hooks, CI systems, and other systems that trigger off a commit, it's
handy to be able to easily create commits without having to edit/touch a dummy file.
https://riptutorial.com/ 59
git commit -m "This is a blank commit" --allow-empty
The basics
After making changes to your source code, you should stage those changes with Git before you
can commit them.
This tells git that you want to add the files to the next commit you do.
git commit
Note that this will open a text editor, which is often vim. If you are not familiar with vim, you might
want to know that you can press i to go into insert mode, write your commit message, then press
Esc and :wq to save and quit. To avoid opening the text editor, simply include the -m flag with your
message
Commit messages often follow some specific formatting rules, see Good commit messages for
more information.
Shortcuts
If you have changed a lot of files in the directory, rather than listing each one of them, you could
use:
Or to add all changes, not including files that have been deleted, from the top-level directory and
subdirectories:
git add .
git add -u
https://riptutorial.com/ 60
If desired, review the staged changes:
Alternately, if you have only modified existing files or deleted files, and have not created any new
ones, you can combine the actions of git add and git commit in a single command:
Note that this will stage all modified files in the same way as git add --all.
Sensitive data
You should never commit any sensitive data, such as passwords or even private keys. If this case
happens and the changes are already pushed to a central server, consider any sensitive data as
compromised. Otherwise, it is possible to remove such data afterwards. A fast and easy solution is
the usage of the "BFG Repo-Cleaner": https://rtyley.github.io/bfg-repo-cleaner/.
The command bfg --replace-text passwords.txt my-repo.git reads passwords out of the
passwords.txt file and replaces these with ***REMOVED***. This operation considers all previous
commits of the entire repository.
If someone else wrote the code you are committing, you can give them credit with the --author
option:
You can also provide a pattern, which Git will use to search for previous authors:
In this case, the author information from the most recent commit with an author containing "John"
will be used.
On GitHub, commits made in either of the above ways will show a large author's thumbnail, with
the committer's smaller and in front:
https://riptutorial.com/ 61
Commiting changes in specific files
You can commit changes made to specific files and skip staging them using git add:
git commit
It is important for someone traversing through the git log to easily understand what each commit
was all about. Good commit messages usually include a number of a task or an issue in a tracker
and a concise description of what has been done and why, and sometimes also how it has been
done.
A way to test if a commit message is written in the correct mood is to replace the blank with the
message and see if it makes sense:
The --date parameter sets the author date. This date will appear in the standard output of git log,
for example.
The date parameter accepts the flexible formats as supported by GNU date, for example:
When the date doesn't specify time, the current time will be used and only the date will be
overridden.
Suppose you have many changes in one or more files but from each file you only want to commit
some of the changes, you can select the desired changes using:
git add -p
or
Each of your changes will be displayed individually, and for each change you will be prompted to
choose one of he following options:
https://riptutorial.com/ 63
y - Yes, add this hunk
d - No, don’t add this hunk, or any other remaining hunks for this file.
Useful if you’ve already added what you want to, and want to skip over the rest.
e - Manually edit the hunk. This is probably the most powerful option.
It will open the hunk in a text editor and you can edit it as needed.
This will stage the parts of the files you choose. Then you can commit all the staged changes like
this:
The changes that were not staged or committed will still appear in your working files, and can be
committed later if required. Or if the remaining changes are unwanted, they can be discarded with:
Apart from breaking up a big change into smaller commits, this approach is also useful for
reviewing what you are about to commit. By individually confirming each change, you have an
opportunity to check what you wrote, and can avoid accidentally staging unwanted code such as
println/logging statements.
or even
If you make a commit as the wrong author, you can change it, and then amend
https://riptutorial.com/ 64
gpg --list-secret-keys --keyid-format LONG
/Users/davidcondrey/.gnupg/secring.gpg
--------------------------------------
sec 2048R/YOUR-16-DIGIT-KEY-ID YYYY-MM-DD [expires: YYYY-MM-DD]
3. As of version 1.7.9, git commit accepts the -S option to attach a signature to your commits.
Using this option will prompt for your GPG passphrase and will add your signature to the
commit log.
https://riptutorial.com/ 65
Chapter 15: Configuration
Syntax
• git config [<file-option>] name [value] # one of the more common use cases of git config
Parameters
Parameter Details
Edits the system-wide configuration file, which is used for every user (on Linux,
--system
this file is located at $(prefix)/etc/gitconfig)
Edits the global configuration file, which is used for every repository you work on
--global
(on Linux, this file is located at ~/.gitconfig
Examples
Username and email address
Right after you install Git, the first thing you should do is set your username and email address.
From a shell, type:
• 6 files:
○ %ALLUSERSPROFILE%\Git\Config (Windows only)
○ (system) <git>/etc/gitconfig, with <git> being the git installation path.
https://riptutorial.com/ 66
(on Windows, it is <git>\mingw64\etc\gitconfig)
○(system) $XDG_CONFIG_HOME/git/config (Linux/Mac only)
○(global) ~/.gitconfig (Windows: %USERPROFILE%\.gitconfig)
○(local) .git/config (within a git repo $GIT_DIR)
○a dedicated file (with git config -f), used for instance to modify the config of
submodules: git config -f .gitmodules ...
• the command line with git -c: git -c core.autocrlf=false fetch would override any other
core.autocrlf to false, just for that fetch command.
The order is important: any config set in one source can be overridden by a source listed below it.
git config --system/global/local is the command to list 3 of those sources, but only git config -l
would list all resolved configs.
"resolved" means it lists only the final overridden config value.
Since git 2.8, if you want to see which config comes from which file, you type:
There are several ways to set which editor to use for committing, rebasing, etc.
Or for all commands run in a terminal. Note: This only applies until you close the terminal.
$ export GIT_EDITOR=nano
• To change the editor for all terminal programs, not just Git, set the VISUAL or EDITOR
environment variable. (See VISUAL vs EDITOR.)
$ export EDITOR=nano
Note: As above, this only applies to the current terminal; your shell will usually have a
configuration file to allow you to set it permanently. (On bash, for example, add the above line
to your ~/.bashrc or ~/.bash_profile.)
Some text editors (mostly GUI ones) will only run one instance at a time, and generally quit if you
already have an instance of them open. If this is the case for your text editor, Git will print the
https://riptutorial.com/ 67
message Aborting commit due to empty commit message. without allowing you to edit the commit
message first. If this happens to you, consult your text editor's documentation to see if it has a --
wait flag (or similar) that will make it pause until the document is closed.
Description
When working with a team who uses different operating systems (OS) across the project,
sometimes you may run into trouble when dealing with line endings.
Microsoft Windows
When working on Microsoft Windows operating system (OS), the line endings are normally of form
- carriage return + line feed (CR+LF). Opening a file which has been edited using Unix machine
such as Linux or OSX may cause trouble, making it seem that text has no line endings at all. This
is due to the fact that Unix systems apply different line-endings of form line feeds (LF) only.
On checkout, This instruction will ensure line-endings are configured in accordance with Microsoft
Windows OS (LF -> CR+LF)
you can use -c <name>=<value> to add a configuration only for one command.
Note: for that example you don't need to precise both user.name and user.email, git will complete
the missing information from the previous commits.
https://riptutorial.com/ 68
Setup a proxy
If you are behind a proxy, you have to tell git about it:
This enables autocorrect in git and will forgive you for your minor mistakes (e.g. git stats instead
of git status). The parameter you supply to help.autocorrect determines how long the system
should wait, in tenths of a second, before automatically applying the autocorrected command. In
the command above, 17 means that git should wait 1.7 seconds before applying the autocorrected
command.
However, bigger mistakes will be considered as missing commands, so typing something like git
testingit would result in testingit is not a git command.
Git config allows you to customize how git works. It is commonly used to set your name and email
or favorite editor or how merges should be done.
If you intend the change to be true for all your repositories, use --global
https://riptutorial.com/ 69
Multiple usernames and email address
Since Git 2.13, multiple usernames and email addresses could be configured by using a folder
filter.
Add:
[includeIf "gitdir:D:/work"]
path = .gitconfig-work.config
[includeIf "gitdir:D:/opensource/"]
path = .gitconfig-opensource.config
Notes
.gitconfig-work.config
[user]
name = Money
email = [email protected]
.gitconfig-opensource.config
[user]
name = Nice
email = [email protected]
[includeIf "gitdir:~/work/"]
path = .gitconfig-work
[includeIf "gitdir:~/opensource/"]
path = .gitconfig-opensource
https://riptutorial.com/ 70
The file content and notes under section Windows.
https://riptutorial.com/ 71
Chapter 16: diff-tree
Introduction
Compares the content and mode of blobs found via two tree objects.
Examples
See the files changed in a specific commit
Usage
git diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] [<common-
diff-options>] <tree-ish> [<tree-ish>] [<path>...]
Option Explanation
-r diff recursively
Option Explanation
https://riptutorial.com/ 72
Option Explanation
-M detect renames.
-C detect copies.
--pickaxe-all show all files diff when -S is used and hit is found.
https://riptutorial.com/ 73
Chapter 17: Display commit history
graphically with Gitk
Examples
Display commit history for one file
gitk path/to/myfile
Let's say you have two commits d9e1db9 and 5651067 and want to see what happened between
them. d9e1db9 is the oldest ancestor and 5651067 is the final descendant in the chain of commits.
If you have the version tag v2.3 you can display all commits since that tag.
gitk v2.3..
https://riptutorial.com/ 74
Chapter 18: Empty directories in Git
Examples
Git doesn't track directories
/build
app.js
git init
git add .
git commit -m "Initial commit"
Assume you added a build step to your application and rely on the "build" directory to be there as
the output directory (and you don't want to make it a setup instruction every developer has to
follow), a convention is to include a ".gitkeep" file inside the directory and let Git track that file.
/build
.gitkeep
app.js
Git will now track the file build/.gitkeep file and therefore the build folder will be made available on
checkout.
https://riptutorial.com/ 75
Chapter 19: External merge and difftools
Examples
Setting up Beyond Compare
[merge]
tool = kdiff3
[mergetool "kdiff3"]
path = D:/Program Files (x86)/KDiff3/kdiff3.exe
keepBackup = false
keepbackup = false
trustExitCode = false
Remember to set the path property to point to the directory where you have installed KDiff3
[diff]
tool = kdiff3
guitool = kdiff3
[difftool "kdiff3"]
path = D:/Program Files (x86)/KDiff3/kdiff3.exe
cmd = \"D:/Program Files (x86)/KDiff3/kdiff3.exe\" \"$LOCAL\" \"$REMOTE\"
[merge]
tool = intellij
[mergetool "intellij"]
cmd = cmd \"/C D:\\workspace\\tools\\symlink\\idea\\bin\\idea.bat merge $(cd $(dirname
"$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE")
$(cd $(dirname "$BASE") && pwd)/$(basename "$BASE") $(cd $(dirname "$MERGED") &&
pwd)/$(basename "$MERGED")\"
keepBackup = false
keepbackup = false
trustExitCode = true
https://riptutorial.com/ 76
The one gotcha here is that this cmd property does not accept any weird characters in the path. If
your IDE's install location has weird characters in it (e.g. it's installed in Program Files (x86), you'll
have to create a symlink
[diff]
tool = intellij
guitool = intellij
[difftool "intellij"]
path = D:/Program Files (x86)/JetBrains/IntelliJ IDEA 2016.2/bin/idea.bat
cmd = cmd \"/C D:\\workspace\\tools\\symlink\\idea\\bin\\idea.bat diff $(cd $(dirname
"$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename
"$REMOTE")\"
The one gotcha here is that this cmd property does not accept any weird characters in the path. If
your IDE's install location has weird characters in it (e.g. it's installed in Program Files (x86), you'll
have to create a symlink
https://riptutorial.com/ 77
Chapter 20: Git Branch Name on Bash
Ubuntu
Introduction
This documentation deals with the branch name of the git on the bash terminal. We developers
need to find the git branch name very frequently. We can add the branch name along with the path
to the current directory.
Examples
Branch Name in terminal
What is PS1
PS1 denotes Prompt String 1. It is the one of the prompt available in Linux/UNIX shell. When you
open your terminal, it will display the content defined in PS1 variable in your bash prompt. In order
to add branch name to bash prompt we have to edit the PS1 variable(set value of PS1 in
~/.bash_profile).
git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\u@\h \[\033[32m\]\w\[\033[33m\]\$(git_branch)\[\033[00m\] $ "
This git_branch function will find the branch name we are on. Once we are done with this changes
we can nevigate to the git repo on the terminal and will be able to see the branch name.
https://riptutorial.com/ 78
Chapter 21: Git Clean
Syntax
• git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>
Parameters
Parameter Details
If the Git configuration variable clean. requireForce is not set to false, git clean
-f, --force will refuse to delete files or directories unless given -f, -n or -i. Git will refuse to
delete directories with .git sub directory or file unless a second -f is given.
-i, --
Interactively prompts the removal of each file.
interactive
-n, --dry-run Only displays a list of files to be removed, without actually removing them.
-q,--quiet Only display errors, not the list of successfully removed files.
Examples
Clean Ignored Files
Will remove all ignored files from the current directory and all subdirectories.
Will remove all untracked directories and the files within them. It will start at the current working
directory and will iterate through all subdirectories.
https://riptutorial.com/ 79
git clean -dn
git clean -f
Clean Interactively
git clean -i
Will print out items to be removed and ask for a confirmation via commands like the follow:
Interactive option i can be added along with other options like X, d, etc.
https://riptutorial.com/ 80
Chapter 22: Git Client-Side Hooks
Introduction
Like many other Version Control Systems, Git has a way to fire off custom scripts when certain
important actions occur. There are two groups of these hooks: client-side and server-side. Client-
side hooks are triggered by operations such as committing and merging, while server-side hooks
run on network operations such as receiving pushed commits. You can use these hooks for all
sorts of reasons.
Examples
Installing a Hook
The hooks are all stored in the hooks sub directory of the Git directory. In most projects, that’s
.git/hooks.
To enable a hook script, put a file in the hooks subdirectory of your .git directory that is named
appropriately (without any extension) and is executable.
pre-push script is called by git push after it has checked the remote status, but before anything
has been pushed. If this script exits with a non-zero status nothing will be pushed.
$1 -- Name of the remote to which the push is being done (Ex: origin)
$2 -- URL to which the push is being done (Ex:
https://<host>:<port>/<username>/<project_name>.git)
Information about the commits which are being pushed is supplied as lines to the standard input in
the form:
Sample values:
local_ref = refs/heads/master
local_sha1 = 68a07ee4f6af8271dc40caae6cc23f283122ed11
remote_ref = refs/heads/master
remote_sha1 = efd4d512f34b11e3cf5c12433bbedd4b1532716f
Below example pre-push script was taken from default pre-push.sample which was automatically
created when a new repository is initialized with git init
https://riptutorial.com/ 81
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).
remote="$1"
url="$2"
z40=0000000000000000000000000000000000000000
exit 0
https://riptutorial.com/ 82
Chapter 23: Git Diff
Syntax
• git diff [options] [<commit>] [--] [<path>…]
• git diff [options] --cached [<commit>] [--] [<path>…]
• git diff [options] <commit> <commit> [--] [<path>…]
• git diff [options] <blob> <blob>
• git diff [options] [--no-index] [--] <path> <path>
Parameters
Parameter Details
-p, -u, --
Generate patch
patch
-s, --no- Suppress diff output. Useful for commands like git show that show the patch by
patch default, or to cancel the effect of --patch
--diff- Choose a diff algorithm. The variants are as follows: myers, minimal, patience,
algorithm= histogram
--name-
Show only names of changed files
only
--name- Show names and statuses of changed files The most common statuses are M
status (Modified), A (Added), and D (Deleted)
Instead of the first handful of characters, show the full pre- and post-image blob
--full-index
object names on the "index" line when generating patch format output
--binary In addition to --full-index, output a binary diff that can be applied with git
apply
https://riptutorial.com/ 83
Parameter Details
Set the color mode; i.e. use --color=always if you would like to pipe a diff to less
--color
and keep git's coloring
Examples
Show differences in working branch
git diff
This will show the unstaged changes on the current branch from the commit before it. It will only
show changes relative to the index, meaning it shows what you could add to the next commit, but
haven't. To add (stage) these changes, you can use git add.
If a file is staged, but was modified after it was staged, git diff will show the differences between
the current file and the staged version.
This will show the changes between the previous commit and the currently staged files.
NOTE: You can also use the following commands to accomplish the same thing:
git status -v
https://riptutorial.com/ 84
The difference being that the output of the latter will actually tell you which changes are staged for
commit and which are not.
This will show the textual difference between the commits, regardless of where they are in the
tree.
Shows the changes between the previous commit of the specified file (myfile.txt) and the locally-
modified version that has not yet been staged.
The above shows the changes between the previous commit of all files in the specified directory (
documentation/) and the locally-modified versions of these files, that have not yet been staged.
To show the difference between some version of a file in a given commit and the local HEAD version
you can specify the commit you want to compare against:
https://riptutorial.com/ 85
git diff 27fa75e ada9b57 myfile.txt
To show the difference between the version specified by the hash ada9b57 and the latest commit
on the branch my_branchname for only the relative directory called my_changed_directory/ you can do
this:
Rather than displaying lines changed, this will display differences within lines. For example, rather
than:
-Hello world
+Hello world!
Where the whole line is marked as changed, word-diff alters the output to:
Hello [-world-]{+world!+}
You can omit the markers [-, -], {+, +} by specifying --word-diff=color or --color-words. This will
only use color coding to mark the difference:
Sets the diff3 style as default: instead of the usual format in conflicted sections, showing the two
files:
<<<<<<< HEAD
left
=======
right
>>>>>>> master
it will include an additional section containing the original text (coming form the common ancestor):
<<<<<<< HEAD
first
second
|||||||
first
=======
https://riptutorial.com/ 86
last
>>>>>>> master
This format makes it easier to understand merge-conflict, ie. in this case locally second has been
added, while remote changed first to last, resolving to:
last
second
The same resolution would have been much harder using the default:
<<<<<<< HEAD
first
second
=======
last
>>>>>>> master
This will show the changes between the previous commit and the current commit.
You can diff UTF-16 encoded files (localization strings file os iOS and macOS are examples) by
specifying how git should diff these files.
[diff "utf16"]
textconv = "iconv -f utf-16 -t utf-8"
Then edit or create a .gitattributes file in the root of the repository where you want to use it. Or
just edit ~/.gitattributes.
*.strings diff=utf16
This will convert all files ending in .strings before git diffs.
You can do similar things for other files, that can be converted to text.
[diff "plist"]
textconv = plutil -convert xml1 -o -
https://riptutorial.com/ 87
and .gitattributes
*.plist diff=plist
Comparing branches
Show the changes between the tip of new and the tip of original:
is equivalent to
Sometimes you just need a diff to apply using patch. The regular git --diff does not work. Try
this instead:
https://riptutorial.com/ 88
To view diff with current branch
https://riptutorial.com/ 89
Chapter 24: Git GUI Clients
Examples
GitHub Desktop
Website: https://desktop.github.com
Price: free
Platforms: OS X and Windows
Developed by: GitHub
Git Kraken
Website:https://www.gitkraken.com
Price: $60/years (free for For open source, education, non‑profit, startups or personal use)
Platforms: Linux, OS X, Windows
Developed by: Axosoft
SourceTree
Website: https://www.sourcetreeapp.com
Price: free (account is necessary)
Platforms: OS X and Windows
Developer: Atlassian
When you install Git, you also get its visual tools, gitk and git-gui.
gitk is a graphical history viewer. Think of it like a powerful GUI shell over git log and
git grep. This is the tool to use when you’re trying to find something that happened in
the past, or visualize your project’s history.
Gitk is easiest to invoke from the command-line. Just cd into a Git repository, and type:
Gitk accepts many command-line options, most of which are passed through to the
underlying git log action. Probably one of the most useful is the --all flag, which tells
gitk to show commits reachable from any ref, not just HEAD. Gitk’s interface looks like
this:
https://riptutorial.com/ 90
Figure 1-1. The gitk history viewer.
On the top is something that looks a bit like the output of git log --graph; each dot
represents a commit, the lines represent parent relationships, and refs are shown as
colored boxes. The yellow dot represents HEAD, and the red dot represents changes
that are yet to become a commit. At the bottom is a view of the selected commit; the
comments and patch on the left, and a summary view on the right. In between is a
collection of controls used for searching history.
You can access many git related functions via right-click on a branch name or a
commit message. For example checking out a different branch or cherry pick a commit
is easily done with one click.
git-gui, on the other hand, is primarily a tool for crafting commits. It, too, is easiest to
invoke from the command line:
$ git gui
https://riptutorial.com/ 91
Figure 1-2. The git-gui commit tool.
On the left is the index; unstaged changes are on top, staged changes on the bottom.
You can move entire files between the two states by clicking on their icons, or you can
select a file for viewing by clicking on its name.
At top right is the diff view, which shows the changes for the currently-selected file. You
can stage individual hunks (or individual lines) by right-clicking in this area.
At the bottom right is the message and action area. Type your message into the text
box and click “Commit” to do something similar to git commit. You can also choose to
amend the last commit by choosing the “Amend” radio button, which will update the
“Staged Changes” area with the contents of the last commit. Then you can simply
stage or unstage some changes, alter the commit message, and click “Commit” again
to replace the old commit with a new one.
gitk and git-gui are examples of task-oriented tools. Each of them is tailored for a
specific purpose (viewing history and creating commits, respectively), and omit the
features not necessary for that task.
Source: https://git-scm.com/book/en/v2/Git-in-Other-Environments-Graphical-Interfaces
SmartGit
Website: http://www.syntevo.com/smartgit/
https://riptutorial.com/ 92
Price: Free for non-commercial use only. A perpetual license costs 99 USD
Platforms: Linux, OS X, Windows
Developed by: syntevo
Git Extensions
Website: https://gitextensions.github.io
Price: free
Platform: Windows
https://riptutorial.com/ 93
Chapter 25: Git Large File Storage (LFS)
Remarks
Git Large File Storage (LFS) aims to avoid a limitation of the Git version control system, that it
performs poorly when versioning large files, especially binaries. LFS solves this problem by storing
the contents of such files on an external server, then instead committing just a text pointer to the
path of those assets in the git object database.
Common file types that are stored via LFS tend to be compiled source; graphical assets, like
PSDs and JPEGs; or 3D assets. This way resources used by projects can be managed in the
same repository, rather than having to maintain a separate management system externally.
Examples
Install LFS
For Brew,
brew install git-lfs
git lfs install
Often you will also need to do some setup on the service that hosts your remote to allow it to work
with lfs. This will be different for each host, but will likely just be checking a box saying you want to
use git lfs.
A common workflow for using Git LFS is to declare which files are intercepted through a rules-
based system, just like .gitignore files.
Much of time, wildcards are used to pick certain file-types to blanket track.
When a file matching the above pattern is added them committed, when it is then pushed to the
remote, it will be uploaded separately, with a pointer replacing the file in the remote repository.
After a file has been tracked with lfs, your .gitattributes file will be updated accordingly. Github
recommends committing your local .gitattributes file, rather than working with a global
.gitattributes file, to help ensure you don't have any issues when working with different projects.
https://riptutorial.com/ 94
Set LFS config for all clones
To set LFS options that apply to all clones, create and commit a file named .lfsconfig at the
repository root. This file can specify LFS options the same way as allowed in .git/config.
For example, to exclude a certain file from LFS fetches be default, create and commit .lfsconfig
with the following contents:
[lfs]
fetchexclude = ReallyBigFile.wav
https://riptutorial.com/ 95
Chapter 26: Git Patch
Syntax
• git am [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--3way] [--interactive] [--committer-date-
is-author-date] [--ignore-date] [--ignore-space-change | --ignore-whitespace] [--
whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>] [--exclude=<path>] [--
include=<path>] [--reject] [-q | --quiet] [--[no-]scissors] [-S[<keyid>]] [--patch-
format=<format>] [(<mbox> | <Maildir>)...]
• git am (--continue | --skip | --abort)
Parameters
Parameter Details
--ignore-date, --ignore-space-change, -
-ignore-whitespace, --
These flags are passed to the git apply program
whitespace=<option>, -C<n>, -p<n>, --
that applies the patch.
directory=<dir>, --exclude=<path>, --
include=<path>, --reject
https://riptutorial.com/ 96
Parameter Details
Examples
Creating a patch
https://riptutorial.com/ 97
To create a patch, there are two steps.
For example, if patches should be generated from the latest two commits:
This will create 2 files, one for each commit since HEAD~~, like this:
0001-hello_world.patch
0002-beginning.patch
Applying patches
We can use git apply some.patch to have the changes from the .patch file applied to your current
working directory. They will be unstaged and need to be committed.
git am some.patch
git am *.patch
https://riptutorial.com/ 98
Chapter 27: Git Remote
Syntax
• git remote [-v | --verbose]
• git remote add [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=<fetch|push>]<name>
<url>
• git remote rename <old> <new>
• git remote remove <name>
• git remote set-head <name> (-a | --auto | -d | --delete | <branch>)
• git remote set-branches [--add] <name> <branch>...
• git remote set-url [--push] <name> <newurl> [<oldurl>]
• git remote set-url --add [--push] <name> <newurl>
• git remote set-url --delete [--push] <name> <url>
• git remote [-v | --verbose] show [-n] <name>...
• git remote prune [-n | --dry-run] <name>...
• git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]
• git remote show <name>
Parameters
Parameter Details
--
git push will behave as if --mirror was passed
mirror=push
--no-tags git fetch <name> does not import tags from the remote repo
--tags git fetch <name> imports every tag from the remote repo
-a, --auto The symbolic-ref's HEAD is set to the same branch as the remote's HEAD
-d, --delete All listed refs are deleted from the remote repository
https://riptutorial.com/ 99
Parameter Details
The remote heads are not queried first with git ls-remote <name>, cached
-n
information is used instead
--dry-run report what branches will be pruned, but do not actually prune them
Examples
Add a Remote Repository
To add a remote, use git remote add in the root of your local repository.
For adding a remote Git repository <url> as an easy short name <name> use
The command git fetch <name> can then be used to create and update remote-tracking branches
<name>/<branch>.
Rename the remote named <old> to <new>. All remote-tracking branches and configuration settings
for the remote are updated.
Remove the remote named <name>. All remote-tracking branches and configuration settings for the
remote are removed.
https://riptutorial.com/ 100
To list all configured remote repositories, use git remote.
It shows the short name (aliases) of each remote handle that you have configured.
$ git remote
premium
premiumPro
origin
To show more detailed information, the --verbose or -v flag can be used. The output will include
the URL and the type of the remote (push or pull):
$ git remote -v
premiumPro https://github.com/user/CatClickerPro.git (fetch)
premiumPro https://github.com/user/CatClickerPro.git (push)
premium https://github.com/user/CatClicker.git (fetch)
premium https://github.com/user/CatClicker.git (push)
origin https://github.com/ud/starter.git (fetch)
origin https://github.com/ud/starter.git (push)
You may want to do this if the remote repository is migrated. The command for changing the
remote url is:
It takes 2 arguments: an existing remote name (origin, upstream) and the url.
git remote -v
origin https://bitbucket.com/develop/myrepo.git (fetch)
origin https://bitbucket.com/develop/myrepo.git (push)
git remote -v
origin https://localserver/develop/myrepo.git (fetch)
origin https://localserver/develop/myrepo.git (push)
You can view more information about a remote repository by git remote show <remote repository
alias>
https://riptutorial.com/ 101
git remote show origin
result:
remote origin
Fetch URL: https://localserver/develop/myrepo.git
Push URL: https://localserver/develop/myrepo.git
HEAD branch: master
Remote branches:
master tracked
Local branches configured for 'git pull':
master merges with remote master
Local refs configured for 'git push':
master pushes to master (up to date)
https://riptutorial.com/ 102
Chapter 28: Git rerere
Introduction
rerere (reuse recorded resolution) allows you to tell git to remember how you resolved a hunk
conflict. This allows it to be automatically resolved the next time that git encounters the same
conflict.
Examples
Enabling rerere
https://riptutorial.com/ 103
Chapter 29: Git revisions syntax
Remarks
Many Git commands take revision parameters as arguments. Depending on the command, they
denote a specific commit or, for commands which walk the revision graph (such as git-log(1)), all
commits which can be reached from that commit. They are usually denoted as <commit>, or <rev>,
or <revision> in the syntax description.
The reference documentation for Git revisions syntax is the gitrevisions(7) manpage.
• [_] Referring to blobs and trees in the repository and in the index: <rev>:<path> and
:<n>:<path> syntax
• [_] Revision ranges like A..B, A...B, B ^A, A^1, and revision limiting like -<n>, --since
Examples
Specifying revision by object name
You can specify revision (or in truth any object: tag, tree i.e. directory contents, blob i.e. file
contents) using SHA-1 object name, either full 40-byte hexadecimal string, or a substring that is
unique to the repository.
You can specify revision using a symbolic ref name, which includes branches (for example
'master', 'next', 'maint'), tags (for example 'v1.0', 'v0.6.3-rc2'), remote-tracking branches (for
example 'origin', 'origin/master'), and special refs such as 'HEAD' for current branch.
https://riptutorial.com/ 104
If the symbolic ref name is ambiguous, for example if you have both branch and tag named 'fix'
(having branch and tag with the same name is not recommended), you need to specify the kind of
ref you want to use:
'HEAD' names the commit on which you based the changes in the working tree, and is usually the
symbolic name for the current branch. Many (but not all) commands that take revision parameter
defaults to 'HEAD' if it is missing.
A ref, usually a branch or HEAD, followed by the suffix @ with an ordinal specification enclosed in a
brace pair (e.g. {1}, {15}) specifies the n-th prior value of that ref in your local repository. You can
check recent reflog entries with git reflog command, or --walk-reflogs / -g option to git log.
$ git reflog
08bb350 HEAD@{0}: reset: moving to HEAD^
4ebf58d HEAD@{1}: commit: gitweb(1): Document query parameters
08bb350 HEAD@{2}: pull: Fast-forward
f34be46 HEAD@{3}: checkout: moving from af40944bda352190f05d22b7cb8fe88beb17f3a7 to master
af40944 HEAD@{4}: checkout: moving from master to v2.6.3
Note: using reflogs practically replaced older mechanism of utilizing ORIG_HEAD ref (roughly
equivalent to HEAD@{1}).
A ref followed by the suffix @ with a date specification enclosed in a brace pair (e.g. {yesterday}, {1
month 2 weeks 3 days 1 hour 1 second ago} or {1979-02-26 18:30:00}) specifies the value of the ref at
a prior point in time (or closest point to it). Note that this looks up the state of your local ref at a
given time; e.g., what was in your local 'master' branch last week.
You can use git reflog with a date specifier to look up exact time where you did something to
https://riptutorial.com/ 105
given ref in the local repository.
$ git log @{upstream}.. # what was done locally and not yet published, current branch
$ git show master@{upstream} # show upstream of branch 'master'
The suffix @{upstream} appended to a branchname (short form <branchname>@{u}) refers to the
branch that the branch specified by branchname is set to build on top of (configured with
branch.<name>.remote and branch.<name>.merge, or with git branch --set-upstream-to=<branch>). A
missing branchname defaults to the current one.
Together with syntax for revision ranges it is very useful to see the commits your branch is ahead
of upstream (commits in your local repository not yet present upstream), and what commits you
are behind (commits in upstream not merged into local branch), or both:
A suffix ^ to a revision parameter means the first parent of that commit object. ^<n> means the
<n>-th parent (i.e. <rev>^ is equivalent to <rev>^1).
A suffix ~<n> to a revision parameter means the commit object that is the <n>-th generation
ancestor of the named commit object, following only the first parents. This means that for example
<rev>~3 is equivalent to <rev>^^^. As a shortcut, <rev>~ means <rev>~1, and is equivalent to <rev>^1,
or <rev>^ in short.
To find such symbolic names you can use the git name-rev command:
Note that --pretty=oneline and not --oneline must be used in the following example
https://riptutorial.com/ 106
$ git log --pretty=oneline | git name-rev --stdin --name-only
master Sixth batch of topics for 2.10
master~1 Merge branch 'ls/p4-tmp-refs'
master~2 Merge branch 'js/am-call-theirs-theirs-in-fallback-3way'
[...]
master~14^2 sideband.c: small optimization of strbuf usage
master~16^2 connect: read $GIT_SSH_COMMAND from config file
[...]
master~22^2~1 t7810-grep.sh: fix a whitespace inconsistency
master~22^2~2 t7810-grep.sh: fix duplicated test name
In some cases the behavior of a command depends on whether it is given branch name, tag
name, or an arbitrary revision. You can use "de-referencing" syntax if you need the latter.
A suffix ^ followed by an object type name (tag, commit, tree, blob) enclosed in brace pair (for
example v0.99.8^{commit}) means dereference the object at <rev> recursively until an object of type
<type> is found or the object cannot be dereferenced anymore. <rev>^0 is a short-hand for
<rev>^{commit}.
A suffix ^ followed by an empty brace pair (for example v0.99.8^{}) means to dereference the tag
recursively until a non-tag object is found.
Compare
with
A colon (':'), followed by a slash ('/'), followed by a text, names a commit whose commit message
matches the specified regular expression. This name returns the youngest matching commit which
is reachable from any ref. The regular expression can match any part of the commit message. To
match messages starting with a string, one can use e.g. :/^foo. The special sequence :/! is
reserved for modifiers to what is matched. :/!-foo performs a negative match, while :/!!foo
matches a literal ! character, followed by foo.
https://riptutorial.com/ 107
A suffix ^ to a revision parameter, followed by a brace pair that contains a text led by a slash, is
the same as the :/<text> syntax below that it returns the youngest matching commit which is
reachable from the <rev> before ^.
https://riptutorial.com/ 108
Chapter 30: git send-email
Syntax
• git send-email [options] <file|directory|rev-list options>…
• git send-email --dump-aliases
Remarks
https://git-scm.com/docs/git-send-email
Examples
Use git send-email with Gmail
Background: if you work on a project like the Linux kernel, rather than make a pull request you will
need to submit your commits to a listserv for review. This entry details how to use git-send email
with Gmail.
[sendemail]
smtpserver = smtp.googlemail.com
smtpencryption = tls
smtpserverport = 587
smtpuser = [email protected]
Then on the web: Go to Google -> My Account -> Connected Apps & Sites -> Allow less secure
apps -> Switch ON
To create and send updated version (version 2 in this example) of the patch:
Composing
https://riptutorial.com/ 109
--from * Email From: --[no-]to * Email To: --[no-]cc * Email Cc: --[no-]bcc * Email Bcc: --subject *
Email "Subject:" --in-reply-to * Email "In-Reply-To:" --[no-]xmailer * Add "X-Mailer:" header
(default). --[no-]annotate * Review each patch that will be sent in an editor. --compose * Open an
editor for introduction. --compose-encoding * Encoding to assume for introduction. --8bit-encoding
* Encoding to assume 8bit mails if undeclared --transfer-encoding * Transfer encoding to use
(quoted-printable, 8bit, base64)
Suppose you’ve got a lot of commit against a project (here ulogd2, official branch is git-svn) and
that you wan to send your patchset to the Mailling list [email protected]. To do so, just open a
shell at the root of the git directory and use:
First command will create a serie of mail from patches in /tmp/ulogd2/ with statistic report and
second will start your editor to compose an introduction mail to the patchset. To avoid awful
threaded mail series, one can use :
source
https://riptutorial.com/ 110
Chapter 31: Git statistics
Syntax
• git log [<options>] [<revision range>] [[--] <path>]
• git log --pretty=short | git shortlog [<options>]
• git shortlog [<options>] [<revision range>] [[--] <path>]
Parameters
Parameter Details
Examples
Commits per developer
Git shortlog is used to summarize the git log outputs and group the commits by author.
By default, all commit messages are shown but argument --summary or -s skips the messages and
gives a list of authors with their total number of commits.
--numbered or -n changes the ordering from alphabetical (by author ascending) to number of
https://riptutorial.com/ 111
commits descending.
git shortlog -sne #Names along with their email ids and the Number of commits
or
Note: Commits by the same person may not be grouped together where their name and/or email
address has been spelled differently. For example John Doe and Johnny Doe will appear separately
in the list. To resolve this, refer to the .mailmap feature.
This will give a nice overview of all commits (1 per line) with date, user and commit message.
The --pretty option has many placeholders, each starting with %. All options can be found here
https://riptutorial.com/ 112
To list all the git repository locations on your you can run the following
If you have gnu locate or mlocate, this will select only the git dirs:
In order to get the total number of commits that each developer or contributor has made on a
repository, you can simply use the git shortlog:
git shortlog -s
which provides the author names and number of commits by each one.
Additionally, if you want to have the results calculated on all branches, add --all flag to the
command:
https://riptutorial.com/ 113
Chapter 32: Git Tagging
Introduction
Like most Version Control Systems (VCSs), Git has the ability to tag specific points in history as
being important. Typically people use this functionality to mark release points (v1.0, and so on).
Syntax
• git tag [-a | -s | -u < keyid >] [-f] [-m < msg > | -F < file >] < tagname > [< commit > | < object
>]
• git tag [-n[< num >]] -l [--contains < commit >] [--contains < commit >] [--points-at < object >]
[--column[=< options >] | --no-column] [--create-reflog] [--sort=< key >] [--format=< format >]
[--[no-]merged [< commit >]] [< pattern >…]
Examples
Listing all available tags
Using the command git tag lists out all available tags:
$ git tag
<output follows>
v0.1
v1.3
https://riptutorial.com/ 114
Create and push tag(s) in GIT
Create a tag:
This will create a local tag with the current state of the branch you are on.
This will create a local tag with the commit-identifier of the branch you are on.
https://riptutorial.com/ 115
Chapter 33: git-svn
Remarks
Cloning really big SVN repositories
If you SVN repo history is really really big this operation could take hours, as git-svn needs to
rebuild the complete history of the SVN repo. Fortunately you only need to clone the SVN repo
once; as with any other git repository you can just copy the repo folder to other collaborators.
Copying the folder to multiple computers will be quicker that just cloning big SVN repos from
scratch.
Your local git commits will be rewritten when using the command git svn dcommit. This command
will add a text to the git commit's message referencing the SVN revision created in the SVN
server, which is very useful. However, adding a new text requires modifying an existing commit's
message which can't actually be done: git commits are inmutable. The solution is create a new
commit with the same contents and the new message, but it is technically a new commit anyway
(i.e. the git commit's SHA1 will change)
As git commits created for git-svn are local, the SHA1 ids for git commits are different between
each git repository! This means that you can't use a SHA1 to reference a commit from another
person because the same commit will have a diferent SHA1 in each local git repository. You need
to rely in svn revision number appended to the commit message when you push to the SVN server
if you want to reference a commit between different copies of the repository.
You can use the SHA1 for local operations though (show/diff an specific commit, cherry-picks and
resets, etc)
Troubleshooting
git svn rebase command issues a checksum mismatch error
The solution to this problem is reset svn to the revision when the troubled file got modified for the
last time, and do a git svn fetch so the SVN history is restored. The commands to perform the SVN
reset are:
• git log -1 -- <path_to_file> (copy the SVN revision number that appear in the commit
message)
https://riptutorial.com/ 116
• git svn reset <revision_number>
• git svn fetch
File was not found in commit When you try to fetch or pull from SVN you get an error similar to
this
This means that a revision in SVN is trying to modify a file that for some reason doesn't exists in
your local copy. The best way to get rid of this error is force a fetch ignoring the path of that file
and it will updated to its status in the latest SVN revision:
Examples
Cloning the SVN repository
You need to create a new local copy of the repository with the command
If your SVN repository follows the standard layout (trunk, branches, tags folders) you can save
some typing:
git svn clone checks out each SVN revision, one by one, and makes a git commit in your local
repository in order to recreate the history. If the SVN repository has a lot of commits this will take a
while.
When the command is finished you will have a full fledged git repository with a local branch called
master that tracks the trunk branch in the SVN repository.
This retrieves all the changes from the SVN repository and applies them on top of your local
commits in your current branch.
https://riptutorial.com/ 117
to retrieve the changes from the SVN repository and bring them to your local machine but without
applying them to your local branch.
The command
will create a SVN revision for each of your local git commits. As with SVN, your local git history
must be in sync with the latest changes in the SVN repository, so if the command fails, try
performing a git svn rebase first.
Working locally
Just use your local git repository as a normal git repo, with the normal git commands:
As the git-svn documentation states "Subversion is a system that is far less sophisticated than Git"
so you can't use all the full power of git without messing up the history in the Subversion server.
Fortunately the rules are very simple: Keep the history linear
This means you can make almost any git operation: creating branches,
removing/reordering/squashing commits, move the history around, delete commits, etc. Anything
but merges. If you need to reintegrate the history of local branches use git rebase instead.
When you perform a merge, a merge commit is created. The particular thing about merge commits
is that they have two parents, and that makes the history non-linear. Non-linear history will confuse
SVN in the case you "push" a merge commit to the repository.
However do not worry: you won't break anything if you "push" a git merge commit to SVN. If
you do so, when the git merge commit is sent to the svn server it will contain all the changes of all
commits for that merge, so you will lose the history of those commits, but not the changes in your
code.
git does not recognice the concept of folders, it just works with files and their filepaths. This means
git does not track empty folders. SVN, however, does. Using git-svn means that, by default, any
change you do involving empty folders with git will not be propagated to SVN.
https://riptutorial.com/ 118
Using the --rmdir flag when issuing a comment corrects this issue, and removes an empty folder
in SVN if you locally delete the last file inside it:
Unfortunately it does not removes existing empty folders: you need to do it manually.
To avoid adding the flag each time you do a dcommit, or to play it safe if you are using a git GUI
tool (like SourceTree) you can set this behaviour as default with the command:
[svn]
rmdir = true
To remove all untracked files and folders that should be kept empty for SVN use the git command:
Please note: the previous command will remove all untracked files and empty folders, even the
ones that should be tracked by SVN! If you need to generate againg the empty folders tracked by
SVN use the command
In practices this means that if you want to cleanup your workspace from untracked files and
folders you should always use both commands to recreate the empty folders tracked by SVN:
https://riptutorial.com/ 119
Chapter 34: git-tfs
Remarks
Git-tfs is a third party tool to connect a Git repository to a Team Foundation Server (“TFS”)
repository.
Most remote TFVS instances will request your credentials on every interaction and installing Git-
Credential-Manager-for-Windows may not help. It can be overcome by adding your name and
password to your .git/config
[tfs-remote "default"]
url = http://tfs.mycompany.co.uk:8080/tfs/DefaultCollection/
repository = $/My.Project.Name/
username = me.name
password = My733TPwd
Examples
git-tfs clone
This will create a folder with the same name as the project, i.e. /My.Project.Name
Cloning from a git repository is ten times faster than cloning directly from TFVS and works well in a
team environment. At least one team member will have to create the bare git repository by doing
the regular git-tfs clone first. Then the new repository can be bootstrapped to work with TFVS.
The following assumes you will use kdiff3 for file diffing and although not essential it is a good
idea.
Git can be installed first so you can state any parameters you wish. Here all the Unix tools are also
installed and 'NoAutoCrlf' means checkout as is, commit as is.
https://riptutorial.com/ 120
C:\> choco install git -params '"/GitAndUnixToolsOnPath /NoAutoCrlf"'
This is all you really need to be able to install git-tfs via chocolatey.
git-tfs Check In
This will take all of your local commits and create a single check-in.
git-tfs push
Note: this will fail if Check-in Notes are required. These can be bypassed by adding git-tfs-force:
rcheckin to the commit message.
https://riptutorial.com/ 121
Chapter 35: Hooks
Syntax
• .git/hooks/applypatch-msg
• .git/hooks/commit-msg
• .git/hooks/post-update
• .git/hooks/pre-applypatch
• .git/hooks/pre-commit
• .git/hooks/prepare-commit-msg
• .git/hooks/pre-push
• .git/hooks/pre-rebase
• .git/hooks/update
Remarks
--no-verify or -n to skip all local hooks on the given git command.
Eg: git commit -n
Information on this page was gathered from the official Git docs and Atlassian.
Examples
Commit-msg
This hook is similar to the prepare-commit-msg hook, but it's called after the user enters a commit
message rather than before. This is usually used to warn developers if their commit message is in
an incorrect format.
The only argument passed to this hook is the name of the file that contains the message. If you
don't like the message that the user has entered, you can either alter this file in-place (same as
prepare-commit-msg) or you can abort the commit entirely by exiting with a non-zero status.
The following example is used to check if the word ticket followed by a number is present on the
commit message
word="ticket [0-9]"
isPresent=$(grep -Eoh "$word" $1)
if [[ -z $isPresent ]]
then echo "Commit message KO, $word is missing"; exit 1;
else echo "Commit message OK"; exit 0;
fi
Local hooks
https://riptutorial.com/ 122
Local hooks affect only the local repositories in which they reside. Each developer can alter their
own local hooks, so they can't be used reliably as a way to enforce a commit policy. They are
designed to make it easier for developers to adhere to certain guidelines and avoid potential
problems down the road.
There are six types of local hooks: pre-commit, prepare-commit-msg, commit-msg, post-commit,
post-checkout, and pre-rebase.
The first four hooks relate to commits and allow you to have some control over each part in a
commit's life cycle. The final two let you perform some extra actions or safety checks for the git
checkout and git rebase commands.
All of the "pre-" hooks let you alter the action that’s about to take place, while the "post-" hooks are
used primarily for notifications.
Post-checkout
This hook works similarly to the post-commit hook, but it's called whenever you successfully check
out a reference with git checkout. This could be a useful tool for clearing out your working directory
of auto-generated files that would otherwise cause confusion.
Post-commit
This hook is called immediately after the commit-msg hook. It cannot alter the outcome of the git
commit operation, therefore it's used primarily for notification purposes.
The script takes no parameters, and its exit status does not affect the commit in any way.
Post-receive
This hook is called after a successful push operation. It is typically used for notification purposes.
The script takes no parameters, but is sent the same information as pre-receive via standard input:
Pre-commit
This hook is executed every time you run git commit, to verify what is about to be committed. You
can use this hook to inspect the snapshot that is about to be committed.
https://riptutorial.com/ 123
This type of hook is useful for running automated tests to make sure the incoming commit doesn't
break existing functionality of your project. This type of hook may also check for whitespace or
EOL errors.
No arguments are passed to the pre-commit script, and exiting with a non-zero status aborts the
entire commit.
Prepare-commit-msg
This hook is called after the pre-commit hook to populate the text editor with a commit message.
This is typically used to alter the automatically generated commit messages for squashed or
merged commits.
• The SHA1 hash of the relevant commit. This is only given if -c, -C, or --amend option was
given.
Pre-rebase
This hook is called before git rebase begins to alter code structure. This hook is typically used for
making sure a rebase operation is appropriate.
1. the upstream branch that the series was forked from, and
2. the branch being rebased (empty when rebasing the current branch).
You can abort the rebase operation by exiting with a non-zero status.
Pre-receive
This hook is executed every time somebody uses git push to push commits to the repository. It
always resides in the remote repository that is the destination of the push and not in the originating
(local) repository.
The hook runs before any references are updated. It is typically used to enforce any kind of
development policy.
The script takes no parameters, but each ref that is being pushed is passed to the script on a
separate line on standard input in the following format:
https://riptutorial.com/ 124
<old-value> <new-value> <ref-name>
Update
This hook is called after pre-receive, and it works the same way. It's called before anything is
actually updated, but is called separately for each ref that was pushed rather than all of the refs at
once.
This is the same information passed to pre-receive, but since update is invoked separately for each
ref, you can reject some refs while allowing others.
Pre-push
1.8
Pre-push hooks can be used to prevent a push from going though. Reasons this is helpful include:
blocking accidental manual pushes to specific branches, or blocking pushes if an established
check fails (unit tests, syntax).
A pre-push hook is created by simply creating a file named pre-push under .git/hooks/, and (
gotcha alert), making sure the file is executable: chmod +x ./git/hooks/pre-push.
#!/bin/bash
protected_branch='master'
current_branch=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,')
if [ $protected_branch = $current_branch ]
then
read -p "You're about to push master, is that what you intended? [y|n] " -n 1 -r <
/dev/tty
echo
if echo $REPLY | grep -E '^[Yy]$' > /dev/null
then
exit 0 # push will execute
fi
exit 1 # push will not execute
else
exit 0 # push will execute
fi
Here's an example from Volkan Unsal which makes sure RSpec tests pass before allowing the
https://riptutorial.com/ 125
push:
#!/usr/bin/env ruby
require 'pty'
html_path = "rspec_results.html"
begin
PTY.spawn( "rspec spec --format h > rspec_results.html" ) do |stdin, stdout, pid|
begin
stdin.each { |line| print line }
rescue Errno::EIO
end
end
rescue PTY::ChildExited
puts "Child process exit!"
end
if errors.zero?
puts "0 failed! #{examples} run, #{pending} pending"
# HTML Output when tests ran successfully:
# puts "View spec results at #{File.expand_path(html_path)}"
sleep 1
exit 0
else
puts "\aCOMMIT FAILED!!"
puts "View your rspec results at #{File.expand_path(html_path)}"
puts
puts "#{errors} failed! #{examples} run, #{pending} pending"
# Open HTML Ooutput when tests failed
# `open #{html_path}`
exit 1
end
As you can see, there are lots of possibilities, but the core piece is to exit 0 if good things
happened, and exit 1 if bad things happened. Anytime you exit 1 the push will be prevented and
your code will be in the state it was before running git push....
When using client side hooks, keep in mind that users can skip all client side hooks by using the
option "--no-verify" on a push. If you're relying on the hook to enforce process, you can get
burned.
Documentation: https://git-scm.com/docs/githooks#_pre_push
Official Sample:
https://github.com/git/git/blob/87c86dd14abe8db7d00b0df5661ef8cf147a72a3/templates/hooks--
pre-push.sample
https://riptutorial.com/ 126
.git/hooks/pre-commit
#!/bin/sh
if [ -s pom.xml ]; then
echo "Running mvn verify"
mvn clean verify
if [ $? -ne 0 ]; then
echo "Maven build failed"
exit 1
fi
fi
post-receive hooks can be used to automatically forward incoming pushes to another repository.
$ cat .git/hooks/post-receive
#!/bin/bash
IFS=' '
while read local_ref local_sha remote_ref remote_sha
do
done
In this example, the egrep regexp looks for a specific branch format (here: JIRA-12345 as used to
name Jira issues). You can leave this part off if you want to forward all branches, of course.
https://riptutorial.com/ 127
Chapter 36: Ignoring Files and Folders
Introduction
This topic illustrates how to avoid adding unwanted files (or file changes) in a Git repo. There are
several ways (global or local .gitignore, .git/exclude, git update-index --assume-unchanged, and git
update-index --skip-tree), but keep in mind Git is managing content, which means: ignoring
actually ignores a folder content (i.e. files). An empty folder would be ignored by default, since it
cannot be added anyway.
Examples
Ignoring files and directories with a .gitignore file
You can make Git ignore certain files and directories — that is, exclude them from being tracked
by Git — by creating one or more .gitignore files in your repository.
In software projects, .gitignore typically contains a listing of files and/or directories that are
generated during the build process or at runtime. Entries in the .gitignore file may include names
or paths pointing to:
When created in the top level directory, the rules will apply recursively to all files and sub-
directories throughout the entire repository. When created in a sub-directory, the rules will apply to
that specific directory and its sub-directories.
1. tracked by Git
2. reported by commands such as git status or git diff
3. staged with commands such as git add -A
In the unusual case that you need to ignore tracked files, special care should be taken. See:
Ignore files that have already been committed to a Git repository.
Examples
Here are some generic examples of rules in a .gitignore file, based on glob file patterns:
https://riptutorial.com/ 128
# Ignore files called 'file.ext'
file.ext
# Ignoring directories
# Both the directory itself and its contents will be ignored.
bin/
gen/
# Glob pattern can also be used here to ignore paths with certain characters.
# For example, the below rule will match both build/ and Build/
[bB]uild/
# Without the trailing slash, the rule will match a file and/or
# a directory, so the following would ignore both a file named `gen`
# and a directory named `gen`, as well as any contents of that directory
bin
gen
# To ignore files only at the top level directory, but not in its
# subdirectories, prefix the rule with a `/`
/*.apk
/*.class
https://riptutorial.com/ 129
# DirectoryA/DirectoryB/
# DirectoryA/DirectoryQ/DirectoryB/
# DirectoryA/DirectoryQ/DirectoryW/DirectoryB/
# Use the backslash as escape character to ignore files with a hash (#)
# (supported since 1.6.2.1)
\#*#
Most .gitignore files are standard across various languages, so to get started, here is set of
sample .gitignore files listed by language from which to clone or copy/modify into your project.
Alternatively, for a fresh project you may consider auto-generating a starter file using an online tool
.
• Edit the .git/info/exclude file (using the same syntax as .gitignore). The rules will be global
in the scope of the repository;
• Set up a global gitignore file that will apply ignore rules to all your local repositories:
Furthermore, you can ignore local changes to tracked files without changing the global git
configuration with:
See more details on differences between the latter flags and the git update-index documentation
for further options.
Note: -X (caps) cleans up only ignored files. Use -x (no caps) to also remove untracked files.
https://riptutorial.com/ 130
See the git clean documentation for more details.
If you ignore files by using a pattern but have exceptions, prefix an exclamation mark(!) to the
exception. For example:
*.txt
!important.txt
The above example instructs Git to ignore all files with the .txt extension except for files named
important.txt.
folder/
!folder/*.txt
In this example all .txt files in the folder would remain ignored.
The right way is re-include the folder itself on a separate line, then ignore all files in folder by *,
finally re-include the *.txt in folder, as the following:
!folder/
folder/*
!folder/*.txt
Note: For file names beginning with an exclamation mark, add two exclamation marks or escape
with the \ character:
!!includethis
\!excludethis
To have Git ignore certain files across all repositories you can create a global .gitignore with the
following command in your terminal or command prompt:
Git will now use this in addition to each repository's own .gitignore file. Rules for this are:
• If the local .gitignore file explicitly includes a file while the global .gitignore ignores it, the
local .gitignore takes priority (the file will be included)
• If the repository is cloned on multiple machines, then the global .gigignore must be loaded
on all machines or at least include it, as the ignored files will be pushed up to the repo while
https://riptutorial.com/ 131
the PC with the global .gitignore wouldn't update it. This is why a repo specific .gitignore is
a better idea than a global one if the project is worked on by a team
This file is a good place to keep platform, machine or user specific ignores, e.g. OSX .DS_Store,
Windows Thumbs.db or Vim *.ext~ and *.ext.swp ignores if you don't want to keep those in the
repository. So one team member working on OS X can add all .DS_STORE and _MACOSX (which is
actually useless), while another team member on Windows can ignore all thumbs.bd
If you have already added a file to your Git repository and now want to stop tracking it (so that it
won't be present in future commits), you can remove it from the index:
This will remove the file from the repository and prevent further changes from being tracked by Git.
The --cached option will make sure that the file is not physically deleted.
Note that previously added contents of the file will still be visible via the Git history.
Keep in mind that if anyone else pulls from the repository after you removed the file from the
index, their copy will be physically deleted.
You can make Git pretend that the working directory version of the file is up to date and read the
index version instead (thus ignoring changes in it) with "skip worktree" bit:
Writing is not affected by this bit, content safety is still first priority. You will never lose your
precious ignored changes; on the other hand this bit conflicts with stashing: to remove this bit, use
It is sometimes wrongly recommended to lie to Git and have it assume that file is unchanged
without examining it. It looks at first glance as ignoring any further changes to the file, without
removing it from its index:
This will force git to ignore any change made in the file (keep in mind that if you pull any changes
to this file, or you stash it, your ignored changes will be lost)
If you want git to "care" about this file again, run the following command:
https://riptutorial.com/ 132
Checking if a file is ignored
You can pass filenames on the command line, and git check-ignore will list the filenames that are
ignored. For example:
$ cat .gitignore
*.o
$ git check-ignore example.o Readme.md
example.o
Here, only *.o files are defined in .gitignore, so Readme.md is not listed in the output of git check-
ignore.
If you want to see line of which .gitignore is responsible for ignoring a file, add -v to the git check-
ignore command:
From Git 1.7.6 onwards you can also use git status --ignored in order to see ignored files. You
can find more info on this in the official documentation or in Finding files ignored by .gitignore.
examples/
output.log
src/
<files not shown>
output.log
README.md
output.log in the examples directory is valid and required for the project to gather an
understanding while the one beneath src/ is created while debugging and should not be in the
history or part of the repository.
There are two ways to ignore this file. You can place an absolute path into the .gitignore file at the
root of the working directory:
# /.gitignore
src/output.log
Alternatively, you can create a .gitignore file in the src/ directory and ignore the file that is relative
to this .gitignore:
# /src/.gitignore
https://riptutorial.com/ 133
output.log
To ignore a file foo.txt in any directory you should just write its name:
If you want to ignore the file only in part of the tree, you can specify the subdirectories of a specific
directory with ** pattern:
Or you can create a .gitignore file in the bar/ directory. Equivalent to the previous example would
be creating file bar/.gitignore with these contents:
.gitignore ignores files locally, but it is intended to be committed to the repository and shared with
other contributors and users. You can set a global .gitignore, but then all your repositories would
share those settings.
If you want to ignore certain files in a repository locally and not make the file part of any repository,
edit .git/info/exclude inside your repository.
For example:
If you are unsure which rules to list in your .gitignore file, or you just want to add generally
accepted exceptions to your project, you can choose or generate a .gitignore file:
• https://www.gitignore.io/
• https://github.com/github/gitignore
Many hosting services such as GitHub and BitBucket offer the ability to generate .gitignore files
based upon the programming languages and IDEs you may be using:
https://riptutorial.com/ 134
Ignoring subsequent changes to a file (without removing it)
Sometimes you want to have a file held in Git but ignore subsequent changes.
The above command instructs Git to assume my-file.txt hasn't been changed, and not to check
or report changes. The file is still present in the repository.
This can be useful for providing defaults and allowing local environment overrides, e.g.:
# commit to Git
git add .env
git commit -m "Adding .env template"
https://riptutorial.com/ 135
# ignore future changes to .env
git update-index --assume-unchanged .env
# no changes!
git status
Sometimes you may want to have local changes in a file you don't want to commit or publish.
Ideally local settings should be concentrated in a separate file that can be placed into .gitignore,
but sometimes as a short-term solution it can be helpful to have something local in a checked-in
file.
You can make Git "unsee" those lines using clean filter. They won't even show up in diffs.
struct settings s;
s.host = "localhost";
s.port = 5653;
s.auth = 1;
s.port = 15653; // NOCOMMIT
s.debug = 1; // NOCOMMIT
s.auth = 0; // NOCOMMIT
Create "nocommit" filter by adding this to Git config file like .git/config:
[filter "nocommit"]
clean=grep -v NOCOMMIT
file1.c filter=nocommit
Caveats:
https://riptutorial.com/ 136
To set ignore flag on a tracked file, use the command update-index:
You can add this snippet to your global git config to have more convenient git hide, git unhide
and git hidden commands:
[alias]
hide = update-index --skip-worktree
unhide = update-index --no-skip-worktree
hidden = "!git ls-files -v | grep ^[hsS] | cut -c 3-"
You can also use the option --assume-unchanged with the update-index function
If you want to watch this file again for the changes, use
When --assume-unchanged flag is specified, the user promises not to change the file and allows
Git to assume that the working tree file matches what is recorded in the index.Git will fail in case it
needs to modify this file in the index e.g. when merging in a commit; thus, in case the assumed-
untracked file is changed upstream, you will need to handle the situation manually.The focus lies
on performance in this case.
While --skip-worktree flag is useful when you instruct git not to touch a specific file ever because
the file is going to be changed locally and you don't want to accidentally commit the changes (i.e
configuration/properties file configured for a particular environment). Skip-worktree takes
precedence over assume-unchanged when both are set.
Sometimes it happens that a file was being tracked by git, but in a later point in time was added to
.gitignore, in order to stop tracking it. It's a very common scenario to forget to clean up such files
before its addition to .gitignore. In this case, the old file will still be hanging around in the
repository.
To fix this problem, one could perform a "dry-run" removal of everything in the repository, followed
by re-adding all the files back. As long as you don't have pending changes and the --cached
parameter is passed, this command is fairly safe to run:
# Remove everything from the index (the files will stay in the file system)
$ git rm -r --cached .
https://riptutorial.com/ 137
# Re-add everything (they'll be added in the current state, changes included)
$ git add .
It is not possible to add and commit an empty folder in Git due to the fact that Git manages files
and attaches their directory to them, which slims down commits and improves speed. To get
around this, there are two methods:
One hack to get around this is to use a .gitkeep file to register the folder for Git. To do this, just
create the required directory and add a .gitkeep file to the folder. This file is blank and doesn't
serve any purpose other than to just register the folder. To do this in Windows (which has
awkward file naming conventions) just open git bash in the directory and run the command:
$ touch .gitkeep
This command just makes a blank .gitkeep file in the current directory
Another hack for this is very similar to the above and the same steps can be followed, but instead
of a .gitkeep, just use a dummy.txt instead. This has the added bonus of being able to easily create
it in Windows using the context menu. And you get to leave funny messages in them too.You can
also use .gitkeep file to track the empty directory. .gitkeep normally is an empty file that is added
to track the empty directoy.
You can list all files ignored by git in current directory with command:
.git
.gitignore
./example_1
./dir/example_2
./example_2
https://riptutorial.com/ 138
example_2
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
.example_1
Ignored files:
(use "git add -f <file>..." to include in what will be committed)
dir/
example_2
If you want to list recursively ignored files in directories, you have to use additional parameter - --
untracked-files=all
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
example_1
Ignored files:
(use "git add -f <file>..." to include in what will be committed)
dir/example_2
example_2
https://riptutorial.com/ 139
Chapter 37: Internals
Examples
Repo
A git repository is an on-disk data structure which stores metadata for a set of files and
directories.
It lives in your project's .git/ folder. Every time you commit data to git, it gets stored here.
Inversely, .git/ contains every single commit.
.git/
objects/
refs/
Objects
is fundamentally a key-value store. When you add data to git, it builds an object and uses the
git
SHA-1 hash of the object's contents as a key.
• blob
• tree
• commit
• tag
HEAD ref
You can see where it's currently pointing by checking the .git/HEAD file.
$cat .git/HEAD
ref: refs/heads/mainline
$ cat .git/HEAD
https://riptutorial.com/ 140
4bb6f98a223abc9345a0cef9200562333
This is what's known as a "detached head" - because HEAD is not attached to (pointing at) any ref,
but rather points directly to an object.
Refs
A ref is essentially a pointer. It's a name that points to an object. For example,
$ cat .git/refs/heads/mainline
4bb6f98a223abc9345a0cef9200562333
This is commonly what are called branches. However, you'll note that in git there is no such thing
as a branch - only a ref.
Now, it's possible to navigate git purely by jumping around to different objects directly by their
hashes. But this would be terribly inconvenient. A ref gives you a convenient name to refer to
objects by. It's much easier to ask git to go to a specific place by name rather than by hash.
Commit Object
A commit is probably the object type most familiar to git users, as it's what they are used to
creating with the git commit commands.
However, the commit does not directly contain any changed files or data. Rather, it contains mostly
metadata and pointers to other objects which contain the actual contents of the commit.
• hash of a tree
• hash of a parent commit
• author name/email, commiter name/email
• commit message
First commit!
https://riptutorial.com/ 141
Tree
A very important note is that the tree objects stores EVERY file in your project, and it stores whole
files not diffs. This means that each commit contains a snapshot of the entire project*.
*Technically, only changed files are stored. But this is more an implementation detail for efficiency.
From a design perspective, a commit should be considered as containing a complete copy of the
project.
Parent
The parent line contains a hash of another commit object, and can be thought of as a "parent
pointer" that points to the "previous commit". This implicitly forms a graph of commits known as the
commit graph. Specifically, it's a directed acyclic graph (or DAG).
Tree Object
A tree basically represents a folder in a traditional filesystem: nested containers for files or other
folders.
A tree contains:
Just as you can use ls or dir to list the contents of a folder, you can list the contents of a tree
object.
You can look up the files in a commit by first finding the hash of the tree in the commit, and then
looking at that tree:
https://riptutorial.com/ 142
Blob Object
A blob contains arbitrary binary file contents. Commonly, it will be raw text such as source code or
a blog article. But it could just as easily be the bytes of a PNG file or anything else.
If you have the hash of a blob, you can look at it's contents.
class Foo {
...
}
...
For example, you can browse a tree as above, and then look at one of the blobs in it.
1. Create blobs and trees to represent your project directory - stored in .git/objects
2. Creates a new commit object with your author information, commit message, and the root tree
from step 1 - also stored in .git/objects
3. Updates the HEAD ref in .git/HEAD to the hash of the newly-created commit
This results in a new snapshot of your project being added to git that is connected to the previous
state.
Moving HEAD
When you run git checkout on a commit (specified by hash or ref) you're telling git to make your
working directory look like how it did when the snapshot was taken.
1. Update the files in the working directory to match the tree inside the commit
2. Update HEAD to point to the specified hash or ref
https://riptutorial.com/ 143
Moving MyBranch to b8dc53:
Running git checkout -b <refname> will create a new ref that points to the current commit.
$ cat .git/head
1f324a
$ cat .git/refs/heads/TestBranch
1f324a
https://riptutorial.com/ 144
Chapter 38: Merging
Syntax
• git merge another_branch [options]
• git merge --abort
Parameters
Parameter Details
--no-commit Pretends the merge failed to allow inspection and tweaking of the result
--squash Allows for a single commit on the current branch with the merged changes
Examples
Merge one branch into another
This merges the branch incomingBranch into the branch you are currently in. For example, if you are
currently in master, then incomingBranch will be merged into master.
Merging can create conflicts in some cases. If this happens, you will see the message Automatic
merge failed; fix conflicts and then commit the result. You will need to manually edit the
conflicted files, or to undo your merge attempt, run:
https://riptutorial.com/ 145
Automatic Merging
When the commits on two branches don't conflict, Git can automatically merge them:
Aborting a merge
After starting a merge, you might want to stop the merge and return everything to its pre-merge
state. Use --abort:
During a merge, you can pass --ours or --theirs to git checkout to take all changes for a file from
one side or the other of a merge.
$ git checkout --ours -- file1.txt # Use our version of file1, delete all their changes
$ git checkout --theirs -- file2.txt # Use their version of file2, delete all our changes
Default behaviour is when the merge resolves as a fast-forward, only update the branch pointer,
without creating a merge commit. Use --no-ff to resolve.
Sometimes you might have branches lying around that have already had their changes merged
into master. This finds all branches that are not master that have no unique commits as compared
to master. This is very useful for finding branches that were not deleted after the PR was merged
into master.
https://riptutorial.com/ 146
Chapter 39: Migrating to Git
Examples
Migrate from SVN to Git using Atlassian conversion utility
Download the Atlassian conversion utility here. This utility requires Java, so please ensure that
you have the Java Runtime Environment JRE installed on the machine you plan to do the
conversion.
Use the command java -jar svn-migration-scripts.jar verify to check if your machine is missing
any of the programs necessary to complete the conversion. Specifically, this command checks for
the Git, subversion, and git-svn utilities. It also verifies that you are performing the migration on a
case-sensitive file system. Migration to Git should be done on a case-sensitive file system to avoid
corrupting the repository.
Next, you need to generate an authors file. Subversion tracks changes by the committer's
username only. Git, however, uses two pieces of information to distinguish a user: a real name
and an email address. The following command will generate a text file mapping the subversion
usernames to their Git equivalents:
where <svn-repo> is the URL of the subversion repository you wish to convert. After running this
command, the contributors' identification information will be mapped in authors.txt. The email
addresses will be of the form <username>@mycompany.com. In the authors file, you will need to
manually change each person's default name (which by default has become their username) to
their actual names. Make sure to also check all of the email addresses for correctness before
proceeding.
where <svn-repo> is the same repository URL used above and <git-repo-name> is the folder name in
the current directory to clone the repository into. There are a few considerations before using this
command:
• The --stdlayout flag from above tells Git that you're using a standard layout with trunk,
branches, and tags folders. Subversion repositories with non-standard layouts require you to
specify the locations of the trunk folder, any/all branch folders, and the tags folder. This can
be done by following this example: git svn clone --trunk=/trunk --branches=/branches --
branches=/bugfixes --tags=/tags --authors-file=authors.txt <svn-repo> <git-repo-name>.
• This command could take many hours to complete depending on the size of your repo.
• To cut down the conversion time for large repositories, the conversion can be run directly on
https://riptutorial.com/ 147
the server hosting the subversion repository in order to eliminate network overhead.
git svn clone imports the subversion branches (and trunk) as remote branches including
subversion tags (remote branches prefixed with tags/). To convert these to actual branches and
tags, run the following commands on a Linux machine in the order they are provided. After running
them, git branch -a should show the correct branch names, and git tag -l should show the
repository tags.
The conversion from svn to Git is now complete! Simply push your local repo to a server and you
can continue to contribute using Git as well as having a completely preserved version history from
svn.
SubGit
svn2git is a Ruby wrapper around git's native SVN support through git-svn, helping you with
migrating projects from Subversion to Git, keeping history (incl. trunk, tags and branches history).
Examples
To migrate a svn repository with the standard layout (ie. branches, tags and trunk at the root level
of the repository):
$ svn2git http://svn.example.com/path/to/repo
In case you do not want to migrate (or do not have) branches, tags or trunk you can use options --
notrunk, --nobranches, and --notags.
To reduce the space required by your new repository you may want to exclude any directories or
files you once added while you should not have (eg. build directory or archives):
https://riptutorial.com/ 148
$ svn2git http://svn.example.com/path/to/repo --exclude build --exclude '.*\.zip$'
Post-migration optimization
If you already have a few thousand of commits (or more) in your newly created git repository, you
may want to reduce space used before pushing your repository on a remote. This can be done
using the following command:
$ git gc --aggressive
Note: The previous command can take up to several hours on large repositories (tens of thousand
of commits and/or hundreds of megabytes of history).
You could migrate from team foundation version control to git by using an open source tool called
Git-TF. Migration will also transfer your existing history by converting tfs checkins to git commits.
To put your solution into Git by using Git-TF follow these steps:
Download Git-TF
You can download (and install) Git-TF from Codeplex: Git-TF @ Codeplex
The --deep switch is the keeyword to note as this tells Git-Tf to copy your checkin-history. You
now have a local git repository in the folder from which you called your cloe command from.
Cleanup
• Add a .gitignore file. If you are using Visual Studio the editor can do this for you, otherwise
you could do this manually by downloading a complete file from github/gitignore.
• RemoveTFS source control bindings from solution (remove all *.vssscc files). You could also
modify your solution file by removing the
GlobalSection(TeamFoundationVersionControl)......EndClobalSection
Complete your conversion by committing and pushing your local repository to your remote.
git add .
git commit -a -m "Coverted solution source control from TFVC to Git"
https://riptutorial.com/ 149
git push origin master
One can use the following methods in order to import a Mercurial Repo into Git:
cd
git clone git://repo.or.cz/fast-export.git
git init git_repo
cd git_repo
~/fast-export/hg-fast-export.sh -r /path/to/old/mercurial_repo
git checkout HEAD
https://riptutorial.com/ 150
Chapter 40: Pulling
Introduction
Unlike pushing with Git where your local changes are sent to the central repository's server,
pulling with Git takes the current code on the server and 'pulls' it down from the repository's server
to your local machine. This topic explains the process of pulling code from a repository using Git
as well as the situations one might encounter while pulling different code into the local copy.
Syntax
• git pull [options [<repository> [<refspec>...]]
Parameters
Parameters Details
--[no-]recurse-submodules[=yes| Fetch new commits for submodules? (Not that this is not
on-demand|no] a pull/checkout)
Remarks
git pullruns git fetch with the given parameters and calls git merge to merge the retrieved
branch heads into the current branch.
Examples
Updating with local changes
When local changes are present, the git pull command aborts reporting :
error: Your local changes to the following files would be overwritten by merge
In order to update (like svn update did with subversion), you can run :
https://riptutorial.com/ 151
git stash
git pull --rebase
git stash pop
2.9
git config --global alias.up '!git stash && git pull --rebase && git stash pop'
2.9
git up
git pull
git fetch
git reset --hard origin/master
Beware: While commits discarded using reset --hard can be recovered using reflog and reset,
uncommitted changes are deleted forever.
Change origin and master to the remote and branch you want to forcibly pull to, respectively, if
they are named differently.
https://riptutorial.com/ 152
Making it the default behavior
To make this the default behavior for newly created branches, type the following command:
And
Check if fast-forwardable
To only allow fast forwarding the local branch, you can use:
This will display an error when the local branch is not fast-forwardable, and needs to be either
rebased or merged with upstream.
Some problems can occur if the .git folder has wrong permission. Fixing this problem by setting
the owner of the complete .git folder. Sometimes it happen that another user pull and change the
rights of the .git folder or files.
Simple pull
When you are working on a remote repository (say, GitHub) with someone else, you will at some
point want to share your changes with them. Once they have pushed their changes to a remote
repository, you can retrieve those changes by pulling from this repository.
https://riptutorial.com/ 153
git pull
Will pull the branch feature-A form origin into your local branch. Note that you can directly supply
an URL instead of a remote name, and an object name such as a commit SHA instead of a branch
name.
Manual pull
To imitate the behavior of a git pull, you can use git fetch then git merge
git fetch origin # retrieve objects and update refs from origin
git merge origin/feature-A # actually perform the merge
This can give you more control, and allows you to inspect the remote branch before merging it.
Indeed, after fetching, you can see the remote branches with git branch -a, and check them out
with
https://riptutorial.com/ 154
Chapter 41: Pushing
Introduction
After changing, staging, and committing code with Git, pushing is required to make your changes
available to others and transfers your local changes to the repository server. This topic will cover
how to properly push code using Git.
Syntax
• git push [-f | --force] [-v | --verbose] [<remote> [<refspec>...]]
Parameters
Parameter Details
Overwrites the remote ref to match your local ref. Can cause the remote
--force
repository to lose commits, so use with care.
<refspec>... Specify what remote ref to update with what local ref or object.
Remarks
When you make changes, you usually want to send them back "upstream" so they
make it into that repository so that everyone pulling from the same source is working
with all the same changes. This is mostly a social issue of how everyone can
coordinate their work rather than a technical requirement of source control. You want to
get your changes into the main project so you're not tracking divergent lines of
development.
Sometimes you'll read about package or release managers (the people, not the tool)
talking about submitting changes to "upstream". That usually means they had to adjust
the original sources so they could create a package for their system. They don't want
to keep making those changes, so if they send them "upstream" to the original source,
https://riptutorial.com/ 155
they shouldn't have to deal with the same issue in the next release.
(Source)
Examples
Push
git push
will push your code to your existing upstream. Depending on the push configuration, it will either
push code from you current branch (default in Git 2.x) or from all branches (default in Git 1.x).
Specify Branch
To push to a specific branch, say feature_x:
Here, master is the branch name on the remote origin. You can use -u as a shorthand for --set-
upstream.
https://riptutorial.com/ 156
To push to a repository that you haven't made yet, or is empty:
Explanation
Push code means that git will analyze the differences of your local commits and remote and send
them to be written on the upstream. When push succeeds, your local repository and remote
repository are synchronized and other users can see your commits.
For more details on the concepts of "upstream" and "downstream", see Remarks.
Force Pushing
Sometimes, when you have local changes incompatible with remote changes (ie, when you cannot
fast-forward the remote branch, or the remote branch is not a direct ancestor of your local branch),
the only way to push your changes is a force push.
git push -f
or
Important notes
This will overwrite any remote changes and your remote will match your local.
Attention: Using this command may cause the remote repository to lose commits. Moreover, it is
strongly advised against doing a force push if you are sharing this remote repository with others,
since their history will retain every overwritten commit, thus rending their work out of sync with the
remote repository.
• Nobody except you pulled the changes you are trying to overwrite
https://riptutorial.com/ 157
• You can force everyone to clone a fresh copy after the forced push and make everyone
apply their changes to it (people may hate you for this).
General syntax
git push <remotename> <object>:<remotebranchname>
Example
Will push your master branch to the wip-yourname branch of origin (most of the time, the repository
you cloned from).
Example
git push origin :wip-yourname
Instead of using the colon, you can also use the --delete flag, which is better readable in some
cases.
Example
https://riptutorial.com/ 158
git push <remotename> <commit SHA>:<remotebranchname>
Example
Assuming a git history like this
to push only commit 347d700 to remote master use the following command
Current updates the branch on the remote repository that shares a name with the current working
branch.
Simple pushes to the upstream branch, but will not work if the upstream branch is called
something else.
Matching pushes all branches that match on the local and the remote git config push.default
upstream
git push
Push tags
Pushes all of the git tags in the local repository that are not in the remote one.
https://riptutorial.com/ 159
Read Pushing online: https://riptutorial.com/git/topic/2600/pushing
https://riptutorial.com/ 160
Chapter 42: Rebasing
Syntax
• git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>]
[<branch>]
• git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] --root
[<branch>]
• git rebase --continue | --skip | --abort | --edit-todo
Parameters
Parameter Details
--continue Restart the rebasing process after having resolved a merge conflict.
Abort the rebase operation and reset HEAD to the original branch. If branch
was provided when the rebase operation was started, then HEAD will be reset
--abort
to branch. Otherwise HEAD will be reset to where it was when the rebase
operation was started.
--keep-
Keep the commits that do not change anything from its parents in the result.
empty
Use merging strategies to rebase. When the recursive (default) merge strategy
is used, this allows rebase to be aware of renames on the upstream side. Note
that a rebase merge works by replaying each commit from the working branch
-m, --merge on top of the upstream branch. Because of this, when a merge conflict
happens, the side reported as ours is the so-far rebased series, starting with
upstream, and theirs is the working branch. In other words, the sides are
swapped.
Show a diffstat of what changed upstream since the last rebase. The diffstat is
--stat
also controlled by the configuration option rebase.stat.
-x, --exec Perform interactive rebase, stopping between each commit and executing
command command
Remarks
Please keep in mind that rebase effectively rewrites the repository history.
Rebasing commits that exists in the remote repository could rewrite repository nodes used by
other developers as base node for their developments. Unless you really know what you are
https://riptutorial.com/ 161
doing, it is a best practice to rebase before pushing your changes.
Examples
Local Branch Rebasing
To rebase a branch, checkout the branch and then rebase it on top of another branch.
A---B---C topic
/
D---E---F---G master
To turn into:
A'--B'--C' topic
/
D---E---F---G master
These operations can be combined into a single command that checks out the branch and
immediately rebases it:
git rebase master topic # rebase topic branch onto master branch
Important: After the rebase, the applied commits will have a different hash. You should not
rebase commits you have already pushed to a remote host. A consequence may be an inability to
git push your local rebased branch to a remote host, leaving your only option to git push --force.
The first thing a rebase does is resetting the HEAD to master; before cherry-picking commits from the
old branch topic to a new one (every commit in the former topic branch will be rewritten and will
be identified by a different hash).
With respect to terminologies used by merge tools (not to be confused with local ref or remote ref)
https://riptutorial.com/ 162
=> local is master ("ours"),
=> remote is topic ("theirs")
That means a merge/diff tool will present the upstream branch as local (master: the branch on top
of which you are rebasing), and the working branch as remote (topic: the branch being rebased)
+-----------------------------------------+
| LOCAL:master | BASE | REMOTE:topic |
+-----------------------------------------+
| MERGED |
+-----------------------------------------+
Inversion illustrated
On a merge:
We don't change the current branch topic, so what we have is still what we were working on (and
we merge from another branch)
On a rebase:
But on a rebase we switch sides because the first thing a rebase does is to checkout the
upstream branch to replay the current commits on top of it!
A git rebase upstream will first set HEAD to the upstream branch, hence the switch of 'ours' and
'theirs' compared to the previous "current" working branch.
https://riptutorial.com/ 163
\--y--y--y(*) <- set HEAD to this commit, to replay x's on it
^ this will be the new "ours"
|
upstream
The rebase will then replay 'their' commits on the new 'our' topic branch:
c--c..x..x..x <- old "theirs" commits, now "ghosts", available through "reflogs"
\
\
\--y--y--y--x'--x'--x'(*) <- topic once all x's are replayed,
^ point branch topic to this commit
|
upstream branch
Interactive Rebase
This example aims to describe how one can utilize git rebase in interactive mode. It is expected
that one has a basic understanding of what git rebase is and what it does.
git rebase -i
The -i option refers to interactive mode. Using interactive rebase, the user can change commit
messages, as well as reorder, split, and/or squash (combine to one) commits.
Say you want to rearrange your last three commits. To do this you can run:
After executing the above instruction, a file will be opened in your text editor where you will be able
to select how your commits will be rebased. For the purpose of this example, just change the order
of your commits, save the file, and close the editor. This will initiate a rebase with the order you've
applied. If you check git log you will see your commits in the new order you specified.
Instead of rearranging the order the commits will be rebased, this time we will change pick, the
default, to reword on a commit where you would like to change the message.
When you close the editor, the rebase will initiate and it will stop at the specific commit message
that you wanted to reword. This will let you change the commit message to whichever you desire.
https://riptutorial.com/ 164
After you've changed the message, simply close the editor to proceed.
As soon as the staging area contains all changes you want in that commit, commit the changes.
The old commit message will be shown and can be adapted to reflect the new commit.
Now, git will stop at the commit you have marked for editing and place all of its content into the
staging area. From that point you can run git reset HEAD^ to place the commit into your working
directory. Then, you can add and commit your files in a different sequence - ultimately splitting a
single commit into n commits instead.
This time replace pick with squash instead. During the rebase, the commit which you've instructed
to be squashed will be squashed on top of the previous commit; turning them into a single commit
instead.
You have started an interactive rebase. In the editor where you pick your commits, you decide that
something is going wrong (for example a commit is missing, or you chose the wrong rebase
destination), and you want to abort the rebase.
To do this, simply delete all commits and actions (i.e. all lines not starting with the # sign) and the
rebase will be aborted!
https://riptutorial.com/ 165
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Note that empty commits are commented out
Sometimes you need rewrite history with a rebase, but git push complains about doing so
because you rewrote history.
This can be solved with a git push --force, but consider git push --force-with-lease, indicating
that you want the push to fail if the local remote-tracking branch differs from the branch on the
remote, e.g., someone else pushed to the remote after the last fetch. This avoids inadvertently
overwriting someone else's recent push.
Note: git push --force - and even --force-with-lease for that matter - can be a dangerous
command because it rewrites the history of the branch. If another person had pulled the branch
before the forced push, his/her git pull or git fetch will have errors because the local history and
the remote history are diverged. This may cause the person to have unexpected errors. With
enough looking at the reflogs the other user's work can be recovered, but it can lead to a lot of
wasted time. If you must do a forced push to a branch with other contributors, try to coordinate
with them so that they do not have to deal with errors.
Since Git 1.7.12 it is possible to rebase down to the root commit. The root commit is the first
commit ever made in a repository, and normally cannot be edited. Use the following command:
Summary
This goal is to reorganize all of your scattered commits into more meaningful commits for easier
code reviews. If there are too many layers of changes across too many files at once, it is harder to
do a code review. If you can reorganize your chronologically created commits into topical commits,
then the code review process is easier (and possibly less bugs slip through the code review
https://riptutorial.com/ 166
process).
This overly-simplified example is not the only strategy for using git to do better code reviews. It is
the way I do it, and it's something to inspire others to consider how to make code reviews and git
history easier/better.
Assuming:
• you're working on a feature branch off of master
• your feature has three main layers: front-end, back-end, DB
• you have made a lot of commits while working on a feature branch. Each commit touches
multiple layers at once
• you want (in the end) only three commits in your branch
○one containing all front end changes
○one containing all back end changes
○one containing all DB changes
Strategy:
• we are going to change our chronological commits into "topical" commits.
• first, split all commits into multiple, smaller commits -- each containing only one topic at a
time (in our example, the topics are front end, back end, DB changes)
• Then reorder our topical commits together and 'squash' them into single topical commits
Example:
$ git log --oneline master..
975430b db adding works: db.sql logic.rb
3702650 trying to allow adding todo items: page.html logic.rb
43b075a first draft: page.html and db.sql
$ git rebase -i master
Change it to this:
https://riptutorial.com/ 167
e 43b075a first draft: page.html and db.sql
e 3702650 trying to allow adding todo items: page.html logic.rb
e 975430b db adding works: db.sql logic.rb
Then git will apply one commit at a time. After each commit, it will show a prompt, and then you
can do the following:
$ git status
rebase in progress; onto 4975ae9
You are currently editing a commit while rebasing branch 'feature' on '4975ae9'.
(use "git commit --amend" to amend the current commit)
(use "git rebase --continue" once you are satisfied with your changes)
Then you will repeat those steps for every commit. In the end, you have this:
https://riptutorial.com/ 168
Change it to this:
NOTICE: make sure that you tell git rebase to apply/squash the smaller topical commits in the
order they were chronologically commited. Otherwise you might have false, needless merge
conflicts to deal with.
When that interactive rebase is all said and done, you get this:
Recap
You have now rebased your chronological commits into topical commits. In real life, you may not
need to do this every single time, but when you do want or need to do this, now you can. Plus,
hopefully you learned more about git rebase.
If your team is following a rebase-based workflow, it may be a advantageous to setup git so that
each newly created branch will perform a rebase operation, instead of a merge operation, during a
git pull.
To setup every new branch to automatically rebase, add the following to your .gitconfig or
.git/config:
[branch]
autosetuprebase = always
Alternatively, you can setup the git pull command to always behave as if the option --rebase was
passed:
[pull]
rebase = true
https://riptutorial.com/ 169
Testing all commits during rebase
Before making a pull request, it is useful to make sure that compile is successful and tests are
passing for each commit in the branch. We can do that automatically using -x parameter.
For example:
will perform the interactive rebase and stop after each commit to execute make. In case make fails,
git will stop to give you an opportunity to fix the issues and amend the commit before proceeding
with picking the next one.
Configuring autostash
Autostash is a very useful configuration option when using rebase for local changes. Oftentimes,
you may need to bring in commits from the upstream branch, but are not ready to commit just yet.
However, Git does not allow a rebase to start if the working directory is not clean. Autostash to the
rescue:
The autostash will be applied whenever the rebase is finished. It does not matter whether the
rebase finishes successfully, or if it is aborted. Either way, the autostash will be applied. If the
rebase was successful, and the base commit therefore changed, then there may be a conflict
between the autostash and the new commits. In this case, you will have to resolve the conflicts
before committing. This is no different than if you would have manually stashed, and then applied,
so there is no downside to doing it automatically.
https://riptutorial.com/ 170
Chapter 43: Recovering
Examples
Recovering from a lost commit
In case you have reverted back to a past commit and lost a newer commit you can recover the lost
commit by running
git reflog
In case you have accidentally commited a delete on a file and later realized that you need it back.
First find the commit id of the commit that deleted your file.
If you have already made local changes to the file (that you do not require!) you can also use the -
-hard option
To recover a deleted branch you need to find the commit which was the head of your deleted
branch by running
https://riptutorial.com/ 171
git reflog
You will not be able to recover deleted branches if git's garbage collector deleted dangling
commits - those without refs. Always have a backup of your repository, especially when you work
in a small team / proprietary project
With Git, you can (almost) always turn the clock back
Don't be afraid to experiment with commands that rewrite history*. Git doesn't delete your commits
for 90 days by default, and during that time you can easily recover them from the reflog:
* Watch out for options like --hard and --force though — they can discard data.
* Also, avoid rewriting history on any branches you're collaborating on.
To get your most recent stash after running git stash, use
Choose a different git stash to restore with the number that shows up for the stash you want
https://riptutorial.com/ 172
You can also choose 'git stash pop', it works same as 'git stash apply' like..
or
git stash pop:- stash data will be remove from stack of stash list.
Ex:-
stash@{0}: WIP on master: 70f0d95 Add user role to localStorage on user login
You can see one stash data is removed (popped) from stash list and stash@{1} became
stash@{0}.
https://riptutorial.com/ 173
Chapter 44: Reflog - Restoring commits not
shown in git log
Remarks
Git's reflog records the position of HEAD (the ref for the current state of the repository) every time
that it is changed. Generally, every operation that might be destructive involves moving the HEAD
pointer (since if anything is changed, including in the past, the tip commit's hash will change), so it
is always possible to revert back to an older state, before a dangerous operation, by finding the
right line in the reflog.
Objects that are not referenced by any ref are usually garbage collected in ~30 days, however, so
the reflog may not always be able to help.
Examples
Recovering from a bad rebase
and by mistake, you squashed or dropped some commits that you didn't want to lose, but then
completed the rebase. To recover, do git reflog, and you might see some output like this:
In this case, the last commit, ddddddd (or HEAD@{n+1}) is the tip of your pre-rebase branch. Thus, to
recover that commit (and all parent commits, including those accidentally squashed or dropped),
do:
You can then create a new branch at that commit with git checkout -b [branch]. See Branching for
more information.
https://riptutorial.com/ 174
Chapter 45: Renaming
Syntax
• git mv <source> <destination>
• git mv -f <source> <destination>
Parameters
Parameter Details
Examples
Rename Folders
then rename the local branch, delete the old remote and set the new renamed branch as
https://riptutorial.com/ 175
upstream:
https://riptutorial.com/ 176
Chapter 46: Resolving merge conflicts
Examples
Manual Resolution
While performing a git merge you may find that git reports a "merge conflict" error. It will report to
you which files have conflicts, and you will need to resolve the conflicts.
A git status at any point will help you see what still needs editing with a helpful message like
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
no changes added to commit (use "git add" and/or "git commit -a")
Git leaves markers in the files to tell you where the conflict arose:
In order to resolve the conflicts, you must edit the area between the <<<<<< and >>>>>>>
markers appropriately, remove the status lines (the <<<<<<<, >>>>>>>, and ======== lines)
completely. Then git add index.html to mark it resolved and git commit to finish the merge.
https://riptutorial.com/ 177
Chapter 47: Rev-List
Syntax
• git rev-list [options] <commit> ...
Parameters
Parameter Details
Examples
List Commits in master but not in origin/master
Git rev-list will list commits in one branch that are not in another branch. It is a great tool when
you're trying to figure out if code has been merged into a branch or not.
• Using the --oneline option will display the title of each commit.
• The ^ operator excludes commits in the specified branch from the list.
• You can pass more than two branches if you want. For example, git rev-list foo bar ^baz
lists commits in foo and bar, but not baz.
https://riptutorial.com/ 178
Chapter 48: Rewriting history with filter-
branch
Examples
Changing the author of commits
You can use an environment filter to change the author of commits. Just modify and export
$GIT_AUTHOR_NAME in the script to change who authored the commit.
chmod +x ./filter.sh
git filter-branch --env-filter ./filter.sh
This command, given a commit range commit1..commit2, rewrites history so that git commit author
becomes also git committer:
https://riptutorial.com/ 179
Chapter 49: Show
Syntax
• git show [options] <object>...
Remarks
Shows various Git objects.
Examples
Overview
For commits:
Shows the commit message and a diff of the changes introduced.
Command Description
Command Description
git show
@~3:src/program.js shows src/program.js as it was 3 commits ago (a blob)
git show @:a.txt @:b.txt shows a.txt concatenated with b.txt from current commit
https://riptutorial.com/ 180
For tags:
Shows the tag message and the referenced object.
https://riptutorial.com/ 181
Chapter 50: Squashing
Remarks
What is squashing?
Squashing is the process of taking multiple commits and combining them into a single commit
encapsulating all the changes from the initial commits.
Pay special attention when squashing commits on a branch that is tracking a remote branch; if you
squash a commit that has already been pushed to a remote branch, the two branches will be
diverged, and you will have to use git push -f to force those changes onto the remote branch. Be
aware that this can cause issues for others tracking that remote branch, so caution should
be used when force-pushing squashed commits onto public or shared repositories.
If the project is hosted on GitHub, you can enable "force push protection" on some branches, like
master, by adding it to Settings - Branches - Protected Branches.
Examples
Squash Recent Commits Without Rebasing
If you want to squash the previous x commits into a single one, you can use the following
commands:
Replacing x with the number of previous commits you want to be included in the squashed
commit.
Mind that this will create a new commit, essentially forgetting information about the previous x
commits including their author, message and date. You probably want to first copy-paste an
existing commit message.
Commits can be squashed during a git rebase. It is recommended that you understand rebasing
before attempting to squash commits in this fashion.
1. Determine which commit you would like to rebase from, and note its commit hash.
https://riptutorial.com/ 182
Alternatively, you can type HEAD~4 instead of a commit hash, to view the latest commit and 4
more commits before the latest one.
3. In the editor that opens when running this command, determine which commits you want to
squash. Replace pick at the beginning of those lines with squash to squash them into the
previous commit.
4. After selecting which commits you would like to squash, you will be prompted to write a
commit message.
At this point your editor of choice pops up where you can describe what you want to do with the
commits. Git provides help in the comments. If you leave it as is then nothing will happen because
every commit will be kept and their order will be the same as they were before the rebase. In this
example we apply the following commands:
https://riptutorial.com/ 183
36d15de Rebase from here
17692d1 Did some more stuff
e647334 Another Commit
2e30df6 Initial commit
Given the following history, imagine you make a change that you want to squash into the commit
bbb2222 A second commit:
Once you've made your changes, you can add them to the index as usual, then commit them
using the --fixup argument with a reference to the commit you want to squash into:
$ git add .
$ git commit --fixup bbb2222
[my-feature-branch ddd4444] fixup! A second commit
This will create a new commit with a commit message that Git can recognize during an interactive
rebase:
Git will propose you to squash the commit you made with the commit --fixup into the correct
position:
To avoid having to type --autosquash on every rebase, you can enable this option by default:
https://riptutorial.com/ 184
You can use git merge --squash to squash changes introduced by a branch into a single commit.
No actual commit will be created.
This is more or less equivalent to using git reset, but is more convenient when changes being
incorporated have a symbolic name. Compare:
When committing changes it is possible to specify that the commit will in future be squashed to
another commit and this can be done like so,
git commit --squash=[commit hash of commit to which this commit will be squashed to]
It is also possible to use words from the commit message instead of the commit hash, like so,
where the most recent commit with the word 'things' would be used.
These commits' message would begin with 'fixup!' or 'squash!' followed by the rest of the commit
message to which these commits will be squashed to.
When rebasing --autosquash flag should be used to use the autosquash/fixup feature.
https://riptutorial.com/ 185
Chapter 51: Staging
Remarks
It's worth noting that staging has little to do with 'files' themselves and everything to do with the
changes within each given file. We stage files that contain changes, and git tracks the changes as
commits (even when the changes in a commit are made across several files).
The distinction between files and commits may seem minor, but understanding this difference is
fundamental to understanding essential functions like cherry-pick and diff. (See the frustration in
comments regarding the complexity of an accepted answer that proposes cherry-pick as a file
management tool.)
Key concepts:
A files is the more common metaphor of the two in information technology. Best practice dictates
that a filename not change as its contents change (with a few recognized exceptions).
A commit is a metaphor that is unique to source code management. Commits are changes related
to a specific effort, like a bug fix. Commits often involve several files. A single, minor bug fix may
involve tweaks to templates and css in unique files. As the change is described, developed,
documented, reviewed and deployed, the changes across the separate files can be annotated and
handled as a single unit. The single unit in this case is the commit. Equally important, focusing just
on the commit during a review allows the unchanged lines of code in the various affected files to
be ignored safely.
Examples
Staging A Single File
git add -A
2.0
git add .
In version 2.x, git add . will stage all changes to files in the current directory and all its
https://riptutorial.com/ 186
subdirectories. However, in 1.x it will only stage new and modified files, not deleted files.
Use git add -A, or its equivalent command git add --all, to stage all changes to files in any
version of git.
git rm filename
To delete the file from git without removing it from disk, use the --cached flag
Interactive add
git add -i (or --interactive) will give you an interactive interface where you can edit the index, to
prepare what you want to have in the next commit. You can add and remove changes to whole
files, add untracked files and remove files from being tracked, but also select subsection of
changes to put in the index, by selecting chunks of changes to be added, splitting those chunks, or
even editing the diff. Many graphical commit tools for Git (like e.g. git gui) include such feature;
this might be easier to use than the command line version.
It is very useful (1) if you have entangled changes in the working directory that you want to put in
separate commits, and not all in one single commit (2) if you are in the middle of an interactive
rebase and want to split too large commit.
$ git add -i
staged unstaged path
1: unchanged +4/-4 index.js
2: +1/-0 nothing package.json
The top half of this output shows the current state of the index broken up into staged and unstaged
columns:
1. index.js has had 4 lines added and 4 lines removed. It is currently not staged, as the current
status reports "unchanged." When this file becomes staged, the +4/-4 bit will be transferred
to the staged column and the unstaged column will read "nothing."
2. package.json has had one line added and has been staged. There are no further changes
since it has been staged as indicated by the "nothing" line under the unstaged column.
https://riptutorial.com/ 187
The bottom half shows what you can do. Either enter a number (1-8) or a letter (s, u, r, a, p, d, q, h).
status shows output identical to the top part of the output above.
update allows you to make further changes to the staged commits with additional syntax.
add untracked allows you to add filepaths previously untracked by version control.
patch allows for one path to be selected out of an output similar to status for further analysis.
You can see what "hunks" of work would be staged for commit using the patch flag:
git add -p
or
This opens an interactive prompt that allows you to look at the diffs and let you decide whether
you want to include them or not.
This makes it easy to catch changes which you do not want to commit.
https://riptutorial.com/ 188
You can also open this via git add --interactive and selecting p.
https://riptutorial.com/ 189
Chapter 52: Stashing
Syntax
• git stash list [<options>]
• git stash show [<stash>]
• git stash drop [-q|--quiet] [<stash>]
• git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]
• git stash branch <branchname> [<stash>]
• git stash [save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet] [-u|--include-untracked]
[-a|--all] [<message>]]
• git stash clear
• git stash create [<message>]
• git stash store [-m|--message <message>] [-q|--quiet] <commit>
Parameters
Parameter Details
Show the changes recorded in the stash as a diff between the stashed state
show
and its original parent. When no <stash> is given, shows the latest one.
List the stashes that you currently have. Each stash is listed with its name (e.g.
stash@{0} is the latest stash, stash@{1} is the one before, etc.), the name of
list
the branch that was current when the stash was made, and a short description
of the commit the stash was based on.
Remove a single stashed state from the stash list and apply it on top of the
pop
current working tree state.
apply Like pop, but do not remove the state from the stash list.
Remove all the stashed states. Note that those states will then be subject to
clear
pruning, and may be impossible to recover.
Remove a single stashed state from the stash list. When no <stash> is given, it
drop removes the latest one. i.e. stash@{0}, otherwise <stash> must be a valid stash
log reference of the form stash@{<revision>}.
Create a stash (which is a regular commit object) and return its object name,
create without storing it anywhere in the ref namespace. This is intended to be useful
for scripts. It is probably not the command you want to use; see "save" above.
Store a given stash created via git stash create (which is a dangling merge
store commit) in the stash ref, updating the stash reflog. This is intended to be useful
for scripts. It is probably not the command you want to use; see "save" above.
https://riptutorial.com/ 190
Remarks
Stashing allows us to have a clean working directory without losing any information. Then, it's
possible to start working on something different and/or to switch branches.
Examples
What is Stashing?
When working on a project, you might be half-way through a feature branch change when a bug is
raised against master. You're not ready to commit your code, but you also don't want to lose your
changes. This is where git stash comes in handy.
modified: business/com/test/core/actions/Photo.c
no changes added to commit (use "git add" and/or "git commit -a")
If you have added files to your working directory these can be stashed as well. You just need to
stage them first.
NewPhoto.c
nothing added to commit but untracked files present (use "git add" to track)
(master) $ git stage NewPhoto.c
(master) $ git stash
Saved working directory and index state WIP on master:
(master) $ git status
On branch master
nothing to commit, working tree clean
https://riptutorial.com/ 191
(master) $
Your working directory is now clean of any changes you made. You can see this by re-running git
status:
To apply the very last stash, run git stash apply (additionally, you can apply and remove the last
stashed changed with git stash pop):
modified: business/com/test/core/actions/Photo.c
no changes added to commit (use "git add" and/or "git commit -a")
Note, however, that stashing does not remember the branch you were working on. In the above
examples, the user was stashing on master. If they switch to the dev branch, dev, and run git
stash apply the last stash is put on the dev branch.
modified: business/com/test/core/actions/Photo.c
no changes added to commit (use "git add" and/or "git commit -a")
Create stash
Save the current state of working directory and the index (also known as the staging area) in a
stack of stashes.
git stash
To include all untracked files in the stash use the --include-untracked or -u flags.
https://riptutorial.com/ 192
To include a message with your stash to make it more easily identifiable later
To leave the staging area in current state after stash use the --keep-index or -k flags.
This will list all stashes in the stack in reverse chronological order.
You will get a list that looks something like this:
You can refer to specific stash by its name, for example stash@{1}.
Show stash
Or a specific stash
Remove stash
Or a specific stash
https://riptutorial.com/ 193
git stash drop stash@{n}
To apply the last stash and remove it from the stack - type:
Or a specific stash
To get your most recent stash after running git stash, use
Choose a different git stash to restore with the number that shows up for the stash you want
Partial stash
If you would like to stash only some diffs in your working set, you can use a partial stash.
git stash -p
https://riptutorial.com/ 194
And then interactively select which hunks to stash.
As of version 2.13.0 you can also avoid the interactive mode and create a partial stash with a
pathspec using the new push keyword.
You've made a stash and wish to checkout only some of the files in that stash.
Interactive Stashing
Stashing takes the dirty state of your working directory – that is, your modified tracked files and
staged changes – and saves it on a stack of unfinished changes that you can reapply at any time.
Suppose you don't want to stash the staged files and only stash the modified files so you can use:
Stash never saves the untracked files it only stashes the modified and staged files. So suppose if
you need to stash the untracked files too then you can use this:
git stash -u
Suppose you need to stash only some part of code from the file or only some files only from all the
modified and stashed files then you can do it like this:
Git will not stash everything that is modified but will instead prompt you interactively which of the
changes you would like to stash and which you would like to keep in your working directory.
If while working you realize you're on wrong branch and you haven't created any commits yet, you
https://riptutorial.com/ 195
can easily move your work to correct branch using stashing:
git stash
git checkout correct-branch
git stash pop
Remember git stash pop will apply the last stash and delete it from the stash list. To keep the
stash in the list and only apply to some branch you can use:
If you have only just popped it and the terminal is still open, you will still have the hash value
printed by git stash pop on screen:
(Note that git stash drop also produces the same line.)
This will show you all the commits at the tips of your commit graph which are no longer referenced
from any branch or tag – every lost commit, including every stash commit you’ve ever created, will
be somewhere in that graph.
The easiest way to find the stash commit you want is probably to pass that list to gitk:
gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
This will launch a repository browser showing you every single commit in the repository ever,
regardless of whether it is reachable or not.
You can replace gitk there with something like git log --graph --oneline --decorate if you prefer a
nice graph on the console over a separate GUI app.
Once you know the hash of the commit you want, you can apply it as a stash:
Or you can use the context menu in gitk to create branches for any unreachable commits you are
https://riptutorial.com/ 196
interested in. After that, you can do whatever you want with them with all the normal tools. When
you’re done, just blow those branches away again.
https://riptutorial.com/ 197
Chapter 53: Submodules
Examples
Adding a submodule
You can include another Git repository as a folder within your project, tracked by Git:
You should add and commit the new .gitmodules file; this tells Git what submodules should be
cloned when git submodule update is run.
When you clone a repository that uses submodules, you'll need to initialize and update them.
This will clone the referenced submodules and place them in the appropriate folders (including
submodules within submodules). This is equivalent to running git submodule update --init --
recursive immediately after the clone is finished.
Updating a Submodule
A submodule references a specific commit in another repository. To check out the exact state that
is referenced for all submodules, run
Sometimes instead of using the state that is referenced you want to update to your local checkout
to the latest state of that submodule on a remote. To check out all submodules to the latest state
on the remote with a single command, you can use
Note that this will just update your local working copy. Running git status will list the submodule
directory as dirty if it changed because of this command. To update your repository to reference
the new state instead, you have to commit the changes:
https://riptutorial.com/ 198
git commit
There might be some changes you have that can have merge conflict if you use git pull so you
can use git pull --rebase to rewind your changes to top, most of the time it decreases the
chances of conflict. Also it pulls all the branches to local.
A submodule is always checked out at a specific commit SHA1 (the "gitlink", special entry in the
index of the parent repo)
But one can request to update that submodule to the latest commit of a branch of the submodule
remote repo.
Rather than going in each submodule, doing a git checkout abranch --track origin/abranch, git
pull, you can simply do (from the parent repo) a:
Since the SHA1 of the submodule would change, you would still need to follow that with:
git add .
git commit -m "update submodules"
cd /path/to/parent/repo
git config -f .gitmodules submodule.asubmodule.branch abranch
Removing a submodule
1.8
https://riptutorial.com/ 199
$ git submodule deinit the_submodule
$ git rm the_submodule
• git submodule deinit the_submodule deletes the_submodules' entry from .git/config. This
excludes the_submodule from git submodule update, git submodule sync and git submodule
foreach calls and deletes its local content (source). Also, this will not be shown as change in
your parent repository. git submodule init and git submodule update will restore the
submodule, again without commitable changes in your parent repository.
• git rm the_submodule will remove the submodule from the work tree. The files will be gone as
well as the submodules' entry in the .gitmodules file (source). If only git rm the_submodule
(without prior git submodule deinit the_submodule is run, however, the submodules' entry in
your .git/config file will remain.
1.8
Moving a submodule
1.8
Run:
1.8
1. Edit .gitmodules and change the path of the submodule appropriately, and put it in the index
with git add .gitmodules.
2. If needed, create the parent directory of the new location of the submodule (mkdir -p
new/path/to).
3. Move all content from the old to the new directory (mv -vi old/path/to/module
new/path/to/submodule).
https://riptutorial.com/ 200
6. Move the directory .git/modules/old/path/to/module with all its content to .git/modules/
new/path/to/module.
7. Edit the .git/modules/new/path/to/config file, make sure that worktree item points to the new
locations, so in this example it should be worktree = ../../../../../old/path/to/module.
Typically there should be two more .. then directories in the direct path in that place. . Edit
the file new/path/to/module/.git, make sure that the path in it points to the correct new
location inside the main project .git folder, so in this example gitdir: ../../../.git/modules/
new/path/to/module.
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: .gitmodules
# renamed: old/path/to/submodule -> new/path/to/submodule
#
https://riptutorial.com/ 201
Chapter 54: Subtrees
Syntax
• git subtree add -P <prefix> <commit>
• git subtree add -P <prefix> <repository> <ref>
• git subtree pull -P <prefix> <repository> <ref>
• git subtree push -P <prefix> <repository> <ref>
• git subtree merge -P <prefix> <commit>
• git subtree split -P <prefix> [OPTIONS] [<commit>]
Remarks
This is an alternative to using a submodule
Examples
Create, Pull, and Backport Subtree
Create Subtree
Add a new remote called plugin pointing to the plugin's repository:
Then Create a subtree specifying the new folder prefix plugins/demo. plugin is the remote name,
and master refers to the master branch on the subtree's repository:
https://riptutorial.com/ 202
2. Checkout new branch for merging, set to track subtree repository:
3. Cherry-pick backports:
https://riptutorial.com/ 203
Chapter 55: Tidying up your local and remote
repository
Examples
Delete local branches that have been deleted on the remote
git fetch -p
Branches that are no longer being tracked will be in the form below, containing 'gone'
you can then use a combination of the above commands, looking for where 'git branch -vv' returns
'gone' then using '-d' to delete the branches
git fetch -p && git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d
https://riptutorial.com/ 204
Chapter 56: TortoiseGit
Examples
Ignoring Files and Folders
Those that are using TortioseGit UI click Right Mouse on the file (or folder) you want to ignore ->
TortoiseGit -> Delete and add to ignore list, here you can choose to ignore all files of that type or
this specific file -> dialog will pop out Click Ok and you should be done.
Branching
https://riptutorial.com/ 205
For those that are using UI to branch click Right Mouse on repository then Tortoise Git -> Create
Branch...
New window will open -> Give branch a name -> Tick the box Switch to new branch (Chances are
you want to start working with it after branching). -> Click OK and you should be done.
https://riptutorial.com/ 206
Assume unchanged
If a file is changed, but you don't like to commit it, set the file as "Assume unchanged"
https://riptutorial.com/ 207
Revert "Assume unchanged"
Need some steps:
https://riptutorial.com/ 208
Squash commits
https://riptutorial.com/ 209
The advanced way
Start the rebase dialog:
https://riptutorial.com/ 210
Read TortoiseGit online: https://riptutorial.com/git/topic/5150/tortoisegit
https://riptutorial.com/ 211
Chapter 57: Undoing
Examples
Undoing merges
If you haven't yet pushed your merge to the remote repository then you can follow the same
procedure as in undo the commit although there are some subtle differences.
A reset is the simplest option as it will undo both the merge commit and any commits added from
the branch. However, you will need to know what SHA to reset back to, this can be tricky as your
git log will now show commits from both branches. If you reset to the wrong commit (e.g. one on
the other branch) it can destroy committed work.
> git reset --hard <last commit from the branch you are on>
A revert is safer, in that it won't destroy committed work, but involves more work as you have to
revert the revert before you can merge the branch back in again (see the next section).
Afterwards you discover that the feature you just merged in broke the system for other developers,
it must be undone right away, and fixing the feature itself will take too long so you simply want to
undo the merge.
https://riptutorial.com/ 212
At this point the gremlins are out of the system and your fellow developers have stopped yelling at
you. However, we are not finished just yet. Once you fix the problem with the add-gremlins feature
you will need to undo this revert before you can merge back in.
At this point your feature is now successfully added. However, given that bugs of this type are
often introduced by merge conflicts a slightly different workflow is sometimes more helpful as it lets
you fix the merge conflict on your branch.
Using reflog
If you screw up a rebase, one option to start again is to go back to the commit (pre rebase). You
can do this using reflog (which has the history of everything you've done for the last 90 days - this
can be configured):
$ git reflog
4a5cbb3 HEAD@{0}: rebase finished: returning to refs/heads/foo
4a5cbb3 HEAD@{1}: rebase: fixed such and such
904f7f0 HEAD@{2}: rebase: checkout upstream/master
3cbe20a HEAD@{3}: commit: fixed such and such
...
You can see the commit before the rebase was HEAD@{3} (you can also checkout the hash):
https://riptutorial.com/ 213
git checkout HEAD@{3}
Now you create a new branch / delete the old one / try the rebase again.
You can also reset directly back to a point in your reflog, but only do this if you're 100% sure it's
what you want to do:
This will set your current git tree to match how it was at that point (See Undoing Changes).
This can be used if you're temporarily seeing how well a branch works when rebased on another
branch, but you don't want to keep the results.
To jump back to a previous commit, first find the commit's hash using git log.
This places you at commit 789abcd. You can now make new commits on top of this old commit
without affecting the branch your head is on. Any changes can be made into a proper branch
using either branch or checkout -b.
Beware: While you can recover the discarded commits using reflog and reset, uncommitted
changes cannot be recovered. Use git stash; git reset instead of git reset --hard to be safe.
Undoing changes
https://riptutorial.com/ 214
git checkout -- file.txt
Used over all file paths, recursively from the current directory, it will undo all changes in the
working copy.
git checkout -- .
To only undo parts of the changes use --patch. You will be asked, for each change, if it should be
undone or not.
With local commits that you have yet to push to a remote you can also do a soft reset. You can
thus rework the files and then the commits.
The above example would unwind your last two commits and return the files to your working copy.
You could then make further changes and new commits.
Beware: All of these operations, apart from soft resets, will permanently delete your changes. For
a safer option, use git stash -p or git stash, respectively. You can later undo with stash pop or
delete forever with stash drop.
Use git revert to revert existing commits, especially when those commits have been pushed to a
remote repository. It records some new commits to reverse the effect of some earlier commits,
which you can push safely without rewriting history.
Don't use git push --force unless you wish to bring down the opprobrium of all other users of that
repository. Never rewrite public history.
If, for example, you've just pushed up a commit that contains a bug and you need to back it out, do
the following:
Now you are free to revert the revert commit locally, fix your code, and push the good code:
https://riptutorial.com/ 215
git revert HEAD~1
work .. work .. work ..
git add -A .
git commit -m "Update error code"
git push
If the commit you want to revert is already further back in the history, you can simply pass the
commit hash. Git will create a counter-commit undoing your original commit, which you can push
to your remote safely.
Assume you want to undo a dozen of commits and you want only some of them.
-i puts rebase in "interactive mode". It starts off like the rebase discussed above, but before
replaying any commits, it pauses and allows you to gently modify each commit as it's replayed.
rebase -i will open in your default text editor, with a list of commits being applied, like this:
To drop a commit, just delete that line in your editor. If you no longer want the bad commits in your
https://riptutorial.com/ 216
project, you can delete lines 1 and 3-4 above.If you want to combine two commits together, you
can use the squash or fixup commands
https://riptutorial.com/ 217
Chapter 58: Update Object Name in
Reference
Examples
Update Object Name in Reference
Use
Update the object name which is stored in reference
SYNOPSIS
git update-ref [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] [--create-reflog] <ref>
<newvalue> [<oldvalue>] | --stdin [-z])
General Syntax
1. Dereferencing the symbolic refs, update the current branch head to the new object.
2. Stores the newvalue in ref, after verify that the current value of the ref matches oldvalue.
above syntax updates the master branch head to newvalue only if its current value is oldvalue.
Use -d flag to deletes the named <ref> after verifying it still contains <oldvalue>.
Use --create-reflog, update-ref will create a reflog for each ref even if one would not ordinarily be
created.
Use -z flag to specify in NUL-terminated format, which has values like update, create, delete,
verify.
Update
Set <ref> to <newvalue> after verifying <oldvalue>, if given. Specify a zero <newvalue> to ensure the
ref does not exist after the update and/or a zero <oldvalue> to make sure the ref does not exist
before the update.
Create
https://riptutorial.com/ 218
Create <ref> with <newvalue> after verifying it does not exist. The given <newvalue> may not be zero.
Delete
Delete <ref> after verifying it exists with <oldvalue>, if given. If given, <oldvalue> may not be zero.
Verify
Verify <ref> against <oldvalue> but do not change it. If <oldvalue> zero or missing, the ref must not
exist.
https://riptutorial.com/ 219
Chapter 59: Using a .gitattributes file
Examples
Disable Line Ending Normalization
* -text
* text=auto
This will result in all text files (as identified by Git) being committed with LF, but checked out
according to the host operating system default.
• input on Linux/macOS
• true on Windows
Git is pretty good at identifying binary files, but you can explicitly specify which files are binary.
Create a .gitattributes file in the project root containing:
*.png binary
If you are unsure which rules to list in your .gitattributes file, or you just want to add generally
accepted attributes to your project, you can shoose or generate a .gitattributes file at:
• https://gitattributes.io/
• https://github.com/alexkaratarakis/gitattributes
https://riptutorial.com/ 220
Chapter 60: Working with Remotes
Syntax
• git remote [-v | --verbose]
• git remote add [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=<fetch|push>]
<name> <url>
• git remote rename <old> <new>
• git remote remove <name>
• git remote set-head <name> (-a | --auto | -d | --delete | <branch>)
• git remote set-branches [--add] <name> <branch>…
• git remote get-url [--push] [--all] <name>
• git remote set-url [--push] <name> <newurl> [<oldurl>]
• git remote set-url --add [--push] <name> <newurl>
• git remote set-url --delete [--push] <name> <url>
• git remote [-v | --verbose] show [-n] <name>…
• git remote prune [-n | --dry-run] <name>…
• git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)…]
Examples
Adding a New Remote Repository
Adds remote git repository represented by git-repository-url as new remote named upstream to
the git repository
Assuming you set the upstream (as in the "setting an upstream repository")
git pull
The pull with --rebase flag command combines a fetch and a rebase instead of merge.
ls-remote
git ls-remote is one unique command allowing you to query a remote repo without having to
clone/fetch it first.
https://riptutorial.com/ 221
It will list refs/heads and refs/tags of said remote repo.
You will see sometimes refs/tags/v0.1.6 and refs/tags/v0.1.6^{}: the ^{} to list the dereferenced
annotated tag (ie the commit that tag is pointing to)
Since git 2.8 (March 2016), you can avoid that double entry for a tag, and list directly those
dereferenced tags with:
It can also help resolve the actual url used by a remote repo when you have "url.<base>.insteadOf"
config setting.
If git remote --get-url <aremotename> returns https://server.com/user/repo, and you have set git
config url.ssh://[email protected]:.insteadOf https://server.com/:
or
If a remote branch has been deleted, your local repository has to be told to prune the reference to
it.
https://riptutorial.com/ 222
Print just the remote's URL:
With 2.7+, it is also possible to do, which is arguably better than the above one that uses the
config command.
git remote
List all the existing remotes associated with this repository in detail including the fetch and push
URLs:
or simply
git remote -v
Getting Started
Example
git push origin master
After you use git checkout to create a new branch, you will need to set that upstream origin to
push to using
After that, you can use git push while you are on that branch.
https://riptutorial.com/ 223
Changing a Remote Repository
To change the URL of the repository you want your remote to point to, you can use the set-url
option, like so:
Example:
git remote -v
# origin https://github.com/username/repo.git (fetch)
# origin https://github.com/usernam/repo.git (push)
git remote -v
# origin https://github.com/username/repo2.git (fetch)
# origin https://github.com/username/repo2.git (push)
Renaming a Remote
git remote
# origin
git remote -v
# origin https://github.com/username/repo.git (fetch)
https://riptutorial.com/ 224
# origin https://github.com/usernam/repo.git (push)
Rename remote
git remote -v
# destination https://github.com/username/repo.git (fetch)
# destination https://github.com/usernam/repo.git (push)
This error means that the remote you tried the old remote name (origin) doesn't exist.
You can obtain the url for an existing remote by using the command
https://riptutorial.com/ 225
Chapter 61: Worktrees
Syntax
• git worktree add [-f] [--detach] [--checkout] [-b <new-branch>] <path> [<branch>]
• git worktree prune [-n] [-v] [--expire <expire>]
• git worktree list [--porcelain]
Parameters
Parameter Details
With add, create a new branch named <new-branch> starting at <branch>, and
-b <new-branch> check out <new-branch> into the new working tree. If <branch> is omitted, it
-B <new-branch> defaults to HEAD. By default, -b refuses to create a new branch if it already
exists. -B overrides this safeguard, resetting <new-branch> to <branch>.
-n --dry-run With prune, do not remove anything; just report what it would remove.
With list, output in an easy-to-parse format for scripts. This format will
--porcelain
remain stable across Git versions and regardless of user configuration.
--expire <time> With prune, only expire unused working trees older than <time>.
Remarks
See the official documentation for more information: https://git-scm.com/docs/git-worktree.
Examples
Using a worktree
https://riptutorial.com/ 226
You are right in the middle of working on a new feature, and your boss comes in demanding that
you fix something immediately. You may typically want use git stash to store your changes away
temporarily. However, at this point your working tree is in a state of disarray (with new, moved,
and removed files, and other bits and pieces strewn around) and you don't want to disturb your
progress.
By adding a worktree, you create a temporary linked working tree to make the emergency fix,
remove it when done, and then resume your earlier coding session:
NOTE: In this example, the fix still is in the emergency-fix branch. At this point you probably want
to git merge or git format-patch and afterwards remove the emergency-fix branch.
Moving a worktree
Currently (as of version 2.11.0) there is no built-in functionality to move an already existing
worktree. This is listed as an official bug (see https://git-scm.com/docs/git-worktree#_bugs).
To get around this limitation it is possible to perform manual operations directly in the .git
reference files.
In this example, the main copy of the repo is living at /home/user/project-main and the secondary
worktree is located at /home/user/project-1 and we want to move it to /home/user/project-2.
Don't perform any git command in between these steps, otherwise the garbage collector might be
triggered and the references to the secondary tree can be lost. Perform these steps from the start
until the end without interruption:
1. Change the worktree's .git file to point to the new location inside the main tree. The file
/home/user/project-1/.git should now contain the following:
gitdir: /home/user/project-main/.git/worktrees/project-2
2. Rename the worktree inside the .git directory of the main project by moving the worktree's
directory that exists in there:
$ mv /home/user/project-main/.git/worktrees/project-1 /home/user/project-
main/.git/worktrees/project-2
https://riptutorial.com/ 227
/home/user/project-2/.git
$ mv /home/user/project-1 /home/user/project-2
If you have done everything correctly, listing the existing worktrees should refer to the new
location:
https://riptutorial.com/ 228
Credits
S.
Chapters Contributors
No
.mailmap file:
Associating
2 Mario, Michael Plotke
contributor and email
aliases
https://riptutorial.com/ 229
Schneider, Jonathan, Joseph Dasenbrock, jrf, kartik,
KartikKannapur, khanmizan, kirrmann, kisanme, Majid, Martin,
MayeulC, Michael Richardson, Mihai, Mitch Talmadge,
mkasberg, nepda, Noah, Noushad PP, Nowhere man,
olegtaranenko, Ortomala Lokni, Ozair Kafray, PaladiN, ᴀɴᴀʏɪᴛɪs,
Priyanshu Shekhar, Ralf Rafael Frix, Richard Hamilton, Robin,
RudolphEst, Siavas, Simone Carletti, the12, Uwe, Vlad,
wintersolider, Wojciech Kazior, Wolfgang, Yerko Palma, Yury
Fedorov, zygimantus
10 Bundles jwd630
Change git
11 xiaoyaoworm
repository name
16 diff-tree fybw id
https://riptutorial.com/ 230
history graphically
with Gitk
Empty directories in
18 Ates Goral
Git
Git Client-Side
22 Kelum Senanayake, kiamlaluno
Hooks
30 git send-email Aaron Skomra, Dong Thang, fybw id, Jav_Rock, kofemann
https://riptutorial.com/ 231
AesSedai101, AnoE, Christiaan Maks, Confiqure, Eidolon,
35 Hooks
Flows, fracz, kaartic, lostphilosopher, mwarsco
37 Internals nighthawk454
https://riptutorial.com/ 232
Reflog - Restoring
44 commits not shown Braiam, Peter Amidon, Scott Weldon
in git log
Resolving merge Braiam, Dartmouth, David Ben Knoble, Fabio, nus, Vivin
46
conflicts George, Yury Fedorov
47 Rev-List mkasberg
49 Show Zaz
https://riptutorial.com/ 233
Using a .gitattributes
59 Chin Huang, dahlbyk, Toby
file
https://riptutorial.com/ 234