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 the 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 you to automate this task); you can leave it empty or fill in the names of files you do not 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.

Git has a rename command git mv, but that is just for 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 of 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 a 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!

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's a trade-off.

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

Don't think of 'rm' as the inverse of 'add'. That will 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").

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

[1]$ edit a-new-file

The above is a 'create', not an 'add'. Git is not involved in this step.

[2]$ git add a-new-file

This is an 'add' — the placement of 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.

Users sometimes want steps 3 and 4 combined, and this meshes well with user expectations when they see the word "rm". Think of "git rm" without "--cached" as a shorthand to do steps 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, whereas steps 1 and 2 cannot, means that "add" and "rm" are not the inverse of one other.

Features

Does Git convert between CRLF and LF for different platforms?

Newline conversion is supported from Git version 1.5 onwards. See gitattributes(5).

Does Git have keyword expansion?

Keyword expansion is not recommended. Keyword expansion causes all sorts of strange problems and isn't really useful anyway, especially within the context of an SCM. You can perform keyword expansion outside of Git using a custom 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.)

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 want to shoot yourself in the foot, in which case 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 http://utsl.gen.nz/git/post-update, 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.

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" will not delete files it does not track, including files it is told to ignore. If reset switches to a version with a different .gitignore file, then some previously ignored files might show up as untracked files in git status output.

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

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

git 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 rebase a branch?

After you have rebased one of your local branches, you try 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 committed 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. However, recent versions of Git disable the ability to push -f by default because it is usually an error. If you have taken care and really know what you are doing (specifically consider any tags that might have been set on commits that have been deleted or have different SHA, and notify everyone else who might have pulled the branch that they need to `git pull --rebase` and/or fix any private tags they might have made), you can disable the server side configuration which prevents a force push from being accepted:

git config receive.denyNonFastForwards false

After doing a `git push -f` you should reset the configuration value back to true (or delete it) to put the seatbelt back on.

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 uncommitted 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 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.

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).

This is not an issue with servers using the smart HTTP transport added in Git version 1.6.6. Smart HTTP will also provide a dynamically created info/refs file for older clients. See also git-http-backend(1).

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.

Why am I "not on any branch"?

"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 occurrences of
searchstring have changed (which is much faster than grepping
the diff).

To see all commits for which searchstring appears
in a changed line, use git log -Gsearchstring.

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:

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.

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:

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:

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 <code>git commit</code> with the -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:

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?

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?

To copy the shared objects into the local repository, repack without the -l flag

git repack -a

Then remove the pointer to the alternate object store

rm .git/objects/info/alternates

