git checkout -p
Discards the damage piece by piece, not the whole file.
The -p for patch turns discarding into an interrogation: git shows each changed hunk and asks, one by one, whether it should go back to what the index holds. y discards the hunk, n keeps it, e opens the piece for manual editing.
It saves the day when a file mixes a legitimate fix with debugging leftovers: instead of losing everything or doing archaeology in the editor, you throw away only the printlns. Modern porcelain offers the same gesture as git restore -p.
$ git checkout -p helpers.go
diff --git a/helpers.go b/helpers.go
@@ -12,6 +12,7 @@
+ log.Println("depurando aqui")
Discard this hunk from worktree [y,n,q,a,d,e,?]? y