mirror of
https://github.com/pcottle/learnGitBranching.git
synced 2025-06-30 17:54:28 +02:00
Merging now worksgit status! and have some nice graph exploration
This commit is contained in:
parent
af76c03ad1
commit
6cb4c6b4a1
7 changed files with 206 additions and 52 deletions
|
@ -12,11 +12,11 @@ function Command(str) {
|
||||||
|
|
||||||
Command.prototype.getShortcutMap = function() {
|
Command.prototype.getShortcutMap = function() {
|
||||||
return {
|
return {
|
||||||
'git commit': /^gc/,
|
'git commit': /^gc($|\s)/,
|
||||||
'git add': /^ga/,
|
'git add': /^ga($|\s)/,
|
||||||
'git checkout': /^gchk/,
|
'git checkout': /^gchk($|\s)/,
|
||||||
'git rebase': /^gr/,
|
'git rebase': /^gr($|\s)/,
|
||||||
'git branch': /^gb/
|
'git branch': /^gb($|\s)/
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,7 +30,8 @@ Command.prototype.getRegexMap = function() {
|
||||||
rebase: /^rebase($|\s)/,
|
rebase: /^rebase($|\s)/,
|
||||||
reset: /^reset($|\s)/,
|
reset: /^reset($|\s)/,
|
||||||
branch: /^branch($|\s)/,
|
branch: /^branch($|\s)/,
|
||||||
revert: /^revert($|\s)/
|
revert: /^revert($|\s)/,
|
||||||
|
merge: /^merge($|\s)/
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,7 +79,7 @@ Command.prototype.parse = function(str) {
|
||||||
_.each(this.getShortcutMap(), function(regex, method) {
|
_.each(this.getShortcutMap(), function(regex, method) {
|
||||||
var results = regex.exec(str);
|
var results = regex.exec(str);
|
||||||
if (results) {
|
if (results) {
|
||||||
str = method + str.slice(results[0].length);
|
str = method + ' ' + str.slice(results[0].length);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -155,6 +156,7 @@ OptionParser.prototype.getMasterOptionMap = function() {
|
||||||
reset: {
|
reset: {
|
||||||
'--hard': false,
|
'--hard': false,
|
||||||
},
|
},
|
||||||
|
merge: {},
|
||||||
rebase: {},
|
rebase: {},
|
||||||
revert: {}
|
revert: {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,6 +29,7 @@ var graphics = {
|
||||||
// ref names
|
// ref names
|
||||||
refFont: '14pt Courier New',
|
refFont: '14pt Courier New',
|
||||||
refFontFill: '#FFF',
|
refFontFill: '#FFF',
|
||||||
|
refSelectedFontFill: 'rgb(255, 30, 10)',
|
||||||
|
|
||||||
// ref arrows
|
// ref arrows
|
||||||
arrowFill: '#FFF',
|
arrowFill: '#FFF',
|
||||||
|
|
165
src/git.js
165
src/git.js
|
@ -116,9 +116,15 @@ GitEngine.prototype.logBranches = function() {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.makeCommit = function(parent) {
|
GitEngine.prototype.makeCommit = function() {
|
||||||
|
// manually copy arguments
|
||||||
|
var parents = [];
|
||||||
|
_.each(arguments, function(arg) {
|
||||||
|
parents.push(arg);
|
||||||
|
});
|
||||||
|
|
||||||
var commit = new Commit({
|
var commit = new Commit({
|
||||||
parents: [parent]
|
parents: parents
|
||||||
});
|
});
|
||||||
this.refs[commit.get('id')] = commit;
|
this.refs[commit.get('id')] = commit;
|
||||||
this.collection.add(commit);
|
this.collection.add(commit);
|
||||||
|
@ -154,6 +160,7 @@ GitEngine.prototype.commit = function() {
|
||||||
var newCommit = this.makeCommit(targetCommit);
|
var newCommit = this.makeCommit(targetCommit);
|
||||||
if (this.getDetachedHead()) {
|
if (this.getDetachedHead()) {
|
||||||
events.trigger('commandProcessWarn', 'Warning!! Detached HEAD state');
|
events.trigger('commandProcessWarn', 'Warning!! Detached HEAD state');
|
||||||
|
this.HEAD.set('target', newCommit);
|
||||||
} else {
|
} else {
|
||||||
var targetBranch = this.HEAD.get('target');
|
var targetBranch = this.HEAD.get('target');
|
||||||
targetBranch.set('target', newCommit);
|
targetBranch.set('target', newCommit);
|
||||||
|
@ -218,6 +225,14 @@ GitEngine.prototype.getCommitFromRef = function(ref) {
|
||||||
return start;
|
return start;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GitEngine.prototype.getOneBeforeCommit = function(ref) {
|
||||||
|
var start = this.resolveId(ref);
|
||||||
|
if (start === this.HEAD) {
|
||||||
|
start = start.get('target');
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
};
|
||||||
|
|
||||||
GitEngine.prototype.numBackFrom = function(commit, numBack) {
|
GitEngine.prototype.numBackFrom = function(commit, numBack) {
|
||||||
// going back '3' from a given ref is not trivial, for you might have
|
// going back '3' from a given ref is not trivial, for you might have
|
||||||
// a bunch of merge commits and such. like this situation:
|
// a bunch of merge commits and such. like this situation:
|
||||||
|
@ -250,6 +265,7 @@ GitEngine.prototype.numBackFrom = function(commit, numBack) {
|
||||||
|
|
||||||
while (pQueue.length && numBack !== 0) {
|
while (pQueue.length && numBack !== 0) {
|
||||||
var popped = pQueue.shift(0);
|
var popped = pQueue.shift(0);
|
||||||
|
console.log(popped);
|
||||||
pQueue = pQueue.concat(popped.get('parents'));
|
pQueue = pQueue.concat(popped.get('parents'));
|
||||||
pQueue.sort(sortFunc);
|
pQueue.sort(sortFunc);
|
||||||
numBack--;
|
numBack--;
|
||||||
|
@ -263,20 +279,92 @@ GitEngine.prototype.numBackFrom = function(commit, numBack) {
|
||||||
return pQueue.shift(0);
|
return pQueue.shift(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GitEngine.prototype.mergeStarter = function() {
|
||||||
|
if (this.generalArgs.length > 2) {
|
||||||
|
throw new GitError({
|
||||||
|
msg: 'merge with more than 2 arguments doesnt make sense!'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!this.generalArgs.length) {
|
||||||
|
throw new GitError({
|
||||||
|
msg: 'Give me a branch to merge into!'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.generalArgs.length == 1) {
|
||||||
|
this.generalArgs.push('HEAD');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_.include(this.generalArgs, 'HEAD') && this.getDetachedHead()) {
|
||||||
|
throw new GitError({
|
||||||
|
msg: 'Cant merge things referencing HEAD when you are in detached head!'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.merge(this.generalArgs[0], this.generalArgs[1]);
|
||||||
|
};
|
||||||
|
|
||||||
|
GitEngine.prototype.merge = function(targetSource, currentLocation) {
|
||||||
|
// first some conditions
|
||||||
|
if (this.isUpstreamOf(targetSource, currentLocation)) {
|
||||||
|
throw new CommandResult({
|
||||||
|
msg: 'Branch already up-to-date'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isUpstreamOf(currentLocation, targetSource)) {
|
||||||
|
// just set the target of this current location to the source
|
||||||
|
var currLoc = this.getOneBeforeCommit(currentLocation);
|
||||||
|
currLoc.set('target', this.getCommitFromRef(targetSource));
|
||||||
|
throw new CommandResult({
|
||||||
|
msg: 'Fast-forwarding...'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// now the part of making a merge commit
|
||||||
|
var parent1 = this.getCommitFromRef(currentLocation);
|
||||||
|
var parent2 = this.getCommitFromRef(targetSource);
|
||||||
|
|
||||||
|
var commit = this.makeCommit(parent1, parent2);
|
||||||
|
var currLoc = this.getOneBeforeCommit(currentLocation);
|
||||||
|
currLoc.set('target', commit);
|
||||||
|
};
|
||||||
|
|
||||||
GitEngine.prototype.checkoutStarter = function() {
|
GitEngine.prototype.checkoutStarter = function() {
|
||||||
|
if (this.commandOptions['-b']) {
|
||||||
|
// the user is really trying to just make a branch and then switch to it. so first:
|
||||||
|
var args = this.commandOptions['-b'];
|
||||||
|
if (!args.length) {
|
||||||
|
throw new GitError({
|
||||||
|
msg: 'I expect a branch name with "checkout -b"!!'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (args.length > 2) {
|
||||||
|
throw new GitError({
|
||||||
|
msg: 'Only two args max with checkout -b please (the new name and target branch)'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are good!
|
||||||
|
if (args.length == 1) {
|
||||||
|
args.push('HEAD');
|
||||||
|
}
|
||||||
|
this.branch(args[0], args[1]);
|
||||||
|
this.checkout(args[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.generalArgs.length != 1) {
|
if (this.generalArgs.length != 1) {
|
||||||
throw new GitError({
|
throw new GitError({
|
||||||
msg: 'I expect one argument along with git checkout (dont reference files)'
|
msg: 'I expect one argument along with git checkout (dont reference files)'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.checkout(this.generalArgs[0]);
|
this.checkout(this.generalArgs[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.checkout = function(idOrTarget) {
|
GitEngine.prototype.checkout = function(idOrTarget) {
|
||||||
console.log('the target', idOrTarget);
|
console.log('the target', idOrTarget);
|
||||||
var target = this.resolveId(idOrTarget);
|
var target = this.resolveId(idOrTarget);
|
||||||
console.log(target);
|
console.log('the result', target);
|
||||||
if (target.get('id') === 'HEAD') {
|
if (target.get('id') === 'HEAD') {
|
||||||
// git checkout HEAD is a
|
// git checkout HEAD is a
|
||||||
// meaningless command but i used to do this back in the day
|
// meaningless command but i used to do this back in the day
|
||||||
|
@ -363,37 +451,59 @@ GitEngine.prototype.dispatch = function(commandObj) {
|
||||||
this[commandObj.method + 'Starter']();
|
this[commandObj.method + 'Starter']();
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.add = function() {
|
GitEngine.prototype.addStarter = function() {
|
||||||
throw new CommandResult({
|
throw new CommandResult({
|
||||||
msg: "This demo is meant to demonstrate git branching, so don't worry about " +
|
msg: "This demo is meant to demonstrate git branching, so don't worry about " +
|
||||||
"adding / staging files. Just go ahead and commit away!"
|
"adding / staging files. Just go ahead and commit away!"
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.execute = function(command, callback) {
|
GitEngine.prototype.getCommonAncestor = function(cousin, ancestor) {
|
||||||
// execute command, and when it's finished, call the callback
|
if (this.isUpstreamOf(cousin, ancestor)) {
|
||||||
// we still need to figure this out
|
throw new Error('Dont use common ancestor if we are upstream!');
|
||||||
|
}
|
||||||
|
|
||||||
var closures = this.getClosuresForCommand(command);
|
var upstreamSet = this.getUpstreamSet(ancestor);
|
||||||
// make a scheduler based on all the closures, and pass in our callback
|
// now BFS off of cousin until you find something
|
||||||
var s = new Scheduler(closures, {
|
|
||||||
callback: callback
|
var queue = [this.getCommitFromRef(cousin)];
|
||||||
});
|
while (queue.length) {
|
||||||
s.start();
|
var here = queue.pop();
|
||||||
|
if (upstreamSet[here.get('id')]) {
|
||||||
|
return here;
|
||||||
|
}
|
||||||
|
queue.concat(here.get('parents'));
|
||||||
|
}
|
||||||
|
throw new Error('something has gone very wrong... two nodes arent connected!');
|
||||||
};
|
};
|
||||||
|
|
||||||
GitEngine.prototype.getClosuresForCommand = function(command) {
|
GitEngine.prototype.isUpstreamOf = function(child, ancestor) {
|
||||||
var numbers = [1,2,3,4,5,6,7,8,9,10];
|
child = this.getCommitFromRef(child);
|
||||||
var closures = [];
|
|
||||||
_.each(numbers, function(num) {
|
// basically just do a completely BFS search on ancestor to the root, then
|
||||||
var c = function() {
|
// check for membership of child in that set of explored nodes
|
||||||
console.log(num);
|
var upstream = this.getUpstreamSet(ancestor);
|
||||||
};
|
return upstream[child.get('id')] !== undefined;
|
||||||
closures.push(c);
|
|
||||||
});
|
|
||||||
return closures;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GitEngine.prototype.getUpstreamSet = function(ancestor) {
|
||||||
|
var commit = this.getCommitFromRef(ancestor);
|
||||||
|
var queue = [commit];
|
||||||
|
|
||||||
|
var exploredSet = {};
|
||||||
|
while (queue.length) {
|
||||||
|
var here = queue.pop();
|
||||||
|
var rents = here.get('parents');
|
||||||
|
|
||||||
|
_.each(rents, function(rent) {
|
||||||
|
exploredSet[rent.get('id')] = true;
|
||||||
|
queue.push(rent);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return exploredSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
var Ref = Backbone.Model.extend({
|
var Ref = Backbone.Model.extend({
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
if (!this.get('target')) {
|
if (!this.get('target')) {
|
||||||
|
@ -422,12 +532,15 @@ var Branch = Ref.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
var Commit = Backbone.Model.extend({
|
var Commit = Backbone.Model.extend({
|
||||||
|
defaults: {
|
||||||
|
type: 'commit',
|
||||||
|
children: []
|
||||||
|
},
|
||||||
|
|
||||||
validateAtInit: function() {
|
validateAtInit: function() {
|
||||||
if (!this.get('id')) {
|
if (!this.get('id')) {
|
||||||
this.set('id', uniqueId('C'));
|
this.set('id', uniqueId('C'));
|
||||||
}
|
}
|
||||||
this.set('type', 'commit');
|
|
||||||
this.set('children', []);
|
|
||||||
|
|
||||||
// root commits have no parents
|
// root commits have no parents
|
||||||
if (this.get('rootCommit')) {
|
if (this.get('rootCommit')) {
|
||||||
|
|
|
@ -36,9 +36,12 @@ Renderer = function(canvas) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
events.trigger('fixNodePositions', particleSystem);
|
||||||
|
|
||||||
ctx.clearRect(0,0, canvas.width, canvas.height);
|
ctx.clearRect(0,0, canvas.width, canvas.height);
|
||||||
particleSystem.eachEdge(this.drawEdge);
|
particleSystem.eachEdge(this.drawEdge);
|
||||||
particleSystem.eachNode(this.drawNode);
|
particleSystem.eachNode(this.drawNode);
|
||||||
|
|
||||||
events.trigger('drawGitVisuals', particleSystem, ctx, canvas);
|
events.trigger('drawGitVisuals', particleSystem, ctx, canvas);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ var gitEngine = null;
|
||||||
var gitVisuals = null;
|
var gitVisuals = null;
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
sys = arbor.ParticleSystem(4000, 500, 0.5, false, 55, 0.005, 'verlet');
|
sys = arbor.ParticleSystem(4000, 200, 0.5, false, 55, 0.005, 'verlet');
|
||||||
sys.renderer = Renderer('#viewport');
|
sys.renderer = Renderer('#viewport');
|
||||||
|
|
||||||
new CommandLineView({
|
new CommandLineView({
|
||||||
|
@ -24,7 +24,8 @@ $(document).ready(function(){
|
||||||
var repulsionBreathe = function(r) {
|
var repulsionBreathe = function(r) {
|
||||||
sys.parameters({repulsion: r});
|
sys.parameters({repulsion: r});
|
||||||
};
|
};
|
||||||
var b = new Breather(repulsionBreathe, 6050, 4000);
|
// TODO: decide on breather
|
||||||
|
// var b = new Breather(repulsionBreathe, 6050, 4000);
|
||||||
|
|
||||||
graphicsEffects.edgeStrokeEffect = new GraphicsEffect('edgeStroke', {wait: 1000});
|
graphicsEffects.edgeStrokeEffect = new GraphicsEffect('edgeStroke', {wait: 1000});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
html,body {
|
html, body {
|
||||||
overflow:hidden;
|
overflow:hidden;
|
||||||
|
|
||||||
background: -moz-radial-gradient(center, ellipse cover, #0066cc 0%, #000000 90%);
|
background: -moz-radial-gradient(center, ellipse cover, #0066cc 0%, #000000 90%);
|
||||||
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,#0066cc), color-stop(90%,#000000));
|
background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,#0066cc), color-stop(90%,#000000));
|
||||||
|
@ -54,7 +54,7 @@ span.arrows {
|
||||||
|
|
||||||
#commandLineHistory {
|
#commandLineHistory {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 500px;
|
height: 200px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
background: #000;
|
background: #000;
|
||||||
opacity: 0.85;
|
opacity: 0.85;
|
||||||
|
|
|
@ -3,9 +3,20 @@ function GitVisuals() {
|
||||||
|
|
||||||
this.collection.on('change', _.bind(this.collectionChanged, this));
|
this.collection.on('change', _.bind(this.collectionChanged, this));
|
||||||
events.on('drawGitVisuals', _.bind(this.drawVisuals, this));
|
events.on('drawGitVisuals', _.bind(this.drawVisuals, this));
|
||||||
|
events.on('fixNodePositions', _.bind(this.fixNodes, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
GitVisuals.prototype.drawVisuals = function(sys, ctx, canvas) {
|
GitVisuals.prototype.drawVisuals = function(sys, ctx, canvas) {
|
||||||
|
|
||||||
|
this.drawRefs(sys, ctx, canvas);
|
||||||
|
};
|
||||||
|
|
||||||
|
GitVisuals.prototype.fixNodes = function(sys) {
|
||||||
|
this.fixRootCommit(sys);
|
||||||
|
};
|
||||||
|
|
||||||
|
GitVisuals.prototype.drawRefs = function(sys, ctx, canvas) {
|
||||||
|
var sFill = graphics.refSelectedFontFill;
|
||||||
// we need to draw refs here
|
// we need to draw refs here
|
||||||
var branches = gitEngine.getBranches();
|
var branches = gitEngine.getBranches();
|
||||||
var detachedHead = gitEngine.getDetachedHead();
|
var detachedHead = gitEngine.getDetachedHead();
|
||||||
|
@ -14,21 +25,32 @@ GitVisuals.prototype.drawVisuals = function(sys, ctx, canvas) {
|
||||||
_.forEach(branches, _.bind(function(branch) {
|
_.forEach(branches, _.bind(function(branch) {
|
||||||
// get the location of the arbor node and then somehow draw the ref to the side?
|
// get the location of the arbor node and then somehow draw the ref to the side?
|
||||||
var node = branch.target.get('arborNode');
|
var node = branch.target.get('arborNode');
|
||||||
var nodePoint = sys.toScreen(node._p);
|
var fillStyle = branch.selected ? sFill : undefined;
|
||||||
|
this.drawLabel(ctx, sys, node, branch.id, fillStyle);
|
||||||
// text position
|
|
||||||
// TODO: better positioning of text here
|
|
||||||
var screenPoint = _.clone(nodePoint);
|
|
||||||
screenPoint.x += 100;
|
|
||||||
|
|
||||||
ctx.font = graphics.refFont;
|
|
||||||
ctx.fillStyle = graphics.refFontFill;
|
|
||||||
ctx.fillText(branch.id, screenPoint.x, screenPoint.y);
|
|
||||||
|
|
||||||
// also draw an arrow
|
|
||||||
var offset = Math.round(graphics.nodeRadius * 2.5);
|
|
||||||
this.drawArrow(ctx, screenPoint, nodePoint, graphics.arrowHeadWidth, offset);
|
|
||||||
}, this));
|
}, this));
|
||||||
|
|
||||||
|
if (detachedHead) {
|
||||||
|
var node = HEAD.get('target').get('arborNode');
|
||||||
|
this.drawLabel(ctx, sys, node, 'HEAD', sFill);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GitVisuals.prototype.drawLabel = function(ctx, sys, node, name, fillStyle) {
|
||||||
|
fillStyle = fillStyle || graphics.refFontFill;
|
||||||
|
|
||||||
|
var nodePoint = sys.toScreen(node._p);
|
||||||
|
// text position
|
||||||
|
// TODO: better positioning of text here
|
||||||
|
var screenPoint = _.clone(nodePoint);
|
||||||
|
screenPoint.x += 100;
|
||||||
|
|
||||||
|
ctx.font = graphics.refFont;
|
||||||
|
ctx.fillStyle = fillStyle;
|
||||||
|
ctx.fillText(name, screenPoint.x, screenPoint.y);
|
||||||
|
|
||||||
|
// also draw an arrow
|
||||||
|
var offset = Math.round(graphics.nodeRadius * 2.5);
|
||||||
|
this.drawArrow(ctx, screenPoint, nodePoint, graphics.arrowHeadWidth, offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
GitVisuals.prototype.drawArrow = function(ctx, start, end, headWidth, offset) {
|
GitVisuals.prototype.drawArrow = function(ctx, start, end, headWidth, offset) {
|
||||||
|
@ -55,3 +77,15 @@ GitVisuals.prototype.drawArrow = function(ctx, start, end, headWidth, offset) {
|
||||||
GitVisuals.prototype.collectionChanged = function() {
|
GitVisuals.prototype.collectionChanged = function() {
|
||||||
// redo the algorithms
|
// redo the algorithms
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GitVisuals.prototype.fixRootCommit = function(sys) {
|
||||||
|
// get the viewports bottom center
|
||||||
|
var bottomPosScreen = {
|
||||||
|
x: Math.round($('#viewport').width() * 0.5),
|
||||||
|
y: $('#viewport').height() - graphics.nodeRadius * 2.5
|
||||||
|
};
|
||||||
|
|
||||||
|
var bottomPos = sys.fromScreen(bottomPosScreen);
|
||||||
|
// fix the root commit to the bottom
|
||||||
|
gitEngine.rootCommit.get('arborNode').p = bottomPos;
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue