Better flip logic, visuals improvement, and also advanced level section

featuring Aaron's modifier tutorial

Merge pull request #80 from aschrab/multiple_parents
This commit is contained in:
Peter Cottle 2013-03-23 13:10:35 -07:00
parent 46d71cd93a
commit 57db1be39e
15 changed files with 510 additions and 47 deletions

View file

@ -3566,6 +3566,7 @@ var Sandbox = Backbone.View.extend({
deferred: whenLevelOpen, deferred: whenLevelOpen,
command: command command: command
}); });
this.hide();
whenLevelOpen.promise.then(function() { whenLevelOpen.promise.then(function() {
command.finishWith(deferred); command.finishWith(deferred);
@ -13975,7 +13976,7 @@ var GitDemonstrationView = ContainedBase.extend({
initVis: function() { initVis: function() {
this.mainVis = new Visualization({ this.mainVis = new Visualization({
el: this.$('div.visHolder')[0], el: this.$('div.visHolder div.visHolderInside')[0],
noKeyboardInput: true, noKeyboardInput: true,
noClick: true, noClick: true,
smallCanvas: true, smallCanvas: true,
@ -15274,7 +15275,7 @@ GitVisuals.prototype.genResizeFunc = function() {
_.bind(function(width, height) { _.bind(function(width, height) {
// refresh when we are ready if we are animating som ething // refresh when we are ready if we are animating som ething
if (GLOBAL.isAnimating) { if (false && GLOBAL.isAnimating) {
var Main = require('../app'); var Main = require('../app');
Main.getEventBaton().trigger('commandSubmitted', 'refresh'); Main.getEventBaton().trigger('commandSubmitted', 'refresh');
} else { } else {
@ -15989,19 +15990,34 @@ var VisBranch = VisBase.extend({
var commit = this.gitEngine.getCommitFromRef(this.get('branch')); var commit = this.gitEngine.getCommitFromRef(this.get('branch'));
var visNode = commit.get('visNode'); var visNode = commit.get('visNode');
var threshold = this.get('gitVisuals').getFlipPos(); this.set('flip', this.getFlipBool(commit, visNode));
// somewhat tricky flip management here
var flip;
if (visNode.get('pos').x > threshold) {
flip = (this.get('isHead')) ? 1 : -1;
this.set('flip', flip);
} else {
flip = (this.get('isHead')) ? -1 : 1;
this.set('flip', flip);
}
return visNode.getScreenCoords(); return visNode.getScreenCoords();
}, },
getFlipBool: function(commit, visNode) {
var threshold = this.get('gitVisuals').getFlipPos();
var overThreshold = (visNode.get('pos').x > threshold);
if (!this.get('isHead')) {
// easy logic first
return (overThreshold) ?
-1 :
1;
}
// now for HEAD....
if (overThreshold) {
// if by ourselves, then feel free to squeeze in. but
// if other branches are here, then we need to show separate
return (this.isBranchStackEmpty()) ?
-1 :
1;
} else {
return (this.isBranchStackEmpty()) ?
1 :
-1;
}
},
getBranchStackIndex: function() { getBranchStackIndex: function() {
if (this.get('isHead')) { if (this.get('isHead')) {
// head is never stacked with other branches // head is never stacked with other branches
@ -16027,8 +16043,25 @@ var VisBranch = VisBase.extend({
return this.getBranchStackArray().length; return this.getBranchStackArray().length;
}, },
isBranchStackEmpty: function() {
// useful function for head when computing flip logic
var arr = this.gitVisuals.branchStackMap[this.getCommitID()];
return (arr) ?
arr.length === 0 :
true;
},
getCommitID: function() {
var target = this.get('branch').get('target');
if (target.get('type') === 'branch') {
// for HEAD
target = target.get('target');
}
return target.get('id');
},
getBranchStackArray: function() { getBranchStackArray: function() {
var arr = this.gitVisuals.branchStackMap[this.get('branch').get('target').get('id')]; var arr = this.gitVisuals.branchStackMap[this.getCommitID()];
if (arr === undefined) { if (arr === undefined) {
// this only occurs when we are generating graphics inside of // this only occurs when we are generating graphics inside of
// a new Branch instantiation, so we need to force the update // a new Branch instantiation, so we need to force the update
@ -16803,6 +16836,9 @@ exports.levelSequences = {
require('../../levels/mixed/1').level, require('../../levels/mixed/1').level,
require('../../levels/mixed/2').level, require('../../levels/mixed/2').level,
require('../../levels/mixed/3').level require('../../levels/mixed/3').level
],
advanced: [
require('../../levels/advanced/1').level
] ]
}; };
@ -16857,6 +16893,14 @@ exports.sequenceInfo = {
'ko': 'Git을 다루는 다양한 팁과 테크닉을 다양하게 알아봅니다', 'ko': 'Git을 다루는 다양한 팁과 테크닉을 다양하게 알아봅니다',
'zh_CN': 'Git技术技巧与贴士' 'zh_CN': 'Git技术技巧与贴士'
} }
},
advanced: {
displayName: {
'en_US': 'Advanced Topics'
},
about: {
'en_US': 'For the truly brave!'
}
} }
}; };
@ -18249,6 +18293,7 @@ require.define("/levels/rampup/3.js",function(require,module,exports,__dirname,_
require.define("/levels/rampup/4.js",function(require,module,exports,__dirname,__filename,process,global){exports.level = { require.define("/levels/rampup/4.js",function(require,module,exports,__dirname,__filename,process,global){exports.level = {
"goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%7D%2C%22pushed%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22pushed%22%7D%2C%22local%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22local%22%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22pushed%22%2C%22id%22%3A%22HEAD%22%7D%7D", "goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%7D%2C%22pushed%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22pushed%22%7D%2C%22local%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22local%22%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22pushed%22%2C%22id%22%3A%22HEAD%22%7D%7D",
"solutionCommand": "git reset HEAD~1;git checkout pushed;git revert HEAD", "solutionCommand": "git reset HEAD~1;git checkout pushed;git revert HEAD",
"compareOnlyBranches": true,
"startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\"},\"pushed\":{\"target\":\"C2\",\"id\":\"pushed\"},\"local\":{\"target\":\"C3\",\"id\":\"local\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"local\",\"id\":\"HEAD\"}}", "startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\"},\"pushed\":{\"target\":\"C2\",\"id\":\"pushed\"},\"local\":{\"target\":\"C3\",\"id\":\"local\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"local\",\"id\":\"HEAD\"}}",
"name": { "name": {
"en_US": "Reversing Changes in Git", "en_US": "Reversing Changes in Git",
@ -19147,6 +19192,110 @@ require.define("/levels/mixed/3.js",function(require,module,exports,__dirname,__
}; };
}); });
require.define("/levels/advanced/1.js",function(require,module,exports,__dirname,__filename,process,global){exports.level = {
"goalTreeString": "{\"branches\":{\"master\":{\"target\":\"C7\",\"id\":\"master\"},\"bugWork\":{\"target\":\"C2\",\"id\":\"bugWork\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C2\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C4\",\"C5\"],\"id\":\"C6\"},\"C7\":{\"parents\":[\"C6\"],\"id\":\"C7\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
"solutionCommand": "git branch bugWork master^^2^",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C7\",\"id\":\"master\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C2\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C4\",\"C5\"],\"id\":\"C6\"},\"C7\":{\"parents\":[\"C6\"],\"id\":\"C7\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
"name": {
"en_US": "Multiple parents"
},
"hint": {
"en_US": "Use `git branch bugWork` with a target commit to create the missing reference."
},
"startDialog": {
"en_US": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Specifying Parents",
"",
"Like the `~` modifier, the `^` modifier also accepts an optional number after it.",
"",
"Rather than specifying the number of generations to go back (what `~` takes), the modifier on `^` specifies which parent reference to follow from a merge commit. Remember that merge commits have multiple parents, so the path to choose is ambiguous.",
"",
"Git will normally follow the \"first\" parent upwards from a merge commit, but specifying a number with `^` changes this default behavior.",
"",
"Enough talking, let's see it in action",
""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Here we have a merge commit. If we checkout `master^` without the modifier, we will follow the first parent after the merge commit. ",
"",
"(*In our visuals, the first parent is positioned directly above the merge commit.*)"
],
"afterMarkdowns": [
"Easy -- this is what we are all used to"
],
"command": "git checkout master^",
"beforeCommand": "git checkout HEAD^; git commit; git checkout master; git merge C2"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Now lets try specifying the second parent instead..."
],
"afterMarkdowns": [
"See! We followed the other parent upwards"
],
"command": "git checkout master^2",
"beforeCommand": "git checkout HEAD^; git commit; git checkout master; git merge C2"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"The `^` and `~` modifiers can make moving around a commit tree very powerful:"
],
"afterMarkdowns": [
"Lightning fast"
],
"command": "git checkout HEAD~; git checkout HEAD^2; git checkout HEAD~2",
"beforeCommand": "git commit; git checkout C0; git commit; git commit; git commit; git checkout master; git merge C5; git commit"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Even crazier, these modifiers can be chained together! Check this out:"
],
"afterMarkdowns": [
"The same movement as before, but all in one command"
],
"command": "git checkout HEAD~^2~2",
"beforeCommand": "git commit; git checkout C0; git commit; git commit; git commit; git checkout master; git merge C5; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Put it to practice",
"",
"To complete this level, create a new branch at the specified destination.",
"",
"Obviously it would be easy to specify the commit directly (with something like `C6`), but I challenge you to use the modifiers we talked about instead!"
]
}
}
]
}
}
};
});
require.define("/src/js/views/levelDropdownView.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore'); require.define("/src/js/views/levelDropdownView.js",function(require,module,exports,__dirname,__filename,process,global){var _ = require('underscore');
var Q = require('q'); var Q = require('q');
// horrible hack to get localStorage Backbone plugin // horrible hack to get localStorage Backbone plugin
@ -25274,6 +25423,7 @@ var Sandbox = Backbone.View.extend({
deferred: whenLevelOpen, deferred: whenLevelOpen,
command: command command: command
}); });
this.hide();
whenLevelOpen.promise.then(function() { whenLevelOpen.promise.then(function() {
command.finishWith(deferred); command.finishWith(deferred);
@ -27365,7 +27515,7 @@ var GitDemonstrationView = ContainedBase.extend({
initVis: function() { initVis: function() {
this.mainVis = new Visualization({ this.mainVis = new Visualization({
el: this.$('div.visHolder')[0], el: this.$('div.visHolder div.visHolderInside')[0],
noKeyboardInput: true, noKeyboardInput: true,
noClick: true, noClick: true,
smallCanvas: true, smallCanvas: true,
@ -29784,7 +29934,7 @@ GitVisuals.prototype.genResizeFunc = function() {
_.bind(function(width, height) { _.bind(function(width, height) {
// refresh when we are ready if we are animating som ething // refresh when we are ready if we are animating som ething
if (GLOBAL.isAnimating) { if (false && GLOBAL.isAnimating) {
var Main = require('../app'); var Main = require('../app');
Main.getEventBaton().trigger('commandSubmitted', 'refresh'); Main.getEventBaton().trigger('commandSubmitted', 'refresh');
} else { } else {
@ -30109,19 +30259,34 @@ var VisBranch = VisBase.extend({
var commit = this.gitEngine.getCommitFromRef(this.get('branch')); var commit = this.gitEngine.getCommitFromRef(this.get('branch'));
var visNode = commit.get('visNode'); var visNode = commit.get('visNode');
var threshold = this.get('gitVisuals').getFlipPos(); this.set('flip', this.getFlipBool(commit, visNode));
// somewhat tricky flip management here
var flip;
if (visNode.get('pos').x > threshold) {
flip = (this.get('isHead')) ? 1 : -1;
this.set('flip', flip);
} else {
flip = (this.get('isHead')) ? -1 : 1;
this.set('flip', flip);
}
return visNode.getScreenCoords(); return visNode.getScreenCoords();
}, },
getFlipBool: function(commit, visNode) {
var threshold = this.get('gitVisuals').getFlipPos();
var overThreshold = (visNode.get('pos').x > threshold);
if (!this.get('isHead')) {
// easy logic first
return (overThreshold) ?
-1 :
1;
}
// now for HEAD....
if (overThreshold) {
// if by ourselves, then feel free to squeeze in. but
// if other branches are here, then we need to show separate
return (this.isBranchStackEmpty()) ?
-1 :
1;
} else {
return (this.isBranchStackEmpty()) ?
1 :
-1;
}
},
getBranchStackIndex: function() { getBranchStackIndex: function() {
if (this.get('isHead')) { if (this.get('isHead')) {
// head is never stacked with other branches // head is never stacked with other branches
@ -30147,8 +30312,25 @@ var VisBranch = VisBase.extend({
return this.getBranchStackArray().length; return this.getBranchStackArray().length;
}, },
isBranchStackEmpty: function() {
// useful function for head when computing flip logic
var arr = this.gitVisuals.branchStackMap[this.getCommitID()];
return (arr) ?
arr.length === 0 :
true;
},
getCommitID: function() {
var target = this.get('branch').get('target');
if (target.get('type') === 'branch') {
// for HEAD
target = target.get('target');
}
return target.get('id');
},
getBranchStackArray: function() { getBranchStackArray: function() {
var arr = this.gitVisuals.branchStackMap[this.get('branch').get('target').get('id')]; var arr = this.gitVisuals.branchStackMap[this.getCommitID()];
if (arr === undefined) { if (arr === undefined) {
// this only occurs when we are generating graphics inside of // this only occurs when we are generating graphics inside of
// a new Branch instantiation, so we need to force the update // a new Branch instantiation, so we need to force the update
@ -31300,6 +31482,111 @@ exports.Visualization = Visualization;
}); });
require("/src/js/visuals/visualization.js"); require("/src/js/visuals/visualization.js");
require.define("/src/levels/advanced/1.js",function(require,module,exports,__dirname,__filename,process,global){exports.level = {
"goalTreeString": "{\"branches\":{\"master\":{\"target\":\"C7\",\"id\":\"master\"},\"bugWork\":{\"target\":\"C2\",\"id\":\"bugWork\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C2\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C4\",\"C5\"],\"id\":\"C6\"},\"C7\":{\"parents\":[\"C6\"],\"id\":\"C7\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
"solutionCommand": "git branch bugWork master^^2^",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C7\",\"id\":\"master\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C2\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C4\",\"C5\"],\"id\":\"C6\"},\"C7\":{\"parents\":[\"C6\"],\"id\":\"C7\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
"name": {
"en_US": "Multiple parents"
},
"hint": {
"en_US": "Use `git branch bugWork` with a target commit to create the missing reference."
},
"startDialog": {
"en_US": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Specifying Parents",
"",
"Like the `~` modifier, the `^` modifier also accepts an optional number after it.",
"",
"Rather than specifying the number of generations to go back (what `~` takes), the modifier on `^` specifies which parent reference to follow from a merge commit. Remember that merge commits have multiple parents, so the path to choose is ambiguous.",
"",
"Git will normally follow the \"first\" parent upwards from a merge commit, but specifying a number with `^` changes this default behavior.",
"",
"Enough talking, let's see it in action",
""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Here we have a merge commit. If we checkout `master^` without the modifier, we will follow the first parent after the merge commit. ",
"",
"(*In our visuals, the first parent is positioned directly above the merge commit.*)"
],
"afterMarkdowns": [
"Easy -- this is what we are all used to"
],
"command": "git checkout master^",
"beforeCommand": "git checkout HEAD^; git commit; git checkout master; git merge C2"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Now lets try specifying the second parent instead..."
],
"afterMarkdowns": [
"See! We followed the other parent upwards"
],
"command": "git checkout master^2",
"beforeCommand": "git checkout HEAD^; git commit; git checkout master; git merge C2"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"The `^` and `~` modifiers can make moving around a commit tree very powerful:"
],
"afterMarkdowns": [
"Lightning fast"
],
"command": "git checkout HEAD~; git checkout HEAD^2; git checkout HEAD~2",
"beforeCommand": "git commit; git checkout C0; git commit; git commit; git commit; git checkout master; git merge C5; git commit"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Even crazier, these modifiers can be chained together! Check this out:"
],
"afterMarkdowns": [
"The same movement as before, but all in one command"
],
"command": "git checkout HEAD~^2~2",
"beforeCommand": "git commit; git checkout C0; git commit; git commit; git commit; git checkout master; git merge C5; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Put it to practice",
"",
"To complete this level, create a new branch at the specified destination.",
"",
"Obviously it would be easy to specify the commit directly (with something like `C6`), but I challenge you to use the modifiers we talked about instead!"
]
}
}
]
}
}
};
});
require("/src/levels/advanced/1.js");
require.define("/src/levels/index.js",function(require,module,exports,__dirname,__filename,process,global){// Each level is part of a "sequence;" levels within require.define("/src/levels/index.js",function(require,module,exports,__dirname,__filename,process,global){// Each level is part of a "sequence;" levels within
// a sequence proceed in the order listed here // a sequence proceed in the order listed here
exports.levelSequences = { exports.levelSequences = {
@ -31323,6 +31610,9 @@ exports.levelSequences = {
require('../../levels/mixed/1').level, require('../../levels/mixed/1').level,
require('../../levels/mixed/2').level, require('../../levels/mixed/2').level,
require('../../levels/mixed/3').level require('../../levels/mixed/3').level
],
advanced: [
require('../../levels/advanced/1').level
] ]
}; };
@ -31377,6 +31667,14 @@ exports.sequenceInfo = {
'ko': 'Git을 다루는 다양한 팁과 테크닉을 다양하게 알아봅니다', 'ko': 'Git을 다루는 다양한 팁과 테크닉을 다양하게 알아봅니다',
'zh_CN': 'Git技术技巧与贴士' 'zh_CN': 'Git技术技巧与贴士'
} }
},
advanced: {
displayName: {
'en_US': 'Advanced Topics'
},
about: {
'en_US': 'For the truly brave!'
}
} }
}; };
@ -33246,6 +33544,7 @@ require("/src/levels/rampup/3.js");
require.define("/src/levels/rampup/4.js",function(require,module,exports,__dirname,__filename,process,global){exports.level = { require.define("/src/levels/rampup/4.js",function(require,module,exports,__dirname,__filename,process,global){exports.level = {
"goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%7D%2C%22pushed%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22pushed%22%7D%2C%22local%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22local%22%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22pushed%22%2C%22id%22%3A%22HEAD%22%7D%7D", "goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%7D%2C%22pushed%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22pushed%22%7D%2C%22local%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22local%22%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22pushed%22%2C%22id%22%3A%22HEAD%22%7D%7D",
"solutionCommand": "git reset HEAD~1;git checkout pushed;git revert HEAD", "solutionCommand": "git reset HEAD~1;git checkout pushed;git revert HEAD",
"compareOnlyBranches": true,
"startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\"},\"pushed\":{\"target\":\"C2\",\"id\":\"pushed\"},\"local\":{\"target\":\"C3\",\"id\":\"local\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"local\",\"id\":\"HEAD\"}}", "startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\"},\"pushed\":{\"target\":\"C2\",\"id\":\"pushed\"},\"local\":{\"target\":\"C3\",\"id\":\"local\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"local\",\"id\":\"HEAD\"}}",
"name": { "name": {
"en_US": "Reversing Changes in Git", "en_US": "Reversing Changes in Git",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
build/bundle.min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -73,6 +73,13 @@ body,
box-flex: 3; box-flex: 3;
} }
.flex10 {
-webkit-box-flex: 10;
-moz-box-flex: 10;
-ms-box-flex: 10;
box-flex: 10;
}
html, html,
body, body,
.vertical { .vertical {

View file

@ -13,7 +13,7 @@
<meta property="og:image" content="http://pcottle.github.com/learnGitBranching/assets/learnGitBranching.png"/> <meta property="og:image" content="http://pcottle.github.com/learnGitBranching/assets/learnGitBranching.png"/>
<meta property="og:description" content="A interactive Git visualization tool to educate and challenge!"/> <meta property="og:description" content="A interactive Git visualization tool to educate and challenge!"/>
<link rel="stylesheet" href="build/main.02d13d1b.css" type="text/css" charset="utf-8"> <link rel="stylesheet" href="build/main.c1dbd088.css" type="text/css" charset="utf-8">
<link rel="stylesheet" href="src/style/font-awesome.css" type="text/css" charset="utf-8"> <link rel="stylesheet" href="src/style/font-awesome.css" type="text/css" charset="utf-8">
</head> </head>
<body> <body>
@ -133,7 +133,7 @@
</script> </script>
<script type="text/html" id="terminal-window-bare-template"> <script type="text/html" id="terminal-window-bare-template">
<div class="terminal-window-holder box flex3 vertical transitionTransform slideOut"> <div class="terminal-window-holder box flex10 vertical transitionTransform slideOut">
<div class="wrapper box vertical"> <div class="wrapper box vertical">
<div class="toolbar box vertical center"> <div class="toolbar box vertical center">
<div class="controls box horizontal justify"> <div class="controls box horizontal justify">
@ -173,7 +173,7 @@
<div class="box flex2"> <div class="box flex2">
</div> </div>
<div class="terminal-window-holder box flex3 vertical transitionTransform"> <div class="terminal-window-holder box flex10 vertical transitionTransform">
<div class="toolbar box vertical center"> <div class="toolbar box vertical center">
<div class="controls box horizontal justify"> <div class="controls box horizontal justify">
<div class="box flex1"> <div class="box flex1">
@ -250,6 +250,8 @@
</div> </div>
<div class="visHolder box vertical flex1"> <div class="visHolder box vertical flex1">
<div class="visHolderInside box flex1">
</div>
</div> </div>
</script> </script>
@ -422,7 +424,7 @@
For a much easier time perusing the source, see the individual files at: For a much easier time perusing the source, see the individual files at:
https://github.com/pcottle/learnGitBranching https://github.com/pcottle/learnGitBranching
--> -->
<script src="build/bundle.min.2e614ec7.js"></script> <script src="build/bundle.min.1493bbdb.js"></script>
<!-- The advantage of github pages: super-easy, simple, slick static hostic. <!-- The advantage of github pages: super-easy, simple, slick static hostic.
The downside? No raw logs to parse for analytics, so I have to include The downside? No raw logs to parse for analytics, so I have to include

View file

@ -319,6 +319,7 @@ var Sandbox = Backbone.View.extend({
deferred: whenLevelOpen, deferred: whenLevelOpen,
command: command command: command
}); });
this.hide();
whenLevelOpen.promise.then(function() { whenLevelOpen.promise.then(function() {
command.finishWith(deferred); command.finishWith(deferred);

View file

@ -227,7 +227,7 @@ var GitDemonstrationView = ContainedBase.extend({
initVis: function() { initVis: function() {
this.mainVis = new Visualization({ this.mainVis = new Visualization({
el: this.$('div.visHolder')[0], el: this.$('div.visHolder div.visHolderInside')[0],
noKeyboardInput: true, noKeyboardInput: true,
noClick: true, noClick: true,
smallCanvas: true, smallCanvas: true,

View file

@ -685,7 +685,7 @@ GitVisuals.prototype.genResizeFunc = function() {
_.bind(function(width, height) { _.bind(function(width, height) {
// refresh when we are ready if we are animating som ething // refresh when we are ready if we are animating som ething
if (GLOBAL.isAnimating) { if (false && GLOBAL.isAnimating) {
var Main = require('../app'); var Main = require('../app');
Main.getEventBaton().trigger('commandSubmitted', 'refresh'); Main.getEventBaton().trigger('commandSubmitted', 'refresh');
} else { } else {

View file

@ -77,19 +77,34 @@ var VisBranch = VisBase.extend({
var commit = this.gitEngine.getCommitFromRef(this.get('branch')); var commit = this.gitEngine.getCommitFromRef(this.get('branch'));
var visNode = commit.get('visNode'); var visNode = commit.get('visNode');
var threshold = this.get('gitVisuals').getFlipPos(); this.set('flip', this.getFlipBool(commit, visNode));
// somewhat tricky flip management here
var flip;
if (visNode.get('pos').x > threshold) {
flip = (this.get('isHead')) ? 1 : -1;
this.set('flip', flip);
} else {
flip = (this.get('isHead')) ? -1 : 1;
this.set('flip', flip);
}
return visNode.getScreenCoords(); return visNode.getScreenCoords();
}, },
getFlipBool: function(commit, visNode) {
var threshold = this.get('gitVisuals').getFlipPos();
var overThreshold = (visNode.get('pos').x > threshold);
if (!this.get('isHead')) {
// easy logic first
return (overThreshold) ?
-1 :
1;
}
// now for HEAD....
if (overThreshold) {
// if by ourselves, then feel free to squeeze in. but
// if other branches are here, then we need to show separate
return (this.isBranchStackEmpty()) ?
-1 :
1;
} else {
return (this.isBranchStackEmpty()) ?
1 :
-1;
}
},
getBranchStackIndex: function() { getBranchStackIndex: function() {
if (this.get('isHead')) { if (this.get('isHead')) {
// head is never stacked with other branches // head is never stacked with other branches
@ -115,8 +130,25 @@ var VisBranch = VisBase.extend({
return this.getBranchStackArray().length; return this.getBranchStackArray().length;
}, },
isBranchStackEmpty: function() {
// useful function for head when computing flip logic
var arr = this.gitVisuals.branchStackMap[this.getCommitID()];
return (arr) ?
arr.length === 0 :
true;
},
getCommitID: function() {
var target = this.get('branch').get('target');
if (target.get('type') === 'branch') {
// for HEAD
target = target.get('target');
}
return target.get('id');
},
getBranchStackArray: function() { getBranchStackArray: function() {
var arr = this.gitVisuals.branchStackMap[this.get('branch').get('target').get('id')]; var arr = this.gitVisuals.branchStackMap[this.getCommitID()];
if (arr === undefined) { if (arr === undefined) {
// this only occurs when we are generating graphics inside of // this only occurs when we are generating graphics inside of
// a new Branch instantiation, so we need to force the update // a new Branch instantiation, so we need to force the update

101
src/levels/advanced/1.js Normal file
View file

@ -0,0 +1,101 @@
exports.level = {
"goalTreeString": "{\"branches\":{\"master\":{\"target\":\"C7\",\"id\":\"master\"},\"bugWork\":{\"target\":\"C2\",\"id\":\"bugWork\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C2\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C4\",\"C5\"],\"id\":\"C6\"},\"C7\":{\"parents\":[\"C6\"],\"id\":\"C7\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
"solutionCommand": "git branch bugWork master^^2^",
"startTree": "{\"branches\":{\"master\":{\"target\":\"C7\",\"id\":\"master\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"},\"C4\":{\"parents\":[\"C3\"],\"id\":\"C4\"},\"C5\":{\"parents\":[\"C2\"],\"id\":\"C5\"},\"C6\":{\"parents\":[\"C4\",\"C5\"],\"id\":\"C6\"},\"C7\":{\"parents\":[\"C6\"],\"id\":\"C7\"}},\"HEAD\":{\"target\":\"master\",\"id\":\"HEAD\"}}",
"name": {
"en_US": "Multiple parents"
},
"hint": {
"en_US": "Use `git branch bugWork` with a target commit to create the missing reference."
},
"startDialog": {
"en_US": {
"childViews": [
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Specifying Parents",
"",
"Like the `~` modifier, the `^` modifier also accepts an optional number after it.",
"",
"Rather than specifying the number of generations to go back (what `~` takes), the modifier on `^` specifies which parent reference to follow from a merge commit. Remember that merge commits have multiple parents, so the path to choose is ambiguous.",
"",
"Git will normally follow the \"first\" parent upwards from a merge commit, but specifying a number with `^` changes this default behavior.",
"",
"Enough talking, let's see it in action",
""
]
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Here we have a merge commit. If we checkout `master^` without the modifier, we will follow the first parent after the merge commit. ",
"",
"(*In our visuals, the first parent is positioned directly above the merge commit.*)"
],
"afterMarkdowns": [
"Easy -- this is what we are all used to"
],
"command": "git checkout master^",
"beforeCommand": "git checkout HEAD^; git commit; git checkout master; git merge C2"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Now lets try specifying the second parent instead..."
],
"afterMarkdowns": [
"See! We followed the other parent upwards"
],
"command": "git checkout master^2",
"beforeCommand": "git checkout HEAD^; git commit; git checkout master; git merge C2"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"The `^` and `~` modifiers can make moving around a commit tree very powerful:"
],
"afterMarkdowns": [
"Lightning fast"
],
"command": "git checkout HEAD~; git checkout HEAD^2; git checkout HEAD~2",
"beforeCommand": "git commit; git checkout C0; git commit; git commit; git commit; git checkout master; git merge C5; git commit"
}
},
{
"type": "GitDemonstrationView",
"options": {
"beforeMarkdowns": [
"Even crazier, these modifiers can be chained together! Check this out:"
],
"afterMarkdowns": [
"The same movement as before, but all in one command"
],
"command": "git checkout HEAD~^2~2",
"beforeCommand": "git commit; git checkout C0; git commit; git commit; git commit; git checkout master; git merge C5; git commit"
}
},
{
"type": "ModalAlert",
"options": {
"markdowns": [
"### Put it to practice",
"",
"To complete this level, create a new branch at the specified destination.",
"",
"Obviously it would be easy to specify the commit directly (with something like `C6`), but I challenge you to use the modifiers we talked about instead!"
]
}
}
]
}
}
};

View file

@ -21,6 +21,9 @@ exports.levelSequences = {
require('../../levels/mixed/1').level, require('../../levels/mixed/1').level,
require('../../levels/mixed/2').level, require('../../levels/mixed/2').level,
require('../../levels/mixed/3').level require('../../levels/mixed/3').level
],
advanced: [
require('../../levels/advanced/1').level
] ]
}; };
@ -75,6 +78,14 @@ exports.sequenceInfo = {
'ko': 'Git을 다루는 다양한 팁과 테크닉을 다양하게 알아봅니다', 'ko': 'Git을 다루는 다양한 팁과 테크닉을 다양하게 알아봅니다',
'zh_CN': 'Git技术技巧与贴士' 'zh_CN': 'Git技术技巧与贴士'
} }
},
advanced: {
displayName: {
'en_US': 'Advanced Topics'
},
about: {
'en_US': 'For the truly brave!'
}
} }
}; };

View file

@ -1,6 +1,7 @@
exports.level = { exports.level = {
"goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%7D%2C%22pushed%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22pushed%22%7D%2C%22local%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22local%22%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22pushed%22%2C%22id%22%3A%22HEAD%22%7D%7D", "goalTreeString": "%7B%22branches%22%3A%7B%22master%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22master%22%7D%2C%22pushed%22%3A%7B%22target%22%3A%22C2%27%22%2C%22id%22%3A%22pushed%22%7D%2C%22local%22%3A%7B%22target%22%3A%22C1%22%2C%22id%22%3A%22local%22%7D%7D%2C%22commits%22%3A%7B%22C0%22%3A%7B%22parents%22%3A%5B%5D%2C%22id%22%3A%22C0%22%2C%22rootCommit%22%3Atrue%7D%2C%22C1%22%3A%7B%22parents%22%3A%5B%22C0%22%5D%2C%22id%22%3A%22C1%22%7D%2C%22C2%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C2%22%7D%2C%22C3%22%3A%7B%22parents%22%3A%5B%22C1%22%5D%2C%22id%22%3A%22C3%22%7D%2C%22C2%27%22%3A%7B%22parents%22%3A%5B%22C2%22%5D%2C%22id%22%3A%22C2%27%22%7D%7D%2C%22HEAD%22%3A%7B%22target%22%3A%22pushed%22%2C%22id%22%3A%22HEAD%22%7D%7D",
"solutionCommand": "git reset HEAD~1;git checkout pushed;git revert HEAD", "solutionCommand": "git reset HEAD~1;git checkout pushed;git revert HEAD",
"compareOnlyBranches": true,
"startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\"},\"pushed\":{\"target\":\"C2\",\"id\":\"pushed\"},\"local\":{\"target\":\"C3\",\"id\":\"local\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"local\",\"id\":\"HEAD\"}}", "startTree": "{\"branches\":{\"master\":{\"target\":\"C1\",\"id\":\"master\"},\"pushed\":{\"target\":\"C2\",\"id\":\"pushed\"},\"local\":{\"target\":\"C3\",\"id\":\"local\"}},\"commits\":{\"C0\":{\"parents\":[],\"id\":\"C0\",\"rootCommit\":true},\"C1\":{\"parents\":[\"C0\"],\"id\":\"C1\"},\"C2\":{\"parents\":[\"C1\"],\"id\":\"C2\"},\"C3\":{\"parents\":[\"C1\"],\"id\":\"C3\"}},\"HEAD\":{\"target\":\"local\",\"id\":\"HEAD\"}}",
"name": { "name": {
"en_US": "Reversing Changes in Git", "en_US": "Reversing Changes in Git",

View file

@ -73,6 +73,13 @@ body,
box-flex: 3; box-flex: 3;
} }
.flex10 {
-webkit-box-flex: 10;
-moz-box-flex: 10;
-ms-box-flex: 10;
box-flex: 10;
}
html, html,
body, body,
.vertical { .vertical {

View file

@ -133,7 +133,7 @@
</script> </script>
<script type="text/html" id="terminal-window-bare-template"> <script type="text/html" id="terminal-window-bare-template">
<div class="terminal-window-holder box flex3 vertical transitionTransform slideOut"> <div class="terminal-window-holder box flex10 vertical transitionTransform slideOut">
<div class="wrapper box vertical"> <div class="wrapper box vertical">
<div class="toolbar box vertical center"> <div class="toolbar box vertical center">
<div class="controls box horizontal justify"> <div class="controls box horizontal justify">
@ -173,7 +173,7 @@
<div class="box flex2"> <div class="box flex2">
</div> </div>
<div class="terminal-window-holder box flex3 vertical transitionTransform"> <div class="terminal-window-holder box flex10 vertical transitionTransform">
<div class="toolbar box vertical center"> <div class="toolbar box vertical center">
<div class="controls box horizontal justify"> <div class="controls box horizontal justify">
<div class="box flex1"> <div class="box flex1">
@ -250,6 +250,8 @@
</div> </div>
<div class="visHolder box vertical flex1"> <div class="visHolder box vertical flex1">
<div class="visHolderInside box flex1">
</div>
</div> </div>
</script> </script>