mirror of
https://github.com/HeyPuter/puter.git
synced 2025-01-23 22:40:20 +08:00
feat(git): Display ref names in git log
and git show
This commit is contained in:
parent
351d3f50ba
commit
45cdfcb5bf
@ -18,6 +18,7 @@
|
||||
*/
|
||||
import { shorten_hash } from './git-helpers.js';
|
||||
import chalk from 'chalk';
|
||||
import { get_matching_refs } from './refs.js';
|
||||
|
||||
export const commit_formatting_options = {
|
||||
'abbrev-commit': {
|
||||
@ -68,9 +69,35 @@ export const process_commit_formatting_options = (options) => {
|
||||
* @param short_hashes Whwther to shorten the hash
|
||||
* @returns {String}
|
||||
*/
|
||||
export const format_oid = async (git_context, oid, { short_hashes = false } = {}) => {
|
||||
// TODO: List refs at this commit, after the hash
|
||||
return short_hashes ? shorten_hash(git_context, oid) : oid;
|
||||
export const format_commit_oid = async (git_context, oid, { short_hashes = false } = {}) => {
|
||||
const hash = short_hashes ? await shorten_hash(git_context, oid) : oid;
|
||||
|
||||
const refs = await get_matching_refs(git_context, oid);
|
||||
if (refs.length === 0)
|
||||
return hash;
|
||||
|
||||
let s = `${hash} (`;
|
||||
s += refs.map(ref => {
|
||||
// Different kinds of ref are styled differently, but all are in bold:
|
||||
// HEAD and local branches are cyan
|
||||
if (ref === 'HEAD') {
|
||||
// TODO: If HEAD points to another ref, that should be shown here as `HEAD -> other`
|
||||
return chalk.bold.cyan(ref);
|
||||
}
|
||||
if (ref.startsWith('refs/heads/'))
|
||||
return chalk.bold.cyanBright(ref.slice('refs/heads/'.length));
|
||||
// Tags are `tag: foo` in yellow
|
||||
if (ref.startsWith('refs/tags/'))
|
||||
return chalk.bold.yellowBright(`tag: ${ref.slice('refs/tags/'.length)}`);
|
||||
// Remote branches are red
|
||||
if (ref.startsWith('refs/remotes/'))
|
||||
return chalk.bold.red(ref.slice('refs/remotes/'.length));
|
||||
// Assuming there's anything else, we'll just bold it.
|
||||
return chalk.bold(ref);
|
||||
}).join(', ');
|
||||
s += ')';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,10 +151,10 @@ export const format_commit = async (git_context, commit, oid, options = {}) => {
|
||||
switch (options.format || 'medium') {
|
||||
// TODO: Other formats
|
||||
case 'oneline':
|
||||
return `${chalk.yellow(await format_oid(git_context, oid, options))} ${title_line()}`;
|
||||
return `${chalk.yellow(await format_commit_oid(git_context, oid, options))} ${title_line()}`;
|
||||
case 'short': {
|
||||
let s = '';
|
||||
s += chalk.yellow(`commit ${await format_oid(git_context, oid, options)}\n`);
|
||||
s += chalk.yellow(`commit ${await format_commit_oid(git_context, oid, options)}\n`);
|
||||
s += `Author: ${format_person(commit.author)}\n`;
|
||||
s += '\n';
|
||||
s += indent(title_line());
|
||||
@ -135,7 +162,7 @@ export const format_commit = async (git_context, commit, oid, options = {}) => {
|
||||
}
|
||||
case 'medium': {
|
||||
let s = '';
|
||||
s += chalk.yellow(`commit ${await format_oid(git_context, oid, options)}\n`);
|
||||
s += chalk.yellow(`commit ${await format_commit_oid(git_context, oid, options)}\n`);
|
||||
s += `Author: ${format_person(commit.author)}\n`;
|
||||
s += `Date: ${format_date(commit.author)}\n`;
|
||||
s += '\n';
|
||||
@ -144,7 +171,7 @@ export const format_commit = async (git_context, commit, oid, options = {}) => {
|
||||
}
|
||||
case 'full': {
|
||||
let s = '';
|
||||
s += chalk.yellow(`commit ${await format_oid(git_context, oid, options)}\n`);
|
||||
s += chalk.yellow(`commit ${await format_commit_oid(git_context, oid, options)}\n`);
|
||||
s += `Author: ${format_person(commit.author)}\n`;
|
||||
s += `Commit: ${format_person(commit.committer)}\n`;
|
||||
s += '\n';
|
||||
@ -153,7 +180,7 @@ export const format_commit = async (git_context, commit, oid, options = {}) => {
|
||||
}
|
||||
case 'fuller': {
|
||||
let s = '';
|
||||
s += chalk.yellow(`commit ${await format_oid(git_context, oid, options)}\n`);
|
||||
s += chalk.yellow(`commit ${await format_commit_oid(git_context, oid, options)}\n`);
|
||||
s += `Author: ${format_person(commit.author)}\n`;
|
||||
s += `AuthorDate: ${format_date(commit.author)}\n`;
|
||||
s += `Commit: ${format_person(commit.committer)}\n`;
|
||||
@ -164,7 +191,7 @@ export const format_commit = async (git_context, commit, oid, options = {}) => {
|
||||
}
|
||||
case 'raw': {
|
||||
let s = '';
|
||||
s += chalk.yellow(`commit ${oid}\n`);
|
||||
s += chalk.yellow(`commit ${await format_commit_oid(git_context, oid, options)}\n`);
|
||||
s += `tree ${commit.tree}\n`;
|
||||
if (commit.parent[0])
|
||||
s += `parent ${commit.parent[0]}\n`;
|
||||
|
93
packages/git/src/refs.js
Normal file
93
packages/git/src/refs.js
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Puter Technologies Inc.
|
||||
*
|
||||
* This file is part of Puter's Git client.
|
||||
*
|
||||
* Puter's Git client is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Map of hash -> array of full reference names
|
||||
import git from 'isomorphic-git';
|
||||
|
||||
const hash_to_refs = new Map();
|
||||
const add_hash = (hash, ref) => {
|
||||
const existing_array = hash_to_refs.get(hash);
|
||||
if (existing_array) {
|
||||
existing_array.push(ref);
|
||||
} else {
|
||||
hash_to_refs.set(hash, [ref]);
|
||||
}
|
||||
}
|
||||
|
||||
// Avoid loading everything multiple times
|
||||
let mark_cache_loaded;
|
||||
let started_loading = false;
|
||||
const cache_loaded = new Promise(resolve => { mark_cache_loaded = resolve });
|
||||
|
||||
/**
|
||||
* Reverse search from a commit hash to the refs that point to it.
|
||||
* The first time this is called, we retrieve all the references and cache them, meaning that
|
||||
* later calls are much faster, but won't reflect changes.
|
||||
* @param git_context {{ fs, dir, gitdir, cache }} as taken by most isomorphic-git methods.
|
||||
* @param commit_oid
|
||||
* @returns {Promise<[string]>} An array of full references, eg `HEAD`, `refs/heads/main`, `refs/tags/foo`, or `refs/remotes/origin/main`
|
||||
*/
|
||||
export const get_matching_refs = async (git_context, commit_oid) => {
|
||||
if (started_loading) {
|
||||
// If someone else started loading the cache, just wait for it to be ready
|
||||
await cache_loaded;
|
||||
} else {
|
||||
// Otherwise, we have to load it!
|
||||
started_loading = true;
|
||||
|
||||
// HEAD
|
||||
add_hash(await git.resolveRef({ ...git_context, ref: 'HEAD' }), 'HEAD');
|
||||
|
||||
// Branches
|
||||
const branch_names = await git.listBranches(git_context);
|
||||
for (const branch of branch_names) {
|
||||
const ref = `refs/heads/${branch}`;
|
||||
add_hash(await git.resolveRef({ ...git_context, ref}), ref);
|
||||
}
|
||||
|
||||
// Tags
|
||||
const tags = await git.listTags(git_context);
|
||||
for (const tag of tags)
|
||||
add_hash(await git.resolveRef({ ...git_context, ref: tag }), `refs/tags/${tag}`);
|
||||
|
||||
// Remote branches
|
||||
const remotes = await git.listRemotes(git_context);
|
||||
for (const { remote } of remotes) {
|
||||
const remote_branches = await git.listBranches({ ...git_context, remote });
|
||||
for (const branch of remote_branches) {
|
||||
const ref = `refs/remotes/${remote}/${branch}`;
|
||||
add_hash(await git.resolveRef({ ...git_context, ref }), ref);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.DEBUG) {
|
||||
console.groupCollapsed('Collected refs');
|
||||
for (const [ hash, ref_list ] of hash_to_refs) {
|
||||
console.groupCollapsed(hash);
|
||||
for (const ref of ref_list)
|
||||
console.log(ref);
|
||||
console.groupEnd();
|
||||
}
|
||||
console.groupEnd();
|
||||
}
|
||||
mark_cache_loaded();
|
||||
}
|
||||
|
||||
return hash_to_refs.get(commit_oid) ?? [];
|
||||
}
|
Loading…
Reference in New Issue
Block a user