Hacker News new | past | comments | ask | show | jobs | submit login
Git Cheat Sheet (gist.github.com)
182 points by akras14 on Dec 14, 2016 | hide | past | favorite | 57 comments



I think that while Git would be great as a library, as a front-facing program it's UX could do an improvement:

A good UX is simple things should be simple, but complicated things should be possible, but now look at the following "basic" git workflow:

1. Add. I want git to track this file. Yes, sometimes I need to add certain lines, files, etc. Keep git add, commit, and push. But have a "git update" or something for beginners (and for 99% of use)

2. History - How can I go through a file to see its history? "git show REV"? What if I want a wikipedia style history? What if I want to go through the history of a file? There should be something like "git history main.c"

3. Undelete file - This is fairly common, yet, the command is

git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"

A command like git undelete $file would probably make life easier.

I haven't gotten to the more complex workflow, and I definitely agree that git is a great revision system, but UX improvements can help

--- EDIT,

Mandatory xkcd

https://xkcd.com/1597/


As someone who spent 13 years using CVS, 8 with SVN and 3 with git, I can only say that I greatly disagree with you. The idea of adding a file to track, committing locally and pushing your commits on a branch to a remote makes perfect sense if you spend the thirty minutes it takes to learn what git actually does. Moreover, this is the minimum number of commands to effectively use git correctly.


1. Sure, if you're an expert, each command is useful. Practically, I commit only when it's ready (building, passes tests). So why would you commit without pushing (unless you're offline)?

2. I know what it does. I've read some manuals :) . The thing is

a. I'm not a VC (Version Control) expert, and most people aren't being paid to be VC experts.

They're paid to produce code.

Now, I (unlike a lot of people) don't mind spending some time learning my text editor (vi) which I use eight hours a day, but I'm not going to become an expert in a tool I use five times a day at most.

I just don't interact with it that often.

b. Good software is really meant to be gradual interaction. Take vi (which is infamous for being complicated) for example, to use vi, you need to know about 4 or 5 commands, each of which is a single letter or two letters at most, "i" to insert, "x" to delete, ":w" to write and ":q" to quit. Now you can use vi as a glorified notepad.

You need a more complicated workflow, you need to copy,paste, undo, fine. Learn each one as you need it.

And this is one of the more obtuse text-editing programs.

Honestly, if I used a text editor as often as I use git, I'd use nano or something.


If you commit whenever you complete a feature, or fix a bug, you'll quickly see the benefits. You can look back and see exactly why you made a change, or where you introduced a bug. And the best feature is being able to make a branch for dev (or each new feature you are adding), and be able to switch to master if there's a bug you need to fix.

Also, if you work with more than one person, committing early and often is invaluable.

Really, Git takes like an hour to learn. You could also just download tortoisegit if you really want to be lazy about it.



> Sure, if you're an expert (...)

> I'm not a VC (Version Control) expert, and most people aren't being paid to be VC experts.

I agree that git could probably use some UI improvements, but to counterweight that - you're a paid professional, it's expected of you to learn the tools of the trade. It's like saying that carpenters are not being paid to know how to use saws and powerdrills.

You can simplify a tool only so much before it starts losing its utility.

--

People's refusal to sit down and spend literally half an hour learning to use something is astounding. Is that the "distraction culture" at work?


I commit often in scenarios where feature I'm working on is complicated and I've broken it down to smaller tasks. When I finish one task A and move on to B, I might end up in situation where A is not actually supporting B so I might need to refactor A . So when I finish A,B and C, refactoring for for A is not needed anymore and in this point, if I wouldn't have the history of modifications to A, I would need to rewrite it, or at least parts instead of just reverting.

And finally, I squash all commits to a single feature commit.


Two people have already described why the git process is so powerful. However, let's put some context to what you are saying. 'git add', 'git commit' and 'git push' take a grand total of 25 characters (including spaces) for three commands. If this is too much overhead and gets in the way of producing, I'd hate to see how much writing a switch statement gets in the way of producing.


> Practically, I commit only when it's ready (building, passes tests). So why would you commit without pushing (unless you're offline)?

I haven't set up a VCS server yet. I've fixed a security issue and haven't hit the embargo date yet. I'm doing exploratory coding (prototypes, refactorings, etc.) that may be discarded or reworked, even if it builds and passes tests right now. It passes all local tests but needs to be fuzz tested overnight before I'm satisfied enough to commit it upstream - but want to keep working in the meantime. I have more related changes to make before wanting to sic reviewers or the CI build process on my changes. I want to push my changes to a dev environment, but not a production environment just yet. I want to rebase to make my history look cleaner, but can't be bothered with doing so just yet.

