feat: add is_ancestor(), like git merge-base --is-ancestor - #3036
Open
Amey Pawar (ameyypawar) wants to merge 2 commits into
Open
Amey Pawar (ameyypawar) wants to merge 2 commits into
Amey Pawar (ameyypawar) wants to merge 2 commits into
Conversation
… merge-base --is-ancestor` Callers who want to know whether one commit is an ancestor of another had to compute merge-bases and compare the result (see GitoxideLabs#2914). `is_ancestor()` answers directly, considers a commit its own ancestor, and returns `false` for unrelated histories. It reuses the merge-base painting and checks whether the candidate was reached from the descendant. With a commit-graph, it answers `false` without traversal if the descendant is in it but the candidate isn't, as a commit-graph contains all ancestors of its commits, or if both have reliable generations and the candidate's isn't lower, as parents have lower generations than their children. Otherwise, a reliable generation of the candidate stops the walk once only commits with a lower generation remain, as these can't reach it. `merge_base()` passes no such bound and is unchanged.
…th_graph()` They answer whether one commit is reachable from another, like `git merge-base --is-ancestor`, without computing merge-bases and comparing them (see GitoxideLabs#2914). Like the merge-base methods, the `_with_graph()` variant reuses a revision graph across calls to speed up repeated queries. `is_ancestor()` carries a `git2` alias for `graph_descendant_of()`, which takes the descendant first and doesn't consider a commit its own descendant.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Created by Claude Code on behalf of Amey, who reviewed it before submitting. Everything below this line is the agent's writing, not his.
Summary
gix_revision::merge_base::is_ancestor(), which tells whether a commit can be reached from another, as asked for in dedicated is-ancestor / reachability check (like `git merge-base --is-ancestor`) #2914 and listed first in Mergebase support #2795. It is built on the existing merge-base painting, as suggested in dedicated is-ancestor / reachability check (like `git merge-base --is-ancestor`) #2914.Repository::is_ancestor()andRepository::is_ancestor_with_graph(), mirroringmerge_base()andmerge_base_with_graph().is_ancestor()carries agit2alias forgraph_descendant_of(), which takes the descendant first and doesn't count a commit as its own descendant.merge_base()is unchanged.Commits
feat: add merge_base::is_ancestor() to check reachability like git merge-base --is-ancestor(gix-revision)feat: add Repository::is_ancestor() and Repository::is_ancestor_with_graph()(gix)Git baseline
git merge-base --is-ancestor A Bsucceeds ifAcan be reached fromB, including when both are the same commit, and fails for unrelated histories. With a commit-graph, Git doesn't walk commits with a lower generation thanA.is_ancestor()does the same and ends the walk once only commits with a lower generation thanAremain. It also answersfalsewithout any traversal ifBis in the commit-graph butAisn't, as a commit-graph contains all ancestors of its commits, or ifA's generation isn't lower thanB's. Only nonzero, unsaturated generations are used.Validation
cargo test—gix-revisionmerge-base 11,gixrepository::revision5, also withGIX_TEST_FIXTURE_HASH=sha256and withGIX_TEST_IGNORE_ARCHIVES=1cargo clippy -p gix-revision -p gix --all-targets,cargo fmt --check,cargo docwith-D warningsfor both crates, andcargo checkwithout therevisionormerge_basefeaturesvalidatetest takes its expectations from the existinggit merge-base --allbaselines:Ais an ancestor ofBexactly ifAis their only merge-base. That rule agrees withgit merge-base --is-ancestor(git 2.52.0) on all 103 single-pair baselines.git merge-base --is-ancestor(git 2.52.0) — 1,078 of them ancestors, with walks through merges and 50 pairs of identical commits — agrees on every pair without a commit-graph, with a complete one, and with one that lacks the newest 1,499 commits.gix-revisiontests on its own.Not addressed here
merge-base --independent, which would exposeremove_redundant(). Happy to follow up on that separately if it's wanted.merge_base(),Repository::is_ancestor()uses the commit-graph whenevercore.commitGraphallows it, so the TODO in Mergebase support #2795 about not using commit-graphs when grafts or object replacements are in effect applies to both.cargo doc -p gix --no-depswith-D warningsstops on an unresolved link toSelf::with_fetch_optionsingix/src/clone/access.rsunlessblocking-network-clientis enabled. It's unrelated to this change, so it's left alone.