From Git SCM Wiki
Revision as of 13:28, 8 March 2010 by Dscho (Talk | contribs)

Jump to: navigation, search


See also:

General Questions

What is git ?

Git is a distributed version control system developed by Junio Hamano and Linus Torvalds.

Git does not use a centralized server.

Git runs on Linux, BSD, Solaris, Darwin, Windows, Android and other operating systems.

Why the 'git' name?

Quoting Linus: "I'm an egotistical ***, and I name all my projects after myself. First 'Linux', now 'git'".

('git' is British slang for "pig headed, think they are always correct, argumentative").

Alternatively, in Linus' own words as the inventor of git: "git" can mean anything, depending on your mood:

  • Random three-letter combination that is pronounceable, and not actually used by any common UNIX command. The fact that it is a mispronunciation of "get" may or may not be relevant.
  • Stupid. Contemptible and despicable. Simple. Take your pick from the dictionary of slang.
  • "Global information tracker": you're in a good mood, and it actually works for you. Angels sing, and a light suddenly fills the room.
  • "Goddamn idiotic truckload of sh*t": when it breaks

What's the difference between fetch and pull?

The short definition is:

Fetch: Download (new) objects and a head from another repository.

Pull: Fetch (as defined above), and then merge what was downloaded with the current development.

What can I use to set up a public repository?

A SSH server, an HTTP server, or the git-daemon. Local networks can also use network filesystems, like NFS or SMBFS/CIFS (the Windows networks).

  • While there was some controversy over whether SMBFS was a safe solution the latest info indicates that it should be fine.
  • See the Git tutorial for more details.

Can I add empty directories?

Currently the design of the git index (staging area) only permits files to be listed, and nobody competent enough to make the change to allow empty directories has cared enough about this situation to remedy it.

Directories are added automatically when adding files inside them. That is, directories never have to be added to the repository, and are not tracked on their own.

You can say "git add <dir>" and it will add files in there.

If you really need a directory to exist in checkouts you should create a file in it. .gitignore works well for this purpose (there is also a tool MarkEmptyDirs using the .NET framework which allows to automate this task); you can leave it empty, or fill in the names of files you expect to show up in the directory.

Why does git not "track" renames?

Git has to interoperate with a lot of different workflows, for example some changes can come from patches, where rename information may not be available. Relying on explicit rename tracking makes it impossible to merge two trees that have done exactly the same thing, except one did it as a patch (create/delete) and one did it using some other heuristic.

On a second note, tracking renames is really just a special case of tracking how content moves in the tree. In some cases, you may instead be interested in querying when a function was added or moved to a different file. By only relying on the ability to recreate this information when needed, Git aims to provide a more flexible way to track how your tree is changing.

However, this does not mean that Git has no support for renames. The diff machinery in Git has support for automatically detecting renames, this is turned on by the '-M' switch to the git-diff-* family of commands. The rename detection machinery is used by git-log(1) and git-whatchanged(1), so for example, 'git log -M' will give the commit history with rename information. Git also supports a limited form of merging across renames. The two tools for assigning blame, git-blame(1) and git-annotate(1) both use the automatic rename detection code to track renames.

As a very special case, 'git log' version 1.5.3 and later has '--follow' option that allows you to follow renames when given a single path.

  • Mail by Linus on this topic.

Git has a rename command git mv, but that is just a convenience. The effect is indistinguishable from removing the file and adding another with different name and the same content.

Why is "git log <filename>" slow?

The answer to the question why git log <filename> takes so long to find a small number of commits which changed a given file lies in the fact that Git looks at all the commits to find that.

Git simply does not have per-file history. Not having per-file history is what allows Git to do git log <directory-or-file> rather than being able to track just one file. You can't do it sanely with per-file history (because to tie the per-file histories back together in a logical sequence, you need the global history to sort it again!).

That said, you might well need to just run git gc to make it hugely faster.

Note that git log <file1> <file2> (or gitk <file1> <file2>) is not simply the union of git log <file1> and git log <file2>; it can contain merges which are in neither of the separate histories. Doing the history for two files together is not at all equivalent to doing the history for those files individually and stitching it together.

To speed up git log, give it a range of interesting revisions; you can also try --remove-empty option (with some caveats).

Why is it wrong to export the environment variable CDPATH?

The CDPATH variable is purely for interactive use. A lot of scripts break if a simple "cd" suddenly outputs a text that was directed at you, the user, and not meant for processing by the script. Having said that, we tried hard to avoid problems by unsetting CDPATH everywhere in the Git scripts and in the Makefiles, but it is quite possible that we missed some places.

By contrast, if you just remove the "export" from your .bashrc, you are guaranteed to never get bitten by that breakage again!

How come gitweb suddenly disappeared from the project list at

Because it got merged into git. See the relevant commit.

What is the difference between a merge and a rebase?

Imagine this history:

- A - B - C - D - remote HEAD
      E - F - G - local HEAD

after merge:

- A - B - C - D - remote HEAD
    \                         \
      E - F - G - local HEAD - new local HEAD

after rebase:

- A - B - C - D - remote HEAD - E' - F' - G' - local HEAD'

So, the merge does not rewrite your commits. They will stay the same. A rebase _will_ rewrite them. The advantage is that the history is easier to follow. The disadvantage is that you usually tested more while developing, so that some obscure feature in, say, "G", could work less nicely together with the changes of, say, "B", than you hope for. In other words, G was tested thoroughly, G' was not. As always, it is a trade-off.

Why is "git rm" not the inverse of "git add"?

Don't think of 'rm' as the inverse of 'add'. That would only confuse you.

When git add is used to add changes made to a file already tracked by git, the inverse of 'git add <file>' is 'git reset HEAD -- <file>'.

In the case of adding a new file, a natural inverse of 'add' is 'un-add', and that operation is called 'rm --cached', because we use that to name the option to invoke an "index-only" variant of a command when the command can operate on index and working tree file (e.g. "diff --cached", "apply --cached").

A life of a file that does _not_ make into a commit goes like this:

[1]$ edit a-new-file

This is 'create', not 'add'. git is not involved in this step.

[2]$ git add a-new-file

This is 'add'; place an existing file in the index. When you do not want it in the index, you 'un-add' it.

[3]$ git rm --cached a-new-file

This removes the entry from the index, without touching the working tree file. If you do not want that file at all (as opposed to, "I am making a series of partial commits, and the addition of this path does not belong to the first commit of the series, so I am unstaging"), this is followed by

[4]$ rm -f a-new-file

Again, git is not involved in this step.

People sometimes want to have steps 3 and 4 combined, and it meshes well with the users' expectation when they see the word "rm". Think of "git rm" without "--cached" as a shorthand to do 3 and 4 in one go to meet that expectation.

Obviously, we cannot usefully combine steps 1 and 2. We could have "git add --create a-new-file" launch an editor to create a new file, but that would not be very useful in practice.

The fact that steps 3 and 4 can be naturally combined, but steps 1 and 2 cannot be, makes "add" and "rm" not inverse of each other.


Does git convert between CRLF and LF for different platforms?

Support for this exists in Git versions 1.5 or later. See gitattributes(5).

Does git have keyword expansion?

Not recommended. Keyword expansion causes all sorts of strange problems and isn't really useful anyway, especially within the context of an SCM. Outside git you may perform keyword expansion using a script. The Linux kernel export script does this to set the EXTRA_VERSION variable in the Makefile.

See gitattributes(5) if you really want to do this. If your translation is not reversible (eg SCCS keyword expansion) this may be problematic. (Hint: The supplied $Id$-expansion puts the 40-character hexadecimal blob object name into the id; you can figure out which commits include this blob by using a script like this.)

See here for a discussion, and here on how GIT may help anyway.

Does git allow arbitrary conversion of contents?

Yes. Not just "keyword expansion" and/or "CRLF conversion", the current version of git allows you to specify filters to munge contents immediately before checking things in. See gitattributes(5) man pages for details.

Does git convert encodings of file names?

No. Filenames are treated as byte sequences.

Does git convert encodings of comments and committer names or file content?

A git repository can store a flag to register the encoding supposedly used for comments (including author names). File content is not converted unless you are inclined to shoot yourself in the foot and use the filtering mechanism described above.

Does git track all file data and metadata?

No. Git has a specific notion of tracked "content", which is basically just the file data. It is thus not directly suitable for tracking directories where additional filesystem information is significant, such as "/etc" or home directories. See ContentLimitations for more details.

Unexpected behavior

Why won't I see changes in the remote repo after "git push"?

The push operation is always about propagating the repository history and updating the refs, and never touches the working tree files. In particular, if you push to update the branch that is checked out in a remote repository the files in the work tree will not be updated.

This is a precautionary design decision. The remote repository's work tree may have local changes, and there is no way for you, who are pushing into the remote repository, to resolve conflicts between the changes you are pushing and the ones in the work tree. However, you can easily make a post-update hook to update the working copy of the checked out branch. The reason for not making this a default example hook is that they only notify the person doing the pushing if there was a problem. The latest draft post-update hook for this is at, which deals with almost all cases, apart from where there is already a conflicted merge on the remote side (as git-stash cannot currently stash this). It also fails to work in instances where it could, such as none of the files are actually conflicting.

A quick rule of thumb is to never push into a repository that has a work tree attached to it, until you know what you are doing.

If you are sure what you are doing, you can do a "git reset --hard" on the side you pushed to. Note that this WILL lose ALL changes you made on that side, resetting the working tree to the newest revision you pushed. See this article about bare repositories for details.

See also the entry (How would I use "git push" to sync out of a firewalled host?) in this FAQ for the proper way to work with push with a repository with a work tree.

Why is git --version not reporting the "full" version number?

There is a bit of a chicken and egg problem involved. The build procedure wants to have an already installed git to figure out the "full" version number. If you are bootstrapping, make clean and rebuild after you install git once would give you a git binary that knows what version it is.

GIT-VERSION-GEN script show current (used) git version, git --version shows git version used at the time git was build.

Why is "git reset --hard" not removing some files?

git reset --hard doesn't remove the files which are in the current version of .gitignore. "git reset" won't delete files it doesn't track (particularly when it has been _told_ to ignore them).

If the version you switched to has an earlier (different) version of the .gitignore file then the files which were not deleted might be not ignored in the reset version, and will for example show in the git status output.

Why is my push rejected with a non-fast forward error?

If you try to push a branch, you might get this error message:

! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to ''

This means that your branch is not a strict superset of the remote side. That is, the remote side has commits that your side does not have. If you would push, the other side would lose changes. The most likely reason for this is that you need to pull from the remote first. You can see what changes the remote side has by fetching first and then checking the log. For example,

	git fetch origin
	git log master..origin/master

will list all the changes the remote side has that your side doesn't. If you want a graphical representation, use gitk --left-right master...origin/master. The arrows to the left are changes you want to push, the arrows to the right are changes on the remote side.

If you have rebased your branch and try to push that, see the next question.

If you think you know what you are doing, you can also try:

	git push origin +branchname

