Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

index.add_frombuffer not adding index unless flags changed #1086

Open
Caleb-T-Owens opened this issue Sep 24, 2024 · 0 comments
Open

index.add_frombuffer not adding index unless flags changed #1086

Caleb-T-Owens opened this issue Sep 24, 2024 · 0 comments

Comments

@Caleb-T-Owens
Copy link
Contributor

I was writing some tests for our index resolving code, and noticed that when we're calling index.add_frombuffer if we don't clear the flags of our our IndexEntry, the tree that we write out ends up with that file missing.

Repro:

main.rs

use std::{
    fs,
    path::{Path, PathBuf},
};

use git2::IndexConflict;
use tempfile::tempdir;

/// Commit whatever is in the current working directory
fn commit<'a>(
    repository: &'a git2::Repository,
    parent: Option<&git2::Commit<'a>>,
) -> git2::Commit<'a> {
    let signature = git2::Signature::now("Caleb", "caleb@gitbutler.com").unwrap();

    let mut index = repository.index().unwrap();
    // Make sure we're not having weird cached state
    index.read(true).unwrap();
    index
        .add_all(["*"], git2::IndexAddOption::DEFAULT, None)
        .unwrap();

    let commit = repository
        .commit(
            None,
            &signature,
            &signature,
            "Committee",
            &repository.find_tree(index.write_tree().unwrap()).unwrap(),
            parent.map(|c| vec![c]).unwrap_or_default().as_slice(),
        )
        .unwrap();

    repository.find_commit(commit).unwrap()
}

fn bytes_to_path(path: &[u8]) -> PathBuf {
    let path = std::str::from_utf8(path).unwrap();
    Path::new(path).to_owned()
}

fn in_memory_repository(repository: &git2::Repository) -> git2::Repository {
    let repository = git2::Repository::open(repository.path()).unwrap();
    repository
        .odb()
        .unwrap()
        .add_new_mempack_backend(999)
        .unwrap();
    repository
}

fn main() {
    let tempdir = tempdir().unwrap();

    let repository = git2::Repository::init(tempdir.path()).unwrap();

    // Make some commits
    fs::write(tempdir.path().join("foo.txt"), "a").unwrap();
    let a = commit(&repository, None);
    fs::write(tempdir.path().join("foo.txt"), "b").unwrap();
    let b = commit(&repository, None);
    fs::write(tempdir.path().join("foo.txt"), "c").unwrap();
    let c = commit(&repository, None);

    let in_memory_repository = in_memory_repository(&repository);

    let mut index: git2::Index = repository
        .merge_trees(
            &a.tree().unwrap(), // Base
            &b.tree().unwrap(), // Ours
            &c.tree().unwrap(), // Theirs
            None,
        )
        .unwrap();

    in_memory_repository.set_index(&mut index).unwrap();

    assert!(index.has_conflicts());

    let mut conflicts = index.conflicts().unwrap().flatten().collect::<Vec<_>>();

    assert_eq!(conflicts.len(), 1);
    let conflict = conflicts.first_mut().unwrap();

    let IndexConflict {
        ancestor: Some(ancestor),
        our: Some(our),
        their: Some(their),
    } = conflict
    else {
        panic!("Ahh");
    };

    index.remove_path(&bytes_to_path(&ancestor.path)).unwrap();
    index.remove_path(&bytes_to_path(&their.path)).unwrap();

    let blob = repository.find_blob(our.id).unwrap();
    // our.flags = 0;
    index.add_frombuffer(&our, blob.content()).unwrap();

    let tree = index.write_tree_to(&repository).unwrap();
    repository.find_tree(tree).unwrap();

    assert_eq!(
        tree,
        git2::Oid::from_str("6e4760ce692776132d52ac0787b7dc1ca2ac15f4").unwrap()
    ) // Ends up being 4b825dc642cb6eb9a060e54bf8d69288fbee4904 (empty tree)
}

Cargo.toml

[package]
name = "strange_behaviour"
version = "0.1.0"
edition = "2021"

[dependencies]
git2 = { version = "0.19.0", features = [
    "vendored-openssl",
    "vendored-libgit2",
] }
tempfile = "3.10"

If we set our.flags to 0 ourselves, before we call add_frombuffer, then we end up with the tree that we expected.

It's a bit strange that we're ending up with this empty tree rather than having some form of error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant