git | glob git branch | | Search

This code provides utilities for interacting with Git repositories, enabling you to fetch remote information, retrieve branch names, and parse commit logs.

Run example

npm run import -- "convert git history to google calendar events"

convert git history to google calendar events

var chrono = require('chrono-node');
var _ = require('lodash');
var importer = require('../Core');
var execCmd = importer.import("spawn child process");
var ISODateString = importer.import("convert date iso");
var correctCalendarId = importer.import("lookup calendar name");
var updateEvent = importer.import("update create merge event");
var offset = (new Date()).getTimezoneOffset() * 60 * 1000;

function gitRemote(project) {
    return execCmd(`
git remote -v
`, {cwd: project})
        .then(r => r[0].trim().split('\n').map(l => {
            if(!l) return {function: '(fetch)', name: false}
            var line = l.split('\t');
            return {
                name: line[0],
                address: line[1].split(' ')[0],
                function: line[1].split(' ')[1]
            };
        }))
}

function gitBranch(project, remote) {
    if(!remote) return 'master'
    return execCmd(`
git remote show ${remote}
`, {cwd: project})
        .then(r => `${remote}/${(/\s*HEAD branch:\s*(.*?)\s/ig).exec(r[0].trim())[1]}`)
}

function gitLog(project, remote, branch) {
    var cmd
    if(remote)
        cmd = `
git fetch ${remote}
git log --name-only --pretty=format:"%h%x09%an%x09%aD%x09%s" ${branch}`
    else
        cmd = `git log --name-only --pretty=format:"%h%x09%an%x09%aD%x09%s" ${branch}`
        
    return execCmd(cmd, {cwd: project})
        .then(log => log[remote ? 1 : 0].split('\n\n').map(l => {
            var fields = l.split('\n')[0].split('\t');
            var files = l.split('\n').slice(1);
            return {
                hash: fields[0],
                author: fields[1],
                date: chrono.parse(fields[2])[0].start.date(),
                message: fields[3],
                files: files
            }
        }))
}

function gitHistory(project, summary, branch) {
    var remote, branch;
    if(typeof project == 'undefined') {
        project = '/Users/briancullinan/planet_quake'
    }
    if(typeof summary == 'undefined') {
        summary = 'Worked on Quake 3'
    }
    return gitRemote(project)
        .then(remotes => remote = remotes.filter(r => r.function == '(fetch)')[0].name)
        .then(() => branch || gitBranch(project, remote))
        .then(b => branch = b)
        .then(() => gitLog(project, remote, branch))
        .then(commits => {
        console.log(commits)
            // group commits by a few hours and make a working event
            var grouped = _.groupBy(commits, c => {
                // round to the nearest 3 hours
                return Math.round(c.date.getTime() / (60 * 60 * 3 * 1000)) * 60 * 60 * 3 * 1000;
            })
            return Object.keys(grouped).map(t => {
                var min = _.min(grouped[t].map(g => g.date)).getTime();
                min = Math.round(min / (60 * 60 * 3 * 1000)) * 60 * 60 * 3 * 1000
                var max = _.max(grouped[t].map(g => g.date)).getTime();
                max = Math.round(max / (60 * 60 * 3 * 1000)) * 60 * 60 * 3 * 1000
                var s = grouped[t].map(g => g.message).filter(g => g != 'no message').join(', ')
                return {
                    start: {
                        dateTime: ISODateString(new Date(parseInt(min) - offset))
                    },
                    end: {
                        dateTime: ISODateString(new Date(parseInt(max) + 60 * 60 * 1000 - offset))
                    },
                    summary: summary + (s != '' ? (', ' + s) : ''),
                    description: JSON.stringify(grouped[t], null, 4)
                }
            })
        })
        .then(results => {
            return importer.runAllPromises(results
                .map(event => resolve => updateEvent(event, {})
                    .then(r => resolve(r))))
        })
}

module.exports = gitHistory;

What the code could have been:

const chrono = require('chrono-node');
const _ = require('lodash');
const importer = require('../Core');
const { spawn } = require('child_process');
const ISODateString = importer.import('convert date iso');
const correctCalendarId = importer.import('lookup calendar name');
const updateEvent = importer.import('update create merge event');

/**
 * Function to execute git remote command and parse output
 * @param {string} project - The path to the git project
 * @returns {Promise} - An array of objects representing the git remotes
 */
