tags:

views:

107

answers:

3

I have an issue where I want to branch off from an old revision but the check out of that branch is not removing files and folders that were only added after that branch in the revision history.

Why is this, and how can I got back to a point in the revision history and check out the entire project restoring the state exactly as it appears in that revision?

Here is how I'm doing it currently:

[add new folder lib/newlib to project, put some files in it]
> git add *
> git commit -a -m "new revision with folder lib/newlib/ and some new files"
> git tag old_version_tag {older revision hash}
> git branch old_version old_version_tag
> git co old_version
> ls lib
newlib
> git status
nothing to commit (working directory clean)
> rm -rf lib/newlib
> git status
nothing to commit (working directory clean)

Is there a better way to do it?

A: 

What is the 'co' alias set to do? Does it work correctly?

Here's my trace output from a shell script - I happened to have a pair of files lu.c and lg.c lurking in the current directory:

+ rm -fr git-exp
+ mkdir git-exp
+ cd git-exp
+ git init
Initialized empty Git repository in /Users/jleffler/tmp/git-exp/.git/
+ cp ../lg.c .
+ git add lg.c
+ git commit -m 'Initial revision - lg.c'
[master (root-commit) 4d904fe] Initial revision - lg.c
 1 files changed, 20 insertions(+), 0 deletions(-)
 create mode 100644 lg.c
+ git tag base
+ mkdir lib
+ cp ../lu.c lib
+ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   lib/
nothing added to commit but untracked files present (use "git add" to track)
+ git add lg.c lib
+ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   lib/lu.c
#
+ git commit -m 'Add lib/lu.c'
[master e1bc008] Add lib/lu.c
 1 files changed, 12 insertions(+), 0 deletions(-)
 create mode 100644 lib/lu.c
+ ls -lR lg.c lib
-rw-r--r--@ 1 jleffler  staff  393 Jan  2 09:43 lg.c

lib:
total 8
-rw-r--r--  1 jleffler  staff  237 Jan  2 09:43 lu.c
+ git branch base-branch base
+ git status
# On branch master
nothing to commit (working directory clean)
+ git checkout base-branch
Switched to branch 'base-branch'
+ ls -lR lg.c
-rw-r--r--@ 1 jleffler  staff  393 Jan  2 09:43 lg.c

The last line shows that checking out the branch with 'git checkout' did remove the lib/lu.c file from the working directory.

Jonathan Leffler
I tried this example and it works. I'm not surprised though, because I've never noticed this problem with files. And only just now with folders. I just did the test again in a fresh git repository, similar to your test. However, if I put a folder in lib and add files to in, then commit the changes then revert the folder does in fact remain in the checkout of the old branch. Also thanks for the idea to check the alias but it is set to 'checkout'.
Joshua
Don't forget that git tracks content - not (empty) directories. So it won't remove directories that have anything in them, I suspect. You can adapt the example to demonstrate that. Git endeavours not to destroy anything that might be useful or wanted. I wondered whether to mention this before.
Jonathan Leffler
Thanks, but at least in my case it's not removing folders that are full either (or failing with an error that (un)tracked data would be removed). Apparently because the content of those folders where not being tracked in the older revision!? This would mean Git does not consider the absence of information to be important, which is a logic error, and would be profoundly bad design for such a wildly used tool. It would also mean git would be unable to restore state to a point in the past. I cannot believe this is the case, it's much more likely that I am not using it correctly.
Joshua
Yes - you should have 'git status' reporting 'clean' before trying to switch branches, always. If you have stuff around that it is not tracking (because you haven't put it into .gitignore yet, perhaps), then the switch of branches will not clean up the stuff that git doesn't know what to do with. **Before you try switching branches, make sure that 'git status' reports a clean directory**.
Jonathan Leffler
A: 

git checkout would make the working tree exactly the same as the specified branch, if there were no local changes.

Check if lib/newlib is committed before doing checkout. git add * would fail if there are untracked files that match .gitignore: Use git add --all instead.

BTW, these three lines

git tag old_version_tag {older revision hash}
git branch old_version old_version_tag
git co old_version

can be replaced by

git co -b old_version {older revision hash}
Iamamac
Great thanks for the usage tips. I can confirm that lib/newlib is not in the older versions of the project. And notice how I can do a git status with it there and it doesn't say it is not added, but I delete it and it doesn't say it's missing either! The parent folder 'lib' is not in the .gitignore so I'm lost as to how this could happen.
Joshua
A: 

In your original example, you showed that newlib still existed in the lib directory. What files exist in newlib after the revert and what is the contents of your .gitignore? So far you haven't really been clear on those.

The example I think that other people are thinking about is if you have files that are ignored by .gitignore they will still exist (say .o files after a compile), not show up in a git status, and force the newlib directory to still exist even if there are no committed/untracked files in it. If this is the case, you can use git clean newlib to delete any untracked/ignored files from that directory (and probably the directory as well).

Xentac