The Git Objects API
A comprehensive guide to working with Git objects (blobs, commits, trees, tags, and refs) in Freestyle
Git Objects API
The Git Objects API allows you to access and explore Git objects directly from your repositories. This API is useful for building tools that need to understand Git repository structure, inspect files, visualize commit history, and more.
Overview
Git stores all data as objects of four fundamental types:
- Blobs - Raw file content
- Trees - Directory listings mapping names to blobs or other trees
- Commits - Snapshots of the repository at a specific point in time
- Tags - References to specific commits with additional metadata
The Git Objects API in Freestyle provides access to all these object types through a consistent REST API.
Usage
Blobs
Blobs represent the content of files in Git. When you retrieve a blob, you get the raw file content (always base64 encoded for binary safety).
Get a Blob
// Using fetch directly with the API
fetch(`https://api.freestyle.sh/git/v1/repo/${repoId}/git/blobs/${blobHash}`, {
headers: {
"Authorization": "Bearer your-api-key"
}
})
.then(response => response.json())
.then(blob => {
// blob.content is base64 encoded
const decodedContent = atob(blob.content);
console.log(decodedContent);
});
Response structure:
interface BlobObject {
// The blob content (base64 encoded)
content: string;
// Always "base64"
encoding: "base64";
// The blob's hash
sha: string;
}
Commits
Commits represent snapshots of your repository at specific points in time.
Get a Commit
fetch(`https://api.freestyle.sh/git/v1/repo/${repoId}/git/commits/${commitHash}`, {
headers: {
"Authorization": "Bearer your-api-key"
}
})
.then(response => response.json())
.then(commit => {
console.log(commit.message);
console.log(commit.author);
console.log(commit.tree.sha);
});
Response structure:
interface CommitObject {
// The commit author
author: {
date: string;
name: string;
email: string;
};
// The committer (may be different from author)
committer: {
date: string;
name: string;
email: string;
};
// The commit message
message: string;
// The tree this commit points to
tree: {
sha: string;
};
// Parent commits (usually one, multiple for merge commits)
parents: Array<{
sha: string;
}>;
// The commit's hash
sha: string;
}
Trees
Trees represent directories in Git. A tree object contains a list of entries, each with a name, type (blob or tree), and hash.
Get a Tree
fetch(`https://api.freestyle.sh/git/v1/repo/${repoId}/git/trees/${treeHash}`, {
headers: {
"Authorization": "Bearer your-api-key"
}
})
.then(response => response.json())
.then(tree => {
// Inspect files and subdirectories
tree.tree.forEach(entry => {
if (entry.type === "blob") {
console.log(`File: ${entry.path}`);
} else if (entry.type === "tree") {
console.log(`Directory: ${entry.path}`);
}
});
});
Response structure:
interface TreeObject {
// The tree's entries (files and subdirectories)
tree: Array<{
// The entry's type: "blob" (file) or "tree" (directory)
type: "blob" | "tree";
// The entry's path (filename or directory name)
path: string;
// The entry's hash
sha: string;
}>;
// The tree's hash
sha: string;
}
Tags
Tags are references to specific objects (usually commits) with additional metadata like tagger information and a message.
Get a Tag
fetch(`https://api.freestyle.sh/git/v1/repo/${repoId}/git/tags/${tagHash}`, {
headers: {
"Authorization": "Bearer your-api-key"
}
})
.then(response => response.json())
.then(tag => {
console.log(tag.name);
console.log(tag.message);
console.log(tag.target.sha);
});
Response structure:
interface TagObject {
// The tag name
name: string;
// The tagger (may be null for lightweight tags)
tagger?: {
date: string;
name: string;
email: string;
};
// The tag message (may be null for lightweight tags)
message?: string;
// The object this tag points to (usually a commit)
target: {
sha: string;
};
// The tag's hash
sha: string;
}
Common Use Cases
Processing Files from a Git Trigger
When a Git trigger is invoked by a push to your repository, Freestyle sends a payload containing information about the event, including the commit hash. You can use this to inspect files that were changed in the commit:
// This function would be called by your webhook handler
async function processGitTriggerWebhook(webhookPayload, apiKey) {
const repoId = webhookPayload.repoId;
const commitHash = webhookPayload.commit;
const headers = {
"Authorization": `Bearer ${apiKey}`
};
// Get the commit to find what was changed
const commitResponse = await fetch(
`https://api.freestyle.sh/git/v1/repo/${repoId}/git/commits/${commitHash}`,
{ headers }
);
const commit = await commitResponse.json();
console.log(`Processing commit: ${commit.message}`);
console.log(`Author: ${commit.author.name} <${commit.author.email}>`);
// Get the tree pointed to by the commit
const treeResponse = await fetch(
`https://api.freestyle.sh/git/v1/repo/${repoId}/git/trees/${commit.tree.sha}`,
{ headers }
);
const rootTree = await treeResponse.json();
// Example: Find package.json in the repository
const packageJsonEntry = treeEntries.find(entry => entry.type === "blob" && entry.path === "package.json")
if (packageJsonEntry) {
// Get the content of package.json
const blobResponse = await fetch(
`https://api.freestyle.sh/git/v1/repo/${repoId}/git/blobs/${packageJsonEntry.sha}`,
{ headers }
);
const blob = await blobResponse.json();
// Parse the package.json content
const packageJson = JSON.parse(atob(blob.content));
console.log(`Project name: ${packageJson.name}`);
console.log(`Dependencies: ${Object.keys(packageJson.dependencies || {}).length}`);
}
}
Building a File Browser
You can build a recursive file browser:
async function exploreDirectory(repoId, treeSha, apiKey, currentPath = "") {
const headers = {
"Authorization": `Bearer ${apiKey}`
};
const treeResponse = await fetch(
`https://api.freestyle.sh/git/v1/repo/${repoId}/git/trees/${treeSha}`,
{ headers }
);
const tree = await treeResponse.json();
for (const entry of tree.tree) {
const entryPath = currentPath ? `${currentPath}/${entry.path}` : entry.path;
if (entry.type === "tree") {
// Recursively explore subdirectories
await exploreDirectory(repoId, entry.sha, apiKey, entryPath);
} else if (entry.type === "blob") {
// Process files
console.log(`File: ${entryPath}`);
// You could fetch the blob content here if needed
}
}
}
Viewing File Contents from a Specific Commit
async function viewFileAtCommit(repoId, commitHash, filePath, apiKey) {
const headers = {
"Authorization": `Bearer ${apiKey}`
};
// Get the commit
const commitResponse = await fetch(
`https://api.freestyle.sh/git/v1/repo/${repoId}/git/commits/${commitHash}`,
{ headers }
);
const commit = await commitResponse.json();
// Get the root tree
let treeResponse = await fetch(
`https://api.freestyle.sh/git/v1/repo/${repoId}/git/trees/${commit.tree.sha}`,
{ headers }
);
let currentTree = await treeResponse.json();
// Navigate the directory structure
const pathParts = filePath.split('/');
const fileName = pathParts.pop();
for (const directory of pathParts) {
const dirEntry = currentTree.tree.find(
entry => entry.type === "tree" && entry.path === directory
);
if (!dirEntry) {
throw new Error(`Directory not found: ${directory}`);
}
treeResponse = await fetch(
`https://api.freestyle.sh/git/v1/repo/${repoId}/git/trees/${dirEntry.sha}`,
{ headers }
);
currentTree = await treeResponse.json();
}
// Find the file in the current directory
const fileEntry = currentTree.tree.find(
entry => entry.type === "blob" && entry.path === fileName
);
if (!fileEntry) {
throw new Error(`File not found: ${fileName}`);
}
// Get the file content
const blobResponse = await fetch(
`https://api.freestyle.sh/git/v1/repo/${repoId}/git/blobs/${fileEntry.sha}`,
{ headers }
);
const blob = await blobResponse.json();
// Decode and return the content
return atob(blob.content);
}
Best Practices
- Cache results when possible - Git objects are immutable, so you can safely cache them
- Handle binary data correctly - Remember that blob content is base64 encoded
Conclusion
The Git Objects API provides low-level access to Git repository data, enabling you to build powerful tools for Git repository management, visualization, and integration with other systems.
For detailed API reference documentation, see the API Reference section.
Refs API coming soon.