When Git deletes or removes a file where does it go? - macos

When Git removes files either through a soft or hard reset - where do these files go? Is there any way to go back to the condition before a mixed reset?
Normally when a file is deleted on an operating system, it goes to a trash can. When files are deleted or removed via Git they seem to go into an ether. Where do these files go?
I have a stack of new files that weren't added properly and I foolishly ran a mixed reset and now these files are no where to be seen.
I'm using SourceTree for OS X by the way.

If you did a --mixed or --soft reset , then the files in your directory would not have gone anywhere because those types of resets do not effect your working tree. With a --hard reset the files in your working tree will be deleted.

Just a small explaination of git reset command usage:
The main parameters are soft, hard and mixed. These tell Git what to do with your index and working copy when performing the reset.
Soft
The --soft parameter tells Git to reset HEAD to another commit, but that’s it. If you specify --soft Git will stop there and nothing else will change. What this means is that the index and working copy don’t get touched, so all of the files that changed between the original HEAD and the commit you reset to appear to be staged.
Mixed (default)
The --mixed parameter (which is the default if you don’t specify anything) will reset HEAD to another commit, and will reset the index to match it, but will stop there. The working copy will not be touched. So, all of the changes between the original HEAD and the commit you reset to are still in the working copy and appear as modified, but not staged.
Hard
The --hard parameter will blow out everything – it resets HEAD back to another commit, resets the index to match it, and resets the working copy to match it as well. This is the more dangerous of the commands and is where you can cause damage. Data might get lost here!
And more thing, You can recover the lost data upto some extent using git reflog.
So, in your case data should be present there only, since you gave --mixed parameter.

When files are deleted or removed via Git they seem to go into an ether. Where do these files go?
When you do a hard reset git will unlink(2) the files.
The data might still be there on the file system but there are no guarantees. Please read https://unix.stackexchange.com/questions/10883 where some recovery tools are mentioned, mostly for ext3.
The git commit, stash and branch commands are often used to save work. Also pay a special attention to the reflog for locating and re-retrieveing runaway leaf changes, especially after a reset.

Related

How do I ask git to clean out and rebuild the entire working tree?

We have something of an ugly mess that needs cleaning up.
In our codebase, certain developers created directories whose name differed only in case. Normally, such a thing would not be an issue; however we are developing on Windows. This proceeded to confuse git and cause us merge conflicts far down the line.
We have since pushed changes to master getting rid of the duplicate directories in the tree (and encountering some Azure DevOps bugs in the process); now all that remains is a large number of incorrect directory names on users' workstations. Due to the case interactions between git and Windows; these won't get cleaned up by a git pull.
How do we actually erase and rebuild the working trees without throwing out the local branch state in .git? I need to send out instructions so everybody on the team can clean this mess up and those wrong-case local directories don't magically reappear in future commits.
Delete all files and then do a git reset --hard.
git rm -r .
# might need an additional rm outside of git if there are directories left over there
# wait 30 seconds or Windows will restore the wrong case
git reset --hard
Just be careful not to have any uncommitted changes hanging around.

Checked out a repo from remote but when I do a git status a file shows up as modified — how to fix?

