Common Git Problems and How to Fix Them
citizen428.net
citizen428.net
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.
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.
* to actively work on open-source projects,
* for learning or teaching on a public academic institution,
* in the spare time to manage projects where you don't get financial compensation for (hobby usage),
* by public charitable organizations primarily targeting philanthropy, health research, education or social well-being.
(Wording is from their license, English is not their first language.)
https://www.syntevo.com/documents/smartgit-license.html
For open source alternatives, a few people I've worked with like SourceTree. I don't think it has the integrated reflog though. I'd be curious about other recommendations too.
The cost of context switching between different tools because of it's licensing makes it a non-starter to use one for open source and the other for commercial work.
Granted, the cost of a tool is minuscule compared to the potential gains from speed of development, and any corporation that balks at paying for tools for their developers won't be in business very long, I still find myself penny pinching and using free and or open source tools, even if inferior or lacking in just one or two bits of functionality.
Hardly anyone is on your hourly rate...
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.
This is also the case with vim. There is the gundo plugin to display a nice tree to navigate, but you can navigate it on stock vim with g- and g+. Emacs C-/ is actually equivalent to vim's g- and not the u command.
EDIT: I wish emacs had something like vim's g+ to move forward in that history. If I wanted to move back to "bar" after the undos that I did, I'd have to undo the undo of the undo with C-/, and undo the undo of the insert with C-/. Then, if I wanted to get back to "foo" again, I'd have to undo the undo of the undo of the insert with C-/, and then undo the undo of the undo of the undo with C-/. This can get confusing quickly without the visual display of the tree, but it's just a matter of hitting C-/ enough times to get to where I wanted to be.
EDIT 2: Now that I think about it, C-/ is not equivalent to g-, but it's the closest thing. It's just different models of undo that avoid any loss of state. While vim's model is an actual tree and undos are movements in it, emacs's is a ring and undos are inserted changes at the end of the ring. In vim you can be at any point of the tree, but in emacs you're always at the end.
EDIT: As to how granular it is, besides :write units, you can specify days, hours, minutes, seconds, or individual change units (the kind that u, g-, and g+ work with. So, `:earlier 10` is the same as `10g-`.
Actually it's enough for the file to hit index (staging area) to be recoverable.
If the latter, how do you do that?
mkdir temp
echo '*' >temp/.gitignore
Quick, dirty, effective. :)Maybe because the article was originally a gist[0] itself.
[0] https://gist.github.com/citizen428/16fb925fcca59ddfb652c7cb2...
https://www.codementor.io/citizen428/git-tutorial-10-common-...
A lot of useful stuff here but not readable until I found this.
[1]: https://help.medium.com/hc/en-us/articles/214550207-Import-p...
[2]: https://gist.github.com/citizen428/16fb925fcca59ddfb652c7cb2...
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 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.
The problem is that the explanations of the commands are wrong.
Reset does not undo a commit. It moves HEAD and updates the work tree. I have no problem with cheat sheets and quick references. Memorizing the commandline interface is not important. Use a cheat sheet. Handwaving over what the commands you are running actually do is asking for trouble.
Edit:
I was witness to a similar debate on IRC the other day. Someone insisted but you can't learn Python without understanding the underlying data model of strings in C. IMO that is ridiculous because the abstraction in Python is close to airtight; you just about never need to think about the implementation of strings when using strings.
Git, on the other hand, frequently exposes implementation details to the user. Casual users are likely to run into edge cases that don't understand. You basically can't resolve rebase conflicts effectively if you don't know what "ours" and "theirs" means. The man pages are indecipherable if you don't know what blobs and trees are. You don't need to teach people that stuff on day one, when they first learn about pull, add, commit, etc. But you had better teach them soon. I see no reason why a discussion of rebase couldn't at least casually explain how it's implemented: "check out base branch, cherry-pick commits from rebased branch", is that so hard? If they don't understand what a common ancestor is, how are they expected to know when to use --onto?
edit: well this one looks interesting https://www.amazon.com/Ingredient-Unveiling-Essential-Elemen...
And here's some books that spend at least as much time talking about how to cook as they do giving lists of ingredients.
_The Zuni Cafe Cookbook_ by Judy Rodgers
_Cooking by Hand_ by Paul Bertolli
The French Laundry book by Thomas Keller is worth a read.
If you're into charcuterie, someone else mentioned Michael Ruhlman; his book _Charcuterie_ with chef Bryan Polcyn is excellent. _The River Cottage Meat Cookbook_ is also good.
If you want to go deep into ingredients, _The Elements of Taste_ by Gray Kunz and Peter Kaminsky (and _The Flavor Bible_ by Karen Page and Andrew Dornenberg (I haven't personally read that one all the way through, though)).
And you can always just pick up a culinary school textbook.
- How to Cook Everything by Mark Bittman (also How to Cook Everything Vegetarian)
- Ratio by Michael Ruhlman
- The Food Lab by J. Kenji Lopez-Alt
- Salt, Fat, Acid, Heat by Samin Nosrat
When I later wrote some teaching material, I realized that there are two bad kinds of educational texts: Cookbooks and math textbooks. One is a simplistic series of steps without explanation, the other is a facts dump with no motivation, context or intuition.
Getting back to git, its documentation manages to combine the disadvantages of both styles: it is a disjointed cookbook where steps are explained in confusing technical terms that only make sense if you already know the theory, which isn't coherently explained.
Edit: And many others too
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.
git diff origin/your-branch..your-branch
to check whether you have made any unintentional changes to the code. For the commits themselves, you can do something like: git log origin/master..origin/your-branch
and git log origin/master..your-branch
to see if the commits differ. You can use the -p switch on the git log commands to see if the diffs have changed. If you do this before pushing up to the remote, then it's much easier to see what you're going to change before you run git push -f.(One of the features of git that I struggle to understand isn't a deal-killer for its adoption is the lack of repo access control; if you want this you have to implement it manually through PRs)
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.
On the flip side, it's a lot easier to do "git add -u" or "git add src/some/folder" for those use cases.
:'<,'>!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.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.
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.
I consider this a UX failure. Give me hg anytime.
1) there's a distinction between the "plumbing" and the "porcelain", and all problems are blamed on the (replaceable) porcelain. So if you don't like it, use different porcelain.
2) Canonical 'git' is the only viable porcelain and we will never fix it.
As long as you avoid dirty state you are guaranteed not to lose work.
You avoid dirty state in three ways.
1. Commit your work frequently in your working branch. You can always squash later using "git reset --soft".
2. Use "git stash".
3. Create throwaway directories if all you want to do is keep your experimental files handy:
mkdir temp
echo '*' >temp/.gitignore
Just like C forces you to be aware of how data structures are allocated internally, git forces you to have hygiene about your local file state.The only "real" problem is when your git admin fails to pay attention and make sure the top-level .gitignore and .gitattributes are set up correctly.
https://www.codementor.io/citizen428/git-tutorial-10-common-...
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.
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
God help you if you're doing front-end development, with deep node_modules and build processes creating and destroying files.
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.
function fuckgit
rm -rf /tmp/fuckgit/
git clone --no-checkout (git config --get remote.origin.url) /tmp/fuckgit/
rm -rf .git/
mv /tmp/fuckgit/.git .
rm -rf /tmp/fuckgit/
endYou use /tmp in an insecure way. Please use "mktemp -d" for creating temporary directories.
That problem is a depressing one and not uncommon [1]