DEV Community

Cover image for Create blob object (Git)
kataoka_nopeNoshishi
kataoka_nopeNoshishi

Posted on

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!

Top comments (0)