
How to undo almost anything with Git (2015) - ljiljana
https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/
======
nneonneo
Also worth noting: you can abort and undo many kinds of in-progress operations
with “git <operation> —abort”. Works for merge, rebase, and a few other
things, and can seriously save your bacon when you do a “git merge
<badbranch>” and are suddenly confronted with a bazillion merge conflicts.

Also, if you’re in a panic because something went screwy, check “git status”
and read every line carefully. status tells you a lot more than you might
expect - what branch you’re on, if you’re even on a branch, what
merge/rebase/commit operation you’re in the middle of (if any), and even how
to go forward with or back out of the current operation.

Finally, commit regularly and often! reflog and rebase mean that you can
always maintain a clean history if you want, while committing makes sure that
your changes are properly tracked and saved by git so you can rewind when
needed. Once you get comfortable with it, git lets you really practice
fearless experimentation, which unlocked a whole new level of productivity for
me.

~~~
Doxin
> check “git status” and read every line carefully.

Seconded, but I'd go even further. Run and read git status before and after
running _any_ git command until you get comfortable enough with git to where
you can predict the output without running it.

Additionally you can go get git prompt[1] installed so you always know your
git status at a glance. Saves a lot of typing in any case.

As a last suggestion I'd say go read git-scm.com[2]. It has the excellently
written man pages for looking up what a command does and which flags it takes.
It also has an amazingly written free ebook explaining git top-to-bottom.
After reading that you'll be a git wizard compared to your peers.

