diff --git a/README.md b/README.md index dbde6362..042dd61c 100644 --- a/README.md +++ b/README.md @@ -116,4 +116,5 @@ Or reported an issue that was successfully closed! * "Goodwine" * Brandon McCaig * Borislav Kosharov +* Ben Heavner diff --git a/build/bundle.js b/build/bundle.js index 31a8030f..d4c888e2 100644 --- a/build/bundle.js +++ b/build/bundle.js @@ -5401,6 +5401,10 @@ require.define("/src/js/intl/strings.js",function(require,module,exports,__dirna 'en_US': 'Quick commit. Go Bears!', 'zh_CN': '快速提交。上啊月熊!' }, + 'git-error-origin-fetch-no-ff': { + '__desc__': 'One of the error messages for git', + 'en_US': 'Your origin branch is out of sync with the remote branch and fetch cannot be performed. try using --force' + }, 'git-error-remote-branch': { '__desc__': 'One of the error messages for git', 'en_US': 'You cannot execute that command on a remote branch' @@ -7789,59 +7793,111 @@ GitEngine.prototype.checkUpstreamOfSource = function( var targetLocationID = target.getCommitFromRef(targetBranch).get('id'); if (!upstream[targetLocationID]) { throw new GitError({ - msg: 'no no' + msg: intl.str('git-error-origin-fetch-no-ff') }); } }; +GitEngine.prototype.getTargetGraphDifference = function( + target, + source, + targetBranch, + sourceBranch +) { + sourceBranch = source.resolveID(sourceBranch); + + var targetSet = target.getUpstreamSet(targetBranch); + var sourceStartCommit = source.getCommitFromRef(sourceBranch); + + var sourceTree = source.exportTree(); + var sourceStartCommitJSON = sourceTree.commits[sourceStartCommit.get('id')]; + + // ok great, we have our starting point and our stopping set. lets go ahead + // and traverse upwards and keep track of depth manually + sourceStartCommitJSON.depth = 0; + var difference = []; + var toExplore = [sourceStartCommitJSON]; + + while (toExplore.length) { + var here = toExplore.pop(); + difference.push(here); + + _.each(here.parents, function(parentID) { + if (targetSet[parentID]) { + // we already have this commit, lets bounce + return; + } + + var parentJSON = sourceTree.commits[parentID]; + parentJSON.depth = here.depth + 1; + toExplore.push(parentJSON); + }, this); + } + return difference.sort(function(cA, cB) { + // reverse sort by depth + return cB.depth - cA.depth; + }); +}; + GitEngine.prototype.fetch = function() { + var localBranch = this.refs['o/master']; + var remoteBranch = this.origin.refs['master']; + // first check if this is even allowed by checking the sync between this.checkUpstreamOfSource( this, this.origin, - this.refs['o/master'], - this.origin.refs['master'] + localBranch, + remoteBranch ); - var oldCommits = this.exportTree().commits; - // HAX HAX omg we will abuse our tree instantiation here :D - var originTree = this.origin.exportTree(); - _.each(originTree.commits, function(commit, id) { - // if we have it, no worries - if (this.refs[id]) { - return; - } - // go make it! - var downloadedCommit = this.getOrMakeRecursive(originTree, this.refs, id); - this.commitCollection.add(downloadedCommit); + // then we get the difference in commits between these two graphs, ordered by + // depth + var commitsToMake = this.getTargetGraphDifference( + this, + this.origin, + localBranch, + remoteBranch + ); + + var makeCommit = _.bind(function(id, parentIDs) { + // need to get the parents first. since we order by depth, we know + // the dependencies are there already + var parents = _.map(parentIDs, function(parentID) { + return this.refs[parentID]; + }, this); + return this.makeCommit(parents, id); }, this); - // since we now might have many commits more than before, lets - // check all the ones that didn't use to exist and make animations - var newCommits = this.exportTree().commits; - var commitsToAnimate = []; - _.each(newCommits, function(commit, id) { - if (oldCommits[id]) { - return; - } - commitsToAnimate.push(this.refs[id]); - }, this); - - // now sort by id... - commitsToAnimate.sort(_.bind(this.idSortFunc, this)); - - _.each(commitsToAnimate, function(newCommit) { - AnimationFactory.genCommitBirthAnimation( - this.animationQueue, + // now make the promise chain to make each commit + var chainStep = _.bind(function(id, parents) { + var newCommit = makeCommit(id, parents); + return AnimationFactory.playCommitBirthPromiseAnimation( newCommit, this.gitVisuals ); }, this); - var originLocation = this.origin.exportTree().branches.master.target; - // yay! now we just set o/master and do a simple refresh - this.setTargetLocation(this.refs['o/master'], this.refs[originLocation]); - AnimationFactory.refreshTree(this.animationQueue, this.gitVisuals); + var deferred = Q.defer(); + var chain = deferred.promise; + + _.each(commitsToMake, function(commitJSON) { + chain = chain.then(function() { + return chainStep( + commitJSON.id, + commitJSON.parents + ); + }); + }); + + chain = chain.then(_.bind(function() { + var originLocationID = remoteBranch.get('target').get('id'); + var localCommit = this.refs[originLocationID]; + this.setTargetLocation(localBranch, localCommit); + return AnimationFactory.playRefreshAnimation(this.gitVisuals); + }, this)); + + this.animationQueue.thenFinish(chain, deferred); }; GitEngine.prototype.pullStarter = function() { @@ -8626,7 +8682,7 @@ GitEngine.prototype.checkout = function(idOrTarget) { var type = target.get('type'); // check if this is an origin branch, and if so go to the commit referenced if (type === 'branch' && target.getIsRemote()) { - //target = this.getCommitFromRef(target.get('id')); + target = this.getCommitFromRef(target.get('id')); } if (type !== 'branch' && type !== 'commit') { @@ -23644,59 +23700,111 @@ GitEngine.prototype.checkUpstreamOfSource = function( var targetLocationID = target.getCommitFromRef(targetBranch).get('id'); if (!upstream[targetLocationID]) { throw new GitError({ - msg: 'no no' + msg: intl.str('git-error-origin-fetch-no-ff') }); } }; +GitEngine.prototype.getTargetGraphDifference = function( + target, + source, + targetBranch, + sourceBranch +) { + sourceBranch = source.resolveID(sourceBranch); + + var targetSet = target.getUpstreamSet(targetBranch); + var sourceStartCommit = source.getCommitFromRef(sourceBranch); + + var sourceTree = source.exportTree(); + var sourceStartCommitJSON = sourceTree.commits[sourceStartCommit.get('id')]; + + // ok great, we have our starting point and our stopping set. lets go ahead + // and traverse upwards and keep track of depth manually + sourceStartCommitJSON.depth = 0; + var difference = []; + var toExplore = [sourceStartCommitJSON]; + + while (toExplore.length) { + var here = toExplore.pop(); + difference.push(here); + + _.each(here.parents, function(parentID) { + if (targetSet[parentID]) { + // we already have this commit, lets bounce + return; + } + + var parentJSON = sourceTree.commits[parentID]; + parentJSON.depth = here.depth + 1; + toExplore.push(parentJSON); + }, this); + } + return difference.sort(function(cA, cB) { + // reverse sort by depth + return cB.depth - cA.depth; + }); +}; + GitEngine.prototype.fetch = function() { + var localBranch = this.refs['o/master']; + var remoteBranch = this.origin.refs['master']; + // first check if this is even allowed by checking the sync between this.checkUpstreamOfSource( this, this.origin, - this.refs['o/master'], - this.origin.refs['master'] + localBranch, + remoteBranch ); - var oldCommits = this.exportTree().commits; - // HAX HAX omg we will abuse our tree instantiation here :D - var originTree = this.origin.exportTree(); - _.each(originTree.commits, function(commit, id) { - // if we have it, no worries - if (this.refs[id]) { - return; - } - // go make it! - var downloadedCommit = this.getOrMakeRecursive(originTree, this.refs, id); - this.commitCollection.add(downloadedCommit); + // then we get the difference in commits between these two graphs, ordered by + // depth + var commitsToMake = this.getTargetGraphDifference( + this, + this.origin, + localBranch, + remoteBranch + ); + + var makeCommit = _.bind(function(id, parentIDs) { + // need to get the parents first. since we order by depth, we know + // the dependencies are there already + var parents = _.map(parentIDs, function(parentID) { + return this.refs[parentID]; + }, this); + return this.makeCommit(parents, id); }, this); - // since we now might have many commits more than before, lets - // check all the ones that didn't use to exist and make animations - var newCommits = this.exportTree().commits; - var commitsToAnimate = []; - _.each(newCommits, function(commit, id) { - if (oldCommits[id]) { - return; - } - commitsToAnimate.push(this.refs[id]); - }, this); - - // now sort by id... - commitsToAnimate.sort(_.bind(this.idSortFunc, this)); - - _.each(commitsToAnimate, function(newCommit) { - AnimationFactory.genCommitBirthAnimation( - this.animationQueue, + // now make the promise chain to make each commit + var chainStep = _.bind(function(id, parents) { + var newCommit = makeCommit(id, parents); + return AnimationFactory.playCommitBirthPromiseAnimation( newCommit, this.gitVisuals ); }, this); - var originLocation = this.origin.exportTree().branches.master.target; - // yay! now we just set o/master and do a simple refresh - this.setTargetLocation(this.refs['o/master'], this.refs[originLocation]); - AnimationFactory.refreshTree(this.animationQueue, this.gitVisuals); + var deferred = Q.defer(); + var chain = deferred.promise; + + _.each(commitsToMake, function(commitJSON) { + chain = chain.then(function() { + return chainStep( + commitJSON.id, + commitJSON.parents + ); + }); + }); + + chain = chain.then(_.bind(function() { + var originLocationID = remoteBranch.get('target').get('id'); + var localCommit = this.refs[originLocationID]; + this.setTargetLocation(localBranch, localCommit); + return AnimationFactory.playRefreshAnimation(this.gitVisuals); + }, this)); + + this.animationQueue.thenFinish(chain, deferred); }; GitEngine.prototype.pullStarter = function() { @@ -24481,7 +24589,7 @@ GitEngine.prototype.checkout = function(idOrTarget) { var type = target.get('type'); // check if this is an origin branch, and if so go to the commit referenced if (type === 'branch' && target.getIsRemote()) { - //target = this.getCommitFromRef(target.get('id')); + target = this.getCommitFromRef(target.get('id')); } if (type !== 'branch' && type !== 'commit') { @@ -25528,6 +25636,10 @@ require.define("/src/js/intl/strings.js",function(require,module,exports,__dirna 'en_US': 'Quick commit. Go Bears!', 'zh_CN': '快速提交。上啊月熊!' }, + 'git-error-origin-fetch-no-ff': { + '__desc__': 'One of the error messages for git', + 'en_US': 'Your origin branch is out of sync with the remote branch and fetch cannot be performed. try using --force' + }, 'git-error-remote-branch': { '__desc__': 'One of the error messages for git', 'en_US': 'You cannot execute that command on a remote branch' diff --git a/build/main.053c68bc.css b/build/main.053c68bc.css deleted file mode 100644 index 7b5a5c71..00000000 --- a/build/main.053c68bc.css +++ /dev/null @@ -1,1120 +0,0 @@ -html { - height: 100%; -} - -body { - margin: 0px; - border: 0px; - padding: 0px; - overflow: hidden; -} - -html, body { - font-family: Monaco, Courier, font-monospace; - color: #eee; -} - -li { - margin: 10px 0; -} - -code { - background: grey; - padding: 4px; - border: 1px solid #333; -} - -p { - word-wrap: break-word; -} - -div.modalTerminal a { - color: rgb(253, 152, 209); - font-weight: bold; -} - -div.modalTerminal p { - line-height: 24px; - margin: 1.5em 0; -} - -.textAlignCenter { - text-align: center; -} - -/* Box Model */ -html, -body, -.box { - display: box; - display: -moz-box; - display: -webkit-box; -} - -body, -.flex1 { - -webkit-box-flex: 1; - -moz-box-flex: 1; - -ms-box-flex: 1; - box-flex: 1; -} - -.flex2 { - -webkit-box-flex: 2; - -moz-box-flex: 2; - -ms-box-flex: 2; - box-flex: 2; -} - -.flex3 { - -webkit-box-flex: 3; - -moz-box-flex: 3; - -ms-box-flex: 3; - box-flex: 3; -} - -.flex10 { - -webkit-box-flex: 10; - -moz-box-flex: 10; - -ms-box-flex: 10; - box-flex: 10; -} - -html, -body, -.vertical { - -webkit-box-orient: vertical; - -moz-box-orient: vertical; - -ms-box-orient: vertical; - box-orient: vertical; -} - -.horizontal { - -webkit-box-orient: horizontal; - -moz-box-orient: horizontal; - -ms-box-orient: horizontal; - box-orient: horizontal; -} - -.centerAlign { - -webkit-box-align: center; - -moz-box-align: center; - -ms-box-align: center; - box-align: center; -} - -.startAlign { - -webkit-box-align: start; - -moz-box-align: start; - -ms-box-align: start; - box-align: start; -} - -.center { - -webkit-box-pack: center; - -moz-box-pack: center; - -ms-box-pack: center; - box-pack: center; -} - -.justify { - -webkit-box-pack: justify; - -moz-box-pack: justify; - -ms-box-pack: justify; - box-pack: justify; -} - -/* Transition */ -.transitionBackground { - -webkit-transition: background 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -moz-transition: background 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -ms-transition: background 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -o-transition: background 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - transition: background 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); -} - -.transitionTransform { - -webkit-transition: -webkit-transform 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -moz-transition: -moz-transform 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -ms-transition: -ms-transform 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -o-transition: -o-transform 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - transition: transform 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); -} - -.transitionOpacity { - -webkit-transition: opacity 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -moz-transition: opacity 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -ms-transition: opacity 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -o-transition: opacity 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - transition: opacity 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); -} - -.transitionOpacityLinear { - -webkit-transition: opacity 700ms linear; - -moz-transition: opacity 700ms linear; - -ms-transition: opacity 700ms linear; - -o-transition: opacity 700ms linear; - transition: opacity 700ms linear; -} - - -.transitionOpacitySlow { - -webkit-transition: opacity 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -moz-transition: opacity 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -ms-transition: opacity 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -o-transition: opacity 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - transition: opacity 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); -} - -.transitionAll { - -webkit-transition: all 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -moz-transition: all 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -ms-transition: all 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -o-transition: all 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - transition: all 700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); -} - -.transitionAllSlow { - -webkit-transition: all 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -moz-transition: all 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -ms-transition: all 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - -o-transition: all 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); - transition: all 1700ms cubic-bezier(0.260, 0.860, 0.440, 0.985); -} - -/* Some interface things */ - -div.canvasTerminalHolder { - width: 100%; - height: 100%; - position: fixed; - top: 0; - left: 0; -} - -#canvasHolder { - position: absolute; - top: 0; - left: 0; - width: 100%; -} - -div.gitDemonstrationView > div.visHolder, -.visBackgroundColor { - background: #5cbcfc; - background-color: #5cbcfc; -} - -#interfaceWrapper { - min-width: 600px; - min-height: 600px; -} - -div.canvasTerminalHolder > div.terminal-window-holder { - margin: 100px 0; - height: 100%; - -webkit-transform: translate3d(0,0,0); - -moz-transform: translate3d(0,0,0); - -o-transform: translate3d(0,0,0); - -ms-transform: translate3d(0,0,0); - transform: translate3d(0,0,0); -} - -div.canvasTerminalHolder > div.terminal-window-holder.slideOut { - -webkit-transform: translate3d(-150%,0,0); - -moz-transform: translate3d(-150%,0,0); - -o-transform: translate3d(-150%,0,0); - -ms-transform: translate3d(-150%,0,0); - transform: translate3d(-150%,0,0); -} - - -div.canvasTerminalHolder > div.terminal-window-holder > div.wrapper { - margin: 0 20px 0px 20px; - height: 80%; - box-shadow: 0 0 30px rgb(0,0,0); - cursor: pointer; -} - -div.canvasTerminalHolder > div.terminal-window-holder div.terminal-text { - padding: 5px 10px; -} - -div.canvasTerminalHolder > div.terminal-window-holder div.toolbar, -div.canvasTerminalHolder > div.terminal-window-holder div.terminal-text, -div.canvasTerminalHolder > div.terminal-window-holder div.inside { - border: 0px; -} - -div.canvasTerminalHolder > div.terminal-window-holder div.terminal-text, -div.canvasTerminalHolder > div.terminal-window-holder div.inside { - background: #ff4c7e; -} - -div.canvasTerminalHolder.startTree > div.terminal-window-holder div.terminal-text, -div.canvasTerminalHolder.startTree > div.terminal-window-holder div.inside { - background: #4CA2FF; -} - -div.canvasTerminalHolder > div.terminal-window-holder div.inside { - min-height: 200px; - border-radius: 0 0 5px 5px; -} - -#controls { - max-width: 400px; -} - -div.canvasTerminalHolder > div.terminal-window-holder { - max-width: 500px; -} - -/* Toolbar */ - -div.toolbar { - /* borrowed from try.github.com along with a bunch of other things */ - background-image: -webkit-linear-gradient(top, #EFEDEE, #C1C1C1); - background-image: -moz-linear-gradient(top, #EFEDEE, #C1C1C1); - background-image: -o-linear-gradient(top, #EFEDEE, #C1C1C1); - background-image: -ms-linear-gradient(top, #EFEDEE, #C1C1C1); - background-image: linear-gradient(top, #EFEDEE, #C1C1C1); - - border-radius: 5px; - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - border: 1px solid #6287A4; - border-bottom: 0; - height: 30px; - position: relative; - text-align: center; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - color: #333; -} - -div.toolbar.level-toolbar { - background-image: -webkit-linear-gradient(top, #B2FF2E, #8AD247); - background-image: -moz-linear-gradient(top, #B2FF2E, #8AD247); - background-image: -o-linear-gradient(top, #B2FF2E, #8AD247); - background-image: -ms-linear-gradient(top, #B2FF2E, #8AD247); - background-image: linear-gradient(top, #B2FF2E, #8AD247); - border-radius: 0; - height: 50px; -} - -span.levelToolbarSpan { - font-weight: 800; - font-style: italic; -} - -div.toolbar.level-toolbar.hidden { - opacity: 0; - height: 0px; -} - -div.toolbar > div.controls { - position: absolute; - top: 9px; - left: 9px; - width: 57px; - height: 13px; -} - -div.toolbar > div.controls div i { - text-shadow: 0.1em 0.1em rgba(255, 255, 255, 0.5); -} - -div.toolbar > div.controls div.box.flex1 { - text-align: center; -} - -div.toolbar > div.controls div.box.flex1 div { - border-radius: 100%; - display: inline-block; - width: 12px; - height: 12px; - margin: 1px 0 0 1px; - position: relative; - text-indent: -9999px; - cursor: default; - - -webkit-box-shadow: 0 2px 0 rgba(255, 255, 255, .8), inset 0 0 3px 1px rgba(0, 0, 0, .6), 0 -1px 1px 1px rgba(0, 0, 0, .4); - box-shadow: 0 2px 0 rgba(255, 255, 255, .8), inset 0 0 3px 1px rgba(0, 0, 0, .6), 0 -1px 1px 1px rgba(0, 0, 0, .4); - - background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0) 50%, #fff 95%, #fff 100%); - background-image: -moz-linear-gradient(rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0) 50%, #fff 95%, #fff 100%); - background-image: -o-linear-gradient(rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0) 50%, #fff 95%, #fff 100%); - background-image: -ms-linear-gradient(rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0) 50%, #fff 95%, #fff 100%); - background-image: linear-gradient(rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0) 50%, #fff 95%, #fff 100%); -} - -div.toolbar > div.controls div.box.flex1 div:hover { - -} - -div.controls div.box.flex1 div.close { - background-color: #fb625f; -} - -div.controls div.box.flex1 div.minimize { - background-color: #f9c57a; -} - -div.controls div.box.flex1 div.plus { - background-color: #8ac872; -} - -/* Command Line */ - -p.commandLine, -div.commandLineResult { - opacity: 1; - font-size: 16px; - margin: 0px; -} - -div.commandLineWarnings p, -div.commandLineResult p { - margin: 0px; -} - -div.commandLineResult p:first-child, -div.commandLineWarnings p:first-child { - padding-top: 8px; -} - -div.commandLineResult p:last-child, -div.commandLineWarnings p:last-child { - padding-bottom: 8px; -} - -div.commandLineWarnings p i.icon-exclamation-sign { - color: yellow; - margin-right: 5px; -} - -p.commandLine span.icons { - float: right; -} - -p.commandLine span.icons i:last-child { - margin-right: 5px; -} - -p.commandLine span.icons i:first-child { - margin-left: 5px; -} - -p.commandLine span.icons i { - opacity: 0; -} - -p.commandLine.inqueue span.icons i.icon-check-empty, -p.commandLine.error span.icons i.icon-exclamation-sign, -p.commandLine.warning span.icons i.icon-exclamation-sign, -p.commandLine.processing span.icons i.icon-retweet, -p.commandLine.finished span.icons i.icon-check { - opacity: 1; -} - -p.commandLine.warning span.icons { - background: #E0FF00; - background-color: #E0FF00; - color: #333; -} - -p.commandLine.inqueue span.icons { - background: #EBEB24; - background-color: #EBEB24; - color: #333; -} - -p.commandLine.processing span.icons { - background: #88E748; - background-color: #88E748; - color: #333; -} - -p.commandLine.finished span.icons { - background: #0066cc; - background-color: #0066cc; - color: white; -} - -p.commandLine.error span.icons { - background: red; - background-color: red; -} - -p.commandResult { - color: blue; -} - -p.commandError, p.errorResult { - color: red; -} - -#commandLineBar #prompt span.promptSign, -p.commandLine span.prompt { - color: greenyellow; - font-weight: bold; -} - -#commandLineBar p.command { - margin: 0; - margin-left: 12px; -} - -#commandLineBar #commandTextField { - position: absolute; - top: -1000px; - left: -1000px; -} - -#commandLineHistory { - margin: 10px; - border-radius: 5px; - box-shadow: 1px 0px 15px rgba(100, 100, 100, 1); -} - -#commandLineHistory #terminal.scrolling { - overflow-y: scroll; - overflow-x: hidden; -} - -#prompt { - text-align: left; - position: relative; - min-height: 22px; -} - -#prompt span { - padding: 0px; - margin: 0px; - border: 0px; - position: absolute; -} - -#prompt span.cursor { - background: #DDD; - opacity: 0; - margin-left: 12px; -} - -#prompt span.cursor.shown { - opacity: 0.7; -} - -#commandLineBar, -.terminal-window .inside, -li.rebaseEntry, -#terminal { - background: #424242; -} - -#terminal, -.terminal-window .inside, -#commandLineBar { - border: 1px solid #303030; -} - -#terminal { - border-bottom: 0; - padding: 0 5px; -} - -.helperBar { - position: absolute; - bottom: 0px; - right: 0px; - background: #424242; - padding: 4px 10px; - border-radius: 5px 0 0 0; - border: 2px solid #EFEDEE; - border-bottom: 0; - border-right: 0; - box-shadow: -1px -1px 5px rgba(0,0,0,0.3); - font-weight: bold; -} - -.helperBar i { - cursor: pointer; -} - -.helperBar a { - cursor: pointer; - font-style: italic; -} - -.helperBar a:after { - content: ' \b7'; - font-style: normal; -} - -.helperBar a:last-child:after { - content: ''; -} - -div.helperBar { - -webkit-transform: translate3d(150%,0,0); - -moz-transform: translate3d(150%,0,0); - -o-transform: translate3d(150%,0,0); - -ms-transform: translate3d(150%,0,0); - transform: translate3d(150%,0,0); -} - -div.helperBar.show { - -webkit-transform: translate3d(0,0,0); - -moz-transform: translate3d(0,0,0); - -o-transform: translate3d(0,0,0); - -ms-transform: translate3d(0,0,0); - transform: translate3d(0,0,0); -} - -#commandLineBar, -.terminal-window .inside { - border-top: 0; - border-radius: 0 0 5px 5px; - padding: 3px; -} - -/* interactive rebase CSS */ -.iRebaseDialog.wrapper { - padding: 20px; -} - -#dialogHolder.shown .iRebaseDialog.wrapper { - margin-top: 30%; -} - -p.helperText, -div.terminal-text p.helperText, -.iRebaseDialog p.helperText { - font-size: 10px; -} - -.iRebaseDialog p.helperText { - color: #999; - margin: 0; - padding: 0; -} - -.iRebaseDialog div.entryHolders { - width: 300px; - margin-left: auto; - margin-right: auto; -} - -.iRebaseDialog div.entryHolders ul.rebaseEntries { - list-style-type: none; - -webkit-padding-start: 0; - -moz-padding-start: 0; - /* optimism, lol */ - -o-padding-start: 0; - -ms-padding-start: 0; -} - -li.rebaseEntry { - margin: 10px; - box-shadow: 0 0 3px rgba(0, 0, 0, 0.5); - cursor: move; - padding: 10px 5px; - border: 1px solid rgba(0, 0, 0, 0.3); -} - -li.rebaseEntry.ui-state-highlight { - padding: 21px; - border: 1px dashed rgba(0, 0, 0, 0.5); -} - -/* wtf jquery UI sortable is barfing here on calculating the position... */ -li.rebaseEntry.ui-sortable-helper { - height: auto !important; - width: auto !important; - position: relative !important; - top: 0px !important; - left: -20px; - display: none; -} - -li.rebaseEntry a#toggleButton { - cursor: pointer; - float: right; - position: relative; - font-size: 14px; - top: -5px; - right: -5px; -} - -li.rebaseEntry.notPicked { - opacity: 0.2; -} -/* Modal Views */ - -div.modalView.box.inFront.show { - overflow-y: auto; -} - -.modalView { - width: 100%; - height: 100%; - position: fixed; - top: 0px; - left: 0px; - - background: rgba(0, 0, 0, 0.6); - z-index: -1; - opacity: 0; -} - -.modalView.inFront { - z-index: 100; -} - -.terminal-window .inside { - padding: 10px; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.7); -} - -.terminal-window .inside h2 { - text-align: center; -} - -.modalView.show { - opacity: 1; -} - -.modalView .terminal-window-holder { - border-radius: 5px; - max-width: 900px; -} - -.modalView .terminal-window { - margin-top: 5%; - margin-bottom: 5%; - -webkit-transform: translate3d(0, -100%, 0); - -moz-transform: translate3d(0, -100%, 0); - -o-transform: translate3d(0, -100%, 0); - -ms-transform: translate3d(0, -100%, 0); - transform: translate3d(0, -100%, 0); -} - -.modalView.show .terminal-window { - -webkit-transform: translate3d(0,0,0); - -moz-transform: translate3d(0,0,0); - -o-transform: translate3d(0,0,0); - -ms-transform: translate3d(0,0,0); - transform: translate3d(0,0,0); -} - -/* Level dropdown view */ -.levelDropdownView { -} - -div.displayName { - border-bottom: 1px dashed grey; - text-align: center; -} - -div.displayName h3 { - margin: 4px; -} - -div.iconHolder { -} - -div.seriesView p.about { - margin: 0px; - padding: 4px; - font-size: 12px; - color: #CCC; -} - -div.levelIcon { - height: 40px; - width: 40px; - border-radius: 5px; - margin: 10px 20px; - box-shadow: 2px 2px 10px rgba(0,0,0,0.7); - background-image: -webkit-linear-gradient(top, white, #AAB1AA); - background-image: -moz-linear-gradient(top, white, #AAB1AA); - background-image: -o-linear-gradient(top, white, #AAB1AA); - background-image: -ms-linear-gradient(top, white, #AAB1AA); - background-image: linear-gradient(top, white, #AAB1AA); - cursor: pointer; -} - -div.levelIcon:hover { - background-image: -webkit-linear-gradient(top, #DADADA, #888686); - background-image: -moz-linear-gradient(top, #DADADA, #888686); - background-image: -o-linear-gradient(top, #DADADA, #888686); - background-image: -ms-linear-gradient(top, #DADADA, #888686); - background-image: linear-gradient(top, #DADADA, #888686); -} - -div.levelIcon:active { - background-image: -webkit-linear-gradient(top, #888686, #7A7A7A); - background-image: -moz-linear-gradient(top, #888686, #7A7A7A); - background-image: -o-linear-gradient(top, #888686, #7A7A7A); - background-image: -ms-linear-gradient(top, #888686, #7A7A7A); - background-image: linear-gradient(top, #888686, #7A7A7A); -} - -div.levelIcon.selected { - box-shadow: 0 0 15px #25F6FF; -} - -div.levelIcon.solved { - background: -webkit-linear-gradient(top, #F3F86B, #35A30F); - background: -moz-linear-gradient(top, #F3F86B, #35A30F); - background: -o-linear-gradient(top, #F3F86B, #35A30F); - background: -ms-linear-gradient(top, #F3F86B, #35A30F); - background: linear-gradient(top, #F3F86B, #35A30F); - border-top: 1px solid #f4ffa1; -} - -div.levelIcon.solved:hover { - border-top-color: #30f03d; - background: #30f03d; -} - -div.levelIcon.solved:active { - border-top-color: #5edb15; - background: #5edb15; -} - -div.levelIcon div.index { - font-weight: 400; - text-shadow: 1px 1px 2px #CCC, 0 2px 0 #C9C9C9; - font-size: 20px; - color: #333; - -webkit-text-stroke: 1px #111; -} - -div.levelIcon div.index i { - display: none; -} - -div.levelIcon.solved div.index i { - display: block; - color: white; - -webkit-text-stroke: 0; - text-shadow: none; - font-size: 30px; -} - -div.levelIcon.solved div.index div.indexNum { - display: none; -} - -/* MultiView Builder */ -.multiViewBuilder div.view { - margin: 10px 0; -} - -.multiViewBuilder .uiButton { - margin: 0 10px; -} - -.multiViewBuilder .buttons { - margin: 20px 0; -} - -.multiViewBuilder div.controlsForView { - margin: 10px 0; - border-top: 1px dashed grey; - padding-top: 10px; -} - -/* DemonstrationBuilder */ - -.demonstrationBuilder { - max-height: 600px; - overflow-y: scroll; - box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.7); - padding: 10px; - margin-bottom: 10px; -} - -.demonstrationBuilder div.buttons { - margin: 8px 0; -} - -.demonstrationBuilder .markdownGrabber{ - min-height: 100px; -} - -.markdownGrabberInput { - margin-top: 32px; -} - -.demonstrationBuilder .markdownGrabber textarea { - height: auto; -} - -.textGrabber textarea { - width: 70%; -} - -/* Git demonstration view, and markdownGrabber */ - -.markdownPresenter textarea { - min-height: 400px; - width: 90%; - margin: 10px; -} - -.markdownGrabber { - padding: 10px; -} - -.markdownGrabber textarea { - width: 90%; - height: 400px; -} - -.demonstrationBuilder .markdownGrabber textarea { - height: 100px; -} - -.markdownGrabberPreview div.insidePreview { - padding: 8px; -} - -.markdownGrabber > div.inputSide, -.gitDemonstrationView > div.demonstrationText { - width: 50%; -} - -div.gitDemonstrationView { - width:100%; -} - -.gitDemonstrationView > div.demonstrationText { - margin-right: 10px; - max-height: 400px; - max-width: 450px; - overflow-y: scroll; - overflow-x: hidden; -} - -.gitDemonstrationView > div.demonstrationText.noLongText { - overflow-y: hidden; -} - -.markdownGrabber div.markdownGrabberPreview, -.gitDemonstrationView > div.visHolder { - box-shadow: 0 0 10px rgba(0, 0, 0, 0.7); - border-radius: 3px; - border: 1px solid #333; -} - -.gitDemonstrationView > div.demonstrationText div.command { - text-align: center; - padding: 10px; -} - -.markdownGrabber, -.gitDemonstrationView { - min-height: 400px; -} - -.gitDemonstrationView div.afterText { - opacity: 0; -} - -.gitDemonstrationView.demonstrated div.afterText { - opacity: 1; -} - -.gitDemonstrationView.demonstrating p.uiButton { - opacity: 0.7; -} - -.gitDemonstrationView.demonstrated p.uiButton { - opacity: 0.4; -} - -/* LeftRightView */ - -.leftRightView div i { - font-size: 45px; - cursor: pointer; -} - -.leftRightView div.hideLeft i { - cursor: default; - opacity: 0; -} - -.leftRightView div { - margin: 0 20px; -} - -.leftRightView div.left { - color: rgb(253, 50, 50); - text-shadow: -1px 1px 3px rgba(0,0,0,0.7); -} - -.leftRightView div.right { - color: rgb(82, 255, 82); - text-shadow: 1px 1px 3px rgba(0,0,0,0.7); -} - -.leftRightView div.right:hover { - color: #74FC74; -} - -.leftRightView div.left:hover { - color: #FF6969; -} - -/* button stuff from liquidGraph */ -.uiButton { - border-top: 1px solid #96d1f8; - background: #65a9d7; - background: -webkit-gradient(linear, left top, left bottom, from(#3e779d), to(#65a9d7)); - background: -webkit-linear-gradient(top, #3e779d, #65a9d7); - background: -moz-linear-gradient(top, #3e779d, #65a9d7); - background: -ms-linear-gradient(top, #3e779d, #65a9d7); - background: -o-linear-gradient(top, #3e779d, #65a9d7); - padding: 5px 10px; - - -webkit-border-radius: 8px; - -moz-border-radius: 8px; - border-radius: 8px; - - -webkit-box-shadow: rgba(0,0,0,1) 0 1px 0; - -moz-box-shadow: rgba(0,0,0,1) 0 1px 0; - box-shadow: rgba(0,0,0,1) 0 1px 0; - text-shadow: rgba(0,0,0,.4) 0 1px 0; - color: white; - - vertical-align: middle; - cursor: pointer; -} - -.uiButton:hover { - border-top-color: #28597a; - background: #28597a; - color: #ccc; -} -.uiButton:active { - border-top-color: #1b435e; - background: #1b435e; -} - -.uiButtonYellow { - border-top: 1px solid #f4ffa1; - background: #288708; - background: -webkit-gradient(linear, left top, left bottom, from(#e0e63c), to(#288708)); - background: -webkit-linear-gradient(top, #e0e63c, #288708); - background: -moz-linear-gradient(top, #e0e63c, #288708); - background: -ms-linear-gradient(top, #e0e63c, #288708); - background: -o-linear-gradient(top, #e0e63c, #288708); -} - -.uiButtonYellow:hover { - border-top-color: #30f03d; - background: #30f03d; - color: #333; -} -.uiButtonYellow:active { - border-top-color: #5edb15; - background: #5edb15; -} - -.uiButtonPink { - border-top: 1px solid #96d1f8; - background: #80007c; - background: -webkit-gradient(linear, left top, left bottom, from(#fa1ee0), to(#80007c)); - background: -webkit-linear-gradient(top, #fa1ee0, #80007c); - background: -moz-linear-gradient(top, #fa1ee0, #80007c); - background: -ms-linear-gradient(top, #fa1ee0, #80007c); - background: -o-linear-gradient(top, #fa1ee0, #80007c); -} -.uiButtonPink:hover { - border-top-color: #fa1ee0; - background: #fa1ee0; - color: #ccc; -} -.uiButtonPink:active { - border-top-color: #80007c; - background: #80007c; -} - -.uiButtonRed { - border-top: 1px solid #ffebee; - background: #cc1212; - background: -webkit-gradient(linear, left top, left bottom, from(#e08992), to(#cc1212)); - background: -webkit-linear-gradient(top, #e08992, #cc1212); - background: -moz-linear-gradient(top, #e08992, #cc1212); - background: -ms-linear-gradient(top, #e08992, #cc1212); - background: -o-linear-gradient(top, #e08992, #cc1212); -} - -.uiButtonRed:hover { - border-top-color: #cc102f; - background: #cc102f; - color: #ccc; -} - -.uiButtonRed:active { - border-top-color: #ff0000; - background: #ff0000; -} - -.uiButtonWhite { - border-top: 1px solid #96d1f8; - background: #449ad4; - background: -webkit-gradient(linear, left top, left bottom, from(#d1edff), to(#449ad4)); - background: -webkit-linear-gradient(top, #d1edff, #449ad4); - background: -moz-linear-gradient(top, #d1edff, #449ad4); - background: -ms-linear-gradient(top, #d1edff, #449ad4); - background: -o-linear-gradient(top, #d1edff, #449ad4); -} - -.uiButtonWhite:hover { - border-top-color: #bae3ff; - background: #bae3ff; - color: #5c5c5c; -} - -.uiButtonWhite:active { - border-top-color: #9bcbeb; - background: #9bcbeb; -} - - -/* Go Home Firefox, you're drunk */ -@-moz-document url-prefix() { - div.wrapper.box.vertical { - -moz-box-flex: 3; - box-flex: 3; - } - - div.toolbar.level-toolbar.box.vertical.center.transitionAll { - width: 100%; - } - - div.controls.box.horizontal.justify { - left: 0 !important; - top: -4px !important; - } - - body { - display: block; - width: 100%; - height: 100%; - } - - #commandLineBar { - min-height: 30px; - } - - #interfaceWrapper { - width: 100%; - height: 100%; - } -} - diff --git a/index.html b/index.html index 861a8151..bf050104 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,7 @@ - + diff --git a/src/js/git/index.js b/src/js/git/index.js index cdb3dbf7..46a7a19a 100644 --- a/src/js/git/index.js +++ b/src/js/git/index.js @@ -762,34 +762,104 @@ GitEngine.prototype.checkUpstreamOfSource = function( GitEngine.prototype.getTargetGraphDifference = function( target, - targetBranch, source, + targetBranch, sourceBranch -) = { +) { sourceBranch = source.resolveID(sourceBranch); var targetSet = target.getUpstreamSet(targetBranch); + var sourceStartCommit = source.getCommitFromRef(sourceBranch); + var sourceTree = source.exportTree(); - var startCommit = sourceTree.commits[ + var sourceStartCommitJSON = sourceTree.commits[sourceStartCommit.get('id')]; + + // ok great, we have our starting point and our stopping set. lets go ahead + // and traverse upwards and keep track of depth manually + sourceStartCommitJSON.depth = 0; + var difference = []; + var toExplore = [sourceStartCommitJSON]; + + while (toExplore.length) { + var here = toExplore.pop(); + difference.push(here); + + _.each(here.parents, function(parentID) { + if (targetSet[parentID]) { + // we already have this commit, lets bounce + return; + } + + var parentJSON = sourceTree.commits[parentID]; + parentJSON.depth = here.depth + 1; + toExplore.push(parentJSON); + }, this); + } + return difference.sort(function(cA, cB) { + // reverse sort by depth + return cB.depth - cA.depth; + }); }; GitEngine.prototype.fetch = function() { + var localBranch = this.refs['o/master']; + var remoteBranch = this.origin.refs['master']; + // first check if this is even allowed by checking the sync between this.checkUpstreamOfSource( this, this.origin, - this.refs['o/master'], - this.origin.refs['master'] + localBranch, + remoteBranch ); // then we get the difference in commits between these two graphs, ordered by // depth + var commitsToMake = this.getTargetGraphDifference( + this, + this.origin, + localBranch, + remoteBranch + ); - // this.commitCollection.add(downloadedCommit); - var originLocation = this.origin.exportTree().branches.master.target; - // yay! now we just set o/master and do a simple refresh - this.setTargetLocation(this.refs['o/master'], this.refs[originLocation]); - AnimationFactory.refreshTree(this.animationQueue, this.gitVisuals); + var makeCommit = _.bind(function(id, parentIDs) { + // need to get the parents first. since we order by depth, we know + // the dependencies are there already + var parents = _.map(parentIDs, function(parentID) { + return this.refs[parentID]; + }, this); + return this.makeCommit(parents, id); + }, this); + + // now make the promise chain to make each commit + var chainStep = _.bind(function(id, parents) { + var newCommit = makeCommit(id, parents); + return AnimationFactory.playCommitBirthPromiseAnimation( + newCommit, + this.gitVisuals + ); + }, this); + + var deferred = Q.defer(); + var chain = deferred.promise; + + _.each(commitsToMake, function(commitJSON) { + chain = chain.then(function() { + return chainStep( + commitJSON.id, + commitJSON.parents + ); + }); + }); + + chain = chain.then(_.bind(function() { + var originLocationID = remoteBranch.get('target').get('id'); + var localCommit = this.refs[originLocationID]; + this.setTargetLocation(localBranch, localCommit); + return AnimationFactory.playRefreshAnimation(this.gitVisuals); + }, this)); + + this.animationQueue.thenFinish(chain, deferred); }; GitEngine.prototype.pullStarter = function() {