I commit when it's not ready: I use WIP commits instead of stashes, and sometimes commit more often than I build. This has advantages: It can keep the individual diffs cleaner - an autoreformatting of a file to fix whitespace issues, and hand-implemented refactoring, should be separate commits for cleaner, more readable and reviewable diffs. This has drawbacks: In a centralized VCS, these will either get merged together into one messy commit (common), or they'll get blindly commited without (re)building for all permutations and occasionally break the build, or you'll slow everything down painstakingly testing the entire build after every minor permutation.

> but I'm not going to become an expert in a tool I use five times a day at most.

I'm no expert either. That said: In the interests of smaller, simpler, more reviewable changes - both for whoever might be doing a code review, and for myself if I mess up and want to figure out what I've done in the past few minutes to break something - I interact with my VCS much more frequently.

There are days I make 30 or so commits, and I likely diffed each commit multiple times before committing and/or submitting.

Aside from making it way easier to figure out what the hell it is that I've done, being able to finger a specific small changelist as having broken something has saved me tons of time I'd otherwise squander on false leads and disbelief. One of the nastiest heisenbugs I've had the misfortune to debug, I manually did the equivalent of a 'git bisect' on a perforce repository to track down the offending commit for. Totally innocuous change, totally to blame for a fruitless 2 week session of debugging in vain thanks to a buggy system API it used. So innocuous and seemingly unrelated, that I had to reproduce the issue in a simple test app to convince myself it was really the problem. I could've easily wasted another 2 weeks had the changelist been a little bit larger.

.

TL;DR: Smaller commits have saved me months of work, I figure. Committing without pushing lets me commit without shifting gears, encouraging smaller commits.


> 2. History - How can I go through a file to see its history? "git show REV"? What if I want a wikipedia style history? What if I want to go through the history of a file? There should be something like "git history main.c"

    git log --stat --patch -- main.c


Make that an alias:

    git config --global alias.history "log --stat --patch --"


What would "update" actually do?

For history, "git log", that is "git log file".

Isn't part three the same as "git checkout HEAD~1 -- file" ?


>What would "update" actually do?

git add . && git commit && git push

>Isn't part three the same as "git checkout HEAD~1 -- file" ?

What if the delete took place three commits ago?


> What if the delete took place three commits ago?

The original command he was suggesting a replacement for used `-n 1`, so it seems kind of silly to point this out to him.


Ah okay. I can see that.

Then you use HEAD~3.


But you first have to find in which commit you deleted the file.


Ah ha, we're starting from different assumptions. Makes sense now, thank you!


As soon as a command requires stuff as "HEAD" and "~" I believe there should be an easier way.


Yep. I really hope someone forks git with these ideas ...


I don't even know if it has to be a fork, maybe a few batch/python scripts could be enough.

The problem is that frequently by the time people become experts in a field, they no longer see the beginner's difficulties.


your 2nd para is gold. I believe this explains the phenomenon where when you join a new company or parachute into a new codebase for the first time, its often painful ramping up. because so much tribal knowledge is undocumented. or docs not kept updated and wrong. or each dev has their own workflow that works for them privately but nobody's maintaining a common one a newbie can use to get started. some shops/projects better about it than others, obviously.


No need for so much work.

Simple commands can be accomplished by adding a git alias. More complex commands can be just a shell script. Put it on PATH with a name like `git-something` and now you can run `git something`.


Yes, git's "frontend" is complicated and confusing. There are a plethora of tools that purport to replace it, partially or fully, with something more intuitive. Just off the top of my head:

http://gitless.com/

http://www.git-legit.org/

However, they never seem to really take off. Why is that? One thought is also a mandatory XKCD: http://xkcd.com/927/


I think most people just have the 5-6 obscure/painful commands they execute more than once a year stuck in an alias, and don't have a strong enough need for Yet Another Thing to Install on fresh systems.

It's also sometimes hard to know what exactly these extra commands will do if you don't use them often enough to know, so safe use still involves checking the docs, at which point you may as well google for "git [description of thing I need to do]"


After having worked with people that were absolutely hell bent on never using the CLI version of git (and having helped them fix the screwups of their GUI tools a good number of times), I actually think most people would be better off trying to understand how git works internally a little bit more instead of just installing another tool after the last one disappointed them. I don't say you'll have to be an expert, but not having a clue what the tool actually tries to do doesn't really help in those cases (neither does it if you want to do something complicated in SVN, for example) - and the abstractions GUIs add on top of git are bound to break sometime.