This will force the update. If you don't have permission, then sometimes this will work:

	git push origin :branchname
	git push origin +branchname

ie, delete the branch remotely first (this is often permitted), then re-push the "new" (or perhaps rewound) branch.

Be warned that if you rewind branches, others might get into problem when pulling. There is the chance that they will merge in the branch that they fetched with the new one that you've published, effectively keeping the changes that you are trying to get rid of. However, it will only be their copies that have the bad revisions. For this reason, rewinding branches is considered mildly antisocial. Nonetheless, it is often appropriate.

Why won't "git push" work after I rebased a branch?

After you have rebased one of your local branches, you are trying to push your changes to a remote repository. But git push fails with this error message:

error: remote 'refs/heads/master' is not a strict subset of local ref 'refs/heads/master'. maybe you are not up-to-date and need to pull first?

This is not a bug, but a safety check: "git push" will not update a remote branch if the remote branch is not a parent of the commit you're trying to push. This check prevents you from overwriting a remote branch to which other people have already commited new changes after you fetched it the last time. Their changes would be lost without the check. And it prevents you from overwriting a remote branch with an unrelated local branch.

When you rebase, you are not continuing the history of the branch from where you currently are. Instead, you are rewriting the history starting from the base you chose for rebasing. So, after rebasing, the remote branch and your new local HEAD are both child commits of that base, but the remote branch is no longer a parent of your new local HEAD. And pushing this new history to the remote branch means replacing a history that other people might already have downloaded.

If you are really sure that you want to push the new reference to the remote repository you can say git push -f. But use this with care and only if you know what you are doing.

Why is "git commit -a" not the default?

Most other version control systems will do a full-tree commit, using the content of files at commit time, by default.

Git does it differently. By default, git commits the content of the index, and only this. git commit -a gives roughly the equivalent of what other systems do. Indeed, there are many concrete reasons why git's way to manage the index is good (and leads to unique features of git):

  • You can select files to commit with a fine granularity, telling git what you want to do little by little (git add file to add the full content of the file to the index, git add -i or git gui to add the content hunk-by-hunk, or even use the hunk splitting feature of git add -i).
  • This fine-grained file selection can help you to keep an uncommited modification in your tree for a reasonably long time. For example, you can increment the version number in the Makefile some time before a release, and use this as a reminder.
  • You can perform several small steps for one commit, checking what you did with git diff, and validating each small step with git add or git add -u. Typically, you can apply a broken patch, updating the index, with git apply --index, and then fix the patch. git diff --cached will show you your fixes, while git diff HEAD will show you the combined diff.
  • This allows excellent management of merge conflicts: git diff --base, git diff --ours, git diff --theirs.
  • This allows git commit --amend to amend only the log message if the index hasn't been modified in the meantime.

So, while using git commit -a is perfectly fine with the simple cycle "edit/review/commit", making it the default would make other workflows less natural.

Indeed, according to Linus, the real reason is more philosophical: git is a content tracker, and a file name has no meaning unless associated to its content. Therefore, the only sane behavior for git add filename is to add the content of the file as well as its name to the index.

See also (mailing list posts):

My HTTP repository has updates, which git clone misses. What happened?

If you push via SSH to the repository, you have to enable the post-update hook (chmod a+x hooks/post-update). If you "push" with rsync, you have to make sure to execute "git update-server-info" _before_ pushing. HTTP is a "dumb" transport, which needs some help. This help is provided in the form of the file info/refs, which contains the current refs (names + commit names of the tips).

Why isn't Git preserving modification time on files?

Modification time on files is a feature that affects build tools. Most build tools compare the timestamp of the source(s) with the timestamp of the derived file(s). If the source is newer, then a rebuild takes place, otherwise nothing happens. This speeds up the build process a lot.

Now consider what would happen if you check out another branch, and modification times were preserved. We assume you already have a fully-built project. If a source file on that other branch has a timestamp that is older than that of the corresponding derived file, the derived file will not be built even if it is different, because the build system only compares modification times. At best, you'll get some kind of weird secondary error; but most likely everything will look fine at first, but you will not get the same result as you would have with a clean build. That situation is unhealthy since you really do not know what code you are executing and the source of the problem is hard to find. You will end up always having to make a clean build when switching branches to make sure you are using the correct source. (Git bisect is another git procedure that checks out old and new revisions where you need a reliable rebuild.)

Git sets the current time as the timestamp on every file it modifies, but only those. The other files are left untouched, which means build tools will be able to depend on modification time and rebuild properly. If build rules change, that can cause a failure anyway, but that is a far less common problem than accidentally not rebuilding.

Why does git use a pager for commands like diff/log and --help?

Usually, you are not interested in the whole log, but only some bits at the beginning. It would not be useful for "git log" to simply let the output whiz by, leaving you looking at the uninteresting parts at the end. And if it did it the other way round, showing you the interesting bits last, it would waste a lot of time showing information that you are not interested in at all. So the only thing that makes sense is to look at the log in a pager. It also helps searching for keywords.

Note that "--help" just spawns "man", so it is not Git's fault there. But you can use git help -w xxx to use a browser instead of "man" if the HTML documentation is installed. See the git help documentation for more information about this.

If you do not like the pager default, you can set core.pager = cat with git config or tell your shell about GIT_PAGER=cat.

Why does diff/log not show color, even though I enabled it?

Set core.pager = less -FXRS with git config to fix this. The most likely culprit is the LESS environment variable. By default, git passes the options -FXRS to less. The -R option tells less to interpret color escape sequences. If LESS is set, however, only those options are used by less.

