33

I've just checked out an old project to fix a bug. git reports:

HEAD detached at origin/master

git status reports I have an untracked file:

<project name>.xcworkspace/xcshareddata/

I'd like to get on and fix the bug but I'm not sure quite what's going on. If I try git checkout master I get:

error: The following untracked working tree files would be overwritten by checkout:
<project name>.xcworkspace/xcshareddata/

Can I just delete this file? Am I on the master branch? If not, how do I get to it?

2
  • Is the provided untracked directory vital for your project? Or don't you know where it came from? Commented Aug 10, 2014 at 19:16
  • The line git status shows you, will be created everytime you have xCode opened. Think this changes everytime you switch a window in xCode so make sure you quit xCode before doing any changes. ( add it to .gitignore file )
    – Alex Cio
    Commented Jan 16, 2015 at 9:58

3 Answers 3

32

As CommuSoft says, you're not on master. You're in "detached HEAD" mode. You get that any time you explicitly check out something that is not a (local) branch name:

$ git checkout origin/master    # detach to "remote branch"

or if there's a tag v1.7:

$ git checkout v1.7             # detach to tag

and you can even explicitly detach when using a local branch name:

$ git checkout --detach master  # forcibly detach

A "detached HEAD" means you're not on a branch. Being "on a branch" means you're not using the detached HEAD mode. Yes, that's pretty circular; see this question and its answers for more details.

As for the:

error: The following untracked working tree files would be overwritten ...

When you get git checkout to move from one commit to another, it does two main things:

  1. choose whether to be in "detached HEAD" mode, and
  2. rearrange the work tree to match the moved-to commit.

Step 2 is where the problem is occurring. You're on the commit identified by origin/master, and in that commit, there is no record of the files git is currently complaining about. You've asked to switch to the commit identified by master, which is obviously a different commit.1 Git sees that in the commit identified by master, there are some (maybe just one) files with the same names, that are different from the files or directories that are in your work-tree right now.

In order to switch from the current commit to the new one, git checkout must remove the existing files-or-directories and replace them with the ones in the new commit—the one you're asking to switch to. If those files or directories were tracked in the current commit, git would be happy to remove and replace them as needed, as git can always get them back for you: just switch back to that old commit, and there they are. But they're not in the current, to-be-switched-away-from, commit. So git tells you: "Hey, if I make this switch you asked for, I can't guarantee that I'll be able to restore these files and/or directories."

It's now up to you, not git, to figure out what to do with these files and/or directories. Based on the error message, it's a directory,2 and switching to master will cause that directory to be removed and replaced with something else (possibly a different directory with some file(s) in it, possibly just a file). Do you:

  • want to save it/them?
  • if so, do you want to save it/them in a commit, or just move them out of the way?
  • or do you just want to blow them away?

To save them, either commit them, or move them out of the way (e.g., rename them to a path that's not part of the work-tree, or to a different untracked name that's "safer", whatever that would be).

To simply blow them away, remove them manually or use git checkout -f (force) to make git do it.

Since you're not on a branch now (are in "detached HEAD" mode), if you want to commit them permanently to the repository, you can use something like the method CommuSoft added while I was writing this up. (You can create the new branch at any time, before or after doing a "git commit".)

You can also use git stash. Git's stash is deceptively complex little script: it makes commits that are not on any branch at all, that can later be transplanted to a branch. Using it is quite simple and easy: you just run git stash save and all pending tracked changes are saved and cleaned up, or run git stash save -u and all pending tracked changes and untracked files are saved and cleaned up. They are now all safely squirreled away in the repository, under a commit, even though it's not a commit-on-a-branch.

There is no single right answer for what to do here.


1Obviously different, because if you were already on the commit you're asking git to move to, then either the file would be in the commit and hence tracked, or it would be not-in-the-commit and hence you would not be asking git to clobber it.

2This is a little odd. If I make a directory that will be clobbered by my git checkout, and I make it as an empty directory, git just goes ahead and clobbers it. Here the difference between master^ and master is that moving forward from master^ to master creates file mxgroup.py (so stepping back removes it):

$ git checkout -q master^  # file goes away, now let's mkdir...
$ mkdir mxgroup.py; git checkout -q master
$ file mxgroup.py
mxgroup.py: Python script, ASCII text executable

However, if I have a non-empty directory, I get a different error message:

$ git checkout -q master^  # file goes away; mkdir and make file
$ mkdir mxgroup.py; touch mxgroup.py/file; git checkout -q master
error: Updating the following directories would lose untracked files in it:
    mxgroup.py

Aborting

But this is with git version 2.0.2; perhaps older gits are not as clever.

3
  • The linked problem was very helpful. I was looking for an answer to why checking out a branch on remote puts me in detached head. The answer is doing git checkout origin/master puts you at a specific revision, whereas git checkout master will resolve to git checkout -b master --track origin/master as documented here.
    – mcp
    Commented Apr 23, 2021 at 13:53
  • @young_souvlaki: Right. Note that the new (in Git 2.23) git switch will tell you that origin/master is not a branch name and thus can only be checked out with the --detach option. The old git checkout assumes you understand this already, and hence inserts --detach for you. The old checkout tries the name as a branch name (and as DWIM mode, though sometimes too late!) but if that fails, proceeds to try it as pathspec and via git rev-parse and will overwrite files or do a detached HEAD checkout correspondingly.
    – torek
    Commented Apr 23, 2021 at 21:48
  • These rules are overly complex and sometimes surprise even experienced Git users. If you have Git 2.23 or later, it's probably wise to retrain yourself to use git switch for branch checkout, and git restore for file checkout. (I still haven't quite done this myself.)
    – torek
    Commented Apr 23, 2021 at 21:49
27

No you're not on the master branch, your on some kind of "newly invented" branch without a name that was once the master.

You simply need to switch back to the master:

git checkout master

However if you wish to fix a bug, you should work at your own branch (according to most git workflows). Thus checkout the master and branch from it:

git checkout master
git checkout -b fix-issue #give the branch a name that refers to the bug

then fix the bug and run:

git checkout master
git merge --no-ff fix-issue -m "Fixed some strange issue, here follows a description"

EDIT

As specified in your question you have an untracked file. If these file(s) are of no importance, you can remove them. If on the other hand you wish to maintain them, you can merge them into the master first.

Therefore you create a temporary branch:

git commit -m "some temporary message"
git checkout -b temporary
git checkout master
git merge --no-ff temporary
1
  • 1
    the explanation is perfect. Commented Aug 30, 2016 at 6:30
2

I was facing the same issue.

I was checking out origin branch directly from local which was wrong-

git checkout origin/dev_branch

Ideally I should fetch origin branches on local and then check out required branch as below-

git fetch

then

git checkout dev_branch

This approach worked for me, Hope will help you too!!!

Not the answer you're looking for? Browse other questions tagged or ask your own question.