This code manages and visualizes Git branches by resetting them to their parent commits and generating SVG representations of the resulting tree structure.
npm run import -- "source tree"
var importer = require('../Core');
var _ = require('underscore');
var fs = require('fs');
var path = require('path');
var {
formatNodes, gitTree, displayBranches,
cloneProject, execCmd
} = importer.import("spawn child process",
"d3.ipynb[format d3 tree]",
"json git tree",
"d3.ipynb[display d3 tree]",
"git project directory");
// TODO: convert this to bash
function getResetCommit(branch, parent, project) {
branch = branch.replace('HEAD -> ', '').trim();
parent = parent.replace('HEAD -> ', '').trim();
return execCmd(`
git checkout ${branch}
git reset --mixed ${parent}
git add -A
git commit -m "auto reset ${branch}"
`, {cwd: project});
}
var svgs = [];
function resetAllBranches() {
var children = [];
var nodeTree = _.sortBy(gitTree(project), a => a.time);
var promises = [];
for (const n of nodeTree) {
var current = n;
var parentCount = 0;
while (typeof current.parent !== 'undefined'
&& current.parent.branch === current.branch) {
current = current.parent;
parentCount++;
}
if (parentCount > 0 && typeof current.parent !== 'undefined') {
// TODO: keep track of the parent so the squashed branch can be merged on to the newly squashed parent
promises.push(((current, n) => resolve => {
if (typeof n.children !== 'undefined') {
children.push(n);
}
return getResetCommit(n.branch, current.parent.name, project)
.then(() => {
var nodeTree = _.sortBy(gitTree(project), a => a.time);
svgs.push(displayBranches(nodeTree));
resolve();
})
})(current, n));
}
}
return importer.runAllPromises(promises)
.then(() => children);
}
function gitTipOfTree(project) {
svgs = [];
return (Promise.resolve(project) || cloneProject(project, true))
// TODO: git checkout command
// TODO: pull all missing remmotes
.then(r => {
project = r;
var nodeTree = _.sortBy(gitTree(project), a => a.time);
const head = nodeTree.filter(r => r.branch.indexOf('HEAD') > -1)[0];
const branch = head
? (nodeTree.filter(r => r.branch.indexOf(head.branch.replace(/HEAD *-*>* */ig, '').split(/\s*,\s*/ig)) > -1)[0] || nodeTree[0])
: nodeTree[0];
return displayBranches([branch]);
})
.then(r => svgs.push(r))
//.then(() => resetAllBranches())
.then(() => svgs)
}
module.exports = gitTipOfTree;
if(typeof $ !== 'undefined') {
var PROFILE_PATH = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE || '';
var project = path.join(PROFILE_PATH, 'Documents/portal-copy-2018-1-24-23-49-46');
$.async();
gitTipOfTree(project)
.then(r => $.html(r.join('')))
.catch(e => $.sendError(e))
}
const { formatNodes, gitTree, displayBranches, cloneProject, execCmd } = require('../Core');
/**
* Resets the commit for a given branch by checking out the branch, resetting to the specified parent commit, adding all files, and committing the changes.
* @param {string} branch The branch to reset.
* @param {string} parent The parent commit to reset to.
* @param {string} project The Git project directory.
* @returns {Promise<string>} The output of the Git commit command.
*/
function getResetCommit(branch, parent, project) {
const command = [
'git checkout',
branch,
'git reset --mixed',
parent,
'git add -A',
'git commit -m',
`auto reset ${branch}`,
].join(' ');
return execCmd(command, { cwd: project });
}
/**
* Resets all branches by iteratively squashing branches until no further squashing is possible.
* @param {string} project The Git project directory.
* @returns {Promise<string[]>} The SVGs representing the branches after squashing.
*/
function resetAllBranches(project) {
const children = [];
const promises = [];
const nodeTree = gitTree(project).sort((a, b) => a.time - b.time);
for (const node of nodeTree) {
let current = node;
let parentCount = 0;
while (current.parent && current.parent.branch === current.branch) {
current = current.parent;
parentCount++;
}
if (parentCount > 0 && current.parent) {
promises.push((current, node) => () => {
children.push(node);
return getResetCommit(node.branch, current.parent.name, project)
.then(() => {
const nodeTree = gitTree(project).sort((a, b) => a.time - b.time);
return displayBranches(nodeTree);
});
})(current, node);
}
}
return Promise.all(promises.map(p => p()))
.then(() => children);
}
/**
* Returns the SVG representation of the tip of the Git tree.
* @param {string} project The Git project directory.
* @returns {Promise<string>} The SVG representing the tip of the tree.
*/
function gitTipOfTree(project) {
const promises = [
cloneProject(project, true),
resetAllBranches(project),
];
return Promise.all(promises)
.then(([clone, children]) => {
const nodeTree = gitTree(project).sort((a, b) => a.time - b.time);
const head = nodeTree.find(node => node.branch.indexOf('HEAD') > -1);
const branch = head
? nodeTree.find(node => node.branch.indexOf(head.branch.replace(/HEAD *-*>* */ig, '').split(/\s*,\s*/ig)) > -1) || nodeTree[0]
: nodeTree[0];
return displayBranches([branch]);
})
.then(svg => [svg]);
}
module.exports = gitTipOfTree;
This code defines functions for managing and visualizing Git branches within a project.
Here's a breakdown:
Imports:
getResetCommit
Function:
resetAllBranches
Function:
getResetCommit
to reset the branch to its parent commit.displayBranches
.gitTipOfTree
Function:
cloneProject
to clone the project if it doesn't exist locally.resetAllBranches
to reset all branches within the project.In essence, this code provides a way to manage and visualize Git branches by resetting them to their parent commits and generating SVG representations of the resulting tree structure.