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(())
}
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"
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
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
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()?;
}
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"
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!
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)