langfield / ki

version control for Anki collections
https://langfield.github.io/ki/
GNU Affero General Public License v3.0
80 stars 3 forks source link

Implement subdeck remotes #162

Closed langfield closed 1 year ago

langfield commented 1 year ago

The following is copied from a comment in #125.

Instead of having submodules in ki repositories, instead we could have a collection/subdecks/ directory that is in the .gitignore. For each deck that we want tracked on GitHub, we have a directory called collection/subdecks/deck1/, collection/subdecks/deck2/, etc. These are git repositories, but they're purely local, and as I said, not submodules or subrepos or anything. Completely separate.

When we've pulled changes into our ki repository, we have a make recipe that dirty-copies all the data from the deck1 directory in the ki repository into collection/subdecks/deck1. (The stuff under subdecks/ will not be user-facing, so we can guarantee that the working tree/index is always clean.)

Then it adds these changes and commits them. So it probably just computes a patch or something and applies the patch (so we get deletions as well). Then the user has another deck1/ repo somewhere on their machine (maybe at pkgs/deck1/), and this one has 2 remotes. The first is the ordinary one, which they can use to push to GitHub or whatever. The second points to the collection/subdecks/deck1/ repo in the ki repository root directory, and this is where they pull changes from.

To push changes back up to the ki repository from pkgs/deck1/...

  1. Pull latest changes from the ki repository into collection/subdecks/deck1/ via a patch. We can compute the correct revision to diff against by storing a tag. Then we can do diff <tag> HEAD -- <subdeck>. Call this . So the command will look like:
cd ~/collection \
 && git diff deck1 HEAD -- deck1/ > /tmp/deck1.patch \
 && cd ~/collection/subdecks/deck1 \
 && git apply /tmp/deck1.patch
  1. Pull changes from collection/subdecks/deck1 into pkgs/deck1, then push changes back to the subdeck (so now <COMMIT2> exists in collection/subdecks/deck1).

  2. Compute a patch from the <COMMIT1> to <COMMIT2>, and copy those changes and commit them in the ki repo.

    Okay, the above procedure is wayyy too complicated.

langfield commented 1 year ago

Investigate using subtree merges to cut out the middle man.

This is probably what we want to follow.

Here is a script that more or less does what we want.

#!/usr/bin/env bash
mkdir big-repo
cd big-repo
git init --initial-branch=main

echo ''
echo '0' > 0
git add .
git commit -m "Initial commit"

echo ''
mkdir little-repo
cd little-repo
echo 'a' > a
git add .
git commit -m "little-repo"
cd ../..

echo ''
git clone ./big-repo little-repo
cd little-repo
git filter-repo --force --subdirectory-filter little-repo --path-rename little-repo/:
cd ..

echo ''
cd big-repo
git rm -r little-repo
git commit -m "Remove little-repo"
git subtree add --prefix little-repo git@github.com:langfield/subtree.git main --squash
langfield commented 1 year ago

Okay this is now working, see below.

https://github.com/langfield/ki/blob/423ba01111d9ee04a9b215c492ffd30abd7bc4a9/subtree.sh#L1-L22

What remains to be done is just to add an argument which is the target of the command. So instead of automatically dumping the new repository for the subdeck into /tmp/ki/<subdeck>, instead we should force the user to specify where they want it to be created.

Edit: Done!

langfield commented 1 year ago

Okay, there is one more thing I want to do, which is to make sure we support local remotes, and then write a test using a local remote (just a simple shell script should do).

langfield commented 1 year ago

Fixed by #163.