Why does git diff sometimes list a file that has no changes?

git diff and other git operations is optimized so it does not even look at files whose status (size, modification time etc) on disk and in git's index are different. This makes git diff extremely fast for small changes. If the file has been touched somehow, git diff has to look at the content of and compare it which is a much slower operation even when there is in fact no change. git diff lists the files as a reminder that it is not used optimally. Running git status will not only show status, but will also update the index with status for unchanged files disk making subsequent operations, not only diff, much faster. A typical case that causes many files to be listed by diff is running mass editing commands like perl -pi -e '...'.

What does the gitk error message "Can't parse git log output:" mean?

This is usually caused by color.diff being set to true in your config. git log outputs log entries in colors when color.diff = true. And gitk can only parse plain output.

It is recommended (as of 1.5.3) that color.diff be kept off. Use git log --color if you need colored output.

This problem should be fixed since version 1.5.4.

Why does gitk on Cygwin display "git 1316 tty_list::allocate: No tty allocated"?

This appears to be an issue with your Cygwin configuration. Make sure your CYGWIN environment variable doesn't contain 'tty'.

Why does git clone, git pull, etc. fail when run on a partition mounted with sshfs (FUSE)?

When running git clone and friends on a partition mounted with sshfs the following error can be triggered:

$ git clone foo
Cannot commit config file!
Cannot commit config file!
Cannot commit config file!
Initialized empty Git repository in foo/.git/
294698 blocks
Cannot commit config file!
fatal: Not a valid object name HEAD

To solve this you need 1) remount your sshfs mounted partition with the -o workaround=rename option, e.g.:

sshfs -o workaround=rename login@machine:foo bar

and 2) use at least the version of git.

Why does "git bisect" make me test versions outside the "good-bad" range?

The reason may be that some commits have been developed starting from a version before the "good" commit, and then merged after the "good" commit.

See for more explanations from Linus.

Why am I "not on any branch"?

You are on a detached HEAD and might lose commits. See for an excellent discussion of the topic.

"git log -S" does not show all commits

The behavior of git log -Ssearchstring is not to compute the diff for each commit and to search for searchstring in it, but to show the commits where the number of occurences of searchstring have changed (which is much faster than grepping the diff).

If you want to see all the commits for which searchstring appear in the diff, you can get close to the behavior you expect with a bit of scripting like:

git log -p -z | perl -ln0e 'print if /[+-].*searchedstring/'

How do I ...

How do I specify what ssh key git should use?

This is not really a git question. However, you can edit your ~/.ssh/config file in order to tell ssh what key to use. More information about this is in the ssh config manpage. The short version is that you can specify a custom Host with its own IdentityFile, like this:

Host GitServer

Then, you can set up git to use "GitServer" as the hostname. It will look up the entry and use the specified key and host.

How do I untrack a file?

If you want to keep a file, but not have it in the next revision, do this:

git rm --cached <filename>

How do I access other branches in a repository?

When a repository is cloned, the clone gets a remote tracking branch for each of the original repository's branch heads, but only a single local branch head is created, usually this will be "master". You can get a list of all remote tracking branches with git branch -r.

Vienna:git pieter$ git branch -r

These remote tracking branches represent the branch heads of the remote repository as of the time you last fetched from the remote. You can use them almost like local branch heads, for example with git log origin/maint, but there's an important exception: git checkout. Trying to checkout a remote tracking branch will leave you with a [[[#detached|detached HEAD]]]. So if you want to work on some of these branches, you should create a local branch head for your work and check that out:

Vienna:git pieter$ git checkout -b maint origin/maint
Branch maint set up to track remote branch refs/remotes/origin/maint.
Switched to a new branch "maint"
Vienna:git pieter$

This will create and checkout a branch head called "maint" that starts at the same commit that the remote tracking branch "origin/maint" currently references.

How do I share a git public repository and use it in a CVS way?

You can use git --bare init --shared=group (or git --bare init --shared=all for unprivileged gitweb) to initialize a shared repository. All users belonging to your group now have permissions to push their changes to the repository. It's O.K. that refs aren't group writable, it's enough that the directory is.

  • See Git's cvs-migration doc, "Emulating the CVS Development Model" section for details.

How do I share a git repository using POSIX ACLs?

You can use setfacl to give permission to individual users on a repository. Suppose your login is alice, and you want to give permission to charlie and bob. Giving the permissions is done by:

setfacl -Rm u:bob:rwx '/home/alice/path/to/repo'
setfacl -Rm u:charlie:rwx '/home/alice/path/to/repo'

Now, we have to set the default ACL, so than new files be created with the same permissions:

setfacl -Rm d:u:bob:rwx '/home/alice/path/to/repo'
setfacl -Rm d:u:charlie:rwx '/home/alice/path/to/repo'
setfacl -Rm d:u:alice:rwx '/home/alice/path/to/repo'

If needed, we also give the permission to traverse the filesystem up to the repository:

setfacl -m u:bob:x '/home/alice/path/to'
setfacl -m u:charlie:x '/home/alice/path/to'
setfacl -m u:bob:x '/home/alice/path'
setfacl -m u:charlie:x '/home/alice/path'
setfacl -m u:bob:x '/home/alice'
setfacl -m u:charlie:x '/home/alice'

Git version <= 1.7.0 will break your ACL mask and create unreadable pack files if you have a umask restricting group access (e.g. umask 077). One can work around this problem by making the repository shared:

git config core.sharedRepository group

How can I add a diff of the commit into the commit message window?

Just call git commit with -v flag:

