Patch removal: - removed patch must be removed from the deps of its ex-children, and replaced with the deps of the removed patch - removed patch wants not to be in list of patches "tb-list" et al any more branches in refs/topbloke-tips ? yes deleted patches do something to the base ? no deleting empty patch: dependencies fine deleting nonempty patch: if any dependencies found, their updates break purpose of deleting? - remove from views of active patches - prevent new commits - remove from dependencies of active patches only makes sense if no active patches depend on it. undeleting - just unmark the patch as deleted Foreign branches: When merging from a foreign dependency, check that it does not have .topbloke metadata Patch naming: needs to be globally unique so put email address in it tg operations search for applicable patches safe charset for patch names . - / 0-9 a-z not permitted (git-check-ref-format(1)) spc ~ ^ : ? * [ \ @{ .lock. (apropos of shell) When pulling, which remotes get to update which patches ? Complicated question! For now, have "blessed" remotes, which we always pull and update from. All these count as sources above. Update operation restrictions available, which restrict use of various sources above ? What about implications for correctness of merge algorithm ? Concept of a "stack" ? Unnecessary - instead, deal with leaf patches Operations like "go up the stack", goes towards leaf. Hopefully unique. "Down" the stack, uses a "conventional" linearisation Stack reordering op ? auto adjust deps When merging, we need to DTRT with our metadata. Do this by running write-tree/read-tree etc. ourselves ? For a source we're merging from, we make a version where the metadata we shouldn't be merging is removed ? Or something. Have discovered that specifying a custom merge driver for a file does not have any effect if the three-way-merge looks trivial based on looking at the file contents - at least, if you use git-merge. Only thing which knows how to do all the gitattributes stuff and conflict markers and what have you is git-merge. (git-merge-tree does too but the output format is unsuitable.) "git-merge-index ... git-merge-one-file" does not honour the merge drivers and is, contrary to what the git docs seem to suggest but don't actually state, not actualy used by git-merge. OK so here is a plan: Use git-merge --no-commit Perhaps on a HEAD, and/or against a tree, which have been massaged to make the metadata suitable as input. Filtering out the "merge was successful but we aren't committing" message. Use a single pipe for stdout/stderr to get interleaving right; the message from git-merge is not i18n'd. Afterwards we: Check for merge success in the index and compare to exit status from git-merge (which is 1 if the merge failed). Adjust the metadata. Print appropriate big fat warnings if we have merge conflicts in our metadata. Commit, adjusting the parents of the new commit to the original parents if we made the merge with special massaged parents. We may still need to have custom merge drivers for metadata. Strategies for each metadata file merge: in base/tip same patch & branch dep -> base base -> tip msg T textual merge rm from src not in src deps B list merge rm from src rm from src deleted T std existence merge rm from src not in src patch- BT must be same rm from src must be same topgit- B std exist/text merge rm from src rm from src [^+]*- ?? textual merge rm from src rm from src +included BT list merge rm from non-tb src list merge +*- ?? textual merge rm from non-tb src textual merge *[^-] ?? die, aborting all ops, if found in any tb src or branch Unwanted removal search subgraphs: rm relevant removal inc rm impossible to undo removal, arrgh, terminates search inc inc.. / ??? \ rm inc.. rm.. merge of a removal, search down the rm path / [inc] \ inc ??? call it an inclusion, terminate the search rm inc merge of an inclusion, terminates search inc.. rm.. / [rm] \ inc ??? call it an inclusion, terminate search rm.. rm.. / ??? \ rm inc inc rm irrelevant rm inc inc inc.. rm rm.. OUR BASE SOURCE OUR IT TIP | | | | | | ADD DEP WH/ inc rm | NEEDS IT /| /\ | / | rm \ | / | ______________'/ \ | inc |' / \ | IT tip / inc REMOVAL rm \ | elsewhere / | / \ | | | / | inc \ | | | some IT | / | | | | | inc | | | | / | | | | | / inc | | | | | / | | | | | / / inc | | | | / | | `------------ | ----<-------- | -.| | / inc inc | | *2 | | |`- | ------------- | ----<--------.| | | | `---inc | 1* / | | | | | / | | RE-INCLUDE inc rm REMOVAL |' | inc \ | | | | | * REMOVAL rm | | | | | / | | |`-------------- | ----------. / | | | | inc ANC2 | | inc inc / | | |`.____________ | / | | | `inc ANC1 / | | | | /`--------<----------- | ---. | without inc / | \/ | | / | / \ RE-INCLUDE inc / | / \ \ | / | / \ * REMOVAL rm / | / \ | / | / \ inc FIRST ADD DEP |/ \ | \ *3 \ | `------------<-------------.| \ | | \ without | \_____ | | `without | | | IT Merge 1* and 2*, diff against some relevant base branch commit or something, and apply to proposed. ??? After we are done: source tip is included in our base Each time: * pick common ancestor * compute whether merge from common anc would unwantedly remove * if so we arrange that the common anc is a "rm" but our branch actually contains IT