Git FAQ

Here you can find the questions I commonly ask myself while managing my source code, over and over again. This serves as a reference to those tasks which are common, but not quite common enough to remember easily. If any of the terms used here are unclear, you can refer to the Git Glossary.

Contents

Creating Repos

How do I set up a repo for some already-existing files?

How do I set up a remote repo for some already-existing files?

Same as above, plus:

How do I "fork" a repo without using GitHub?

Sometimes I want to create a private copy of a repo, which GitHub does not allow. For example, how would I "fork" something from GitHub to alternative service Bitbucket? This is almost equivalent to just cloning the repository, with some small additions. This is different from purely duplicating the repository.

Let's say you want to create some new-invention on Bitbucket based on some prior-art from GitHub. In essence, what you want is (1) a "mirror clone" of the prior art, and (2) a way to pull changes from the upstream prior art and merge them with your own new invention.

To set up the new repository (mirror clone):

Whenever you want to grab the latest changes from the prior art:

You must specify the branch you want to pull. This merges upstream/master into whatever local branch you're currently on (the output of git branch). Don't accidentally merge two branches that aren't supposed to be the same!

Undoing Mistakes

How do I undo something?

You have (at least) four choices.

    • To erase changes in your working copy.
    • “I made some changes but I don’t want them anymore.”
    • To fix just the most recent commit.
    • “I forgot to mention something in the commit message.”
    • “I forgot to add this one file to the commit.”
    • To fix local errors and errors in your working copy.
    • “Oops, I didn’t mean to ‘git add’ those changes.”
    • “I messed up a merge, I want to start over and try again.”
    • “I decided the last few commits were all wrong. I want to destroy them forever.”
    • “I decided the last few commits were all wrong. I want to modify them and re-commit.”
    • “I accidentally merged from the wrong branch, or merged the wrong commits. Where’s the reset button on this thing?!”
    • To fix already-pushed errors.
    • “Someone discovered something seriously wrong with my bugfix. We need to revert the change right away.”
    • “Someone ported a patch from a previous version of the software, but it doesn’t belong there. We just need to undo it.”

Just reset everything. Get me back in sync with everyone else.

Please, God, why is this so hard?! I just want what’s in the repository. I don’t care what’s in here now, I don’t care that it would be “overwritten by merge”—kill them with fire—nuke them from orbit—I JUST WANT WHATEVER EVERYONE ELSE HAS!

The only annoying thing about this is it still won't delete all your untracked files; you'll have to do that yourself.

Oopsie, I didn’t mean to ‘git add’ those changes.

See also the FAQ about different ways to undo things.

How do I undo an accidental commit?

See also the FAQ about different ways to undo things.

I moved some directories and I want to mark them as renames.

No need! Git will detect this automatically!

I accidentally committed and pushed a file I don't want to track in the repo.

See How to stop tracking (remove) a file without deleting it? If you haven't already pushed, you should definitely instead see git reset or git commit --amend above!

Otherwise, unfortunately, there's no easy way to undo this. You will need to remove the file from your repo, so it will still be stuck in the repo history taking up space, unless you go much deeper. Furthermore your colleagues and your other machines will have the file deleted when they pull, so all other machines must backup the local file before they pull the removing change, then pull, then restore the file. The ideal method is to remove the file and add it to .gitignore in a single commit.

If it is necessary for you to try harder to fix this, there may be solutions for you; check here.

Inspecting Repo Content

How do I list all tracked files?

How do I pull down all remote branches?

Update 2021-10-12: I wrote this some time ago, and I'm no longer sure why you would really want to do this, unless you were backing up or migrating the code somewhere. Maybe if you wanted to browse all the branches without a web interface? In any case, you can still do it if you like...

Method 1:

For each remote branch in git branch -r:

Then execute once:

This method will leave your working copy where it is.

Method 2:

For each remote branch in git branch -r:

OR

This method will change your working copy to the checked-out branch.

Method 3:

You can also see how this appears in your .git/config, and even set it up manually.

Adding/Removing Files

How to stop tracking (remove) a file without deleting it?

Warning: When you commit this, if others pull it, their local copy of this file will get deleted.

