DEV Community

Cover image for Create blob object (Git)
kataoka_nopeNoshishi
kataoka_nopeNoshishi

Posted on

3 1 1 1 1

Create blob object (Git)

Hello Dev community!

I'm noshishi, a apprentice engineer in Tokyo.
This article is about understanding Git from the inside by creating a simple program that add and commit.

I would like to continue my previous article on developing Git using Rust. Let's start by implementing the code to create a blob object.

The repository I actually created is My original git nss. The quality of the code isn't quite there yet and many parts are still incomplete, but you can do a straight line of local development!

Blob Object

"Blob" is an object that corresponds to file data.

// env method
use std::env;
// Pathbuf sturuct
use std::path::PathBuf;
// File sturuct
use std::fs::File;
// Trait for File sturuct
use std::io::prelude::*; 
// sha1 calculate crate
use sha1::{Digest, Sha1};

fn main() -> std::io::Result<()> {
    let filename = "first.txt";

    // Gathering the file content
    let mut path = env::current_dir()?; // get cwd
    path.push(PathBuf::from(filename)); // to absolute path

    let mut f = File::open(path)?; // open file
    let mut content = String::new(); // create buffer
    f.read_to_string(&mut content)?; // write buffer

    // objectは `header`+`\0`+`content`
    let blob_content = format!("blob {}\0{}", content.len(), content); // Note: In Rust, len() function returns the byte count of a string, not the character count.

    // Content to be stored
    println!("blob content: {}", blob_content);

    // Calculate hash value
    let blob_hash = Sha1::digest(blob_content.as_bytes());
    println!("blob hash: {:x}", blob_hash);

    Ok(())
}
Enter fullscreen mode Exit fullscreen mode

Before executing, we are using an external crate called sha1, so we list the dependency in Cargo.toml as follows.

[dependencies]
sha-1 = "0.9.1"
Enter fullscreen mode Exit fullscreen mode

So let's create a new file first.txt and run it.

% echo Hello World! >> first.txt
% echo This is my original git project! >> first.txt
% cargo run
blob content: blob 45Hello World!
This is my original git project!
blob hash: b4aa0076e9b36b2aed8ca8a21ccdd210c905660a
Enter fullscreen mode Exit fullscreen mode

Does this match the Blob object created by Git? You can use the git hash-object command to verify that it really does.

% git hash-object first.txt
b4aa0076e9b36b2aed8ca8a21ccdd210c905660a
Enter fullscreen mode Exit fullscreen mode

Excellent! They matched properly!

Finally, we implement the process of writing the Object to the repository.

// omitting...

use std::fs; //add

// Compression crate
use flate2::Compression; //add
use flate2::write::ZlibEncoder; //add

fn main() {
    // omitting ...

    // Compressing the stored content in the object
    let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
    encoder.write_all(&blob_content.as_bytes())?; // Write by bytes
    let compressed = encoder.finish()?;

    // hash to string
    let hash = format!("{:x}", blob_hash);
    // Up to 2 characters of the hash value is the directory path and 38 characters is the file path
    let (dir, file) = hash.split_at(2);

    // Specify the save location by absolute path
    let mut current_path = env::current_dir()?; // path/to/ngit
    current_path.push(".git/objects"); // path/to/ngit/.git/objects
    current_path.push(dir); // path/to/ngit/.git/objects/b4

    let object_dir = current_path.clone(); // Not moving

    // Create a directory to store in `.git/obejects/`
    fs::create_dir_all(object_dir)?;

    // file path is 38 characters of the hash value
    current_path.push(file); // path/to/ngit/.git/objects/b4/aa0076e9b36b2aed8ca8a21ccdd210c905660a
    let object_path = current_path;
    // File contents are compressed contents
    let mut f = File::create(object_path)?;
    f.write_all(&compressed)?;
    f.flush()?;
}
Enter fullscreen mode Exit fullscreen mode

Since we used a new external crate, we will also add it to the toml file.

[dependencies]
flate2 = "1.0.25" # add
sha-1 = "0.9.1"
Enter fullscreen mode Exit fullscreen mode

Now let's run it.

% cargo run
blob content: blob 45Hello World!
This is my original git project!
blob hash: b4aa0076e9b36b2aed8ca8a21ccdd210c905660a

# Objects are properly stored.
% ls .git/objects/b4
aa0076e9b36b2aed8ca8a21ccdd210c905660a

# look at the contents with `git-cat-file`
% git cat-file -p aa0076e9b36b2aed8ca8a21ccdd210c905660a
Hello World!
This is my original git project!
Enter fullscreen mode Exit fullscreen mode

We can easily create a blob object. In the next article, we will create a function to create this blob! See the next one if you like!

Thanks for reading to the end!

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay