git Lost and Found
I got asked a git question the other day and thought I should blog my reply.
Is it safe to run this?
git branch -f master origin/master
To which I replied: Yes, with a but.
##The But? Any local commits you have maybe orphaned.
##Why?
What you need to know about that command is that if (and let’s assume it does) the branch master
exists, then
the -f
switch will mean that the local branch gets reset to the remote branch, thus removing any local commits.
See the Options section under Branching in the manual, http://git-scm.com/docs/git-branch, for more.
##Let’s see what I mean
We will work with a local repository and two branches for this example.
E:\_scratch\gitlostfound> git init
Initialized empty Git repository in E:/_scratch/gitlostfound/.git/
E:\_scratch\gitlostfound [master]> "first test" | Out-File first.txt
E:\_scratch\gitlostfound [master]> git add . ; git commit -m "First file"
[master (root-commit) b5ee354] First file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 first.txt
E:\_scratch\gitlostfound [master]> "second test" | Out-File second.txt
E:\_scratch\gitlostfound [master]> git add . ; git commit -m "Second file"
[master d986f3b] Second file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 second.txt
E:\_scratch\gitlostfound [master]> git checkout -b somebranch
Switched to a new branch 'somebranch'
E:\_scratch\gitlostfound [somebranch]> "third test" | Out-File third.txt
E:\_scratch\gitlostfound [somebranch]> git add . ; git commit -m "Third file"
[somebranch f4203be] Third file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 third.txt
E:\_scratch\gitlostfound [somebranch]> "fourth test" | Out-File fourth.txt
E:\_scratch\gitlostfound [somebranch]> git add . ; git commit -m "Fourth file"
[somebranch ef3ce58] Fourth file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 fourth.txt
E:\_scratch\gitlostfound [somebranch]> git checkout master
Switched to branch 'master'
E:\_scratch\gitlostfound [master]> "fifth test" | Out-File fifth.txt
E:\_scratch\gitlostfound [master]> git add . ; git commit -m "Fifth file"
[master 693e3b1] Fifth file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 fifth.txt
E:\_scratch\gitlostfound [master]> git log --graph --abbrev-commit --decorate --format=format:'%C(bold normal)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all
* 693e3b1 - Fri, 9 May 2014 10:23:52 +1000 (65 seconds ago) (HEAD, master)
| ' Fifth file - Jonathan Bourke
| * ef3ce58 - Fri, 9 May 2014 10:23:09 +1000 (2 minutes ago) (somebranch)
| | ' Fourth file - Jonathan Bourke
| * f4203be - Fri, 9 May 2014 10:22:52 +1000 (2 minutes ago)
|/ ' Third file - Jonathan Bourke
* d986f3b - Fri, 9 May 2014 10:21:02 +1000 (4 minutes ago)
| ' Second file - Jonathan Bourke
* b5ee354 - Fri, 9 May 2014 10:19:40 +1000 (5 minutes ago)
' First file - Jonathan Bourke
E:\_scratch\gitlostfound [master]>
So after all that what we have is a repository with two branches. Now if we run the branch reset command that was mentioned at this start of this post an interesting thing occurs. Let’s take a look…
E:\_scratch\gitlostfound [master]> git branch -f somebranch master
E:\_scratch\gitlostfound [master]> git log --graph --abbrev-commit --decorate --format=format:'%C(bold normal)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all
* 693e3b1 - Fri, 9 May 2014 10:23:52 +1000 (4 minutes ago) (HEAD, somebranch, master)
| ' Fifth file - Jonathan Bourke
* d986f3b - Fri, 9 May 2014 10:21:02 +1000 (7 minutes ago)
| ' Second file - Jonathan Bourke
* b5ee354 - Fri, 9 May 2014 10:19:40 +1000 (8 minutes ago)
' First file - Jonathan Bourke
E:\_scratch\gitlostfound [master]>
Where’d the work on somebranch
go?
##How do you get them back?
First we need to switch back to somebranch
. This is very important because if we perform the next steps in
master
then the history will show that the work was originally done there and not in somebranch
.
E:\_scratch\gitlostfound [master]> git checkout somebranch
Switched to branch 'somebranch'
E:\_scratch\gitlostfound [somebranch]> git fsck --lost-found
Checking object directories: 100% (256/256), done.
dangling commit ef3ce583d09f7b438c06da450f33620043cd2ce6
E:\_scratch\gitlostfound [somebranch]>
Once you ascertain which commits to reapply, simply merge that commit:
E:\_scratch\gitlostfound [somebranch]> git merge ef3ce58
Merge made by the 'recursive' strategy.
fourth.txt | Bin 0 -> 28 bytes
third.txt | Bin 0 -> 26 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 fourth.txt
create mode 100644 third.txt
E:\_scratch\gitlostfound [somebranch]> git log --graph --abbrev-commit --decorate --format=format:'%C(bold normal)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all
* 9e45311 - Fri, 9 May 2014 10:29:19 +1000 (5 seconds ago) (HEAD, somebranch)
|\ ' Merge commit 'ef3ce58' - Jonathan Bourke
| * ef3ce58 - Fri, 9 May 2014 10:23:09 +1000 (6 minutes ago)
| | ' Fourth file - Jonathan Bourke
| * f4203be - Fri, 9 May 2014 10:22:52 +1000 (7 minutes ago)
| | ' Third file - Jonathan Bourke
* | 693e3b1 - Fri, 9 May 2014 10:23:52 +1000 (6 minutes ago) (master)
|/ ' Fifth file - Jonathan Bourke
* d986f3b - Fri, 9 May 2014 10:21:02 +1000 (8 minutes ago)
| ' Second file - Jonathan Bourke
* b5ee354 - Fri, 9 May 2014 10:19:40 +1000 (10 minutes ago)
' First file - Jonathan Bourke
E:\_scratch\gitlostfound [somebranch]>
Done! Of course this is a very simply example, your mileage may vary.