I am using Windows and Git and I had modified a file. No matter how many times I did a git add and commit, the file kept showing up as modified and i could not for example do a git pull --rebase. I assume I did something wrong and screwed up the local Git repo so I decided to clone the repo from github, into a completely new directory. To my surprise, even in this new directory tree when I do a git status the same file shows up as modified -- it is as if it is somehow modified in the github (remote) repo which does not make sense to me. Moreover, the version of the file in cloned local repo does not have the latest version of the code that i can see when i look at the code on github. How can i fix this? I am concerned that someone else cloning the code will end up with the same problem. (Apparently only I am seeing this problem -- I did not somehow manage to corrupt the github repo which leads me to believe this is a git/windows issue.) As far as what I think I did wrong is when I modified a file and did a git add, i misspelled the directory path by using a lower case letter instead of an uppercase and then adding one file resulted in the other, properly spelled path showing up as modified and vice versa. I don't know if a symlink on windows got created -- the file contents are identical. But one would think cloning (via Eclipse) into a completely new directory tree would make this a non-issue.
I looked through replies but it seems like the basic problem is Window's case insensitivity and this caused some (to me) weird behavior. In particular, I simply could not delete one of the folders -- they were "entangled." So the simple solution was to delete the folder and its contents from unix which is case sensitive. Then I checked out a fresh repo and problems appear to be completely resolved.
You mentioned in a comment that you discovered one commit containing two problematic files: one named Login/Login.tsx and one named login/Login.tsx. This comment is on a related question; see my answer there for a discussion of Git's method of naming files in its index, vs what your OS requires in your working tree.
Your solution—use a Unix or Linux machine, where you get a case-sensitive file system, to repair the situation—is probably the easiest and best way to deal with this. If you can establish a case-sensitive file system on your own machine, that also allows easy dealing with this (see my answer to another related question for a macOS-specific way to make a case-sensitive file system).
Given that what you wanted was simply to delete one of the spellings, though, git rm should allow you do that. In particular git rm --cached login/Login.tsx would drop login/Login.tsx from Git's index, without affecting Login/Login.tsx. This could leave your working tree with an existing login folder, though.
It's important—at all times, really, but especially when working within a situation like this—to realize that Git itself doesn't actually need or use your working tree to make new commits. Each commit contains a full snapshot of every file that Git knows about. These files exist as "copies" in Git's index.1 Hence there are actually three copies of each file:
A frozen version of each file appears in the current commit (whatever that commit's hash ID is).
A "copy" (see footnote 1) of that version appears in Git's index. You can replace this copy with different content, and the read-only copy in the commit doesn't change. You can remove this copy entirely, and the read-only copy still doesn't change. Nothing in any existing commit can or will ever change. The index copy exists precisely so that you can replace it, or remove it, or whatever. In effect, the index—or staging area, if you prefer this term—acts as your proposed next commit. It's merely filled in from a commit.
Finally, there's a regular, ordinary, everyday file. This copy goes into your working tree or work-tree. To put this copy in place, Git must use your OS's file-manipulation facilities. That may require creating folders and files within the folders. If those are case-insensitive, and Git goes to create a Login folder when a login folder exists, or vice versa, the OS will say: nope, sorry, already exists. Git will do its best to accommodate the OS by using the "wrong" case anyway, and will create a file within that wrong-case folder—or perhaps destroy some other work-tree file that has the same name except for case, or whatever.
This last bit, where your work-tree files end up with the wrong names and/or in the wrong folders and/or end up overwriting similar files whose name differs in case somewhere, is a problem for you. It's not a problem for Git, though. Git just keeps using the index copies of each file. The next git commit you run uses whatever is in Git's index. The fact that your work-tree doesn't match is not a problem for Git. It's just a problem for you, because the normal everyday git add command means make the Git index entry for this file match the copy that's in my work-tree, and if that's the wrong copy, well, that's a problem.
In any case, once you have a correct commit in Git as your current commit, and extracted into Git's index, you can do whatever you like to your work-tree, including remove large swaths of it, or rename folders, or whatever. Get it set up however you like, then use git checkout or git restore to re-extract all or part of the current commit to your work-tree. Now that you've eliminated the name-case-issues in Git's commit and index, and cleaned up or removed any problematic files and/or folders in your work-tree, Git can create correct-case folders and/or files as needed. It's the process of getting the correct commit into Git that's painful, except on a case-sensitive file system.
1"Copies" is in quotes here because the files in Git's index—which Git also calls the staging area—are in a special Git-only format that de-duplicates content. When the copies that are in Git's index match the copies that are in some existing commit, Git is really just re-using the existing commit's files. Files with all-new content actually require a new internal blob object, which Git creates as needed; after that, the content will be de-duplicated as usual.

Exclude in git deleted important file

I have 2 branches master, testing. I git checkout testing and added an exclusion in .git/info/exclude
I added this into exclude: MyProject/MyProject.xcodeproj/project.pbxproj
I did this so it wouldnt prompt me to add it and commit it everytime because it changes whenever I change tab or stuff like that.
I committed this to testing and pushed, then I git checkout master and git merge testing.
In the terminal it said this: delete mode 100644 MyProject/MyProject.xcodeproj/project.pbxproj
And after this I cant open my xcode project anymore, it says cannot be opened because it is missing its project.pbxproj file
And now I cant seem to get it back, I cant find it in my github under commits. ;_;
Usually you put this stuff in your .gitignore rather than .git/info/exclude.
To get it back you could check out the commit right before removing it (assuming there is such a commit), move it someplace safe, and then re-add it after switching back to master.
If it's a file that is needed in the repository, then making git ignore it doesn't really make any sense (think of the guy cloning a fresh copy). Perhaps you'll have to live with either committing changes to it all the time, or get into the habit of leaving that file unstaged most of the time.

How do you undo a hard reset in Git Gui or Gitk on Windows?

I'm using Git Gui and Gitk on Windows. How do I undo a hard reset from within the past two hours?
(Is it possible to do this from these applications, without using the command line?)
I saw this SO post, which says that undos are possible before git's garbage collection occurs. I might have quit and reopened one or both of these applications.
If you had changes in your working tree that were not committed when you did git reset --hard, those changes are gone for ever. You have to use your memory (in your head) to recreate them.
Changes that were committed after the commit to which you switched are not lost. They likely have no reference pointing to them, making them more difficult to locate. The tool to list all low-level changes to the repo is git reflog.
After you locate the commit which you want to revert to observe the hash number in the first row and use git reset --hard #hashnumber or git checkout #hashnumber to get the changes.
I found this useful line on http://quirkygba.blogspot.com/2008/11/recovering-history-with-git-reflog.html:
gitk --all $(git reflog | cut -c1-7)
This will display all the hidden changes in gitk, where you can comfortably view, point, click and create new branches.
As you mentioned the unreferenced commits are normally being kept in the repository for 30 days.
EDIT: I have to add stuff here so that my edit is at least 6 characters. I know, sometimes code fixes are less than 6 characters, but there might, after all, be something else to improve in this post.
See the answers by Brian Riehman and Pat Notz in the link in the question.
One solution is to use the command line.
In Windows, open DOS in the directory containing your .git directory.
Type something like the following to see what commit you want to go to:
"c:\Program Files\Git\bin\git.exe" reflog
To go to a certain commit, type something like the following, where the last expression is the SHA1 code of that commit:
"c:\Program Files\Git\bin\git.exe" reset --hard 5eb4080
I don't think you can undo a hard reset to get uncommitted changes back - you can undo a rebase because the blobs are still available, but if you never committed your newest changes to Git ever, anything it overwrote is most likely history. I'd love to find out that I'm wrong though!

Using TortoiseGit deleting all after a certain commit

Using TortoiseGit (I'm trying to avoid command line usage) how does one delete all commits that accended from a certain commit, and "get back in the past" (example usage: continued doing something, figured I didn't like where it was going, and decided to go "back" disregarding all in between).
In short I wish to go 5 commits "back", and delete them afterwards.
Go to TortoiseGit -> Show log. Select the most recent commit you want to keep, everything above will be erased. Then right click on it and select "Reset "master" to this" and choose Hard. Be careful though because once you do this all the commits after it will be forever lost unless they are stored off in another branch somewhere.
I've never used Tortoise anything (unless you count the electronica group), but I'll give you this info in case you don't find a way to do it with the GUI or you end up deciding to go CLI after all.
As #Tuxified mentions, you can accomplish this with git reset --hard <COMMIT>. You need to specify a commit, which can be done in any of an intimidating panoply of possible ways; the most common have forms like HEAD~4, which specifies a commit 4 commits before the head of the current branch, and deadbeef42, which specifies a commit whose SHA1 starts with 0xdeadbeef42. If you're running linux or OSX, you can get the full details on commit specifiers via man git-rev-parse, under "SPECIFYING REVISIONS".
You can also rename the current branch (git branch -m new_branch_name) and then create a new branch with its head at the place you want to revert to. The advantage is that if you end up wanting to use all or some of the stuff you did there, you can still readily access it; and if you typo the commit, you're saved from a big holycrap moment. Plus git branches are super lightweight so the only real downside is that there will be another branch listed. To make the new master branch you would use git branch master <COMMIT>, and then you check it out. So the net effect here is the same as the first option, except that you still have your old changes saved in the branch new_branch_name. You can even merge those changes back in later, after new commits to master, if you feel like it.
Note that either of these techniques are considered "rewriting history" and will cause issues if you're sharing your repo with others. If you're being smart and pushing to a backup repo in cloud city or another pc, you will have to fix things on that end before you can push to it again.
This is probably way more info than you need right now, but if you end up using git a lot you'll probably want to learn this stuff at some point. Sorry I don't know how to use Tortoise...

Resources