git commit -v

How would I use "git push" to sync out of a host that I cannot pull from?

When you work on two machines, each with its own work tree, a typical way to synchronise between them is to run git pull from each other. However, you may be able to make a TCP connection only in one direction but not in the other direction in certain situations (e.g. you have a firewall between them, one machine is not running an ssh server, or one machine has intermittent connectivity). Suppose you start a project on machine A (mothership), and clone from there to a machine B (satellite). You work on B and would want to slurp the change back to your repository on machine A. Even if you wanted to, you cannot run git fetch on machine A to fetch from B, as B does not allow incoming connections. What should you do in such a case?

You can realize that a push is a mirror operation of a fetch and take advantage of it. If B were not firewalled, you would instead run fetch on A from B. And such a fetch is arranged to fetch 'master' from B and store that in 'refs/remotes/B/master' in A.

Pushing 'master' branch on B to 'master' branch on A, however, is never what you would want to do in such a case. Push is a reverse of fetch in the sense that it propagates the objects and update the branch tips, but does not touch the working tree in the target repository, and you (and git) will be utterly confused when you go back to machine A after you update 'master' that way, as the contents of 'master' have changed, but your working tree still reflects an older state.

So the simple solution to work around such a firewalled setup is to push 'master' from B into 'refs/remotes/B/master' of A, like this:

machineB$ git push machineA:repo.git master:refs/remotes/B/master

When you go back to machineA to work further, it is as if you did a git fetch from machineB, like this:

machineA$ git fetch machineB:repo.git master:refs/remotes/B/master

When you are ready to integrate the changes you did on machineB into the master branch on machineA, you can:

machineA$ git merge B/master ;# shorthand for refs/remotes/B/master

This is no different from the case where you actually pulled from B on A. You can set up your .git/config file to largely automate the above git push, so that you can just say:

machineB$ git push

See also

How do I check out the tree at a particular tag?

So you cloned that shiny repository and now would like to get the working tree to the state as of some tag? Use git tag -l to list all available tags, then just do a git checkout TAGNAME. If you want to build some work on it, use git checkout -b newbranch TAGNAME instead. If you want to return to your latest revision later, do git checkout ORIGINALBRANCH (usually it is master, you can list them with git branch).

How to share objects between existing repositories?


echo "/source/git/project/.git/objects/" > .git/objects/info/alternates

and then follow it up with

git repack -a -d -l

where the '-l' means that it will only put local objects in the pack-file (strictly speaking, it will put any loose objects from the alternate tree too, so you'll have a fully packed archive, but it won't duplicate objects that are already packed in the alternate tree).

How to stop sharing objects between repositories?

There doesn't seem to be a built-in way to do this, but you can do it manually by copying over the unique remote objects and then removing the alternate repository pointer:

(cd /path/to/alternate/repo.git/objects && tar cp .) | (cd .git/objects && tar xvpk)
# some objects will already exist and be skipped, leading to an error on exit, which is fine
rm .git/objects/info/alternates
# or if there's more than one and you're only removing one, edit the alternates file and remove only that pointer

How do I tell git to ignore files?

You can put shell-style globs (e.g. *.o) in either .git/info/exclude or .gitignore.

.git/info/exclude is local to your repository only, and not shared by others who might fetch from your repository.

.gitignore is more commonly used, as it can be checked into the repository and thereby automatically shared with all users of the project.

  • See the
git-ls-files(1) man page, section "Exclude Patterns" for details.

How do I save some local modifications?

Sometimes it is necessary to put some local changes aside, and come back to them later (typically, when one hits an easily-fixable bug in the middle of non-trivial work, and wants to fix the bug before anything else).

With recent versions of git, you can use "git stash" to save temporary modifications and come back to a "clean" tree, and then "git stash apply" to re-apply it.


One can use a temporary branch, to merge later:

$ git checkout -b tempBranch
$ git commit -a -m "to test"

where tempBranch is the unique (original) throwaway branch name.

Another solution is to save changes in a patch, to apply later:

$ git diff --binary HEAD > tempPatch.diff
$ git reset --hard

(warning: git reset --hard removes changes to the working tree!)

How to manually resolve conflicts when Git failed to detect rename?

What to do when you renamed a bunch of files, the merge is having a hard time autoresolving, and you have a couple of conflicts? Suppose the project originally had util/endian.h, and during the course of your development you moved it to src/util/endian.h. Your friend kept working on util/endian.h and it is time to merge the two branches. Sometimes recursive merge strategy (the default) detects this situation, and merge the changes your friend made to util/endian.h to src/util/endian.h without problems (you may still have to resolve the conflict in the contents of the file). But when git thinks you removed util/endian.h and created an unrelated src/util/endian.h file, you will see merge conflicts "your side removed, other side modified" on util/endian.h.

First, check which files have conflicts to resolve using git ls-files --unmerged. Then you can see the blob object names for each merge stage; stage1 is from the common ancestor and stage3 is from your friend's branch. When this type of conflict happens, you don't have stage2 for src/util/endian.h, because that path is "only your side created, other side did nothing" case, and (incorrectly) cleanly resolved:

$ git ls-files --unmerged --abbrev
100755 33cd1f76... 1 util/endian.h
100755 7f531bb7... 3 util/endian.h

Then to do merge between the versions for the "undetected rename" file, extract two blobs (whose sha1 you have from git-ls-files(1) or git-status(1) output) to temporary files, and run "merge" command by hand, e.g.

$ git cat-file blob 33cd1f76 >endian.h-1
$ git cat-file blob 7f531bb7 >endian.h-3
$ merge src/util/endian.h endian.h-1 endian.h-3

