0

I am new to git and I wanted to try the branch feature. I am working with a local repository. The problem is that if I create a new branch and then go back to the master branch, some files are lost.

This is what I do:

I have two directories:

$ ls
g_LT  LT

and a source code file lt_mp2.F in the LT directory:

$ ls LT/ | grep lt_mp2.F
lt_mp2.F

The other directory contains a relative symlink to this file:

$ ls -l g_LT/ | grep lt_mp2.F
lt_mp2.F -> ../LT/lt_mp2.F

Both files are lost if I create a new branch and then go back to the master branch. So, let me show this:

Before I create the new branch, let's check that there is nothing to commit:

$ git status
HEAD detached from 2617e8a
nothing to commit, working directory clean here

Let's also check that we are in the master branch and that the last commit is from Oct 13 2016

$ git branch -a
* (detached from 2617e8a)
master

$ git log
commit 3484261bdd585671bf7c74568542a62610c2deaf
Author: [...]
Date:   Thu Oct 13 09:25:06 2016 +0200
[...]

Now I create a new branch:

$ git checkout -b testbranch
Switched to a new branch 'testbranch'

The source files are still there:

$ ls LT/ | grep lt_mp2.F
lt_mp2.F
$ ls -l g_LT/ | grep lt_mp2.F
lt_mp2.F -> ../LT/lt_mp2.F

Now I go back to the master branch:

$ git checkout master
Switched to branch 'master'

But now the source files are gone:

$ ls LT/ | grep lt_mp2.F
(no output)
$ ls -l g_LT/ | grep lt_mp2.F
(no output)

Moreover the last commit is suddenly from Dec 2015 instead of Oct 13 2016:

$ git log
commit 634741172ed34cd687fd91f14da45004b3328f8b
Author: [...]
Date:   Tue Dec 1 18:54:57 2015 +0100
[...]

What is happening here and why am I losing my source files?

thyme
  • 388
  • 5
  • 18

1 Answers1

1

You're not (losing any files, nor any commits).

This part of your starting claim is wrong:

Let's also check that we are in the master branch [snip]

$ git branch -a
* (detached from 2617e8a)
master

This shows that you are not on branch master at the start. Instead, you have a "detached HEAD". The most recent explicit git checkout of a raw hash ID, or equivalent—such as a tag name, or a remote-tracking branch name—checked out commit 2617e8a. Your git log output shows that the current commit is probably1 3484261bdd585671bf7c74568542a62610c2deaf, and the "detached from" wording suggests that you probably made this commit yourself (Git uses "detached at" when you have not moved HEAD, and "detached from" when you have).

The git log command defaults to showing commits starting from your current (HEAD) commit2 and working backwards. This is true whether HEAD is "detached" or not. (A non-detached HEAD is a HEAD that refers to a branch name, such as master. Running git checkout branchname gives you a non-detached HEAD, i.e., HEAD now points to branchname, so that commits are found using the named branch.)

If you want to see more or other commits, you can tell git log to start somewhere else. Wherever you tell it to start, it works backwards from there.

Thus, this just means that master, the branch name, points to a commit from back in 2015. Once HEAD points to master, git log (with no additional arguments) starts with its most recent commit and works backwards from there.

Presumably if master is that out of date, all the real work has been happening on some other branch(es).

The files disappear when you switch from 3484261... to 6347411... (this is probably the commit identified by master) because they are in the former commit and are not in the latter. So Git removes them from the index and work-tree when switching commits. Switching back to 3484261... (by checking it out by ID, or by the new name you gave it) will put them back into the index and work-tree.


1git log sorts its output by date, by default, showing commits with later dates first. This code changed somewhat at some point that I missed, because it used to be possible to "post-date" a commit into 2038 or so, so that it was always shown at the top of git log output, if it was to be shown at all. This had stopped working when I tested it recently.

2See footnote 1, and note that you can change the sort order, and/or constrain it, e.g., with --topo-order. Adding --graph sets --topo-order. Usually, commits' dates are more or less in line with their graph topology, so that these flags do not make huge changes in sorting order.

torek
  • 448,244
  • 59
  • 642
  • 775
  • Thanks for this detailed answer. But how can I resolve this "detached HEAD" thing? As far as I can remember I started using git with "git init" and then I always just used "git add -A" and "git commit -a". – thyme Nov 17 '16 at 13:54
  • I don't know exactly how you got the detached HEAD in the first place. Git records a lot of useful information in "reflogs" (there's one for each branch, and one more for `HEAD` itself), but reflog entries expire after a while: 30 days for some, 90 for others, by default. Since it looks like your `master` was last touched almost a year ago, the traces in the HEAD reflog are likely long gone. [continued] – torek Nov 17 '16 at 14:08
  • As long as you can *find* the commits, though, all you have to do is give them a name, such as a branch name. You did this with `git checkout -b testbranch`. If you run `git log testbranch` you will see those commits. With `git log --branches`, you will see all commits reachable from all branches, which at this point is just `master` and `testbranch`. Using `git log master testbranch`will thus do the same thing. Using `--all` gets all references (mainly branches and tags). Add `--oneline --decorate --graph` to your `git log` to get a graph drawing with labels (or try a GUI—I usually hate GUIs) – torek Nov 17 '16 at 14:12
  • (... but they *are* useful for drawing pretty graphs.) – torek Nov 17 '16 at 14:12
  • Ok, and what about merging testbranch with master? Would result in a single master branch that I desire? – thyme Nov 17 '16 at 15:10
  • It's not possible to tell without viewing the graph, or some part of it at least. Merging is all about *combining* two *different* sets of changes: those from the merge base to one branch tip, and those from the merge base to the other branch tip. But what is the merge base? *That* is determined by the graph. – torek Nov 17 '16 at 15:14