π΅ now playing… π§
π The “Seinfeld” Strategy βοΈ
(long time no post!)
One of these days, I’ll get around to writing some sort of summary of Atomic Habits, since I feel I got a lot out of it. For now, just a little tidbit. I want to talk a little bit about my github page and what motivates me.
There’s an oft quoted “Seinfeld Strategy” that was allegedly shared by a comedian named Brad Isaac, describing Seinfeld’s answer when he asked for advice:
He said the way to be a better comic was to create better jokes and the way to create better jokes was to write every day.
He told me to get a big wall calendar that has a whole year on one page and hang it on a prominent wall. The next step was to get a big red magic marker. He said for each day that I do my task of writing, I get to put a big red X over that day.
βAfter a few days youβll have a chain. Just keep at it and the chain will grow longer every day. Youβll like seeing that chain, especially when you get a few weeks under your belt. Your only job is to not break the chain.β
Apparently Jerry himself has stated this this isn’t true, but I think it’s still helpful advice nonetheless.
β Applying the Strategy β
I’m on a currently on a 42-day leetcode streak; going strong!
But how does this relate to my github?
Well, you know how github has the “calendar” with the green blocks that showcase which days you made a commit, and which you didn’t? That doesn’t track forked repos!
I had been slowly but surely moving my entire Linux setup onto github so I could remake my configuration at a moment’s notice, but it was a bit of a bummer never seeing a chain develop, since nearly all of my daily driver-related repos were forked.
The fix?
π΄ Unforking your Repos π΄
- Clone your repo to somewhere local.
- Rename the repo to something else, such as renaming
dotfiles
todotfiles2
. - Create a new repo with the same name, for example
dotfiles
; make sure not to include a license or do any further initialization! - Push your local repo back up.
- Once you’re certain everything looks good, delete the old repo.
π CARBS π
I should probably make a dedicated post about this instead, but here’s much of what I’ve been working on.
I’ve been using Luke Smith’s LARBS for something like a combined 3+ years at this point. CARBS is essentially just LARBS and its associated repos but “mine,” with some minor updates to this or that application. It’s still a work in progress, but this is what I have on github so far, as it relates to my daily driver:
And the simple, but (in my opinion) most important update: CARBS now uses GNU stow to manage dotfiles. The implementation is a little hacky, but it seems to work consistently, and it allows the user to keep their dotfiles synced between devices from a central repo (or merge from upstream).
π± stow Implementation π₯‘
The script is really simple:
setup_stow() {
# Grab dotfiles repo
putgitrepo "$dotfilesrepo" "$repodir/dotfiles" "$repobranch"
# Remove existing symlinks
rm -rf "/home/$name/.zprofile" "/home/$name/.xprofile" "/home/$name/.local/share/bg" \
"/home/$name/.config/sxiv" "/home/$name/.gtkrc-2.0"
# Hacky way of maintaining file structure of repo but still using stow
cd "$repodir/dotfiles" || error "Didn't create dotfiles directory"
stow --target=/home/"$name" . --adopt
cd - || error "Strange error..."
}
After the user’s dotfiles are cloned to /home/$name
(and the README, license, etc are cleaned up), the above setup_stow()
function is called. This function clones that same dotfiles repo and places it alongside the build files for dwm
, dwmblocks
, etc. (these applications are also configured from their source code, so this location makes perfect sense). It then removes all existing symlinks from /home/$name/
and runs a stow
command that essentially says to take all of the dotfiles from $repodir/dotfiles
and create symlinks to them in /home/$name
.
But wait, don’t these files already exist? Indeed they do! But the --adopt
switch essentially says “if you see a file already there, adopt that into our stow repo and then create the symlink.” This is certainly redundant and I’ll likely patch it to be more elegant in the future, but it’s been working great in my testing (PRs welcome of course, but I’d like to keep the file structure of the dotfiles repo identical to what it currently is).
From here, the user can simply enter $repodir/dotfiles
and do whatever git stuff they want; a short guide for merging from upstream is below.
β Merging from Upstream π
Let’s say that you’ve forked my dotfiles repo and made some changes of your own. You’ve installed via CARBS and you see that I have updates on my repo that you’d like to merge into your own.
git remote add upstream https://github.com/corbin-zip/dotfiles
git fetch upstream master
git merge upstream/master
At this point, you’ll be handed a list of any merge conflicts (if there are any) and can “simply” go file-by-file correcting the conflicts. Sometimes this is something trivial, while other times you have a lot of work ahead of you. The conflicts will look something like this:
<<<<<<< HEAD
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
* ClkClientWin, or ClkRootWin */
static Button buttons[] = {
/* click event mask button function argument */
#ifndef __OpenBSD__
{ClkWinTitle, 0, Button2, zoom, {0}},
{ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1}},
{ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2}},
{ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3}},
{ClkStatusText, 0, Button4, sigdwmblocks, {.i = 4}},
{ClkStatusText, 0, Button5, sigdwmblocks, {.i = 5}},
{ClkStatusText, ShiftMask, Button1, sigdwmblocks, {.i = 6}},
#endif
{ClkStatusText, ShiftMask, Button3, spawn,
SHCMD(TERMINAL " -e nvim ~/.local/src/dwmblocks/config.h")},
{ClkClientWin, MODKEY, Button1, movemouse, {0}},
{ClkClientWin, MODKEY, Button2, defaultgaps, {0}},
{ClkClientWin, MODKEY, Button3, resizemouse, {0}},
{ClkClientWin, MODKEY, Button4, incrgaps, {.i = +1}},
{ClkClientWin, MODKEY, Button5, incrgaps, {.i = -1}},
{ClkTagBar, 0, Button1, view, {0}},
{ClkTagBar, 0, Button3, toggleview, {0}},
{ClkTagBar, MODKEY, Button1, tag, {0}},
{ClkTagBar, MODKEY, Button3, toggletag, {0}},
{ClkTagBar, 0, Button4, shiftview, {.i = -1}},
{ClkTagBar, 0, Button5, shiftview, {.i = 1}},
{ClkMonNum, 0, Button1, focusmon, {.i = +1}},
{ClkMonNum, 0, Button3, focusmon, {.i = -1}},
{ClkRootWin, 0, Button2, togglebar, {0}},
=======
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static const Button buttons[] = {
/* click event mask button function argument */
#ifndef __OpenBSD__
{ ClkWinTitle, 0, Button2, zoom, {0} },
{ ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1} },
{ ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2} },
{ ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3} },
{ ClkStatusText, 0, Button4, sigdwmblocks, {.i = 4} },
{ ClkStatusText, 0, Button5, sigdwmblocks, {.i = 5} },
{ ClkStatusText, ShiftMask, Button1, sigdwmblocks, {.i = 6} },
#endif
{ ClkStatusText, ShiftMask, Button3, spawn, SHCMD(TERMINAL " -e nvim ~/.local/src/dwmblocks/config.h") },
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
{ ClkClientWin, MODKEY, Button2, defaultgaps, {0} },
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
{ ClkClientWin, MODKEY, Button4, incrgaps, {.i = +1} },
{ ClkClientWin, MODKEY, Button5, incrgaps, {.i = -1} },
{ ClkTagBar, 0, Button1, view, {0} },
{ ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
{ ClkTagBar, 0, Button4, shiftview, {.i = -1} },
{ ClkTagBar, 0, Button5, shiftview, {.i = 1} },
{ ClkRootWin, 0, Button2, togglebar, {0} },
>>>>>>> upstream/master
This should be relatively self-explanatory. The conflict begins with <<<<<<< HEAD
and ends at >>>>>>> upstream/master
, with the =======
dividing the two. In the example above, the differences appear to be cosmetic; it seems I’ve accidentally formatted my copy of dwm’s config.h
, which led to this being considered a change from upstream. I have this particular example handy because I’ve accidentally done this to several source files, and not all of the changes are cosmetic. I really need to set aside some time to work on these :).
Anyhow, depending on which side of the conflict looks closer to what you want (HEAD or upstream/master), you may want to go line-by-line and correct one half, while deleting corrected lines from the other half.
Once you’ve reconciled these conflicts, you may delete the merge markers (<<<<<<< HEAD
, =======
, and >>>>>>> upstream/master
) and mark the conflicts as resolved by git add
‘ing the file. Or, after you’ve finished resolving the conflict and have removed the merge markers, break out trusty lazygit to finish this up; next time you open lazygit after all conflicts have been resolved, it will process the repo for a moment before stating that your conflicts are resolved and asking how you’d like to proceed. And that’s all there is to it!
π Conclusion π
I’m not sure exactly how I ended up jumping from some not-even-really-from-Seinfeld “productivity hack” to giving a basic intro to git merge
, but here we are. Hope you enjoyed the read. Maybe I’ll attach more pictures to my next post…maybe :).
c.zip