(that is merge yours, original and his). Of course instead of merge from RCS you can use your favorite 3-way file merge program, e.g. Ediff3 from Emacs (see also MergingWithEmacs at Mercurial wiki), vimdiff/gvimdiff, Meld, xxdiff or KDiff3. In newer versions of Git you could use ":<stage>:<filename>" instead of SHA1 to extract files to temporary files (:1:util/endian.h and :3:util/endian.h, respectively); check RevisionSpecification and references therein.

Once you come up with the desired state in your file (src/util/endian.h in our example), then you have to inform Git that file was renamed, i.e. say "git update-index --remove util/endian.h" in our example (removing the file from working directory as well, if it exist there) and then "git update-index src/util/endian.h" (you should have it already in the index, so you do not have to say --add).

How to revert file to version from current commit?

If you messed up a file, or removed it accidentally, and want to revert file change to version at current commit, you can use:

git checkout HEAD -- <file>

If you want to revert to version in index (i.e. the last version you ran git add on), use

git checkout -- <file>

How to view an old revision of a file or directory?

Use command "git show" with a colon and filename:

git show <commit>:path/file

The <commit> can be commit id, branch name, tag, relative pointer like HEAD~2 etc. If you don't give any path or file (i.e. just <commit>:), git will display the file listing of repository's root directory. Examples:

git show v1.4.3:git.c
git show f5f75c652b9c2347522159a87297820103e593e4:git.c
git show HEAD~2:git.c
git show master~4:
git show master~4:doc/
git show master~4:doc/ChangeLog

How do I make a diff between two arbitrary files in different revisions?

With command "git diff" you can refer to a commit and file pair:

git diff <commit1>:path/file <commit2>:otherpath/otherfile

As usual, commits can be commit ids, branch names, tags or relative references like HEAD~2. For example:

git diff 06de3718c389fd5038697151c49519f6e9f2dbe0:ChangeLog HEAD~2:ChangeLog.old

How to fix a broken repository?

As Linus said (on gmane):

"Generally, the best way to fix things is (I've written this up at somewhat more length before, but I'm too lazy to find it):

  • back up all your state so that anything you do is re-doable if you corrupt things more!
  • explode any corrupt pack-files
    • See "man git-unpack-objects", and in particular the "-r" flag. Also, please realize that it only unpacks objects that aren't already available, so you need to move the pack-file away from its normal location first (otherwise git-unpack-objects will find all objects that are in the pack-file in the pack-file itself, and not unpack anything at all)
  • replace any broken and/or missing objects
    • This is the challenging part. Sometimes (hopefully often!) you can find the missing objects in other copies of the repositories. At other times, you may need to try to find the data some other way (for example, maybe your checked-out copy contains the file content that when hashed will be the missing object?).
  • make sure everything is happy with "git fsck --full"
  • repack everything to get back to an efficient state again.

And remember: git does _not_ make backups pointless. It hopefully makes backups *easy* (since cloning and pulling is easy), but the basic need for backups does not go away!"

In another thread (on gmane) Linus explained how to find and fix a corrupt object:

"First off, move the corrupt object away, and *save* it. The most common cause of corruption so far has been memory corruption, but even so, there are people who would be interested in seeing the corruption - but it's basically impossible to judge the corruption until we can also see the original object, so right now the corrupt object is useless, but it's very interesting for the future, in the hope that you can re-create a non-corrupt version.


$ mv .git/objects/4b/9458b3786228369c63936db65827de3cc06200 ../

This is the right thing to do, although it's usually best to save it under it's full SHA1 name (you just dropped the "4b" from the result ;).

Let's see what that tells us:

$ git fsck --full
> broken link from    tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
>              to    blob 4b9458b3786228369c63936db65827de3cc06200
> missing blob 4b9458b3786228369c63936db65827de3cc06200

Ok, I removed the "dangling commit" messages, because they are just messages about the fact that you probably have rebased etc, so they're not at all interesting. But what remains is still very useful. In particular, we now know which tree points to it!

Now you can do

   git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8

which will show something like

   100644 blob 8d14531846b95bfa3564b58ccfb7913a034323b8    .gitignore
   100644 blob ebf9bf84da0aab5ed944264a5db2a65fe3a3e883    .mailmap
   100644 blob ca442d313d86dc67e0a2e5d584b465bd382cbf5c    COPYING
   100644 blob ee909f2cc49e54f0799a4739d24c4cb9151ae453    CREDITS
   040000 tree 0f5f709c17ad89e72bdbbef6ea221c69807009f6    Documentation
   100644 blob 1570d248ad9237e4fa6e4d079336b9da62d9ba32    Kbuild
   100644 blob 1c7c229a092665b11cd46a25dbd40feeb31661d9    MAINTAINERS

and you should now have a line that looks like

   10064 blob 4b9458b3786228369c63936db65827de3cc06200     my-magic-file

in the output. This already tells you a *lot* it tells you what file the corrupt blob came from!

Now, it doesn't tell you quite enough, though: it doesn't tell what *version* of the file didn't get correctly written! You might be really lucky, and it may be the version that you already have checked out in your working tree, in which case fixing this problem is really simple, just do

   git hash-object -w my-magic-file

again, and if it outputs the missing SHA1 (4b945..) you're now all done!

But that's the really lucky case, so let's assume that it was some older version that was broken. How do you tell which version it was?

The easiest way to do it is to do

   git log --raw --all --full-history -- subdirectory/my-magic-file