Following this, you may want to add the file to your .gitignore

Managing Branches

How do I start my own branch?

Typically, you want your branch to track the branch which it stems from, so you can easily merge/rebase upstream changes into your branch. This also makes it easier to maintain a chain of branches with parent/child relationships. So I will provide instructions for that. You normally also want to switch to the new branch immediately to start working on it. So you really want to do three things:

  • Create a new branch from a particular starting point.
  • Set the starting point as the "upstream" branch (a.k.a. "tracking" branch).
  • Switch to the new branch.

You can do all three things with a single command:

<start-point> is optional, and will default to HEAD if omitted. It can be branch name, commit-id, or tag.

However, if it is a remote branch (of the form origin/<branch-name>), then in fact "switching" to a branch with a matching name will automatically create a local tracking copy of that branch, so all you need to do is:

It used to be that you were forced to do this in two separate steps, which you can still do if you prefer to switch to the branch later:

How do I share my branch with others?

Once you've started your branch and you're ready to share it with the world, you need a special command to push it for the first time.

If you set up a local upstream tracking branch (the -t option when creating the branch, as described in the previous question), things are much simpler:

WARNING: If you have push.default set to upstream in your .gitconfig, then this will push directly onto the main branch instead of a new remote branch! You must instead specify the destination name explicitly (see below).

Notes:

  • You could instead choose to push to any other remote you have access to.
  • The resulting remote branch becomes origin/<local-branch-name>.
  • [Optional] The -u flag: Set up this branch to track the remote branch.
    • If you are maintaining a chain of local branches that depend on each other, then you may want to maintain those relationships, in which case you will omit the -u.
  • If you used both -u and origin, then for subsequent pushes you can simply call git push. Otherwise, you will need to say git push origin.

If you are not tracking branches locally, then you will need to manually specify the destination:

Notes:

  • You could instead choose to push to any other remote you have access to.
  • To avoid confusion, the destination name should almost always be the same name as what it's named locally, so that the resulting remote branch becomes origin/<local-branch-name>.
  • If you used both -u and origin, then for subsequent pushes you can simply call git push. Otherwise, you will need to say git push origin.

Start a new branch based on my current changes.

I made a whole ton of changes, and all of a sudden I now realize that this is too big to go into a few commits, it really needs its own branch. How do I start a new branch after the fact?

Answer: the same way you start a branch normally!

Commit as normal, you are now on the branch.

Same as above, but I already committed the changes to master. Oops. How do I pull them out of master and into a new branch?

As long as you haven’t pushed the changes, you can do this: Commit everything first. If you have, let's say, three commits:

You’re now on the new branch.

How do I rebase one branch on top of another?

Sometimes you're working on two things in parallel, and then decide instead that one of them needs to depend on the other. Or you need to depend on someone else's branch. Or you have two branches in series, but you want to change the order in which they get merged, because a child is ready to merge but the parent isn't ready yet. In all these cases and more, you may want to rebase your branch onto another.

First, I'll assume your branch has no merge commits in it. See more notes about this below.

As long as that is true, you can rebase your branch onto another and update the tracking information. How to do this varies based on how the tracking branch is set up...

On a branch with a local upstream

This is the easiest situation—your branch is tracking another local branch. Your branch's upstream must already be set properly (which can be done with git branch -u <current-upstream>). You can view this information with git branch -vv. <current-upstream> is often just main, if your branch has no other parents.

Let <new-upstream> be the new parent you want to be branched off of.

That's it!

On a branch with a remote upstream

Often, people have each of their local branches track the remote counterpart, even if it is dependent on some local branch. This will be the default case if you've checked out a branch that was created on another machine. In this case, we sadly are lacking the information about which commits should be moved, so we need a more manual approach. If you use the above approach for this type of branch, you will lose your commits! (But they can always be recovered using the reflog.)

