2

I was trying to switch to a branch I'm working on and accidentally included the '-C' argument for the git switch command, which tells it to create a new branch.

Essentially, I did git switch -C foo where foo is an already-existing branch, and now the foo branch refers to something completely different from what it's supposed to, with the original foo now absent from git log.

There is no corresponding origin branch to pull from a remote repo, it's all local.

boguslavsky
  • 155
  • 1
  • 7
  • Can you show the actual command that you typed by mistake? It sounds like you did `git switch -C foo` where `foo` is an already-existing branch, and now the `foo` branch refers to something completely different from what it's supposed to, with the original `foo` now absent from `git log`. Is that right? – shadowtalker Feb 14 '23 at 16:59
  • Yes, that's exactly right – boguslavsky Feb 14 '23 at 17:00
  • 2
    It's best to add that clarification in the text of your question. Comments are not indexed for searching and users are encouraged to treat them as possibly ephemeral. – shadowtalker Feb 14 '23 at 17:33

2 Answers2

7

You can retrieve the history of your branch name using:

git reflog show <branch-name>

That will show you the commit ID the branch was previously pointing to. You can put it back by grabbing that commit ID and then:

git branch -f <branch-name> <commit-ID-from-reflog>

# or if checked out:
git switch <branch-name>
git reset --hard <commit-ID-from-reflog>

Note you used git switch -C, and the capital C option is equivalent to:

git branch -f <new-branch>
git switch <new-branch>

Had you used a lowercase -c option, the equivalent branch command would've omitted the -f option, and therefore would have errored instead of overwriting the existing branch. In general, some Git command options can take a lowercase or capital letter, and the capital letter oftentimes means "force it", so use with caution and perhaps default to the lowercase letter option first.

Side Note: The show option in the git reflog command isn't necessary, since it is the default. However, I like to include it, mainly because when using reflog with branch names, tab completion won't work without it. (At least I've found this to be true with Git Bash.)

TTT
  • 22,611
  • 8
  • 63
  • 69
1

Let's say you have branches dev and main.

Recall that a Git repository is a "graph" of commits, and branches are "pointers" to specific commits in that graph.

Your mistake has resulted in removing a branch pointer from branch foo, and placed it elsewhere in the commit graph. The commits are still there, but they no longer have a branch pointing to them. Eventually, they will be "garbage collected" and deleted, but they are probably still there.

Your commit graph might look like this before the mistake:

$ git log --graph --oneline --decorate

  * 7da3c3 (dev) add
  | * cb44c2 (HEAD -> main) update
  |/
  * c62eda Add a

Then you run git branch -C dev.

After this mistake, your commit graph might look like this:

$ git log --graph --oneline --decorate

  * cb44c2 (HEAD -> dev, main) update
  * c62eda Add a

Commit 7da3c3 seems to have disappeared!

Don't panic. The commit is not deleted, it's just no longer visible in the default git log output, because there's nothing pointing to it.

If you already happen to know that the "lost" branch pointed to 7da3c3, you could just run git branch -f dev 7da3c3 (or git switch -C dev 7da3c3) to move the dev branch pointer back to its original location. But we usually don't know commit hashes off the top of our heads, so we need to figure out what hash we need to move the branch pointer to.

We can view "lost" commits using git log --reflog, as shown in Get a list of all git commits, including the 'lost' ones:

$ git log --reflog --graph --oneline --decorate

  * 7da3c3 add
  | * cb44c2 (HEAD -> dev, main) update
  |/
  * c62eda Add a

Here we can see our old commit 7da3c3 without any branch pointer. Then all we have to do is move the branch pointer back to the right place, using git branch -f dev 7da3c3 as I stated above. The -f/--force option is required because git branch will otherwise refuse to re-create/move a branch that already exists without "force"-ing.

You can also use the git reflog dev command as shown in the other answer to view the history specifically of the dev branch, which might be more directly useful, but doesn't provide as nice of a visual overview as log --graph.

Note also that your reflog output might look a lot busier than in my simple example, if you have performed other branch moves, rebases, etc. Usually git reflog <branch> should show the correct commit directly at the top of the list, but that won't always be the case in "recovery" operations like this one. You might need to look around for a while in order to find the right one. You may use git show to view commits by their hash (e.g. git show 7da3c3), or use git checkout/git switch --detached to move around the repository in "detached head" mode.

shadowtalker
  • 12,529
  • 3
  • 53
  • 96