That is - of course - if you are using git in more than just some basic way. If you're the single person committing code, it will "work" anyway. Perhaps that's the problem: Some people don't see that collaborating on the same set of files in more usable, but also more complex ways (than they are used to) requires more orchestration than just "lock - update - release"...


Thanks for posting the xkcd comic. I was intrigued by the phrase "distributed graph theory tree model." It is definitely missing some hyphens. Ultimately I decided it should be "distributed graph-theory-tree model." That is, "graph theory" is an adjective modifying tree, and tree is an adjective modifying model.


Don't you use an ide/sourcetree ? All that functionality is available.


I'm going to describe a small issue I've been having with Git that I've tried Googling for in the past but have never found a solution.

I use a custom `git log` alias that prints out a nicely colored commit graph.

  [alias]
    lg = log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all -n 15
The issue is that this includes everyone else's branches that have been pushed to origin. I only want to see the history for local branches. (I guess I'd also want to be able to see origin/master, but I recognize that there's nothing distinguishing that from the other branches on origin I don't want to see.)

I think the issue is that I run `git pull --prune` to get rid of any remote branches that have been deleted. I usually do this after I pull master, so I think I should just be running `git pull origin master --prune` as a single command.


Replace `--all` with `origin/master --branches`.


A version control system should be simple. Engineers should be able to focus on getting things to work/done, not battling with a complicated, confusing version control system.

Most engineers should be performing two operations/two command s the vast majority of the time:

check-in <latest change> check-out <latest version> or <last good version>

If a file is new, check-in should ask you if you want to add it to the project.

That should be it.

The proliferation of tutorials, cheat sheets, books, front end user interfaces like SourceTree for Git is a symptom of a problem.

KISS (Keep It Simple Stupid)


This is what I used to think. Until I started using it. And mind you I'm not a power user - I'm barely a developer at all.

I think the reason that git has this proliferation of tutorials, cheat sheets, etc. is not that it's not easy to use, because (as I've discovered) it is easy to use. No, I think the reason is that people have a pre-conceived intuition of what version control should be, and that intuition is actually wrong. So when they encounter something that does it right (git) it doesn't feel right. The tutorials and cheat sheets help the committed user get over the hump and start to "think git", but if we didn't bring our biases to the party there wouldn't need to be so many of them.

As for front-end interfaces, some of that is an attempt to shoe-horn git into something it isn't, which is dumb. But some of it is just adding visual features that are sometimes nice to have and not easily replicated in a terminal.


For example, how often do you use "staging" (as in not git add .) and how efficient is it's use?

In my workflow, you need a feature - you develop, you build, it works, you commit.

Because think about it like this, you need a feature. You build, it works, then before committing you notice a bug.

You fix it. Now you need to commit in two batches, the new feature and the bug.

This is the commonly given reason for the add/commit/push workflow.

But at some point it's probably faster to either revert, fix bug, then merge with main than to make your staging precise (especially you don't play with staging in your IDE where you can test code as you type)