and that will show you the whole log for that file (please realize that the tree you had may not be the top-level tree, so you need to figure out which subdirectory it was in on your own), and because you're asking for raw output, you'll now get something like

   commit abc

   :100644 100644 4b9458b... newsha... M  somedirectory/my-magic-file

   commit xyz

   :100644 100644 oldsha... 4b9458b... M   somedirectory/my-magic-file

and this actually tells you what the *previous* and *subsequent* versions of that file were! So now you can look at those ("oldsha" and "newsha" respectively), and hopefully you have done commits often, and can re-create the missing my-magic-file version by looking at those older and newer versions!

If you can do that, you can now recreate the missing object with

   git hash-object -w <recreated-file>

and your repository is good again!

(Btw, you could have ignored the fsck, and started with doing a

   git log --raw --all

and just looked for the sha of the missing object (4b9458b..) in that whole thing. It's up to you - git does *have* a lot of information, it is just missing one particular blob version.

Trying to recreate trees and especially commits is *much* harder. So you were lucky that it's a blob. It's quite possible that you can recreate the thing."

How to set up a git server?

Look for "Repository Administration" in the everyday git document.

To setup a git server over http, see the relevant document.

As well, it's worth mentioning gitosis is an excellent tool for setting up secure git servers.

How to create the first project?

See the Git tutorial.

How do I publish my repo via SFTP?

At the moment, git is not able to use a (dumb) sftp protocol for pushing. There is a work around, though: Use sshfs. But make sure that you execute 'git update-server-info' in the pushed repository!

Alternatively, you can use whatever means to mirror your .git/ directory to the server (rsync, scp -r, ...). But make sure that 'git update-server-info' was run in that repository _before_ mirroring!

How do I do a quick clone without history revisions?

If you just want to checkout the latest source code of a project which may have a very large repo, you can use

    git clone --depth 1 your_repo_url

How do I use git for large projects, where the repository is large, say approaching 1 TB, but a checkout is only a few hundred MB? Will every developer need 1 TB of local disk space?

In general, git is not a viable solution for the the case of a large repository with relatively small individual checkouts. However, if developers do not intend to clone, fetch, push into or push from their repositories, then use shallow clones

    git clone --depth 1 <url>

How do I obtain a list of files which have changed in a given commit?

    git diff --name-only <commit>^!

or (to get also the commit message):

    git show --name-only <commit>

How do I remove all the old objects after using filter-branch?

Note: It is recommended you backup your repository before using git filter-branch.

First, remove the backup references filter-branch created in refs/original:

    git for-each-ref --format='%(refname)' refs/original | \
        while read ref
            git update-ref -d "$ref"

Then clean your reflogs:

    git reflog expire --expire=0 --all

And finally, repack and drop all the old unreachable objects:

    git repack -ad
    git prune # For objects that repack -ad might have left around

How do I mirror a SVN repository to git?

Initialize bare repo:

    mkdir project.git
    cd project.git
    git init --bare
    cd ..

Initialize "fetch"-repo:

    git svn clone -s svn://.../project
    git remote add bare /path/to/project.git
    git config --unset remote.bare.fetch
    git config remote.bare.push 'refs/remotes/*:refs/heads/*'
    git push bare

Update "fetch" repo:

    cd project
    git svn fetch

Update the "bare" repo by pushing to it:

    cd project
    git push bare

To clone the mirror repository use

    git clone git://$your_repo

To enable usage of git svn in the clone use

    git svn init -s --prefix=origin/ svn://.../project

How do I edit the root commit?

git rebase -i allows you to conveniently edit any previous commits, except for the root commit. The following commands show you how to do this manually.

    # tag the old root
    git tag root `git rev-list HEAD | tail -1`
    git checkout -b new-root root
    # edit...
    git commit --amend

    # check out the previous branch
    git checkout @{-1}
    # replace old root with amended version
    git rebase --onto new-root root

    # cleanup
    git branch -d new-root
    git tag -d root

How do I clone a subdirectory?

Currently, you cannot. There are plans for narrow and sparse clone support.

In the meantime, you can use the subdirectory-filter of git filter-branch to extract a subdirectory. You can also merge changes back using the subtree merge strategy. Or you can use submodules.

It is possible, however, to download subdirectories or even individual files if the server enables the upload-archive service. The following example retrieves the source code for the main git executable of version 1.6.0.

    git archive --remote=git:// v1.6.0 git.c > git.c.tar

Use git ls-remote to list available versions.

How do I make existing non-bare repository bare?

After making sure that there are no uncommitted changes, etc.:

    $ mv repo/.git repo.git
    $ git --git-dir=repo.git config core.bare true
    $ rm -rf repo

The problem with the above process is that it doesn't take into account future internal changes of Git. A safer method is to let Git handle all the internal settings for you by doing something like this.

   * ssh to remote server
   * git clone --bare -l <path_to_repos> <new_dir>
   * renamed old repository directory
   * renamed new repository dir to what old repository used to be.

How do I find large files?

Save the following script to git-find-large in a directory listed in $PATH. The command git find-large will then list 10 paths corresponding to the largest blobs in your repository. Note that only one path is listed per blob, even if the blob has copies or different names in history.

# From

usage() {
        echo "usage: `basename $0` [<limit>]"
        exit 1

if test $# -gt 1
elif test $# -eq 1

git rev-list --all --objects |
        sed -n $(git rev-list --objects --all |
                cut -f1 -d' ' | git cat-file --batch-check | grep blob |
                sort -n -k3 | tail -n$limit | while read hash type size;
                        echo -n "-e s/$hash/$size/p ";
                done) |
        sort -n -k1

Error diagnostic

Git commit is dying telling me "fatal: empty ident <user@myhost> not allowed", what's wrong?

Make sure your Full Name is not empty in chsh or the 5th field of your user line in /etc/passwd isn't empty. You can also set the GIT_AUTHOR_NAME environment variable. If your @myhost is empty make sure your hostname is correctly set. Use git var -l to make git display user identity variables.

Why won't git let me change to a different branch?

Using git checkout <branch> or git checkout -b <branch> it just says:

fatal: Entry 'foo.c' not uptodate. Cannot merge.

You have changes to files in your working directory that will be overwritten, removed or otherwise lost if the checkout and change to the new branch were to proceed. To fix this you may either check your changes in, create a patch of your changes and revert your files, or use the -m flag like this:

$ git checkout -m -b my-branch

refs/heads/pu: does not fast forward to branch 'pu'

The "pu" branch often won't fast forward because some commits have been completely deleted in it since the last time you pulled.

If you want to track it, add a plus (+) sign to the proper line in your .git/config file, like this:

[remote "origin"]
        fetch = +refs/heads/pu:refs/remotes/origin/pu

Which tells git to deal with the problem for you by simply skip the fast forward check (overwriting your old ref with the new one). Or you can just delete that line completely if you don't want to track the pu branch at all.

It is conceivable that in future versions of git we might want to be able to mark some branches "this is expected to be rewound" explicitly and make the clone operation to take notice, to give you the plus sign automatically.

protocol error: bad line length character

If you see the following errors:

fatal: protocol error: bad line length character
error: failed to push to ''
fatal: The remote end hung up unexpectedly

It likely means you have some extraneous characters, info message or something upon logging into ssh in command mode.

To test this, do:

ssh echo testing commands

You should only see testing commands returned. If there are any other characters, you should examine your dot shell rc file to find any echo or other commands that may produce output.

"unable to chdir or not a git archive" while pushing

If you see the following errors:

fatal: '': unable to chdir or not a git archive
fatal: The remote end hung up unexpectedly
error: failed to push to ''

The most likely cause of this error is that you have incorrectly specified the path in the git url.

See the git-push(1) man page for more info on valid git urls.

"needs update" and "not uptodate"

foo: needs update
fatal: Entry 'frotz' not uptodate. Cannot merge.

TO DO: Explain first of those messages

Second of those error messages is described in git-checkout(1) man page, in the "EXAMPLES" section. It means that you have local modifications to 'frotz', which would be lost on checkout. You can give '-m' option to git checkout, which would try three-way merge.

Sometimes the solution is to commit.

"git-receive-pack: command not found" on push/fetch/pull

Basically the problem is that 'git-receive-pack' is not in the default $PATH on the remote end. You can see the problem using:

$ ssh servername 'echo $PATH'

Whereas you probably installed git to your $HOME or something like that. The workarounds include;

  • Install git to /usr/bin
  • Making sure you have the correct path set up in .bashrc (not only .bash_profile)
  • Specify --receive-pack=PATH/TO/git-receive-pack at push time
  • Set remote.<name>.receivepack using git config (see git-config(1))

My username contains a '@', I can't clone through HTTP/HTTPS

$ git clone
error: Couldn't resolve host '' while accessing

Solution : URL-escape the '@' sign in your username, i.e. replace it with %40, like git clone

Explanation : Git delegates the URL handling to curl, which doesn't allow '@' signs in usernames because RFC 3986 doesn't allow it. See this bug report for example.

Importing from other revision control systems

See the [[InterfacesFrontendsAndTools#rcs-interaction|InterfacesFrontendsAndTools]] page ("Interaction with other Revision Control Systems" section), for a good reference on how to interact with other revision control systems.

Note that you can add/import old history from other revision control system later, and join the histories using Graft Points.

Can I import from tar files (archives)?

To import from archives (one archive file per version), to make Git know which files changed between versions despite the fact that time stamps on everything changed (i.e. --atime-preserve option of tar didn't work), use

$ git update-index --refresh

between versions, so the index thinks things are newer. It won't touch the "really changed" files.

Can I import from CVS?

Yes, use git-cvsimport(1), which needs CVSps (CVSps patches), or use parsecvs, which parses directly ,v files. cvs2svn version 2.1 or later has a git output mode in which it creates dump files that can be read by git fast-import. Lastly, there is also FromCVS toGit, which is a speedy solution with incremental import and branch support, but it currently does not support normal tags.

Can I import from svn?

Yes, use git-svn(1). Check also git-svnconvert (in Ruby) in InterfacesFrontendsAndTools. There is also an idea to use svnadmin dump "dumpfile" format as an input for Subversion to Git repository conversion, (similary to what parsecvs does for CVS repositories).

Merge tracking information added to svn repositories by svk, svnmerge, or version 1.5 or later of subversion itself, is not properly converted.

Can I import from arch/baz/tla?

Yes, use git-archimport(1), or bzr-fast-export from `exporters` subdirectory of the bzr-fastimport project.

Can I import from Perforce?

Yes, there is a number of importers, including one in contrib/ directory of Git source distribution. Search Git mailing list archives for others.

Can I import from Mercurial?

Yes, use for example Rocco Rutte's hg-fast-export (from fast-export.git on

You can also use hg-git mercurial plugin ( that adds to the Mercurial repository ability to push to and pull from a Git server.

Can I import from other SCMs?

Maybe, check if Tailor (homepage) can do it. Take a look at InterfacesFrontendsAndTools page ("Interaction with other Revision Control Systems" section)


Personal tools