git | json git tree | Display graphs of different commands and scenarios using dry-run | Search

This code manages and visualizes Git branches by resetting them to their parent commits and generating SVG representations of the resulting tree structure.

Run example

npm run import -- "source tree"

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))
}

What the code could have been:

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:

  1. Imports:

  2. getResetCommit Function:

  3. resetAllBranches Function:

  4. gitTipOfTree Function:

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.