What? I'd stash the changes I'm working on for the new feature, cut a fresh branch from whatever trunk/master/develop we're using, fix bug, checkout my other branch again, stash pop/apply, and we're back to where we were 10 minutes ago (or 5 days, if that's how long the bug-fix took).

Branches are cheap. Stash is cheap. Use them.


I'm not sure I follow your example exactly...

What works for me (and I am just one person, and - again - not really a professional developer) is that I think in terms of branches. If I want to add a new feature, step one is to create a new branch. I do whatever I want in there, make 1 commit or 50 commits, push to the repo 1 time or 50 times (note that sometimes I might want to push incomplete work so I can load the branch on multiple machines), test in a realistic but isolated environment, fix whatever bugs come up, and generally work however I want to work. Then I merge (or submit a merge request as the case may be) when I'm satisfied. And then I delete the branch, purge it from the repo, may it never be heard from again. If I got something wrong or want to change the work I just submitted, I start over with a new branch.

This is certainly not the only workflow, undoubtedly not the best workflow, and maybe not even a good workflow. And it probably breaks down if your changes are sufficiently complicated (though I avoid this by always working in bite-sized chunks, which I've learned to do the hard way). But it works for me and - as far as anyone on my team has ever told me - my colleagues and collaborators.

I can't comment on git's other features or alternative workflows - I rarely or never use them! But what I described is functional, simple, and covers 100% of the cases I've encountered in my (brief) career in software. And I think for 99% of users just getting started with git, if they just pick a simple workflow and don't fight the way git wants them to do it, they'd also find that git is surprisingly easy to learn and to use.


I use it frequently. Even if I'm only using add ., I check the staging area before I commit.

Reverting wouldn't be faster and wouldn't separate out files that are meant to be committed from those that aren't. It's also harder once you've pushed. So staging is more efficient as well.

I used both cvs and subversion for many years. They have their own complexities, but lack git's ability to manage them.


This is essentially the attitude i referred to earlier [1]. You don't see the problem git is actually trying to solve and project your own "world view" onto it - that's how you come up with sentences like "A VCS should do X."

Version control does consist of more workflows than just yours. If you want to have meaningful collaboration with many people, the model you refer to does not work at all (hell, even in the small team I work in currently, it slows everybody down).

If you're not using gits features, use another tool. You're essentially complaining about the UI of a chainsaw, when what you want to use is an axe.

Also, if you're forced to use git, chances are either you or the person(s) forcing you don't see the full picture.

[1]: https://news.ycombinator.com/item?id=13182911


> The proliferation of tutorials, cheat sheets, books, front end user interfaces like SourceTree for Git is a symptom of a problem.

This is a silly statement. This proliferationi of tutorials only indicates that Git has become a very popular tool and there's a lot of people who decided to take their time to write about it.

If you happen to browse through those tutorials, they are essentially all the same, touch precisely the same basic and trivial use patterns, and are devised to help newbies get up and running in no time.

Initialize a local repository. Check out something from a remote repository. Commit a change. Create a branch. Mergue branches. Pull from a remote repository. Push to a remote repository...

That's all. Very basic stuff.

In fact, can you come up with a single distributed VCS that is simpler and easier to use as Git and provides the same level of functionality?

No, you can't.


Except that doesnt work well for large teams implementing different features in a shared code base. When you have a complex product you may need a complex solution. Which is exactly what git was designed for.


One is welcome to use a "Simple Stupid" VCS for one's own projects. Large complex projects, however, need more. That's why git exists, and that's why large complex projects use git.

git isn't that hard to use anyway. If you have a problem, just look at one of the many online cheat sheets. b^)


> If you have a problem, just look at one of the many online cheat sheets.

Honestly, I'm too scared to break history, or of clogging it up with commits like "let's see, maybe this will work" "nope, last commit is junk, let's try again","junk","junk","arghh",".","." :)


You don't have to experiment on the "canonical" repo. Cloning is easy. If you have some code that isn't checked in and you need to experiment to find the particular method you need to use to check it in, just "git diff" to get a diff file you can move around and apply whenever.


> clogging it up with commits like "let's see, maybe this will work" "nope, last commit is junk, let's try again","junk","junk","arghh",".","." :)

You can use `git rebase` for this, which lets you pick/remove/merge commits.


... and you can use trick of copying your .git directory somewhere safe before doing that in case you mess it up, since copying it back to overwrite your mistake is almost always faster than figuring out the "right" way to fix any given mistake, unless you have a really big repo or a really slow disk. :-)


Can you keep your .git folder in git? :)


Well, stick to subversion then?


Subversion: for those who think branching and copying directories around a directory tree is the same thing.


Well, you need branches (beta, development, release, old-release, etc.)


I always give this interactive cheatsheet [1] to git newbies to help them conceptualize the state transfer.

[1] http://ndpsoftware.com/git-cheatsheet.html


My favourite remains Zack Rusin's, from 9 years ago. The state graph was pretty useful as I was learning:

http://zrusin.blogspot.com/2007/09/git-cheat-sheet.html



My more intermediate-level cheat sheet: https://gingkoapp.com/git-notes


Not as organized as the above two, but having being able to access it from the commandline beats anything:

[1] Client: https://github.com/evidanary/grepg-python [2] Cheat Sheet: https://greppage.com/evidanary/5


At this point we need a Git Cheatheets Cheatsheet.


I'm also maintaining a small Git cheat sheet. It's my personal list of stuff that I always find useful but can never remember how to type.

Let me know if you find it useful!

https://gist.github.com/mplewis/a7563c7cb589048a071b


> # Unstage pending changes, and reset files to pre-commit state. If

If what?


git diff --staged should be in there. I always accidentally add stuff I've had the chance to look at the diff. Then this command comes in handy.


Don't like how it is based around merges. Cherry-pick workflow is so much simpler and provides clean history. "No merges" was the policy in every project I worked.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: