The git config command can be used to change your Git configuration.
The complete configuration is visible using git config -l, and the git-config man page explains the meaning of each option.
Troubleshooting
My name doesn’t show up on GitHub
If the email used in a commit matches a verified GitHub user account, the account’s username is used, instead of the username set by Git.
If you have any local copies of personal repositories you have created or forked, you can find your username in the URL of the remote repository.
New commits aren’t using the right name
If git config user.name reports the correct username for the repository you’re viewing, but your commits are using the wrong name, your environment variables may be overriding your username.
Make sure you have not set the GIT_COMMITTER_NAME or GIT_AUTHOR_NAME variables. You can check their values with the following command:
My old commits still have my old username
Changing your username in Git only affects commits that you make after your change.
To rewrite your old commits, you can use git filter-branch to change the repository history to use your new username.
A Common Git Workflow
This tutorial explains how to import a new project into Git, make changes to it, and share changes with other developers.
By default, the first branch on any git project is called “master”.
Your local repository consists of three “trees” maintained by git. the first one is your Working Directory which holds the actual files. the second one is the Index which acts as a staging area and finally the HEAD which points to the last commit you’ve made.
Importing a new project
Assume you have a tarball project.tar.gz with your initial work. You can place it under Git revision control as follows.
Your changes are now in the HEAD of your local working copy.
If you have not cloned an existing repository and want to connect your repository to a remote server, you need to add it with
To send those changes to your remote repository, execute
If you want to delete a branch from the server (note the colon before the branch name):
Replacing Local Changes
In case you did something wrong, you can replace local changes using the command
If you instead want to drop all your local changes and commits, fetch the latest history from the server and point your local master branch at it like this:
Viewing Project History
Managing Branches
Branches are cheap and easy, so this is a good way to try something out.
As a general rule, you should try to split your changes into small logical steps, and commit each of them. They should be consistent, working independently of any later commits, pass the test suite, etc. This makes the review process much easier, and the history much more useful for later inspection and analysis, for example with git-blame and git-bisect.
Don’t be afraid of making too small or imperfect steps along the way. You can always go back later and edit the commits with git rebase --interactive before you publish them. You can use git stash save --keep-index to run the test suite independent of other uncommitted changes.
In Git you can drop your current work state in to a temporary storage area stack and then re-apply it later. The simple case is as follows:
Committing to the Wrong Branch
Let’s assume you committed to master but should have created a topic branch called experimental instead. To move those changes over, you can create a branch at your current point, rewind head and then checkout your new branch:
This can be more complex if you’ve made the changes on a branch of a branch of a branch etc. Then what you need to do is rebase the change on a branch on to somewhere else:
This is a cool feature, let’s say you’ve made 3 commits but you want to re-order them or edit them (or combine them):
Then you get your editor pop open with some instructions. All you have to do is amend the instructions to pick/squash/edit (or remove them) commits and save/exit. Then after editing you can git rebase — continue to keep stepping through each of your instructions.
If you choose to edit one, it will leave you in the state you were in at the time you committed that, so you need to use git commit — amend to edit it.
Note: DO NOT COMMIT DURING REBASE — only add then use --continue, --skip or --abort.
Storing/Retrieving from the File System
Some projects (the Git project itself for example) store additional files directly in the Git file system without them necessarily being a checked in file.
This can be useful for utility files that developers may need (passwords, gpg keys, etc) but you don’t want to actually check out on to disk every time (particularly in production).
Cleaning Up
If you’ve committed some content to your branch (maybe you’ve imported an old repo from SVN) and you want to remove all occurrences of a file from the history:
If you’ve already pushed to origin, but have committed the rubbish since then, you can also do this for your local system before pushing:
Miscellaneous Tips
tbc
Using Git for Collaboration
Suppose that you’ve started a new project with a Git repository in /home/me/project, and that someone, who has a home directory on the same machine, wants to contribute.
Then, someone makes some changes and commits them:
When he’s ready, he tells you to pull changes from the repository at /home/someone/projectForked. You can do this with:
Note that in general, you would want your local changes committed before initiating this “pull”. If someone’s work conflicts with what you did since your histories forked, you will use your working tree and the index to resolve conflicts, and existing local changes will interfere with the conflict resolution process (Git will still perform the fetch but will refuse to merge — You will have to get rid of your local changes in some way and pull again when this happens).
You can peek at what someone did without merging first
This operation is safe even if you have uncommitted local changes. The range notation “HEAD..FETCH_HEAD” means “show everything that is reachable from the FETCH_HEAD but exclude anything that is reachable from HEAD”. You already knows everything that leads to your current state (HEAD), and reviews what someone has in his state (FETCH_HEAD) that you have not seen with this command.
You can visualize what someone did by issuing the following command:
When you are working in a small closely knit group, it is not unusual to interact with the same repository over and over again. By defining remote repository shorthand, you can make it easier:
Note that git pull always merges into the current branch, regardless of what else is given on the command line.
Later, someone can update his repo with your latest changes using
Note that he doesn’t need to give the path to your repository; when someone cloned your repository, Git stored the location of your repository in the repository configuration, and that location is used for pulls:
Git also keeps a pristine copy of your master branch under the name “origin/master”:
Rule: Topic branches
Make a side branch for every topic (feature, bugfix, …). Fork it off at the oldest integration branch that you will eventually want to merge it into.
Finding Who Dunnit
Often it can be useful to find out who changed a line of code in a file.
Sometimes the change has come from a previous file (if you’ve combined two files, or you’ve moved a function) so you can use:
Sometimes it’s nice to track this down by clicking through changes and going further and further back. There’s a nice in-built gui for this:
Merging Upwards
There are two main tools that can be used to include changes from one branch on another: git-merge and git-cherry-pick.
Merges have many advantages, so we try to solve as many problems as possible with merges alone. Cherry-picking is still occasionally useful.
Most importantly, merging works at the branch level, while cherry-picking works at the commit level. This means that a merge can carry over the changes from 1, 10, or 1000 commits with equal ease, which in turn means the workflow scales much better to a large number of contributors (and contributions). Merges are also easier to understand because a merge commit is a “promise” that all changes from all its parents are now included.
As a given feature goes from experimental to stable, it also “graduates” between the corresponding branches of the software. git.git uses the following integration branches:
maint tracks the commits that should go into the next “maintenance release”, i.e., update of the last released stable version;
master tracks the commits that should go into the next release;
next is intended as a testing branch for topics being tested for stability for master.
There is a fourth official branch that is used slightly differently:
pu (proposed updates) is an integration branch for things that are not quite ready for inclusion yet.
Each of the four branches is usually a direct descendant of the one above it.
Conceptually, the feature enters at an unstable branch (usually next or pu), and “graduates” to master for the next release once it is considered stable enough.
The “downwards graduation” discussed above cannot be done by actually merging downwards, however, since that would merge all changes on the unstable branch into the stable one. Hence the following:
Rule: Merge upwards
Always commit your fixes to the oldest supported branch that require them. Then (periodically) merge the integration branches upwards into each other.
This gives a very controlled flow of fixes. If you notice that you have applied a fix to e.g. master that is also required in maint, you will need to git-cherry-pick it downwards. This will happen a few times and is nothing to worry about unless you do it very frequently.
Merge Workflow
The merge workflow works by copying branches between upstream and downstream. Upstream can merge contributions into the official history; downstream base their work on the official history.
There are three main tools that can be used for this:
1 git push <remote> <branch> copies your branches to a remote repository
2 git fetch <remote> copies remote branches to your repository, staying up to date
3 git pull <url> <branch> merges remote topics (Do the fetch and merge in one)
Note the last point. Do not use git pull unless you actually want to merge the remote branch.
Patch Workflow
1 git format-patch -M upstream..topic to turn them into preformatted patch files
2 git send-email --to=<recipient> <patches>
Exploring history
Every commit usually has one “parent” commit which points to the previous state of the project:
If you intend to share this name with other people (for example, to identify a release version), you should create a “tag” object, and perhaps sign it; see git-tag for details.
In Git there are two types of tag — a lightweight tag and an annotated tag. A lightweight tag is simply a named pointer to a commit. You can always change it to point to another commit. An annotated tag is a name pointer to a tag object, with it’s own message and history. As it has it’s own message it can be GPG signed if required.
Creating the two types of tag is easy (and one command line switch different)
Any Git command that needs to know a commit can take any of these names. For example:
Be careful with that last command: in addition to losing any changes in the working directory, it will also remove all later commits from this branch. If this branch is the only branch containing those commits, they will be lost. Also, don’t use git reset on a publicly-visible branch that other developers pull from, as it will force needless merges on other developers to clean up the history. If you need to undo changes that you have pushed, use git revert instead.
The git grep command can search for strings in any version of your project, so
If you leave out the commit name, git grep will search any of the files it manages in your current directory. So
Many Git commands also take sets of commits, which can be specified in a number of ways. Here are some examples with git log:
The Git Object Database
It turns out that every object in the Git history is stored under a 40-digit hex name. That name is the SHA-1 hash of the object’s contents. The 7 char hex strings here are simply the abbreviation of such 40 character long strings.
We can ask Git about this particular object with the cat-file command.
A tree can refer to one or more “blob” objects, each corresponding to a file. In addition, a tree can also refer to other tree objects, thus creating a directory hierarchy. You can examine the contents of any tree using ls-tree:
So now we know how Git uses the object database to represent a project’s history:
“commit” objects refer to “tree” objects representing the snapshot of a directory tree at a particular point in the history, and refer to “parent” commits to show how they’re connected into the project history.
“tree” objects represent the state of a single directory, associating directory names to “blob” objects containing file data and “tree” objects containing subdirectory information.
“blob” objects contain file data without any other structure.
References to commit objects at the head of each branch are stored in files under .git/refs/heads/.
The name of the current branch is stored in .git/HEAD.
Note, by the way, that lots of commands take a tree as an argument. But as we can see above, a tree can be referred to in many different ways— (1) by the SHA-1 name for that tree, (2) by the name of a commit that refers to the tree, (3) by the name of a branch whose head refers to that tree, etc.–and most such commands can accept any of these names.
The index file
The primary tool we’ve been using to create commits is git-commit -a, which creates a commit including every change you’ve made to your working tree. But what if you want to commit changes only to certain files? Or only certain changes to certain files?
git diff is comparing against the index file, which is stored in .git/index in a binary format, but whose contents we can examine with ls-files.
What git add did was store a new blob and then put a reference to it in the index file. If we modify the file again, we’ll see that the new modifications are reflected in the git diff output:
By default git commit uses the index to create the commit, not the working tree; the “-a” option to commit tells it to first update the index with all changes in the working tree.
Since the current state of close.txt is cached in the index file, it is listed as “Changes to be committed”. Since file.txt has changes in the working directory that aren’t reflected in the index, it is marked “changed but not updated”. At this point, running git commit would create a commit that added close.txt (with its new contents), but that didn’t modify file.txt.
Also, note that a bare git diff shows the changes to file.txt, but not the addition of close.txt, because the version of close.txt in the index file is identical to the one in the working directory.