Mastering Manual File Recovery: A Guide to Cherry-Picking Deleted Files
In this article, we’ll explore manual file recovery using hashes and leverage the powerful git cherry-pick command to streamline your workflow.
Introduction.
To begin with, git is a tool, and it is essential for every developer working with a team. Being good at it feels really awesome and can get your work done easily when working with a team on the same project.
In this guide, we will work on git and how we can recover lost files in git manually and using Cherry pick. We will demo using examples to get your hands on.
Prerequisites
Knowledge on git is essential in this guide, you should also be able to know the basics of terminal commands.
Terminologies
- git commit: A commit is a snapshot of your repository at a specific point in time. Each commit has a unique hash identifier.
- git cherry-pick: This command allows you to apply the changes introduced by existing commits from another branch into your current branch.
- git checkout: This command is used to switch branches or restore working tree files. It can be used to recover files from a previous commit.
- git-reflog: Reflog is a mechanism in Git that records updates to the tips of branches and other references. It allows you to view the history of all actions performed in your repository, even those not reachable by branches. This can be particularly useful for recovering lost commits, which come in handy at a later stage in this article.
Basic usage
git reflog -3
The output will look something like this below.
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2F8414add6500bca45e212c8f07da53094788492cf-815x97.jpg%3Fw%3D815%26auto%3Dformat&w=3840&q=75)
Its shortcut is: git reflog show HEAD
For example, HEAD@{1} means "where HEAD used to be one move ago".
You can have it followed by the number (optional) to give you how many you want it to show in the front and tail, git reflog -5
and git reflog --tail -3
OPTIONS
git reflog
accepts different options, including:
--verbose
: Provides detailed information about each entry.--rewrite
: Adjusts the reflog entries to reflect changes such as rewritten commits.-n
: Limits the number of entries displayed.
And there are many more options to tailor the output to your needs. You can learn more about it here.
The command git reflog -n 2
will return the last two entries in the Git reflog. Each entry in the reflog represents a change or update to the tip of branches or other references. By specifying -n 2
, you're limiting the output to just the two most recent changes.
git reflog -n 2
Here's an example of what the output might look like:
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2F778f103917f1275b5535264aee63e8a361715a3f-815x97.jpg%3Fw%3D815%26auto%3Dformat&w=3840&q=75)
In this example:
f7bc05e (HEAD -> main) HEAD@{0}:
commit:update: subscribe
is the most recent entry.fdcce31 HEAD@{1}:
commit:update: footer
is the second most recent entry.
Each entry shows:
- The commit hash (f7bc05e and fdcce31).
- The reference (e.g., HEAD -> main).
- The reflog entry number (HEAD@{0} and HEAD@{1}).
- The type of action (commit).
- The commit message or description of the action (update: subscribe and update: footer).
Try Kodaschool for free
Click below to sign up and get access to free web, android and iOs challenges.
The Danger Zone: Accidentally deleting a file.
Create a new directory named git-reflog
and navigate into it using the commands mkdir git-reflog
followed by cd git-reflog
. Initialize a Git repository in this directory with the command git init
. Add content to these files; for example, in README.md
, you could start with `# Project Name` and in `CONTRIBUTING.md`, begin with `# Contributing Guidelines`.
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2Fbcda1078e3640dfafeb3eb34032c4aceb46192b0-916x193.jpg%3Fw%3D916%26auto%3Dformat&w=3840&q=75)
Moving forward, let’s add the files to the staging area and commit them. Use the commands git add .
and git commit -m 'first commit'
. As stated earlier, we might work with a team and would want to contribute. Therefore, we need to create a branch where we can make our contributions.
You can do this by running the following command from the main branch (it might be different on your end - my branch is named ‘trunk’): git checkout -b contribute
. This command creates a new branch name contribution (if we don’t already have one) and switches to it.
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2Fc87911483ac0a9c2924ed2b8bd9595bdbddbdf36-916x101.jpg%3Fw%3D916%26auto%3Dformat&w=3840&q=75)
let's make some changes to the changes to the files, you can edit any of the files. You can run this command to add some text to the contributing file. echo 'this is my first message' >> CONTRIBUTING.md
or you can edit it manually, whichever way you like. When you check the status (`git status`) you will see that you've modified the file. You can then add and commit it.
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2Fc64437583f9925977fc583c2bb41c8b71aa5eca5-1524x378.jpg%3Fw%3D1524%26auto%3Dformat&w=3840&q=75)
Deletion
Now let's delete it. We assume that we may delete the branch accidentally by the command git branch -D contribution
but first checkout to your main branch - in my case trunk.
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2Fa9772ffd01d48727b88a7949c212d1537a174e0f-1524x152.jpg%3Fw%3D1524%26auto%3Dformat&w=3840&q=75)
And if you check the branch, you will notice that you only have one branch, the trunk (in my case).
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2F16f6402451794793f002801558ea8b5d253cff30-1524x152.jpg%3Fw%3D1524%26auto%3Dformat&w=3840&q=75)
Now what?
Your hard work of contributing has gone that way? you've completely deleted your branch. If you check the history, you won't find it. How can we recover it? Well, we have 2 ways we can do it.
Manual recovery
First step
The first line of defense. We can use reflog
to recover our lost data. We can reflog the last 3 history commits we made. Run the following command git reflog -2
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2F70ea0df5e7943baac0c9f4494ac3718e1824b2bc-1524x145.jpg%3Fw%3D1524%26auto%3Dformat&w=3840&q=75)
You can see our history and our changes. We see our last commit - update: contributing file
Now that we have the 'sha' - 1279451
. With that, we can rebuild the whole repo just from this little, tiny sha.
Run this command : git cat-file –p 1279451
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2Ff91e019fbcca71d62b87b60fab4bc5531d840743-1524x222.jpg%3Fw%3D1524%26auto%3Dformat&w=3840&q=75)
When you run the above command, you can see it is right here with us. This means that even if we deleted a branch, it doesn't mean we deleted what we've changed. Our files are on the computer. And so, we can retrieve it from git.
Second step
You can go into the tree. You can see earlier we have tree, parent, author ... in the reflog of our 'sha' info.
To check the tree info, you can run the following command:
git cat-file -p 50e8badf9e1cbb8ddad75e5bd095d5a5c34fc0af
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2F548d024f980a9418f265ffdd8a3f6e4f01e2b37b-1524x189.jpg%3Fw%3D1524%26auto%3Dformat&w=3840&q=75)
we can see our blob file, CONTRIBUTING.md.
then if we then `cat-file` it with the following command,
git cat-file -p 8e835656024de97bbf7cfe5cfe858dad9d810a7d
we can see what we wrote/updated earlier.
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2F974dc4b04b6d25d0dd654d1609984f8bb746d98c-1524x118.jpg%3Fw%3D1524%26auto%3Dformat&w=3840&q=75)
Optional: You can cat it out into a different file and save it there. that's it. You can do the same with files that you created differently and cat it out the changes.
You're now getting a promotion. Let's keep going.
That seems hard to go by. Well, we have a quicker and easier way to do it. This might be your first time hearing it, if not, well let's get along, it is by using the Cherry-pick.
Advanced Recovery: Using Git Cherry-Pick
remember we had our `sha' earlier and how to get it, right? 1e3b6f3. And if I would need these changes to my 'trunk' branch I would just merge it using the same sha by running:
git merge 1279451
![Image](/_next/image?url=https%3A%2F%2Fcdn.sanity.io%2Fimages%2Fbu96b58t%2Fproduction%2Fee4d5d2cdcd07b0084954d279bdde35f1390e7ca-1524x163.jpg%3Fw%3D1524%26auto%3Dformat&w=3840&q=75)
Look at that, we have our changes we made on contributing branches to our trunk branch. We could just bring it in. This is super easy, yeah? We didn't have to do the magical-hacker thing we did earlier right? Yaayyy!!
hint: Your commit ‘sha’ is a key piece of information.
You might think this ends here, NO, this doesn't end here, we may have some problems with merge - If histories have diverged far enough, this could cause some problems as you wouldn't just be merging the one commit, but all the commits in between 1279451
and trunk
.
To solve that is much even easier with cherry pick
. Given one or more existing commits, apply the change each one introduces, recording a new commit for each. This requires your working tree to be clean (no modifications from the HEAD commit).
You can learn a bit from it by running the man's thingy man git-cherry-pick
.
Cherry pick allows you to take just one or more commits, specifically. Maybe at any time you just have that change and don't want to merge it, you can cherry pick it in. It works with remotes - as long as you're up to date with it and you can cherry pick it in if you need to.
Cherry-pick
Well, the ball this time is on you, if you did not merge the above changes, you can cherry pick it by running the following command. git cherry-pick: git cherry-pick 1279451
. And that's it, you will merge right in. Fantastic.
References
Git documentation: git reflog
Conclusion
Recovering accidentally deleted files in Git can be straightforward if you know the right commands. By utilizing git reflog and git cherry-pick, you can easily restore lost files and continue your work seamlessly. Practice these methods to become proficient in handling such situations.