In my master branch, I got 2 files:
file1.txt
file2.txt
I created new branch named b1 from there. In b1, I modified file2.txt, and accidentally deleted file1.txt (from disk, when I open windows explorer to the source folder, file1.txt isn't there). Now I want to keep the changes in file2.txt and recover file1.txt from master (I don't need the deleted version). I switched to master, did a merge to b1, no conflict happened, it said 'all up-to-date' but file1.txt isn't there. What should have I done?Tks.
I think there are several questions you are asking here. The first one appears to be "How do I recover file1.txt
?" Assuming your revision graph looks something like this:
M
(master) o -- o --- o ------o HEAD
\ /
(b1) o -- o -- o
A B C
You can get the previous copy of file1.txt
via git checkout
:
git checkout HEAD~1 -- file1.txt
That will resurrect file1.txt
and stage it in your working copy. You can the git commit
and the file will be back. Note: HEAD~1
says take the first parent of HEAD
, which points to the state of master before you merged b1. If you know the commit id, you can use that instead of HEAD~1
as well.
The other question you seem to be asking is "What should have I done in branch b1 to avoid this?" The most obvious choice would have been not to delete file1.txt
in the first place. But let's assume you thought you needed to, and decided that choice was wrong. Next, let's assume you didn't share branch b1 by pushing the changes somewhere. If you noticed that you deleted the file right away, you could do:
git checkout HEAD~1 -- file1.txt
git commit --amend
That would say, "give me back file1.txt, and then merge that file into the latest commit." This has the effect of appearing like you never removed the file in the first place.
If you didn't notice the file was removed right away, and you had several commits in between, then you may want to look at using git rebase
to fix things up.
If you deleted the file in it's own commit, then you can use git rebase -i
to drop the commit from the history of the branch. Let's suppose that B
was the commit that deleted the file, and that's the only thing done in that commit. While on b1, you'd run something like:
git rebase -i B~1
Remove the line that contains the offending commit (B
), save and exit. Your branch just had it's history re-written without B
in it. For example, I ran git rebase -i
and this was shown in the editor:
pick 40f76a7 removed bar
pick 30a25f5 modified foo
I then dropped 40f76a7
from the list and then left me with:
pick 30a25f5 modified foo
The history now looks like this after you merge:
M
(master) o -- o --- o ------o HEAD
\ /
(b1) o ------- o
A C'
Note the commit id of C'
is different than C
because B
no longer exists, and the parent sha1s are part of the commit id. IOW, the sha1 of C changed because we re-wrote history.
If you removed file1.txt
and had a bunch of other changes in the same commit, then there are a few more steps. First, bring back the file and commit it:
git checkout B~1 -- file1.txt
git commit -m "Reinstate file1.txt"
Let's call the new commit D
. Our revision graph now looks like
M
(master) o -- o --- o -----------o HEAD
\
(b1) o -- o -- o -- o
A B C D
Now, do:
git rebase -i B~1
And move the line containing commit id D
to the just after commit id B
, and change pick
to squash
. For example, I get this when running git rebase -i B~1
:
pick 40f76a7 removed bar plus other changes
pick 30a25f5 modified foo
pick 6177cb7 add bar
6177cb7
is the commit that reinstates bar. So I move it just below 40f76a7
and change the command to squash
:
pick 40f76a7 removed bar plus other changes
squash 6177cb7 fix bar
pick 30a25f5 modified foo
Save and exit. It will ask you to fix up the commit message. Do that. When you're all done, you end up with a history that looks like this:
M
(master) o -- o --- o -----------o HEAD
\
(b1) o -- o -- o
A B' C'
The new B'
no longer removes file1.txt
. At this point, you're ready to merge with master.
A few closing remarks. Be careful with git rebase
. You can lose history, if you aren't careful. Make sure to read the git rebase man page. There is lots of useful information on there. Note: all this work with git rebase
is only necessary if you want to remove the fact that you deleted the file from history. If you're okay with having a commit showing you bringing the file back, then by all means, use git checkout
to restore the file, and commit it. It's far less tedious, and easier for a new git user. git rebase
is pretty advanced, and takes some practice. However, if you invest the time and learn it well, it's really quite useful.
Merging is not something you do in this case, it is normal that Git kept the deletion when merging back to master. If you want to get a file from another branch or tag, it's git checkout master -- filename
.
In your case, you need to cancel the merge before:
git status
shows no change)cancel the merge you made
git reset --hard master@{1}
go back to b1
git checkout b1
checkout file1.txt
from master in your working copy:
git checkout master -- file1.txt
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With