function getGitRemotes(project) {
    return new Promise((resolve, reject) => {
        const cmd = 'git remote -v';
        childProcess.exec(cmd, { cwd: project }, (error, stdout, stderr) => {
            if (error) {
                reject(error);
            } else {
                const remotes = stdout.trim().split('\n').map(line => {
                    if (!line) return { function: '(fetch)', name: false };
                    const [name, address] = line.split('\t');
                    const [function] = line.split(' ').pop().trim().split('(')[1].split(')')[0].split(',');
                    return { name, address, function };
                });
                resolve(remotes);
            }
        });
    });
}

/**
 * Function to execute git branch command and parse output
 * @param {string} project - The path to the git project
 * @param {string} remote - The name of the git remote to show
 * @returns {Promise} - The name of the current branch
 */
function getGitBranch(project, remote) {
    return new Promise((resolve, reject) => {
        const cmd = `git remote show ${remote}`;
        childProcess.exec(cmd, { cwd: project }, (error, stdout, stderr) => {
            if (error) {
                reject(error);
            } else {
                const branch = stdout.trim().match(/\s*HEAD branch:\s*(.*?)\s/ig)?.[1];
                resolve(branch);
            }
        });
    });
}

/**
 * Function to execute git log command and parse output
 * @param {string} project - The path to the git project
 * @param {string} remote - The name of the git remote to fetch from
 * @param {string} branch - The name of the git branch to log
 * @returns {Promise} - An array of objects representing the git commits
 */
function getGitLog(project, remote, branch) {
    return new Promise((resolve, reject) => {
        let cmd;
        if (remote) {
            cmd = `git fetch ${remote} && git log --name-only --pretty=format:"%h%x09%an%x09%aD%x09%s" ${branch}`;
        } else {
            cmd = `git log --name-only --pretty=format:"%h%x09%an%x09%aD%x09%s" ${branch}`;
        }
        childProcess.exec(cmd, { cwd: project }, (error, stdout, stderr) => {
            if (error) {
                reject(error);
            } else {
                const commits = stdout.trim().split('\n\n').map(log => {
                    const [hash, author, date, message] = log.split('\n')[0].split('\t');
                    const files = log.split('\n').slice(1);
                    return {
                        hash,
                        author,
                        date: chrono.parse(date)[0].start.date(),
                        message,
                        files,
                    };
                });
                resolve(commits);
            }
        });
    });
}

/**
 * Function to group commits by a few hours and create a working event
 * @param {string} project - The path to the git project
 * @param {string} summary - The summary of the event
 * @param {string} branch - The name of the git branch
 * @returns {Promise} - An array of objects representing the events
 */
function gitHistory(project, summary, branch) {
    return getGitRemotes(project)
       .then(remotes => {
            const remote = remotes.find(r => r.function === '(fetch)').name;
            return getGitBranch(project, remote);
        })
       .then(branch => {
            if (!branch) branch ='master';
            return getGitLog(project, remote, branch);
        })
       .then(commits => {
            const grouped = _.groupBy(commits, c => {
                const min = Math.round(c.date.getTime() / (60 * 60 * 3 * 1000)) * 60 * 60 * 3 * 1000;
                return min;
            });
            const events = Object.keys(grouped).map(t => {
                const min = Math.round(_.min(grouped[t].map(g => g.date)).getTime() / (60 * 60 * 3 * 1000)) * 60 * 60 * 3 * 1000;
                const max = Math.round(_.max(grouped[t].map(g => g.date)).getTime() / (60 * 60 * 3 * 1000)) * 60 * 60 * 3 * 1000;
                const messages = grouped[t].map(g => g.message).filter(m => m!== 'no message').join(', ');
                return {
                    start: {
                        dateTime: ISODateString(new Date(parseInt(min) - offset)),
                    },
                    end: {
                        dateTime: ISODateString(new Date(parseInt(max) + 60 * 60 * 1000 - offset)),
                    },
                    summary: summary + (messages!== ''? `, ${messages}` : ''),
                    description: JSON.stringify(grouped[t], null, 4),
                };
            });
            return importer.runAllPromises(events.map(event => resolve => updateEvent(event, {}).then(r => resolve(r))));
        });
}

const childProcess = require('child_process');

module.exports = gitHistory;

This code defines several functions for interacting with Git repositories, including fetching remote information, retrieving branch names, and parsing commit logs.

Here's a breakdown:

  1. Imports:

  2. gitRemote Function:

  3. gitBranch Function:

  4. gitLog Function:

  5. gitHistory Function:

In essence, this code provides a set of utilities for interacting with Git repositories, allowing you to fetch remote information, retrieve branch names, and parse commit logs.