I think the most powerful tool for fixing mistakes is "git reflog". It doesn't fix everything, but it works very well as long as you view git with the right mental model: a git repo is an ever-growing tree of immutable commits, with branches and tags pointing to the most interesting ones. As long as code has ever made it into that tree (by being in any commit at any time), it's recoverable, and reflog lets you trace your steps back to any point in the past on that tree. Supposedly-destructive operations like amend and rebase actually just build the tree at a different point and move branches to other places in the tree, but (pretty much) nothing in the tree is ever destroyed.
For the actually-destructive git commands like checkout and reset, another tool that I'd highly recommend is a "local history" feature in your editor. JetBrains IDEs do this by default, and other editors have plugins for it. It automatically records changes as you make them so you can go back to previous versions of any file. Usually git is enough to save me, but I've also had plenty of times where I make some mistake outside of git commit history and am saved by digging through local history.
SmartGit has a brilliant implementation of the reflog.
The Git command line reflog is just a list of hashes and messages. If you're not sure which of those commits is the one you want, it's a fairly laborious process to dig through them. What if you have several commits with the same message, as will happen if you've rebased or amended any commits?
In SmartGit, you simply click the Recyclable Commits checkbox in the Log view, and now everything in the reflog shows up in the log tree, just like any other commit. You can see immediately the parent of each reflog commit, and to see what you changed, just click one of them as you would any other commit in the log. SmartGit shows the differences immediately.
Same thing for stashes. After all, stashes are really just commits by another name. Click the Stashes checkbox and they show up in the log too.
SmartGit is full of features like this where something cumbersome on the command line is straightforward and easy. I've used it for years and recommend it highly.
> For the actually-destructive git commands like checkout and reset, another tool that I'd highly recommend is a "local history" feature in your editor.
Amen. Both vim and emacs do this by default, too. They keep all changes under a tree, so you can even undo your undos.
Another thing that's saved me from destructive changes is the terminal scrollback buffer, which typically represents a timeline of my work. I have a habit of looking at `git diff` frequently. If I lose any of those because of an accidental `y` in `git checkout -p`, I can just execute `git apply` copy the hunks that I want (with the initial file diff header) and paste them in the same terminal, then Ctrl-D to finish.
> As long as code has ever made it into that tree (by being in any commit at any time), it's recoverable, and reflog lets you trace your steps back to any point in the past on that tree.
Actually it's enough for the file to hit index (staging area) to be recoverable.
I would recommend never using git checkout to clear local changes, and instead recommend either git stash or git stash -p depending on whether you want to save the whole work tree or just part of it. The stash subcommand internally creates commits for the stashed content, so you can probably also get to them via the reflog, though I haven't personally needed to do this.
Understanding reset and checkout is not hard if you understand the underlying data model. If you don't understand te data model, it's all black magic.
Interestingly, I feel the same way about actual recipe books for cooking. It's one thing to keep around as a reference. But if you don't know what a bay leaf tastes like and what it does to a dish, you won't learn anything from someone telling you to use it in a particular recipe.
I don't understand this fad that programmers should know only first principles, and shun checklists in favor of deriving everything from scratch every time.
I know how my car works but I still pull out the service manual when I need to change an air filter. Nothing under the hood is 'black magic' but seeing the procedure written out saves me a ton of time.
And: git commands are hard, even if you understand the underlying data model. (I've only been using it for 8 or 9 years. Maybe I'm just too dumb?) Understanding the data model won't help me remember that the "--amend" flag is how I edit the commit message (though I could probably build it myself from reset + commit, if I really wanted to), or what folder I should put global pre-commit hooks in.
I found the list helpful, with just about everything I would expect in a list such as this.
If I could make one suggestion: I found it to be quite annoying to have to click through to a two-line gist for every single one command. Having those commands be in the article itself would be considerably easier to read.
Better yet, don’t use push —force at all unless you specifically intend to undo commits on the remote. Resolve conflicts locally and never force push to a shared branch.
I really wish they'd switch these around so --force used the lease logic by default and you had to turn it off. I don't think backward compatibility is anywhere near worth the problems this default causes. :/
That's one of the reasons why I've always preferred a GUI for most of my day-to-day operations. It's a lot easier to click "Add Hunk", or CTRL-click a couple lines and click "Unstage Lines", then it is to go through the CLI options for dozens of hunks. Similarly, SourceTree's interactive rebase UI is great, and when I briefly played with Tower's latest beta, they made it as simple as drag-and-drop for individual commits.
On the flip side, it's a lot easier to do "git add -u" or "git add src/some/folder" for those use cases.
I've gone further with this when staging parts of the diff while viewing the output of git diff in vim. You can visually highlight the part of the diff along with the diff header lines and run
:'<,'>!git-apply --cached -
git apply is one of the git "plumbing" commands that can be used to apply patches to the working directory or the git index.
Not only is it a reversible, but it is destructive. It will overwrite untracked changes and even untracked files, without so much as a warning. I personally consider this a critical bug in Git, but apparently the mailing list denizens do not agree with me.
Can someone explain to me the fascination for git, despite the constant stream of "how to fix [insert various git issues]" articles showing it's very difficult to use, at least compared to the alternatives? Most people's work streams only need something as simple as hg, which would also save them a lot of time and hassle.
My personal impression is that it's a fashion thing (people think it's cool to waste a lot of time on git, because git is cool and fixing git problems feels like real work, because you're using your keyboard and all that), but maybe someone has a different perspective.
Out of all these, I wish I could use git bisect the most. Working on large codebases with large teams, the command itself is a godsend.
Unfortunately a PC with Symantec Endpoint Protection makes the filesystem dog slow to the point that the one time I needed it and it should've taken about 13 steps to find where the bug was introduced, it was faster to redo the feature without accessing the previous code
Intrusive anti-virus products imposed by people that don't know better than to click on dodgy porn sites and download and run untrusted binaries is a great way to waste tens of thousands of dollars of developer productivity.
God help you if you're doing front-end development, with deep node_modules and build processes creating and destroying files.
As much as I like rerere, I have had it result in silently[1] producing the wrong end result. Especially since I merge / rebase frequently, and end up recording lots of small conflict resolutions. Always always always check non-clean merges by hand or you'll eventually be surprised.
And sometimes I just resolved it incorrectly once, and now it always does it wrong. Is there a way to make rerere forget a resolution?
[1]: relatively speaking. it doesn't fail / pause the operation, so it's "silent", even though it prints out that it applied a conflict-fix.
[+] [-] alangpierce|7 years ago|reply
For the actually-destructive git commands like checkout and reset, another tool that I'd highly recommend is a "local history" feature in your editor. JetBrains IDEs do this by default, and other editors have plugins for it. It automatically records changes as you make them so you can go back to previous versions of any file. Usually git is enough to save me, but I've also had plenty of times where I make some mistake outside of git commit history and am saved by digging through local history.
[+] [-] Stratoscope|7 years ago|reply
The Git command line reflog is just a list of hashes and messages. If you're not sure which of those commits is the one you want, it's a fairly laborious process to dig through them. What if you have several commits with the same message, as will happen if you've rebased or amended any commits?
In SmartGit, you simply click the Recyclable Commits checkbox in the Log view, and now everything in the reflog shows up in the log tree, just like any other commit. You can see immediately the parent of each reflog commit, and to see what you changed, just click one of them as you would any other commit in the log. SmartGit shows the differences immediately.
Same thing for stashes. After all, stashes are really just commits by another name. Click the Stashes checkbox and they show up in the log too.
SmartGit is full of features like this where something cumbersome on the command line is straightforward and easy. I've used it for years and recommend it highly.
https://www.syntevo.com/smartgit/
[+] [-] jolmg|7 years ago|reply
Amen. Both vim and emacs do this by default, too. They keep all changes under a tree, so you can even undo your undos.
Another thing that's saved me from destructive changes is the terminal scrollback buffer, which typically represents a timeline of my work. I have a habit of looking at `git diff` frequently. If I lose any of those because of an accidental `y` in `git checkout -p`, I can just execute `git apply` copy the hunks that I want (with the initial file diff header) and paste them in the same terminal, then Ctrl-D to finish.
[+] [-] Boulth|7 years ago|reply
Actually it's enough for the file to hit index (staging area) to be recoverable.
[+] [-] eslaught|7 years ago|reply
[+] [-] magoon|7 years ago|reply
[+] [-] michaelmrose|7 years ago|reply
[+] [-] dewiz|7 years ago|reply
[+] [-] apple4ever|7 years ago|reply
[+] [-] andybak|7 years ago|reply
[+] [-] ecthiender|7 years ago|reply
[+] [-] SomeHacker44|7 years ago|reply
[+] [-] sus_007|7 years ago|reply
Maybe because the article was originally a gist[0] itself.
[0] https://gist.github.com/citizen428/16fb925fcca59ddfb652c7cb2...
[+] [-] lilbobbytables|7 years ago|reply
[+] [-] nerdponx|7 years ago|reply
Understanding reset and checkout is not hard if you understand the underlying data model. If you don't understand te data model, it's all black magic.
Interestingly, I feel the same way about actual recipe books for cooking. It's one thing to keep around as a reference. But if you don't know what a bay leaf tastes like and what it does to a dish, you won't learn anything from someone telling you to use it in a particular recipe.
[+] [-] ken|7 years ago|reply
I know how my car works but I still pull out the service manual when I need to change an air filter. Nothing under the hood is 'black magic' but seeing the procedure written out saves me a ton of time.
And: git commands are hard, even if you understand the underlying data model. (I've only been using it for 8 or 9 years. Maybe I'm just too dumb?) Understanding the data model won't help me remember that the "--amend" flag is how I edit the commit message (though I could probably build it myself from reset + commit, if I really wanted to), or what folder I should put global pre-commit hooks in.
[+] [-] ollysb|7 years ago|reply
edit: well this one looks interesting https://www.amazon.com/Ingredient-Unveiling-Essential-Elemen...
[+] [-] levi_n|7 years ago|reply
If I could make one suggestion: I found it to be quite annoying to have to click through to a two-line gist for every single one command. Having those commands be in the article itself would be considerably easier to read.
[+] [-] doodhwala|7 years ago|reply
https://news.ycombinator.com/item?id=17634075
[+] [-] 0x0|7 years ago|reply
[+] [-] fcarraldo|7 years ago|reply
[+] [-] stygiansonic|7 years ago|reply
[+] [-] stormbrew|7 years ago|reply
[+] [-] bostonvaulter2|7 years ago|reply
[+] [-] cdubzzz|7 years ago|reply
[+] [-] hyperpape|7 years ago|reply
[+] [-] magoon|7 years ago|reply
git add -p
for interactive staging. It’ll present each hunk of code with a y/n prompt. This is a good habit to prevent committing any debug code or stray marks.
[+] [-] acemarke|7 years ago|reply
On the flip side, it's a lot easier to do "git add -u" or "git add src/some/folder" for those use cases.
[+] [-] u801e|7 years ago|reply
[+] [-] shocks|7 years ago|reply
[+] [-] Hello71|7 years ago|reply
1. it doesn't clearly say that git checkout with a path is irreversible.
2. it says that git reset --hard is irreversible, which is not correct. (see 3.)
3. it doesn't mention one of the most powerful git features for fixing mistakes, the reflog.
4. git remove is not a git command.
5. gitingore is not a git file.
6. git-amend is not a git command.
7. It doesn't adequately explain why force-pushing causes problems.
It looks like clicking through to the gists was such a pain that even the author didn't proofread them.
[+] [-] nerdponx|7 years ago|reply
git checkout with a path is irreversible
Not only is it a reversible, but it is destructive. It will overwrite untracked changes and even untracked files, without so much as a warning. I personally consider this a critical bug in Git, but apparently the mailing list denizens do not agree with me.
[+] [-] davidgerard|7 years ago|reply
https://www.codementor.io/citizen428/git-tutorial-10-common-...
[+] [-] Tomis02|7 years ago|reply
My personal impression is that it's a fashion thing (people think it's cool to waste a lot of time on git, because git is cool and fixing git problems feels like real work, because you're using your keyboard and all that), but maybe someone has a different perspective.
[+] [-] majewsky|7 years ago|reply
[+] [-] StavrosK|7 years ago|reply
[+] [-] arenaninja|7 years ago|reply
Unfortunately a PC with Symantec Endpoint Protection makes the filesystem dog slow to the point that the one time I needed it and it should've taken about 13 steps to find where the bug was introduced, it was faster to redo the feature without accessing the previous code
[+] [-] megaman22|7 years ago|reply
God help you if you're doing front-end development, with deep node_modules and build processes creating and destroying files.
[+] [-] forg0t_username|7 years ago|reply
[+] [-] majewsky|7 years ago|reply
[+] [-] nottorp|7 years ago|reply
[+] [-] Groxx|7 years ago|reply
And sometimes I just resolved it incorrectly once, and now it always does it wrong. Is there a way to make rerere forget a resolution?
[1]: relatively speaking. it doesn't fail / pause the operation, so it's "silent", even though it prints out that it applied a conflict-fix.
[+] [-] microtherion|7 years ago|reply
[+] [-] StavrosK|7 years ago|reply
[+] [-] jwilk|7 years ago|reply
You use /tmp in an insecure way. Please use "mktemp -d" for creating temporary directories.
[+] [-] paulddraper|7 years ago|reply
That problem is a depressing one and not uncommon [1]
[1] https://stackoverflow.com/q/18678853/1212596
[+] [-] throw7|7 years ago|reply