Learn Git Branching
pcottle.github.com
pcottle.github.com
The link everyone should see is the demo: http://pcottle.github.com/learnGitBranching/?demo
That shows a few example commands, the completion of a level, and finishes with the help dialog.
Some interesting technical highlights
- I made heavy use of javascript "Promises" to route control through the entire app. The source code has some nice examples, but it would be callback spaghetti without it
- You can import and export trees to share with your friends ("import tree" and "export tree" commands)
- You can build levels from within the app with "build level". The intro diaog should step you through the process
- It even supports interactive rebasing! Try it out with "git rebase -i HEAD~3"
Git is a fairly complex too that can be explained really well graphically. I never understood what I was doing until I saw diagrams in the git manpages and various books around on the internet. I wanted there to be an interactive form of these diagrams but it didn't exist --- so I built it.
9,000 lines of JS later I have this. There's still some polishing to be done, but I'd love for the community to share their knowledge about different git workflows and different ways to explain git concepts.
I tried to make the bar for contributing as low as possible. You can build a level and submit a pull request without even cloning the repo!
Some notes: I "cheated" and used cherry-pick before it was introduced, not sure if that should or should not be allowed. Sometimes I was frustrated because my graph looked like the goal except for "ghosted" nodes, had to go back and figure out a different way to solve the level the right way. I wished I had an "undo" feature to take back moves rather than resetting everything. Lots more hints would be good, this stuff is hard.
Honestly I learned more git in the last 10 minutes than I've learned in a year of using git, or from several hours reading git tutorials.
Levels support a "disable-map" that will prevent certain commands from executing. I somewhat foolishly assume that users only learn commands as I introduce them, but I should go back and lock down some of the levels.
Also, I'm working on a way to compare trees without the ghosted nodes --- it's a bit tricky, but if anyone loves graph traversal and would love to help, chime in on github!
I think the next thing on my plate is to implement origins, so you can demonstrate what a fetch / pull / pull --rebase really does
By the way, what are some recommended git GUIs for linux?
Colour me impressed.
Unfortunately it seems to assume some knowledge. For example, rebase is introduced in a very understandable way, but then I need to know what "rebase -i HEAD~4" does without being introduced to those concepts.
Open up a github issue and I'll definitely throw something up
The app in general is supremely awesome though, I love it, I hope github hires the author to fully flesh it out and make it part of their tutorial. It is insanely useful for people whom are new to git.
If you created a way for a company to easily define levels that mimic their typical workflow it would be a great on-boarding tool for new employees, a great interview tool and also a great reference tool for 'i need to do X, how does the company prefer I do X?'. I can definitely see this justifying a subscription fee for a lot of companies.
Awesome work! I really wish this had existed when I first learned git.
Alternatively - some way of level reset should be provided.
Anyway - this is great work!
Simply enough, http://pineapple.io/ was disscussed in another thread [0] few hours ago and your link happens to be second on the list at http://pineapple.io/?reset=true
Now, hurry up. :)
"A commit in git is a recorded set of changes that you have made"
Git commits are _not_ deltas. They are entire snapshots of the repository and a single (optional) pointer to an ancestor commit[1]. Git may handle _compression_ in terms of deltas (see 'Packfiles' in [2]), but logically, a commit should be thought of as equivalent to the state of all files that are being tracked. That difference is that if you were only looking at diffs, commits would be the _edges_ of a graph, rather than a node plus a single edge. This is why rebases change the commit SHAs but not merges (and why merges create a new commit). This is why if you are on a merge branch, 'git checkout HEAD~3' may not bring you to where 'git log' would naively suggest.
Version control systems that actually do think of 'commits' as pure 'deltas' are ones such as darcs.
A really good, low level explanation, of git is here
http://git-scm.com/book/en/Git-Internals-Git-Objects
(BUG REPORT) The commit created with 'git merge b2' from branch b1 should have HEAD~1 point to the previous head of b1, not b2.
(that said, this is a really cool thing. :) I look forward to the author adding support for conflict resolution. )
[1] http://git-scm.com/book/en/Git-Internals-Git-Objects#Commit-...
It's a tricky line to walk though, because commands like "git show" and "git patch" clearly show the delta-like nature of a single commit. I also don't want newcomers to think that commits are heavy and should be used sparingly.
I'm totally down to discuss this on a github issue with you, we could go over the wording. Maybe something like "a commit specifies the entire state of a repository, but is usually stored on disk as a set of changes"?
EDIT: moving discussion to: https://github.com/pcottle/learnGitBranching/issues/6
EDIT: fixed in: https://github.com/pcottle/learnGitBranching/commit/168852b2...
The first step to committing is staging what should be included.
The staging process specifies an index of files that are to be added to the next commit. When the commit is recorded, git checks every file/chunk in the index; a hash is calculated per each of these blobs, each blob and hash are stored in a key<->object store, the object store, and the hashes are written into the index of the commit.
If a blob already exists in the store then it is not added again.
When changes are made and committed after this point, the resulting blobs are then hashed and stored again. Any unchanged blob does not need to be stored again; any changed blobs are stored.
When a commit is recreated, it's index is evaluated. Each blob is retrieved from the object store and placed into the tree in the appropriate location.
The most important thing to take out of this? Rebuilding a tree from blobs is fast. Second thing to take out? Git only stores each version of a blob (be it a file or a chunk) once, so most 'unpacked' repositories are still quite small.
Now, this is obviously not the smallest representation of the repository, so git has a packed format which calculates deltas between blob files. This will calculate blob-deltas even if they are completely separated in the history; deltas are not between commits, instead they are between objects. Unpacking deltas recreates the blob objects required to build the tree.
The packing process happens every now and then, but it is definitely not done every time a commit is made (by default). The most visible place it is used is when transferring over network protocols (I can't recall if it is done for every network transfer, but I suspect it is). It is done when running garbage collection as well.
----
The reason why all this is important is as I laid out before: rebuilding trees is fast, which makes fast branching possible, and the object store allows this without exploding the size of the repository.
Do you think it's important for beginners to understand all these subtleties? I think I could maybe eventually introduce them, but for the first level on the first screen, I don't think throwing a bunch of concepts at them will help with learning. Feel free to re-open the task if you disagree
I don't think that you need to understand all the plumbing, however it is important to understand how the index works, and that git stores the entire snapshot. The way it currently appears makes it seem like every time you switch branches git has to figure out the end state based on deltas, which is not true. Git has fast branch switching precisely because it stores the snapshot in its entirety.
[EDIT] Here is what I wrote if anyone is interested: http://gist.io/4969804
index 1ef56e5..2c756d0
in a diff refers to. I'm now poking around in the object store with `git cat-file -p <hash>` and it's very enlightening.Nit: A commit can have multiple ancestors, as in a merge.
Still, nice idea.
Branching is huge, awesome, powerful, but I know I as well as a lot of developers I know could use a good lesson on it.
Branching really is a very simple thing to understand but what I think gets people in the end is building a mental model of one's own setup and creating good habits like always running `git status` when sitting down at a new machine to be sure you're on the branch you think you are, always pushing to your main remote before switching machines, and making sure to push to the correct branch in that remote, and so on.
http://pcottle.github.com/learnGitBranching/?demo
Is far better
http://pcottle.github.com/learnGitBranching/?demo
Shows the help page, an example level, and the whole shebang
That said, the intro lesson introduces commits as exclusively deltas. This isn't accurate, and would probably cause confusion with later concepts.
Commits are really snapshots of a tree object (with probably a whole lot of sub trees, and a whole lot of blobs). Since part of the commit meta-data is the parent sha, it's really easy for git to show you the delta, but at it's core git cares about linked snapshots of trees.
I am now done being anal retentive :-) thanks again for the great site, excited to see it more fleshed out
But overall, this is super handy, great idea :)
How about letting me worry about that and continue anyway? What is the worst that could happen, I have to use a scrollbar?
If you're at a normal zoom level and getting that message, certainly let me know -- the zoom level detection logic is a unfortunately pretty hacky.
I had other issues with that level as well. It seems to be teaching inefficient habits by forcing strange rebases rather than a single one with an "edit" on C2. I understand this might be a limitation on the (really cool) visualization, but maybe those levels shouldn't be included if you can't show the most intuitive way (at least to me) to accomplish the goal.
Otherwise, awesome work!
I have trouble understanding the rebase workflow: What is the difference between these two sequences?
git checkout -b bugFix
git commit -m "fix"
git checkout master
git commit -m "master stuff"
git rebase bugFix
git checkout bugFix
git rebase master
and git checkout -b bugFix
git commit -m "fix"
git checkout master
git commit -m "master stuff"
git checkout bugFix
git rebase master
git checkout master
git rebase bugFix
Is it just the order of the commits in the final tree that will be different? Or I am missing something else?Instinctively I would tend to do the first one, but that was not what lesson 4 expected...
git checkout bugFix
git rebase master
to git rebase master bugFixIf you rebase, then anyone who has the old commits in their repo will have to use git reset --hard to switch to the new branch. In other words, rebase inconveniences all other users of a branch. So you can use it freely on branches that only you work on, but you should be reluctant to use it on branches used by other people -- especially popular branches like "master".
If you use your first workflow, the app clearly shows that you discard the commit C3 ("master stuff") and replace it with a different commit C3'. This requires everyone on master to reset.
If you use your second workflow, the commit that you're discarding is C2 ("fix") instead. This means that only people who checked out C2 on bugFix need to reset.
After reading these comments, it became obvious how great the thing is and going back with that in mind made the app more enjoyable
I rely pretty heavily on the box model for layout, but if you look at the CSS I included almost every browser extension (even Opera)
You can't see what's happening and the box seems to be improperly sized and spaced as well as problems with the terminal-style text editing window. The text flows off the bottom and cursor is misaligned: http://imm.io/WxrS
http://pcottle.github.com/learnGitBranching/index.html?demo
I never understood why some repos only accept rebase commits until I actually looked up how the graph is wildly different depending on the command
My apologies again -- I only noticed it was on HN when I got an email about it...
Seriously, very very well done.
I also like the fact that there are no instructions on the page which would make this really useful as a quiz tool to see how students / interview candidates / etc approach the problem space. I fully intend to fork and try to make my own levels when I get some free time.
Great concept. Is this based on something else similar or entirely new?
How did you create the branch visualization? Did you use some sort of library for displaying and animating connected nodes, or is it all coded from scratch?
I think a lot of educational value is in the animations as well, so it made sense to roll my own. The majority of the code involves all the visual and GUI elements -- re-implementing git (ironically) wasn't too bad!
https://github.com/pcottle/learnGitBranching/tree/master/lib
git checkout -b bugFix
git commit
git checkout master
git commit
git merge bugFix master
And git branch bugFix
git commit
git checkout master
git commit
git merge bugFix master git branch bugFix
does not automatically check it out, so you'd have to follow it up with git checkout bugFix
but if you do git checkout -b bugFix
it will create the branch and then check it out all in one step.try it in the website and you’ll see that in the second case bugFix never changes. the merge will say nothing needs to be done because bugFix already contains all changesets in master.
Another direction you can go with this is to make a series of Git puzzles. Basically, starting with this diagram A, convert to diagram B in the least number of moves. To be extra useful, these could revolve around common Git pitfalls.
Suppose I'm in master and already modified a file, and now I notice that it would be better to work on a devel branch with those changes, so I could pull upstream changes from master and merge locally. I think I did something like this:
git stash
git checkout -b devel
git stash apply
git add file.txt
git commit -m "XYZ new changes"
git checkout master
git fetch
git rebase origin/master (to avoid an empty merge, changes
upstream were in independent files)
git merge devel (to get commit "XYZ")
In the end of this, I had lost my changes in file.txt.I could commercialize it but it deserves to be free!
That being said, I've heard the GNU license is sometimes too prohibitive (albeit no definitive examples). If you know licenses at all, I'd love some advice
Right now, you cant be disappointed if the license allows it. If you have doubts, change it now. In terms of licenses, I'm not really an expert. But you could just roll your own. Just take the one you have right now, and remove what allows people to sell it. Still won't stop some people from doing it, though.
For example, I forked your repo. Why? Because its such a nice platform, that I want to learn how it works. I saw that about other 20 people had forked it too. What is stopping them from putting up a website and selling it? Nothing. Nothing at all.
Open source is awesome and all. But you have to also be aware that there are a lot of ruthless people out there waiting for programmers like you to put out software like this one under such licensing terms. Its like buying a car, and listing everyone you know as an owner in the title. Can't get mad when they sell it.
(again I apologize about the discoverability for different commands -- was going to document all this before submitting)
Showing the concept of a "modified" commit is hard though. That's why I did all the C1' sillyness (like the man pages do). The apostrophes also scale nicely (up to C1'^99) where reverting a reverted rebased commit might make the text too big.
EDIT: Fixed, see: https://github.com/pcottle/learnGitBranching/issues/7
I built it about a year ago, mostly for learning and fun. I haven't advertised it a lot but it seems relevant in here. I hope it's not off topic!
- 'git checkout -b branch_name' to create a branch
- 'git checkout branch_name' to switch branches
- 'git commit' to add dummy commits (no need to git add stuff)
Edit: formatting
-'git rebase branch_name'
-'git merge branch_name'
-'git checkout C6' to enter a detached head state