summaryrefslogtreecommitdiff
path: root/sys/src/cmd/git/ref.c
AgeCommit message (Collapse)Author
2023-04-17git/send: correctly delete branches with no local mirrorOri Bernstein
2023-02-18git: fix nil dereference in corrupt repositoriesOri Bernstein
2022-03-14git/query: implement range using paint()Michael Forney
The current range algorithm does not work correctly when merge commits are involved with an ancestor of the base commit. For example, consider the graph b ↙ ↖ a d ← e ← f ↖ ↙ c where b is d's first parent, and c is d's second parent. This graph is symmetrical, so we should get the same results for b..f and c..d (modulo the symmetry), but currently range() returns [d] for b..f and [d, e, f] for c..f. In the first case, we traverse to b, our base, then unwind to d and add [d] to our results. Then, we traverse [c, a], but don't find b this time, so unwind back to f. In the second case, we traverse all the way to a through b, unwind to d, then find our base, c, and unwind back to f and add [d, e, f] to our results. The problem here is that the determining factor for whether a commit is pushed during unwinding is whether the *last* parent reached the base commit, when it should be if *any* parent reached the base commit. Also, when a is not an ancestor of b, the current algorithm traverses the entire graph then returns an empty list, despite git's behavior and git9's documentation ("Between is defined as the set of all commits which are reachable from b but not reachable from a"). For the above example, we'd expect that b..f contain c, since c is not reachable from b. Range is almost identical to findtwixt, so to fix this we can reuse the same paint() algorithm for both operations. The only difference is that we want results in traversal order (rather than an arbitrary ordering). Add a third mode to paint() to save 'keep' commits in an array in the order we reach them, then return the non-dropped and non-skipped commits, preserving that order.
2022-03-16git/query: refactor graph painting algorithm (findtwixt, lca)Michael Forney
We now keep track of 3 sets during traversal: - keep: commits we've reached from head commits - drop: commits we've reached from tail commits - skip: ancestors of commits in both 'keep' and 'drop' Commits in 'keep' and/or 'drop' may be added later to the 'skip' set if we discover later that they are part of a common subgraph of the head and tail commits. From these sets we can calculate the commits we are interested in: lca commits are those in 'keep' and 'drop', but not in 'skip'. findtwixt commits are those in 'keep', but not in 'drop' or 'skip'. The "LCA" commit returned is a common ancestor such that there are no other common ancestors that can reach that commit. Although there can be multiple commits that meet this criteria, where one is technically lower on the commit-graph than the other, these cases only happen in complex merge arrangements and any choice is likely a decent merge base. Repainting is now done in paint() directly. When we find a boundary commit, we switch our paint color to 'skip'. 'skip' painting does not stop when it hits another color; we continue until we are left with only 'skip' commits on the queue. This fixes several mishandled cases in the current algorithm: 1. If we hit the common subgraph from tail commits first (if the tail commit was newer than the head commit), we ended up traversing the entire commit graph. This is because we couldn't distinguish between 'drop' commits that were part of the common subgraph, and those that were still looking for it. 2. If we traversed through an initial part of the common subgraph from head commits before reaching it from tail commits, these commits were returned from findtwixt even though they were also reachable from tail commits. 3. In the same case as 2, we might end up choosing an incorrect commit as the LCA, which is an ancestor of the real LCA.
2022-01-23git/query: leave range commits in topological orderMichael Forney
This prevents commits from getting reordered incorrectly during rebase or export.
2021-12-08git: fully init objqOri Bernstein
we were leaving objq.best uninitialized, and would therefore read garbage if we didn't find a best match.
2021-09-11git/query: fix spurious merge requestsOri Bernstein
Due to the way LCA is defined, a using a strict LCA on a graph like this: <--a--b--c--d--e--f--g \ / +-----h------- can lead to spurious requests to merge. This happens because 'lca(b, g)' would return 'a', since it can be reached in one step from 'b', and 2 steps from 'g', while reaching 'b' from 'a' would be a longer path. As a result, we need to implement an lca variant that returns the starting node if one is reachable from the other, even if it's already found the technically correct least common ancestor. This replaces our LCA algorithm with one based on the painting we do while finding a twixt, making it give the resutls we want. git/query: fix spurious merge requests Due to the way LCA is defined, a using a strict LCA on a graph like this: <--a--b--c--d--e--f--g \ / +-----h------- can lead to spurious requests to merge. This happens because 'lca(b, g)' would return 'a', since it can be reached in one step from 'b', and 2 steps from 'g', while reaching 'b' from 'a' would be a longer path. As a result, we need to implement an lca variant that returns the starting node if one is reachable from the other, even if it's already found the technically correct least common ancestor. This replaces our LCA algorithm with one based on the painting we do while finding a twixt.
2021-05-31git/send: pick minimal delta set correctly (thanks igor)Ori Bernstein
We weren't giving all objects to the twixt() function, and it was making bad life choices -- gambling, smoking, drinking, and packing in too much data. With more information, it doesn't do the last.
2021-05-16git: got git?Ori Bernstein
Add a snapshot of git9 to 9front.