(If the repository is edited between the two steps, it could become corrupted when the alternates file is removed. If you're unsure, you can use git fsck to check for corruption. If things go wrong, you can always recover by replacing the alternates file and starting over).

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.

How do I tell Git to ignore tracked files?

A common reason to ask this question are configuration files which are added to a project as an example or default, but which individual developers may want to change. Keeping uncommitted changes around is undesirable in the long run, because git diff will always show the changes and they will be added for commit if commands such as commit -a or add -u are used.

This problem can be solved in different ways:

Option a: Rename the configuration file to config.template or something like that, and tell the user to use it as a template. The install script for your system could also copy the template configuration to the appropriate location.

Option b: Allow configuration options to be overwritten in a seprate file. For example, in Makefiles it is common to add a line -include config.mak, which allows users to add custom configuration in config.mak, rather than changing the Makefile itself.

Option c: Make Git ignore changes to the configuration file. There is no automatic centralized way to do that. But on a per-clone basis you can tell Git to do it using either git update-index --assume-unchanged <file> or sparse checkout (see the corresponding section in git-read-tree(1) for details). Note that neither feature was designed for that purpose. Use at own risk.

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.

Alternatively:

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:

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.

(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).

There is an experimental script that aims at making it easy to reassociate the base, left and right version of a file after a merge conflict. Feedback appreciated. It was only tested on CONFLICT (delete/modify) cases yet.

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 can I tweak the date of a commit in the repo?

If you wish to tweak the authorship date of HEAD, then the easiest way is as follows (the -C HEAD is just to bypass editing the commit message):

$ git commit --amend --date='<see documentation for formats>' -C HEAD

Setting the commitership date requires the use of the COMMITER_DATE environment variable; see the later script.

You can use programs like GNU date to figure out the new date in a reasonable way:

If you want to set a different time zone as well, then just set the TZ environment variable appropriately (see `info "(libc)TZ Variable"'; in particular, change the previous new_date=... line to the following in order to render the date in the U.S. Pacific time zone:

If you only want to change the time zone or tweak the date by some easily computed number of seconds, then it's probably easier to work with the raw Unix time stamp that git stores internally. For instance, to use the same date as HEAD but change the time zone to UTC, you could do the following (notice the use of %at to get the raw timestamp):

If you want to tweak the date of one of HEAD's ancestors, then just use git bisect -i to select the commits at which you'd like to stop while rebasing, so that you can modify them. Or, if your alterations are rather uniform, then you could use the x directive of git rebase -i to specify the commands that should be run while rebasing; a more general version of such a programmatic approach is to use git filter-branch, as in this following script (which shows date-related environment variables that can be used):

How to fix a broken repository?

"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.

So:

$ 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 ;).

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, 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

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 remove all broken refs from a repository?

So fixing the repository as per GitFaq#fix-broken-repo did not work out, or maybe you just want to cut your losses and get on with it? This is how you do it. Again, it is advisable to backup (cp -a) your repository in case the following process removes more data than you like.

It may not be possible to remove some of those refs using the regular branch -d or tag -d commands, since they will die if git notices the corruption. So use the plumbing command git update-ref -d $ref instead. Note that in case of local branches, this command may leave stale branch configuration behind in .git/config. It can be deleted manually (look for the [branch "$ref"] section).

2. After all refs are clean, there may still be broken commits in the reflog. You can clear all reflogs using git reflog expire --expire=now --all. If you do not want to lose all of your reflogs, you can search the individual refs for broken reflogs:

How to create the first project?

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:

How do I clone a subdirectory?

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.

How do I make existing non-bare repository bare?

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.

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.

How do I recover uncommitted changes?

Changes that were never added or stashed are not known to git and therefore cannot be recovered. Committed changes can generally be recovered using the reflog. The following script can help you recover changes that were added to the index, but never committed. It shows a list of dangling blob sha1's. These are generally objects that were discarded from the index. A blob can be dumped to standard output using git show <sha1>. To dump all dangling blobs into files use git fsck --lost-found.

How do I merge a patch from a gmane.org URL?

You can get the raw article by appending /raw to a message URL (reachable from the "Direct link" link at the bottom of the thread view). Then, using wget and git am, you can apply a patch with a single command-line like:

How do I clone a repository with all remotely tracked branches?

Suppose you have a repository configured with several remotes: origin (the default), foreign1, foreign2. You want to do a clone
but do not want to set up all foreigns again and still be able to checkout any branch from foreign1 or foreign2 (you have origin for
free).

There's a git-clone option --mirror which sets up all remotely tracked branches. So far this is a fundamental knowledge obtained from frequent
documentation readings *cough*. But, --mirror also implies --bare option, ie. the clone will will not be created as a working copy
and you cannot checkout the branches. Here's how to fix it:

How do I remove my uncommitted changes from branch A and add them to a new branch B?

This question is rooted in a misunderstanding. Uncommitted changes are not part of any branch. This goes for both unstaged and staged changes. They are a property of the worktree.

git checkout in branch-switching mode will take care to "move along" any uncommitted changes in the tree when completing the branch switch. This may occasionally cause it to refuse the switch, either because it would have to attempt a nontrivial merge inside a file or because it would have to overwrite an untracked file with its tracked counterpart in the target branch.

Most users asking this question did some work on e.g. 'master', but before committing it realized they should commit it to a new branch 'topic' instead of 'master'. This is as easy as

Now, you can use ediff by $ git ediff <normal git-diff arguments>. "git-diff" can also be used as before.

Error diagnostic

Git push fails with "fatal: The remote end hung up unexpectedly"?

If, when attempting git push, you get a message that says:

fatal: The remote end hung up unexpectedly

There are a couple of reasons for that, but the most common is that authorization failed.
You might be using a git:// URL to push, which has no authorization whatsoever and hence has
write access disabled by default. Or you might be using an ssh URL, but either your public key was not installed correctly, or your account does not have write access to that repository/branch.

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 'git.example.com:/Repo/Project.git'
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 user@git.example.com 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: 'git.exaple.com/wrong-path': unable to chdir or not a git archive
fatal: The remote end hung up unexpectedly
error: failed to push to 'git.exaple.com/wrong-path'

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

"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'
/usr/bin:/bin
$

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) if your shell is bash or .zshenv if your shell is zsh.

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?

Note: if you are getting "Unknown: error" when running cvsimport, this may be caused by an old version of cvs. In particular, if you are running Mac OS X and have set the CVS_SERVER to ocvs, this causes git to also run ocvs, which does not work correctly with cvsimport. If you unset the environment variable, import will likely succeed.