I use a git repo to store my vimwiki, a personal wikipedia which houses diaries, some latex, but mostly markdown wiki files. I then have this repo locally stored on two machines, one at work, and one at home.
To complicate matters each computer has it's own local database, or DVCS database (Something I just learned).
┌─────────────┐ ┌─────────────┐
│ repo folder │ │ repo folder │
│ │ │ │
│ │ │ │
└─────────────┘ └─────────────┘
▲ ▲
│ │
│ │
│ │
│ │
┌──────┴──────┐ ┌──────┴──────┐
│ computer A │ │ computer B │
│ │ │ │
│ database │ │ repo DB │
│ │ │ │
└─────────────┘ └─────────────┘
On each computer, for a long time I typically ignore commits and make changes freely, and the two repos are isolated from each other. For the most part this isn't a problem, but vimwiki diary structure contains a funny quirk that does create a conflict. When running VimwikiMakeDiaryNote, the plugin
command, vimwiki creates a filename using date +%F
under the diary
folder, and if I use this command on each computer
within 24 hours git will give me a merge conflict for that day. Follow this pattern for a year and I will have 364 merge conflicts on new year's day.
This is presumedly because they have no common ancestor, are the same file on both systems in namespace, and have no common lines. To combat this nearing catastrophe I have read up a bit on merge strategies, and followed answers to other stack overflow posts, specifically this ( strategy for git and append-mostly files ), developing a schema to append differing files to one another.
This involves the following. (1.) Creating a
merge driver in your git config .git/config
, and (2.), specifying rules for that merge driver in a .gittattributes
file.
path/.git/config ...
[merge "aggregate"]
name = aggregate both new sections for diary entries
driver = git merge-file --union -L %P %A %O %B
path/to/.gitattributes ...
test.txt merge=aggregate
diary.txt merge=aggregate
diary/* merge=aggregate
At this point the history of the two repos is important. The database on Computer A, as it's name suggests, has been given many more commits than it's counterpart on B. For this reason I wished to merge only the files under folders poetry
, and diary
.
/path/to/vimwiki/
.
├── bin
│ └── lib
├── poetry
│ └── bin
├── diary
├── searches
├── images
├── latex
│ ├── first\ pgf\ gnatt\ chart
│ ├── flowcharts
│ ├── images
│ ├── sections
│ ├── tables
│ └── venn_diagrams
├── lilypond
│ ├── htmloutput
│ └── tmp
├── mail
└── mathematics
After having staged the objective thus far, I made some preparations to merge the two repos. On computer B, I ran:
git checkout -b stem
git add .
git commit -m 'added entries since last log, including need diaries'
git push ~/.git-repos/vimwiki
On Computer A, I ran:
git checkout -b phone
git fetch ssh://XXX.XXX.X.XX/path/to/path/to/home/.git-repos/vimwiki stem:leaf
From this point I had created a branch to merge into, phone
, and fetched the vimwiki repo into another branch leaf
.
An interesting hurdle in this process was my desire to have the in congruencies visible after the merge. I searched for a way to create a driver to do this, and when I couldn't resolved a simple for
loop that I suppose is part of the linux philosophy. It appended, suffixed foldmarkers to the files I need to merge.
for i in $(git --no-pager \
diff --name-only --diff-filter=AMCR \
phone..leaf -- ./diary | head -n 12 | tail -n 11);do
echo "$i";
gsed -i -e '1i\ %% B Diaries {{{1 %%' -e '$a\ %% 1}}} %%' $i
done
I then commited these changes to my leaf
branch and was ready to merge them into the phone
branch.
I had tested the git merge --no-commit
on another repository going through the steps to make sure it respected the rules in my .git/config
, and .gitattributes
as I've shown above, but here I needed to only copy over files from the diary
folder. For this I chose
git merge --no-commit -X subtree=diary leaf
This is when I encountered problems, although the code worked as intended, appended the files in leaf
to those in phone
, it did not do so without behaving in two ways that weren't intended.
Firstly, it seemed to ignore the -X subtree
argument and tried to merge in greedy fashion.
I had thought that -X subtree
would isolate only those files below the tree to merge.
I have also tried this with the -s recursive
option and it produces the same result: git attempts to merge greedily, staging every files that differs.
Secondly, it complained that the merge failed.
Asking me to fix the conflicts and then commit the result.
While testing the merge driver out on another repository the test exited with the message: Automatic merge went well; stopped before committing as requested
. This was the result that I'd intended with my vimwiki repo.
Here is an example conflict message I receive:
CONFLICT (add/add): Merge conflict in diary/2023-06-02.md Auto-merging diary/2023-06-02.md
Some of the questions that I've asked myself are, does using optional arguments -s recursive
or -X subtree
prevent the merge driver from working. Presumedly, no, because although git ignores those options, it does append the files with the merge rule as expected.
I'd like to know how to get this two pronged objective of mine completed. (1.), merge using a merge driver, and (2.), do so while using a sparse, or subtree merge.