[1]
[https://github.com/git/git/blob/master/contrib/completion/gi...](https://github.com/git/git/blob/master/contrib/completion/git-
prompt.sh) [2] [https://git-scm.com/](https://git-scm.com/)

~~~
tduberne
I totally second reading the book front to back. It is not that long and
fairly well written, and can save so much time and frustration in the long
run. Giving the link is the first thing I do when helping someone with git.

Unfortunately so many people put that aside and never read it, and then come
back to me a few weeks later because they messed everything up again, and
still do not understand what I mean with "index".

Git is very powerful but a bit awkward, so I consider knowing the underlying
concepts necessary to use it properly.

~~~
Doxin
I don't even think git is all that awkward. It's incredibly elegant but that
also makes it somewhat orthogonal compared to how you're used to think about
stuff.

I dunno, git is probably one of the few instances where I feel like RTFM is a
valid remark.

------
onekorg
The thing that made git click for me was to understand the data structures
that make git work.

There's beauty and elegance in the implementation details of git. You can do
and undo with confidence once you can translate the changes you want to make
to git object transformations.

To get an overview of the concepts behind git I recommend this article by one
of the GitHub founders: [http://tom.preston-werner.com/2009/05/19/the-git-
parable.htm...](http://tom.preston-werner.com/2009/05/19/the-git-parable.html)

To understand the data structures I suggest:
[https://codewords.recurse.com/issues/two/git-from-the-
inside...](https://codewords.recurse.com/issues/two/git-from-the-inside-out)

~~~
hrgiger
Here also my 'git from scratch' TODO for the new year list :
[https://wyag.thb.lt/](https://wyag.thb.lt/)

~~~
anongraddebt
This looks great!

------
godot
I'm actually somewhat surprised that this wasn't mentioned in the comments
yet: [https://ohshitgit.com/](https://ohshitgit.com/) Which is a page that
covers common mistakes using git and quick ways to fix your mistakes. I've
found myself making a mistake mentioned on this page with regularity and
always refer to the site to help myself fix it quickly.

(It looks like they have a swearing-safe version now at
[https://dangitgit.com/](https://dangitgit.com/))

~~~
Stratoscope
If you have to use the command line, those "gosh darn it git" sites have some
good recipes. Because if the problem is "I accidentally committed to the wrong
branch!" who is going to remember all this off the top of their head:

    
    
      # undo the last commit, but leave the changes available
      git reset HEAD~ --soft
      git stash
      # move to the correct branch
      git checkout name-of-the-correct-branch
      git stash pop
      git add . # or add individual files
      git commit -m "your message here";
      # now your changes are on the correct branch
    

Or you can use a powerful GUI like SmartGit. Then you don't have to memorize
anything or look up a recipe. For the situation above, you simply drag your
branch markers to where you want them in the log. Done!

Similarly, for situations where you would look up hashes in the reflog, just
click the Recyclable Commits checkbox, and everything in the reflog shows up
as ordinary commits in the same commit tree as everything else. You can even
see diffs between the reflog commits and your regular commits without having
to do any temporary checkouts.

I know many developers like the command line and don't want to consider using
a GUI. But I encourage you to give SmartGit a try. It works in conjunction
with the command line, so you you're not locked into the GUI, you can use
either one whenever you want.

~~~
maksimum
> It works in conjunction with the command line

Do you know of git GUIs that explicitly maintain a bijection between the GUI
and the underlying command history? It'd be cool to use the GUI and see the
command history, or use the CLI and see updates in the GUI.

~~~
Stratoscope
I'm not sure if this is exactly what you're looking for, but maybe close?
SmartGit has an Output window that shows the underlying Git commands that it
uses when you drag things around or use its commands. And if you make changes
in the command line and then switch back to the SmartGit window, it updates to
match.

------
3pt14159
It has always bugged me that

    
    
        git commit --amend 
    

Doesn't automatically resign (or fail to resign if the key isn't available) a
signed git commit message. Anytime there is a non-verified git commit message
in my history you can be sure it's because I was a dummy on the original
message.

~~~
stouset
Wait, seriously? I sign all my commits as habit and I `--amend` regularly. If
this means my signature histories are broken…

~~~
sadjad

      git config commit.gpgsign true

~~~
stouset
I already have this set, which is how I sign all my commits. If that ensures
`git commit --amend` re-signs, then I'm happy.

~~~
sadjad
AFAIK, it does.

------
kbenson
This flowchart[1] has been useful to me a few times when I've been lost on how
to fix something. I usually keep it as a bookmark, but I don't have it saved
on this computer, so I just did a google image search and was able to fine it
fairly quickly. A google image search for "git solution workflow" or "git fix
flowchart" finds it right away, in case this tickles your brain in the future
and you want to find it again, and vaguely remember it's easy to find through
image search.

Edit: Updated the link to go to the site referenced in the image. Might as
well send you to who developed it so they get some credit.

1: [http://justinhileman.info/article/git-
pretty/](http://justinhileman.info/article/git-pretty/)

~~~
thefunnyman
Why does the rebase command here include the --force flag? I don't think it's
necessary.

------
RickJWagner
Git is one of those once-a-decade technologies that's compicated, user un-
friendly, takes months to master and is absolutely worth it.

~~~
karmakaze
Git shouldn't take months to master if you can understand it conceptually
rather than by use-cases. If instead of trying to learn commands to affect the
working directory, staged files, or history, you learn how git organizes
historical tree of commit hashes, then base what each operation does, it
becomes much clearer. It's similar to trying to learn strings of shell pipe
commands to get things done rather than realizing that there's pieces of work
that each command can do. One tip is to use (even very temporary) branches
rather than `stash`es unless it's absolutely short lived. And if you ever get
lost, `reflog` is your friend.

For me, I had trouble first using `git` after experience with `cvs` and
`subversion`. At some point, everything clicked because I inferred its
internal model.

~~~
DaiPlusPlus
git’s problem to newcomers - even people without any prior experience with
diff-paradigm systems like SVN and TFS - is the idea of a commit representing
a snapshot of a file system is difficult to comprehend because it feels so
crazy and impractical (especially as CS101 makes a huge deal about
computational complexity). The fact that git internally is actually quite
efficient is buried in heavy articles about git’s plumbing.

Oh, and the fact that a ‘git checkout’ is an unrelated concept to ‘svn
checkout’ - and how SVN branches are “spatial” compared to git’s “parallel-
universes” model is also a source of confusion.

If I could go back in time to 2005 (in addition to getting in super early on
bitcoin) I’d beg Linus to not reuse SVN terminology. Personally I’d go with
“git switch” instead of checkout, and “timeline” or “line” for short instead
of “branch”. The fact that git branches are not 1-connected graph routes is
enough reason not to call them “branches”.

I’d also convince him to include a “gitd” mode that would automatically fetch
from upstream and automatically add commits when it detects file-move/rename
changes. (I understand why git doesn’t have an exact “rename” op, but tooling
today still isn’t good enough to detect rename-then-edit or rename-then-split
operations without an intermediate rename-only commit. My dream “gitd” would
also make auto-commits every 30 seconds just to give me a powerful filesystem
undo feature. If you had hours of work that resulted in new files before you
staged them and you accidentally did a hard reset then you’re sol - and this
has happened to me already :/

~~~
thinkingemote
When I used to use NetBeans the main feature I loved was the history feature.

Basically every save to every file was stored and diffable in a kind of self
contained repo.

I've missed this feature in every other editor since.

~~~
qw
IntelliJ IDEA has that feature (local history)

~~~
james_s_tayler
Can confirm.

------
deft
This page is from 2015 yet hasn't once came up on my searches to do a bunch of
these things. Thanks for resharing.

------
dang
Discussed at the time:
[https://news.ycombinator.com/item?id=9679367](https://news.ycombinator.com/item?id=9679367)

~~~
noir_lord
Managed to miss this first time, this is cool.

Also Merry Christmas and Happy New Year.

------
chx
Except you can't undo git reset --hard unless of course you build a safety
net.
[https://gist.github.com/chx/3a694c2a077451e3d446f85546bb9278](https://gist.github.com/chx/3a694c2a077451e3d446f85546bb9278)

------
saboot
For several months now I've been wondering how to get rid of a 700 MB data
file that was accidentally committed to our shared git repo. Now everyone has
it, and a clean pull takes forever. Appreciate any thoughts.

~~~
Trisell
You should be able to run a command that cleans the git tree of the file in
all commits. I’ve had to do it because of committed passwords in files.

[https://stackoverflow.com/questions/35115585/remove-file-
fro...](https://stackoverflow.com/questions/35115585/remove-file-from-all-
commits)

~~~
karmakaze
When using `git filter-branch` it's much faster (up to 100x) to use the
`--index-filter` option rather than `--tree-filter` as it only updates the git
history and not the working directory. Docs and examples at [https://git-
scm.com/docs/git-filter-branch](https://git-scm.com/docs/git-filter-branch)

------
sadness2
Not reading. Nothing is ever as good as this flow chart:
[http://sethrobertson.github.io/GitFixUm/fixup.html](http://sethrobertson.github.io/GitFixUm/fixup.html)

------
SlowRobotAhead
> You started a new branch feature based on master, but master was pretty far
> behind origin/master

I’m bad at git. So... wait what now?

When is Master not Origin/Master? I don’t understand what is going on there.
Explain?

~~~
godot
It means your local master is behind remote origin/master. (i.e. you needed to
git pull)

~~~
SlowRobotAhead
OHH... ok! That makes sense. My last two projects I’ve been the only one
committing so this pretty much can’t happen. Thanks.

------
juliangamble
It's missing git revert merges

    
    
      git revert -m 1 88113a64a21bf8a51409ee2a1321442fd08db705

~~~
chrisweekly
PSA: You can safely refer to those long "commit-ish" identifiers using just
the first 7 or 8 chars (eg `88113a64`) without real risk of collision. Let
alone in examples / gists!

~~~
lpghatguy
Git will even warn you if the hash prefix you provide is ambiguous!

I had a collision the other day on a mediums-sized when using a 6 character
hash and was surprised. Git let me know and told me which objects collided.

~~~
maksimum
Wow, that's super unlikely. How many commits did the repo have?

According to [1] using 3 letters you'd need at least 72 commits to have at
least 50% chance to observe a clash. Using 6 letters you'd need at least 3977
commits, lol.

[1]
[https://en.wikipedia.org/wiki/Birthday_problem#The_generaliz...](https://en.wikipedia.org/wiki/Birthday_problem#The_generalized_birthday_problem)

~~~
mikestew
I’ve been using git for going on ten years. You don’t think I can pull off
just one commit/day?

I use six character hashes, I don’t recall that I’ve had a collision yet. But
I guess I’m “due”. :-)

------
amelius
But can it also undo the undo?

Anyway, shouldn't git just come with a "undo" command?

~~~
fiddlerwoaroof
Yes

------
jldugger
git-extras has a tool called `git undo`. It's just a fancy wrapper around `git
reset --soft HEAD` though.

~~~
UweSchmidt
Well you never know what these wrappers and aliases do, and ultimately need to
understand what goes on under the hood.

Intellij has a "shelve" command, I decided to stick with "git stash". Magit
has the "i", that does "ignore" but also cleans up already committed files,
something like "git rm -r --cached ."

------
crazypython
I use GitUp.

------
m4r35n357
TLDR: Reflog. That is all.