So, in our case we need to manually look at our git log and figure out which commits belong exclusively to this branch and should be carried over to the newly-rebased branch.

  1. View your git log (I highly recommend using the git lg alias included in my .gitconfig), and figure out which commit starts the current branch (this may not be obvious from the branch tags and you may need to pay close attention to the commit messages, so I hope you wrote descriptive commit messages).
  2. Then, copy the git-sha hash for the immediate parent to this commit. We will refer to this as the <previous-upstream>.
  3. Now, we can rebase:
  4. If you want to, you can use the same command as above to set the new tracking branch, but I assume most of the time you won't want this if you are tracking a remote branch.

On a branch with merge commits

The above techniques both assume your branch has no merge commits in it. This assumes you are using a "rebase" workflow, or you haven't merged in any changes from the upstream since starting the branch.

If you have been merging in commits from main/upstream, that's going to be more painful, because now your branch is a mix of commits. I'm not currently sure if the above works for that situation, although it might. I'm not sure of the right way to do it. But when I find out I'll try to update this page.

How do I update a branch with the latest remote version after a force-push?

If only new commits have been added (to the local, or the remote, or both), then we can use rebase very easily:

However, if some of the pre-existing commits were removed or changed, I'm fairly sure we need a more drastic approach:

The above will not preserve any local commits you had, or any unstaged changes in your working tree. You can preserve the unstaged changes with a soft reset:

But this still won't recover your local commits. This is fine if you are just tracking a colleague's branch and hadn't made any un-pushed changes. Otherwise, I think you'll need to create a new branch and cherry-pick the missing commits from the old one:

Diffs

How do I diff my current branch with master?

My diff shows nothing but I have made changes! Where are they?

If you git add your changes then they will no longer show up in git diff. This is because diff shows the difference between the working copy and the index. If you want to see the difference between the index and the current branch, you need to:

How do I see the affects of a single commit?

(In other words, how do I diff any commit with its parent?)

How do I diff any two things?

This works between any two commits, or any two refs, in the whole repository. If you specify only one commit/ref, then newthing defaults to HEAD. To diff any two files outside the repository, you can use:

How do I find the source of a buggy commit?

This command is super cool!

Or, if you already know the faulty line(s) of code, but you want to know why they were committed:

Miscellaneous

What are the ways to refer to a commit?

How the hell do I refer to one of these “commitishes”? Do I really have to copy-paste this whole damn SHA-1 hash??

Luckily, no. There are many ways of specifying a commit:

  • By its SHA1 name, which you can get from git log.
  • By the first few characters of its SHA1 name.
  • By a head. For example, HEAD refers to the commit object referenced by HEAD. You can also use the name, such as master.
  • Relative to a commit. Putting a caret (^) after a commit name retrieves the parent of that commit. For example, HEAD^ is the parent of the current head commit. origin/master^ would be the parent of wherever the remote repository currently is at.
  • Relative to a commit. You can also use the notation HEAD~1 to walk an arbitrary number of steps back in history. HEAD~1 == HEAD^ and HEAD~3 == HEAD^^^
  • You can also say: HEAD@{-1}. But this is a very special case! It refers to wherever HEAD was last, which could be backward or forward or on a whole other branch! Read about the reflog before you use it.

How do I commit a file once and ignore it thereafter?

This often comes up when you have a template file that programmers will customize to their liking. You don't want their customizations to make it into the team's central repo. However, you do want some kind of default version, for those who don't customize it.

If you place this file in your .gitignore, then you'd have to create it from scratch every time you clone a fresh copy of the repo. That's no good. Instead, commit the default version of the file, then do this:

After that any changes to this file will no longer show up in git status. But you'll still be able to commit new changes to the default by explicitly adding them to the index:

Recommended graphical clients?

  • GitX on Mac, TortoiseGit on Windows, ?? on Linux
  • Versions on Mac, TortoiseSVN on Windows, ?? on Linux

Recommended graphical differs?

Beats me.

Well then what do you use?

I use an IDE, but lately I’ve been using them only for hairy conflicting merges. IntelliJ IDEA and Eclipse both work well.

But I don’t wanna use an IDE!

Well then use vimdiff, you hippie.

I already have an SVN repository but I want to start using Git.

If migrating from SVN, don't use git-svn, git-svn slow and terrible; use SubGit instead, SubGit is fast and awesome.

Comments are closed.