<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged source-control</title>
<link>https://coderlegion.com/tag/source-control</link>
<description>Powered by Question2Answer</description>
<item>
<title>Learn Git fast as if your job depends on it</title>
<link>https://coderlegion.com/11776/learn-git-fast-as-if-your-job-depends-on-it</link>
<description>&lt;h3 id=&quot;tl-dr&quot;&gt;TL;DR&lt;/h3&gt;
&lt;p&gt;In this post, with a grain of humor, I'm going to show you the minimum number of Git commands that you need to learn in order to start being productive and get that code from your machine to the company Git server. Also, I'll cover a bit of theory and Git installation as well.&lt;/p&gt;
&lt;h3 id=&quot;disclaimer&quot;&gt;Disclaimer&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ Nobody in this story, and no outfit or corporation, thank God, is based upon an actual person or outfit in the real world. But I can tell you this; as my journey through the software jungle progressed, I came to realize that, by comparison with the reality, my story was as tame as a holiday postcard. ~ John le Carré&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;setting-the-stage&quot;&gt;Setting the stage&lt;/h3&gt;
&lt;p&gt;So, let's set a scene; it's your first day as a junior developer straight out of college. You get to work, greet your superior that's supposed to be responsible for you, and since he's too busy with putting down some fire that just popped up, he, conversely, while you're trying to keep up walking aside him tells you something like:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;I've set the Git access for you to my website project.&lt;/p&gt;
&lt;p&gt;You have a ticket in our project management tool assigned to you. No worries, it's just some simple stuff that needs to be changed.&lt;/p&gt;
&lt;p&gt;Just check the email details, and you can start immediately.&lt;/p&gt;
&lt;p&gt;I'm aware that you may not be familiar with Git. I'm not trying to be an asshole, but just deal with it, learn it, OK? Don't they, like, teach you kids nothing in school these days?&lt;/p&gt;
&lt;p&gt;Ah, I gotta run.&lt;/p&gt;
&lt;p&gt;Oh, and one more thing, look up branching and do not EVER, and I repeat - EVER, commit to master; do a PR instead! Good luck and see ya later!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;OK. You sit down at your cubicle, open up your email client, log in, and there you see the email (without the subject line, of course) with the contents:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Hitman666/MrSupervisorWebsite&quot;&gt;Here's a link to the Git repo on Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Good luck,&lt;br&gt;
Mr. Superior&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;reality-sets-in&quot;&gt;Reality sets in&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;⚠️ This, in and of itself is a poor onboarding if you ask me, but I personally have seen it way too many times, so here are the things you need to do to get productive fast and learn the ropes as fast as you can.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So now you're, in lack of better words, screwed (you know the exact word, but we're not supposed to be using profanity here, ae?).&lt;/p&gt;
&lt;p&gt;You're lost. You heard about Git before, but you never used it. Now you're kicking yourself for not learning it properly yourself. But, it is what it is, and since you're really determined to make it in this 'programming' world, you're ready to do what it takes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/YZ4W1Ao.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I would question the fact that if you are 'so into it', how come you haven't learned it yet, but as Mr. Superior said, I'm not trying to be an asshole&lt;/em&gt; &lt;/p&gt;
&lt;p&gt;Therefore, buckle up young padawan, you're in for a ride!&lt;/p&gt;
&lt;h3 id=&quot;what-is-this-git-thing-&quot;&gt;What is this Git thing?&lt;/h3&gt;
&lt;p&gt;First, let me start off with a few problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Say you're writing a seminar and you make some changes, save them, go out of the text editor, come back, and you want to see all of your changes that you did last in the file. Or, for example, you want to undo some changes that you did last night (writing a seminar after returning from a party is a noble act, but not a very smart one!).&lt;/li&gt;
&lt;li&gt;While writing this seminar you create several versions of the same file and you don't even know what's changed in which version; you would really love to know what was, for example, changed in this current version based on the, say, a version from a few days ago.&lt;/li&gt;
&lt;li&gt;You're working on a group project and someone deletes your changes 'by accident'.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/Version_control&quot;&gt;VCS&lt;/a&gt; (Version Control Systems) tends to solve these problems. And, let me start off by saying that no, you don't need to use VCS &lt;em&gt;only&lt;/em&gt; for writing code (thus the seminar example). You can use it for any textual project. One of VCS solutions is &lt;a rel=&quot;nofollow&quot; href=&quot;https://git-scm.com/&quot;&gt;Git&lt;/a&gt;. One other popular VCS, that's still used to some extent today is &lt;a rel=&quot;nofollow&quot; href=&quot;https://subversion.apache.org/&quot;&gt;Subversion&lt;/a&gt;. You can see a detailed list of Version Control Systems &lt;a rel=&quot;nofollow&quot; href=&quot;https://en.wikipedia.org/wiki/List_of_version_control_software&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Git was made by the ever so slightly genius Linus Torvalds, the father of Linux:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/ESoSiQq.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Git is a distributed version control system (VCS).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Version control&lt;/strong&gt; means that you use it to store versions of your documents. True, it seems it's very popular among developers, but designers and other people (that are a bit more tech savvy) also use it to track versions of their files.&lt;/p&gt;
&lt;p&gt;This whole &lt;strong&gt;distributed&lt;/strong&gt; part is one of the things that makes it different from other VCS. Rather than have only one single place for the full version history of the software, as is common in once-popular VCS like CVS or Subversion, in Git every developer's working copy is also a repository that can contain the &lt;strong&gt;full history of all changes&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;ok-but-what-is-github-&quot;&gt;OK, but what is Github?&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;Something like Dropbox, but customized for Git.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/&quot;&gt;Github&lt;/a&gt; is a hosting service for Git projects, with some additional batteries included that we're not going to get into at this point, as you're short on time. Think of it as a place where you store your Git 'stuff'.&lt;/p&gt;
&lt;h3 id=&quot;installing-git&quot;&gt;Installing Git&lt;/h3&gt;
&lt;p&gt;To install Git, go to the &lt;a rel=&quot;nofollow&quot; href=&quot;https://try.github.io/&quot;&gt;official website&lt;/a&gt; and download the executable for your machine. I'm not going into the installation details as they're really just a bunch of &lt;code&gt;Next, Next, Next, yes to malware, Finish&lt;/code&gt; set of steps. &lt;em&gt;I'm kidding about the malware OFC&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To make sure your installation was successful, run the following command in your Terminal/Command prompt:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git --version&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You should get something like:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git version 2.10.1&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;fetching-the-repo&quot;&gt;Fetching the repo&lt;/h3&gt;
&lt;p&gt;OK, so let's finally get some action. In your email, you received an URL to the Git repository. It was this: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Hitman666/MrSupervisorWebsite&quot;&gt;https://github.com/Hitman666/MrSupervisorWebsite&lt;/a&gt;. You click the link, and you see something like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/nvz9ulq.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Click the &lt;code&gt;Clone or download&lt;/code&gt; button, make sure you see the &lt;code&gt;Use SSH&lt;/code&gt; in the top right corner of a popup and copy the link.&lt;/p&gt;
&lt;p&gt;To get this repository to your computer, you have to execute the following command in your Terminal/Command prompt (I'll use Terminal in the rest of the post):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git clone https://github.com/Hitman666/MrSupervisorWebsite.git&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The output of the command should look something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Cloning into 'MrSupervisorWebsite'...
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 7 (delta 0), reused 7 (delta 0), pack-reused 0
Receiving objects: 100% (7/7), done.
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;checking-out-the-code&quot;&gt;Checking out the code&lt;/h3&gt;
&lt;p&gt;Now, go into the newly created &lt;code&gt;MrSupervisorWebsite&lt;/code&gt; folder and open it in your editor.&lt;/p&gt;
&lt;p&gt;You should see three files: &lt;code&gt;index.htmnl&lt;/code&gt;, &lt;code&gt;style.css&lt;/code&gt;, and &lt;code&gt;README.md&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You quickly go and click to open the &lt;code&gt;README.md&lt;/code&gt; file, but all you see is this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# MrSupervisorWebsite
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hmm, so, no help there.&lt;/p&gt;
&lt;p&gt;You open up the &lt;code&gt;index.html&lt;/code&gt; file and you see:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
    &amp;lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot;&amp;gt;
    &amp;lt;title&amp;gt;MrSupervisorWebsite&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1 class=&quot;title&quot;&amp;gt;Welcome to MrSupervisorWebsite!&amp;lt;/h1&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OK, finally something that you're familiar with! You also open up the &lt;code&gt;style.css&lt;/code&gt; file, and you see:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.title {
    color: blue;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, you take a look at the ticket assigned to you in the project management tool that Mr.Superior mentioned, and it looks something like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/UV33DqY.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;You take a deep breath, finally something that you know how to handle! &lt;/p&gt;
&lt;p&gt;You're a bit taken aback by the 'manly color', so you go and ask Google:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/lgoY0Ui.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;You pick the &lt;code&gt;4872A2,&lt;/code&gt; and you're happy. You think to yourself: OK, now I just need to change this color in the &lt;code&gt;style.css&lt;/code&gt; file, somehow add this to this Git thing and 'publish' it.&lt;/p&gt;
&lt;p&gt;You're right, but not so fast! You remember that note from Mr.Supervisor that you shouldn't commit to master, EVER?&lt;/p&gt;
&lt;h3 id=&quot;creating-a-new-branch&quot;&gt;Creating a new branch&lt;/h3&gt;
&lt;p&gt;So, what is this &lt;code&gt;master&lt;/code&gt; anyway? You go online, and you find that:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Git has branches, and its main one is called &lt;code&gt;master&lt;/code&gt;. You can create as many of them as you want, based on any other existing one.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Also, you read a bit about the PR, and you learn that:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;PR is short for Pull Request. Pull requests let you tell others about changes you've pushed to a repository on GitHub. Once a pull request is opened, you can discuss and review the potential changes with collaborators and add follow-up commits before the changes are merged into the repository.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So, this is smart, right? You can add your code to the Git repo without breaking any existing stuff on the &lt;code&gt;master&lt;/code&gt; branch, and through this PR you can then ask a more experienced developer to do a CR (code review) on your PR and accept it or not.&lt;/p&gt;
&lt;p&gt;You're smart; you see the huge benefit of this vs. just committing something to &lt;code&gt;master&lt;/code&gt; and potentially breaking something in production.&lt;/p&gt;
&lt;p&gt;Now, to circle back a bit and explain how could it be that you would break something!? Well, there's a thing called CI (Continuous Integration) and CD (Continuous Deployment), and you can read more about it, but in essence, it's this:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Every time someone pushes a new commit to &lt;code&gt;master&lt;/code&gt; branch, a whole set of deploy scripts are being triggered, and essentially the new code that's pushed is going to appear in production.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What this means is that if you change that color and you commit it to &lt;code&gt;master&lt;/code&gt; (you'll learn in a minute how to actually do this &lt;code&gt;commit&lt;/code&gt; action), it will 'automagically' appear in the production on the website.&lt;/p&gt;
&lt;p&gt;⚠️ Of course, the premise is that the service is set like that in the first place.&lt;/p&gt;
&lt;p&gt;So, you get the point and value of additional branches, and you &lt;strong&gt;create a new branch&lt;/strong&gt; by executing the following command in your Terminal:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git checkout -b poppingTitle&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The upper command is a shortcut for two commands:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git branch poppingTitle
git checkout poppingTitle
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first one creates a new branch called &lt;code&gt;poppingTitle&lt;/code&gt; from the current branch that you're on (in our case that's &lt;code&gt;master&lt;/code&gt;). The second one 'checks it out'. Meaning, it places you on that branch.&lt;/p&gt;
&lt;h3 id=&quot;adding-some-code&quot;&gt;Adding some code&lt;/h3&gt;
&lt;p&gt;Now you're finally ready to add some code!&lt;/p&gt;
&lt;p&gt;Open up the &lt;code&gt;style.css&lt;/code&gt; file, change the color, and save the file. It should look like this now:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.title {
    color: #4872A2;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One useful command that you'll use a lot is &lt;code&gt;git status&lt;/code&gt;, which will you tell you the status of your git project. If you execute that in your Terminal you will see that the &lt;code&gt;style.css&lt;/code&gt; file was modified:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;On branch poppingTitle
Changes not staged for commit:
  (use &quot;git add &amp;lt;file&amp;gt;...&quot; to update what will be committed)
  (use &quot;git checkout -- &amp;lt;file&amp;gt;...&quot; to discard changes in working directory)

    modified:   style.css

no changes added to commit (use &quot;git add&quot; and/or &quot;git commit -a&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, in the instructions from the output, these changes are not yet added to the commit. To do that, execute the command &lt;code&gt;git add style.css&lt;/code&gt;. Of course, if you were to have multiple files you would not have to list each and every one of them, you would just use &lt;code&gt;git add .&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;If you run the &lt;code&gt;git status&lt;/code&gt; command again, you'll see that we have changes that are ready to be committed: &lt;/p&gt;
&lt;pre&gt;&lt;code&gt;On branch poppingTitle
Changes to be committed:
  (use &quot;git reset HEAD &amp;lt;file&amp;gt;...&quot; to unstage)

    modified:   style.css
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;committing-code&quot;&gt;Committing code&lt;/h3&gt;
&lt;p&gt;To commit (one could use words like save or apply here for better clarity) the added changes to your local repository, just run:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git commit -m &quot;Changed the title color&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Of course, the commit message can be anything, but please do yourself a favor and write meaningful commit messages.&lt;/p&gt;
&lt;p&gt;If you run the &lt;code&gt;git status&lt;/code&gt; command again, you'll see that we have a clean repository:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;On branch poppingTitle
nothing to commit, working tree clean
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;pushing-to-a-remote-repository&quot;&gt;Pushing to a remote repository&lt;/h3&gt;
&lt;p&gt;So, great, at this point you have the change locally in your repository, but you'd like to get this back to Github (the so-called remote repository, or &lt;code&gt;origin&lt;/code&gt; as it's usually referred to).&lt;/p&gt;
&lt;p&gt;For that you have to execute the following command:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git push origin poppingTitle&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;You should get an output similar to this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Counting objects: 3, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 299 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To github.com:Hitman666/MrSupervisorWebsite.git
 * [new branch]      poppingTitle -&amp;gt; poppingTitle
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;doing-a-pr&quot;&gt;Doing a PR&lt;/h3&gt;
&lt;p&gt;If you check Github now, you'll see that we've pushed this new branch:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/hoaLPE4.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now, click on the &lt;code&gt;Compare &amp;amp; pull request&lt;/code&gt; button.&lt;/p&gt;
&lt;p&gt;Here you can add some comment summarizing your pull request:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/NZDFScl.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Finally, click the &lt;code&gt;Create pull request&lt;/code&gt; button.&lt;/p&gt;
&lt;p&gt;And now (if we're playing by the book) someone else from your team would come and review your code. At this point, you could let someone know about this via your Project Management Tool (JIRA, Trello, Leankit, Kanbanflow, etc...) by putting this task/card in the appropriate column.&lt;/p&gt;
&lt;h3 id=&quot;your-pr-is-accepted&quot;&gt;Your PR is accepted&lt;/h3&gt;
&lt;p&gt;When the pull request is approved (you get a notification from Github when someone approves or rejects it), you as the author go back to Github and just click on the &lt;code&gt;Merge pull request&lt;/code&gt; button, and that's it:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/oDzK7ZE.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Finally, click the &lt;code&gt;Delete branch&lt;/code&gt; button as it's a good practice to not keep the merged branches in the remote repo:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/2XZfov5.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;you-get-to-live-another-day&quot;&gt;You get to live another day&lt;/h3&gt;
&lt;p&gt;Your merge to &lt;code&gt;master&lt;/code&gt; goes well, it's auto-deployed, you check the website and all is cool. You update the ticket in your ticketing system by placing it in the 'Deployed' column (or some similarly named column). &lt;/p&gt;
&lt;p&gt;It's 17:12, you close your laptop and cheerfully go home to learn more about this awesome Git thingy. &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.imgur.com/0jaodld.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/11776/learn-git-fast-as-if-your-job-depends-on-it</guid>
<pubDate>Mon, 16 Feb 2026 19:40:07 +0000</pubDate>
</item>
<item>
<title>DevLog 20250927: Use Fossil as Binary Asset VCS</title>
<link>https://coderlegion.com/6593/devlog-20250927-use-fossil-as-binary-asset-vcs</link>
<description>&lt;blockquote&gt;&lt;p&gt;It's clean and elegant.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;overview&quot;&gt;Overview&lt;/h3&gt;
&lt;p&gt;As discussed in a &lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/4483/devlog-20250806-change-version-file-changes-history-only-version-control-binary-assets?show=6524#a6524&quot;&gt;previous post&lt;/a&gt; about binary file version control, keeping binaries well-versioned has always been challenging.&lt;/p&gt;
&lt;p&gt;Years ago, when I first discovered SQLite, I also found Fossil. At that time, it didn't meet my needs - Git proved far better for collaboration and text-based workflows (especially with GitHub and GitHub Desktop).&lt;/p&gt;
&lt;p&gt;However, Fossil may perform better for binary files under ~2GB, provided some manual bookkeeping and syncing.&lt;/p&gt;
&lt;p&gt;Beyond versioning, Fossil offers several useful built-in tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/doc/tip/www/chat.md&quot;&gt;Chatroom&lt;/a&gt;: Configurable 7-day ephemeral chat for authorized users. Supports &lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/help?name=/chat-poll&quot;&gt;HTTP API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/doc/tip/www/wikitheory.wiki&quot;&gt;Wiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/doc/tip/www/embeddeddoc.wiki&quot;&gt;Embedded Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/doc/tip/www/event.wiki&quot;&gt;Tech Notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/doc/tip/www/webui.wiki&quot;&gt;Web UI Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Direct file views: HEX, Text, Download&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/doc/tip/www/forum.wiki&quot;&gt;Forum&lt;/a&gt;: Permanent records; CDN support for images&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/doc/tip/www/bugtheory.wiki&quot;&gt;Bug Tracking / Tickets / Issues&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/doc/tip/www/webui.wiki&quot;&gt;Full-text search&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;framework&quot;&gt;Framework&lt;/h3&gt;
&lt;p&gt;This framework describes how I'm beginning to &lt;strong&gt;use Fossil alongside Git&lt;/strong&gt; for version control.&lt;/p&gt;
&lt;h4 id=&quot;using-fossil-git&quot;&gt;Using Fossil + Git&lt;/h4&gt;
&lt;p&gt;The plan is simple: Use git for text files; fossil for binary assets.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# Create repo
cd &quot;&amp;lt;Repo Folder&amp;gt;&quot;
fossil init ../MyRepo.fossil    # The convention is to create fossil repository outside the repo folder
fossil open -k ../MyRepo.fossil # Creates the _FOSSIL_ tracking file; -k skips checkout

# Create fossil-settings (See commit message below)
mkdir -p .fossil-settings
printf &quot;.git\n.git/*\n.gitignore\n&quot; &amp;gt; .fossil-settings/ignore-glob
fossil add .fossil-settings
fossil commit -m &quot;Add Fossil ignore rules for Git files&quot;

# Manually ignore files already tracked by Git, then commit again if needed
# fossil changes
# fossil commit -m &quot;Update ignore file&quot;

# In Git (e.g. via GitHub Desktop), ignore Fossil's contents, especially:
# *.fossil
# _FOSSIL_

# Treat all files as binary
printf &quot;*&quot; &amp;gt; .fossil-settings/binary-glob
fossil add .fossil-settings/binary-glob
fossil commit -m &quot;Treat all files as binary in Fossil&quot;

# Inspect
# fossil changes
# fossil extras

fossil add .
fossil commit -m &quot;Initial Fossil import alongside Git&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setup cannot keep Fossil and Git perfectly synchronized. Manual bookkeeping is necessary to restore past states accurately.&lt;/p&gt;
&lt;h4 id=&quot;summary&quot;&gt;Summary&lt;/h4&gt;
&lt;p&gt;Key conventions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep the &lt;code&gt;.fossil&lt;/code&gt; file outside the Git repo folder.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.fossil-settings/binary-glob&lt;/code&gt;: mark all files as binary.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.fossil-settings/ignore-glob&lt;/code&gt;: define ignore patterns.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_FOSSIL_&lt;/code&gt; and &lt;code&gt;.fossil-settings&lt;/code&gt; can be deleted safely.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;quick-reference&quot;&gt;Quick Reference&lt;/h4&gt;
&lt;p&gt;Common commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fossil init &amp;lt;Repo&amp;gt; [--project-name &amp;lt;Name&amp;gt;]&lt;/code&gt;  -  create repo; edit name later in UI if omitted&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil add .&lt;/code&gt;  -  add all&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil add &amp;lt;File&amp;gt;&lt;/code&gt;  -  add file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil rm &amp;lt;File&amp;gt;&lt;/code&gt;  -  remove file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil commit -m &amp;lt;Message&amp;gt;&lt;/code&gt;  -  commit all local changes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil commit file1.c file2.h -m &amp;lt;Message&amp;gt;&lt;/code&gt;  -  commit specific files&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil open --keep &amp;lt;DB&amp;gt;&lt;/code&gt;  -  open repo without checkout&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil open --force &amp;lt;DB&amp;gt;&lt;/code&gt;  -  open repo, overwrite with latest&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil status&lt;/code&gt; or &lt;code&gt;fossil info&lt;/code&gt;  -  show repo info&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil changes&lt;/code&gt;  -  list modified tracked files&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil extras&lt;/code&gt;  -  list untracked files&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil diff&lt;/code&gt;  -  show content changes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil timeline&lt;/code&gt;  -  history view&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil ui [&amp;lt;Repo&amp;gt;]&lt;/code&gt;  -  launch web UI&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fossil server [&amp;lt;Repo&amp;gt;]&lt;/code&gt;  -  start web server for &lt;code&gt;push&lt;/code&gt;/&lt;code&gt;pull&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The typical &lt;code&gt;git status&lt;/code&gt; is achieved with &lt;code&gt;fossil changes&lt;/code&gt; + &lt;code&gt;fossil extras&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;recipes&quot;&gt;Recipes&lt;/h3&gt;
&lt;h4 id=&quot;ignore-blender-versioning-files&quot;&gt;Ignore Blender versioning files&lt;/h4&gt;
&lt;p&gt;Use this pattern:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*.blend[0-9]*
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;importing-git-repos&quot;&gt;Importing Git Repos&lt;/h4&gt;
&lt;p&gt;Not required here, but reference: &lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/doc/trunk/www/inout.wiki&quot;&gt;https://fossil-scm.org/home/doc/trunk/www/inout.wiki&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;stashing-and-committing-specific-files&quot;&gt;Stashing and Committing Specific Files&lt;/h4&gt;
&lt;p&gt;Fossil lacks Git's staging (&lt;code&gt;git add -p&lt;/code&gt;) feature. The checkout directory is treated as one working tree snapshot. Still, you can commit selectively.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Commit specific files&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can pass the filenames explicitly to &lt;code&gt;fossil commit&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;fossil commit file1.c file2.h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will commit only the listed files, even if you changed other files in the checkout. The other modified files will stay uncommitted.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use stash to isolate changes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you want to set aside changes temporarily:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Stash away all changes: &lt;code&gt;fossil stash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Reapply only the files you want: &lt;code&gt;fossil stash pop file1.c file2.h&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Commit those files: &lt;code&gt;fossil commit file1.c file2.h&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Optionally reapply remaining changes: &lt;code&gt;fossil stash pop&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Revert unwanted files&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you've edited several files but only want to commit some:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;fossil revert fileX.c fileY.c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This discards edits to those files, leaving only the desired ones for commit. Use stash first if you want to preserve them.&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;p&gt;Learn Fossil quickly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://fossil-scm.org/home/doc/trunk/www/quickstart.wiki&quot;&gt;Quickstart Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>CI/CD Pipelines</category>
<guid isPermaLink="true">https://coderlegion.com/6593/devlog-20250927-use-fossil-as-binary-asset-vcs</guid>
<pubDate>Fri, 17 Oct 2025 14:50:27 +0000</pubDate>
</item>
<item>
<title>Fixing mistakes with Git</title>
<link>https://coderlegion.com/4593/fixing-mistakes-with-git</link>
<description>&lt;blockquote&gt;&lt;p&gt;Bob is my uncle… &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;He dropped his ice cream. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;He didn’t know how to git.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;p&gt;Now he has no ice cream.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;DONT BE LIKE BOB&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lucky for you I am here to share some ways to fix your mistakes on your project. This is assuming you already know git, if not read these articles:&lt;/p&gt;
&lt;p&gt;If you are new to git, maybe start with these first:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/3484/understanding-the-basics-of-git&quot;&gt;Understanding the basics of GIT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://coderlegion.com/3525/rewinding-time-in-git-exploring-commits-branching&quot;&gt;Rewinding Time in Git: Exploring Commits &amp;amp; Branching&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you prefer video: &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.youtube.com/watch?v=RGOj5yH7evk&quot;&gt;Git and GitHub for Beginners — Crash Course — YouTube&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;how-git-can-fix-my-project-&quot;&gt;How git can fix my project?&lt;/h3&gt;
&lt;p&gt;Well, git has a full history(from the day of git init to today) of your project development. All you have to do is view the history and select the day you wanna go back and boom. This all will workout assuming you’ve named your commits properly.&lt;/p&gt;
&lt;p&gt;You can not fix the mistakes once you pushed the changes to remote, theoretically of course. I mean you could, but it will mess up everyone else working on the branch so it is not advised not to fix something that is already on the remote unless all the contributors agree to it.&lt;/p&gt;
&lt;h4 id=&quot;reset&quot;&gt;reset&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;git reset&lt;/code&gt; undo’s changes by removing the commits from the branch.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git reset --soft
git reset --mixed
git reset --hard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each command above moves your current version of your project to the last recent version. You can go back to a specific commit by appending HEAD~n where n is the number of commits to go back.&lt;/p&gt;
&lt;p&gt;i.e., &lt;code&gt;git reset --soft HEAD~3&lt;/code&gt; to go back in 3 commits.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--soft&lt;/code&gt; flag only moves the HEAD pointer to the commit but doesn’t affect the working directory and staged changes, meaning if you have created some files but that doesn’t exist on the older commit now it will be there because it still exists in the staging area and the working directory.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--mixed&lt;/code&gt; flag is the default and this moves the HEAD but it resets the staging area but not the working directory. So, if you have issued agit add . before reset it will be removed from the staging area but it will still be in the working directory.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--hard&lt;/code&gt; flag will do a factory reset to the specific commit. Anything and everything and between is vaporized.&lt;br&gt;
Please do not do this in a public branch(a branch that is already pushed to remote) instead use the safer version revert.&lt;/p&gt;
&lt;p&gt;You can also use &lt;code&gt;git reset &amp;lt;filename&amp;gt;&lt;/code&gt; or &lt;code&gt;git reset &amp;lt;commit-hash&amp;gt; &amp;lt;filename&amp;gt;&lt;/code&gt; to unstage a file without removing it from the filesystem.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1100/format:webp/1*go-1D2jYwa6zIFK8BVPYTg.gif&quot; alt=&quot;git reset by Visualizing Git (git-school.github.io)&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;revert&quot;&gt;revert&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;git revert&lt;/code&gt; is a safer version of undoing a commit. Revert works by finding a way to create a new commit without the changes introduced by the specified commit and appends it to the current tree. &lt;/p&gt;
&lt;p&gt;Meaning it will not delete any commits instead it will create an inverse version of the specified commit.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git revert HEAD
git revert &amp;lt;commit-hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unlike reset, revert requires a commit hash to act.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1100/format:webp/1*zX7tg4ye5euuytZ4dsLm7w.gif&quot; alt=&quot;git revert by Visualizing Git (git-school.github.io)&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can see in the above image that unlike reset it doesn’t just remove the previous commits instead creates a new commit and preserves the commits and doesn’t create problems with other branch contributors.&lt;/p&gt;
&lt;p&gt;If revert and reset do the same which should I use?&lt;/p&gt;
&lt;h5 id=&quot;reset-&quot;&gt;&lt;em&gt;Reset:&lt;/em&gt;&lt;/h5&gt;
&lt;p&gt;Don’t use it in a public branch.&lt;br&gt;
Will remove all the commits after the specified commit (i.e., resetting to two days old commit will remove all the commits made in the last two days).&lt;br&gt;
Use it if you are the only one using the branch or if the commits haven’t reached the remote repo.&lt;/p&gt;
&lt;h5 id=&quot;revert-&quot;&gt;&lt;em&gt;Revert:&lt;/em&gt;&lt;/h5&gt;
&lt;p&gt;Use it anywhere. Afterall it just gonna look like a new commit…&lt;br&gt;
Edit commit messages&lt;br&gt;
Sometimes you make a silly spelling mistake in your most recent commit message and if you want to edit you can re-commit with the &lt;code&gt;--amend&lt;/code&gt; flag. You can also add new files and use amend to update the most recent commit snapshot.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git commit --amend -m &quot;new message that doesn't trigger your OCD&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Again, do not amend a commit that is pushed to a remote.&lt;/p&gt;
&lt;p&gt;But the &lt;code&gt;--amend&lt;/code&gt; the flag will only work for the most recent commit, what if you want to edit a commit message that is older than the most recent commit?&lt;/p&gt;
&lt;p&gt;You can use rebase to change older commit messages. Rebase is also used to integrate changes from other branches just like git merge but rebase gives you finer control on how the history of the base branch should look after integrating.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git rebase -i HEAD~n&lt;/code&gt; n is the number of commits to go back.&lt;/p&gt;
&lt;p&gt;This will open your default editor and show n number of commits with the work “pick” before it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1100/format:webp/1*PyG_V89w1QZsHoSOTu6-Rg.png&quot; alt=&quot;git rebase -i HEAD~5&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now change the word “pick” to “reword” from the commits that you want to change the message. &lt;strong&gt;DO NOT CHANGE THE COMMIT MESSAGE HERE YET…&lt;/strong&gt; Just change the word “pick” -&amp;gt; “reword”.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1100/format:webp/1*VvIcYyEt6Jmj3KNdMmoQOw.png&quot; alt=&quot;Like this&quot;&gt;&lt;/p&gt;
&lt;p&gt;Save the file and close the editor.&lt;/p&gt;
&lt;p&gt;Now you will get a new editor with the commit message. Change it to your new commit message and save it, then close the editor. If you have are trying to reword multiple commits, then you will get each editor windows one by one. That’s it. R&lt;strong&gt;emember, rebase will rewrite the history not just update the message so avoid it in remote branches.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;move-a-commit-to-a-new-branch&quot;&gt;Move a commit to a new branch&lt;/h3&gt;
&lt;p&gt;Sometimes you wanna work on a specific commit but you don’t want to mess with the main/master branch by performing a reset. For this, you can create a branch that contains that specific commit and work there and merge it later.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git branch -b fix
git checkout fix
git reset --hard &amp;lt;commit-hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or you can do it in one line: &lt;code&gt;git checkout -b fix &amp;lt;commit-hash&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;cherry-pick&quot;&gt;cherry-pick&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;git cherry-pick&lt;/code&gt; is used to pick a specific commit from a branch and place it in the current branch.&lt;/p&gt;
&lt;h4 id=&quot;why-in-the-world-would-i-do-that-&quot;&gt;Why in the world would I do that?&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;You created a commit in the wrong branch. Oops.&lt;/li&gt;
&lt;li&gt;You want to include a commit from your branch “fix_contrast” to your main/master branch but you don’t want to merge the whole branch just yet.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Checkout to your base branch where you want the picked commit to be and then issue the command.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git cherry-pick &amp;lt;commit-hash-from-other-branch&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1100/format:webp/1*Vr8u9FxwYMZ0-6xCHe3-VQ.gif&quot; alt=&quot;git cherry-pick by Visualizing Git (git-school.github.io)&quot;&gt;&lt;/p&gt;
&lt;p&gt;This will copy that commit from the target branch to your current/base branch. This will not delete the commit on the target branch, it just makes a copy. This will have the same commit message as the target branch commit message, if you want to edit it you can use -edit the flag to rename it before cherry-picking finishes. Or if you don’t want to commit the target branch commit, use &lt;code&gt;--no-commit&lt;/code&gt; the flag to copy only the changes to the working directory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Even though the reset did remove the commits it looked like it left a phantom of the commits behind…&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1100/format:webp/1*5xBw1OjqBAfdiHNJDrSXqQ.png&quot; alt=&quot;spooky ghost boi…&quot;&gt;&lt;/p&gt;
&lt;p&gt;If the commits are removed then it shouldn’t have its hash right? YES and NO.&lt;/p&gt;
&lt;p&gt;Although you reset your branch history every time you make critical actions like reset or merge git stores these actions in a special record called reference logs (aka &lt;code&gt;reflog&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;So, if for some reason you think you made a mistake by hard resetting a branch and if you want the commits back, you can get it back.&lt;/p&gt;
&lt;p&gt;Issue the command git reflog and it will return the log of all critical mistakes you’ve done so far.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1100/format:webp/1*Gy4pt-12TZQ58jGVYJR1dQ.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can again use the git resetto get back to the previous stage but this time the syntax is a little different, &lt;code&gt;git reset HEAD@{n}&lt;/code&gt; where n is the number shown in &lt;code&gt;reflog&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And that’s it. You can fix mistakes and fix the fixed mistakes that turned out to be a mistake by themselves. Also, remember to avoid any of these operations on a public branch with multiple collaborators working on it.&lt;/p&gt;
&lt;p&gt;There are some other ways too but I only used the above commands for the most part and I hope this article should give you an intro to cleaning up yours's and your colleges’ mess.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExZHF1bm41czk3YWl6MHhxMG9xanZqamgxMmE4am1yaDN1ZGNteWNjaiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/YfOP4V0GugHohdb4US/giphy.gif&quot; alt=&quot;That’s it baby (giphy.com)&quot;&gt;&lt;/p&gt;
</description>
<category>Command Line Tools</category>
<guid isPermaLink="true">https://coderlegion.com/4593/fixing-mistakes-with-git</guid>
<pubDate>Mon, 11 Aug 2025 19:10:50 +0000</pubDate>
</item>
<item>
<title>DevLog 20250806: &quot;Change Version&quot; - File Changes History-Only Version Control for Binary Assets</title>
<link>https://coderlegion.com/4483/devlog-20250806-change-version-file-changes-history-only-version-control-binary-assets</link>
<description>&lt;h3 id=&quot;overview-1&quot;&gt;Overview&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/MethodoxTech/cv&quot;&gt;&lt;code&gt;cv&lt;/code&gt;&lt;/a&gt; is a command-line utility I originally used for personal Unreal Engine projects, where proper version control for binary assets was lacking - but I still wanted to track what had changed, at least at the file-system level. It served its purpose well, but after switching from Unreal Engine to Godot, I haven't needed it as much.&lt;/p&gt;
&lt;p&gt;For &lt;strong&gt;Divooka&lt;/strong&gt;, as our repository grows and more GUI-related work gets involved, we've increasingly run into the issue of syncing assets across different workstations. Perhaps it's time to bring this old tool back to life.&lt;/p&gt;
&lt;h3 id=&quot;demand&quot;&gt;Demand&lt;/h3&gt;
&lt;p&gt;The core requirements are simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;View file change history - ideally alongside corresponding Git commit history.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compare differences&lt;/strong&gt; - similar to Git commits, but focused on files, not content.&lt;/li&gt;
&lt;li&gt;Synchronize files between machines.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Regarding the third point, we’ve made some adjustments to fit our workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Since we generally focus on one PR at a time and aren’t concerned with previous builds, collaborators mainly need the &lt;strong&gt;latest version&lt;/strong&gt; of assets - not their version history.&lt;/li&gt;
&lt;li&gt;Everything must remain &lt;strong&gt;simple, maintainable, and cost zero&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;reference-workflow&quot;&gt;Reference Workflow&lt;/h3&gt;
&lt;p&gt;Based on my previous experience at a game company working on AAA titles, our typical flow involved:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Git for source code&lt;/li&gt;
&lt;li&gt;Perforce for asset versioning&lt;/li&gt;
&lt;li&gt;Azure DevOps (ADO) for task tracking&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each PR included a GitHub pull request, a corresponding Perforce commit, and an ADO task - usually cross-referenced manually. Every Perforce commit needed to mention which GitHub PR it related to.&lt;/p&gt;
&lt;h3 id=&quot;the-implementation&quot;&gt;The Implementation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Change Version (cv)&lt;/strong&gt; is a CLI tool that provides quick check against a repo's changes without saving any changed contents. It does so by recording only the update time. The outputs is just like git status, without diff.&lt;/p&gt;
&lt;p&gt;This is useful for cases when we DO NOT want to do version control yet would still want the capability to see which files has changed, as in the case of multimedia projects (e.g. game projects).&lt;/p&gt;
&lt;h4 id=&quot;usage&quot;&gt;Usage&lt;/h4&gt;
&lt;p&gt;The utility supports the following key commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;init&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;log&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;commit -m &amp;lt;Message&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;output-folders-amp-files&quot;&gt;Output Folders &amp;amp; Files&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.cv&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;cv&lt;/strong&gt; saves history inside the &lt;code&gt;.cv&lt;/code&gt; folder. File update time is stored as utc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.cvignore&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;cv&lt;/strong&gt; uses a &lt;code&gt;.cvignore&lt;/code&gt; file, which shares the same &lt;code&gt;.gitignore&lt;/code&gt; format as git, this is used to decide which files cv should consider when issuing &lt;code&gt;status&lt;/code&gt; command; Notice we are using a new file name instead of using &lt;code&gt;.gitignore&lt;/code&gt; directly - this is to allow the same place having a git repo.&lt;/p&gt;
&lt;h4 id=&quot;ignore-rules&quot;&gt;Ignore Rules&lt;/h4&gt;
&lt;p&gt;I've decided to follow Git's philosophy: everything is considered &quot;important&quot; by default, unless explicitly ignored.&lt;/p&gt;
&lt;p&gt;Here’s a basic implementation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;private static string[]? ReadIgnoreRules()
{
string[]? ignoreRules = null;
if (File.Exists(IgnoreFilename))
ignoreRules = File.ReadAllLines(IgnoreFilename)
.Where(l =&amp;gt; !string.IsNullOrWhiteSpace(l) &amp;amp;&amp;amp; !l.Trim().StartsWith('#'))
.ToArray(); // Skip empty lines and comments
return ignoreRules;
}
private static bool ShouldIgnore(string[] rules, string path)
=&amp;gt; rules.Any(path.StartsWith);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To support more robust wildcard patterns, here’s an upgraded version:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class IgnoreRule
{
    #region Properties
    private readonly Regex _regex;
    public bool IsNegation { get; }
    #endregion

    #region Construction
    public IgnoreRule(string pattern)
    {
        // Support for !foo to &quot;unignore&quot;
        if (pattern.StartsWith('!'))
        {
            IsNegation = true;
            pattern = pattern[1..];
        }

        // Anchor pattern at repo root if it starts with '/'
        bool anchored = pattern.StartsWith('/');
        if (anchored) 
            pattern = pattern[1..];

        // Convert Git-style glob to regex
        _regex = new Regex(
            &quot;^&quot; +
            Regex.Escape(pattern)
                 .Replace(@&quot;\*\*/&quot;, &quot;(@@SLUG@@/)&quot;)
                 .Replace(@&quot;\*\*&quot;, &quot;.*&quot;)
                 .Replace(@&quot;\*&quot;, @&quot;[^/]*&quot;)
                 .Replace(@&quot;\?&quot;, @&quot;[^/]&quot;)
                 .Replace(&quot;@@SLUG@@&quot;, &quot;.*&quot;) +
            (anchored ? &quot;$&quot; : &quot;(?:$|/)&quot;),
            RegexOptions.Compiled | RegexOptions.IgnoreCase
        );
    }
    #endregion

    #region Methods
    public bool IsMatch(string path, string repoRoot)
    {
        // If anchored, the path is relative to repoRoot already
        return _regex.IsMatch(path);
    }
    #endregion
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this stage, creating a &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/MethodoxTech/cv/commit/c811447b7ed47b5d9d540b4aa16c7a68bb505060&quot;&gt;unit test&lt;/a&gt; feels essential.&lt;/p&gt;
&lt;p&gt;Based on what we have so far, it seems plausible to implement a layer of file transfer service to achieve synching of files between workstations with the help of an intermediate file server.&lt;/p&gt;
&lt;h3 id=&quot;file-transfer&quot;&gt;File Transfer&lt;/h3&gt;
&lt;p&gt;I talked about the &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/methodox/devlog-20250804-simple-file-uploading-service-1g26&quot;&gt;need for a simple file-uploading service&lt;/a&gt; just yesterday. Today’s use case is a bit different, as it's strictly internal - we don’t need to support multi-tenant scenarios and we have a fairly accurate idea of our storage needs. Scalability isn’t a major concern.&lt;/p&gt;
&lt;h4 id=&quot;server-options&quot;&gt;Server Options&lt;/h4&gt;
&lt;p&gt;We’re considering ASP.NET Core vs raw TCP sockets for the server:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Concern             &lt;/th&gt;&lt;th&gt;Raw TCP / FTP                    &lt;/th&gt;&lt;th&gt;HTTP (ASP.NET Core)&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Reliability&lt;/strong&gt;     &lt;/td&gt;&lt;td&gt;Requires custom framing, retries &lt;/td&gt;&lt;td&gt;Built-in streaming, timeouts, retries&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;        &lt;/td&gt;&lt;td&gt;Must implement SSH/SSL manually  &lt;/td&gt;&lt;td&gt;HTTPS support out-of-the-box, auth middleware&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Chunking/Resume&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Reinvent the protocol            &lt;/td&gt;&lt;td&gt;Use &lt;code&gt;Range&lt;/code&gt; headers, &lt;a rel=&quot;nofollow&quot; href=&quot;https://tus.io&quot;&gt;tus.io&lt;/a&gt;, etc.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Deployment&lt;/strong&gt;      &lt;/td&gt;&lt;td&gt;Requires FTP daemon, ports, etc. &lt;/td&gt;&lt;td&gt;ASP.NET + Kestrel or NGINX&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Extensibility&lt;/strong&gt;   &lt;/td&gt;&lt;td&gt;Hard to add endpoints            &lt;/td&gt;&lt;td&gt;Minimal APIs, MVC, SignalR, gRPC, DI, etc.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Because we plan to expose the server on the internet, &lt;strong&gt;authentication is a must&lt;/strong&gt;, even if it adds some programming overhead.&lt;/p&gt;
&lt;h4 id=&quot;endpoints&quot;&gt;Endpoints&lt;/h4&gt;
&lt;p&gt;To start, simple endpoints suffice for basic usages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET  /files&lt;/code&gt;: Returns a JSON list of all tracked paths.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET  /files/{**path}&lt;/code&gt;: Streams the latest copy of a single file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PUT  /files/{**path}&lt;/code&gt;: Uploads or overwrites a file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /files/{**path}&lt;/code&gt; Removes a file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;testing-the-server&quot;&gt;Testing the Server&lt;/h3&gt;
&lt;p&gt;Example usage:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# List files
curl -H &quot;X-Api-Key: my-super-secret-key&quot; https://localhost:5001/files

# Upload a file
curl -X PUT -H &quot;X-Api-Key: my-super-secret-key&quot; --data-binary @myfile.txt https://localhost:5001/files/docs/myfile.txt

# Download a file
curl -H &quot;X-Api-Key: my-super-secret-key&quot; https://localhost:5001/files/docs/myfile.txt -o downloaded.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;summary-1&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Today, I focused on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Modernizing and refactoring code; upgrading the framework&lt;/li&gt;
&lt;li&gt;Making the program AoT-compatible&lt;/li&gt;
&lt;li&gt;Drafting the setup for file sync and server&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A few &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/MethodoxTech/cv/blob/master/TODO.md&quot;&gt;TODO items&lt;/a&gt; still need to be addressed before safe syncing can be implemented.&lt;/p&gt;
&lt;p&gt;Notably, the server doesn’t need to understand &lt;code&gt;cv&lt;/code&gt; or &lt;code&gt;RepoStorage&lt;/code&gt; - its only job is to &lt;strong&gt;store the latest version&lt;/strong&gt; of each file. Maintaining accurate timestamps isn’t practical; instead, &lt;strong&gt;storing an MD5 checksum&lt;/strong&gt; is a better way to avoid unnecessary uploads/downloads.&lt;/p&gt;
&lt;p&gt;In an ideal world, we’d have a tool tailored perfectly to our needs. In reality, we often find ourselves choosing between overengineered tools that don’t quite fit or having no suitable tool at all.&lt;/p&gt;
&lt;p&gt;When the need is real, it’s worth rolling up your sleeves and investing some time in building the right tooling.&lt;/p&gt;
&lt;h3 id=&quot;references-1&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Wiki: &lt;a rel=&quot;nofollow&quot; href=&quot;https://wiki.methodox.io/en/Utilities/CLI/cv&quot;&gt;https://wiki.methodox.io/en/Utilities/CLI/cv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Source: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/MethodoxTech/cv&quot;&gt;https://github.com/MethodoxTech/cv&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>CI/CD Pipelines</category>
<guid isPermaLink="true">https://coderlegion.com/4483/devlog-20250806-change-version-file-changes-history-only-version-control-binary-assets</guid>
<pubDate>Wed, 06 Aug 2025 20:37:18 +0000</pubDate>
</item>
<item>
<title>Working with git on large projects with large binary assets.</title>
<link>https://coderlegion.com/4061/working-with-git-on-large-projects-with-large-binary-assets</link>
<description>&lt;p&gt;When I started the now-defunct &lt;em&gt;Steel Hunters (RIP)&lt;/em&gt;, I wrestled with how to best handle version control for the project. Managing Unreal Engine is easy enough, as Epic has structured its repository to be as git friendly as it can be.&lt;/p&gt;
&lt;p&gt;The actual game projects built with Unreal Engine: not so much. Especially when it’s a fairly large-scale, high-fidelity project.&lt;/p&gt;
&lt;h3 id=&quot;command-line-work&quot;&gt;Command Line Work&lt;/h3&gt;
&lt;p&gt;Before I continue — because it will be critical for the rest of this article — let’s talk about using a command line for work.&lt;/p&gt;
&lt;p&gt;Up until about a year or so ago, I &lt;em&gt;rarely&lt;/em&gt; ever worked with a command line. It was always a last resort or for dealing with projects that were specifically setup to be managed from the command line. I just like my GUIs. And, as far as coding, I wouldn’t trade Visual Studio for anything (though I now routinely use &lt;a rel=&quot;nofollow&quot; href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt; for non-C++ or C# work).&lt;/p&gt;
&lt;p&gt;I don’t really know what specifically changed that; maybe it was the OS X terminal or PowerShell that made command line work more palatable. And then I discovered &lt;a rel=&quot;nofollow&quot; href=&quot;https://conemu.github.io/&quot;&gt;ConEmu&lt;/a&gt; which made everything even &lt;em&gt;more&lt;/em&gt; user-friendly. And recently, in response to my &lt;a rel=&quot;nofollow&quot; href=&quot;https://medium.com/engineering-joy/software-for-gamedev-management-writing-and-life-a9902144fb42&quot;&gt;article about my software recommendations&lt;/a&gt;, a reader told me about &lt;a rel=&quot;nofollow&quot; href=&quot;http://cmder.net/&quot;&gt;Cmder&lt;/a&gt; which, now, I wouldn’t trade for anything. Unless I found something better.&lt;/p&gt;
&lt;p&gt;And now that I’ve gotten used to working within the command line, I couldn’t recommend it strongly enough. And, no, you don’t have to go to an extreme with its use; I would &lt;em&gt;never&lt;/em&gt; use a command-line text editor, I don’t use it for all of my tasks and needs, and I certainly would never use it to make an ASCII representation of the &lt;a rel=&quot;nofollow&quot; href=&quot;https://joy-machine.com/&quot;&gt;Joy Machine&lt;/a&gt; logo.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images.squarespace-cdn.com/content/v1/6837dd32e0d4765d46376796/65964851-2442-45b2-ad52-541f4b126856/tqrsrv1o.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Joy Machine Logo&lt;/p&gt;
&lt;p&gt;He’s so cute.&lt;/p&gt;
&lt;p&gt;I also have no memory whatsoever of the gamut of commands that I should know by heart. The variety of flags a given command can take are just things I don’t want to take up space in my brain — &lt;em&gt;especially&lt;/em&gt; the PowerShell commands, which follow unconventional standards, are verbose as can be, and, in general, just dumb. The same is true of git commands which, while I always remember the basics, can get so crazy complex that there’s no way I want to — ahem — &lt;em&gt;commit&lt;/em&gt; them to memory. But that’s what git aliases are for, but that’s for later. For now, here are some resources on the &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/trentpolack/joymachine-public&quot;&gt;one of my public GitHub repositories&lt;/a&gt; (each subfolder in the &lt;code&gt;scripts&lt;/code&gt; root folder has its own &lt;code&gt;README&lt;/code&gt; file for details, but I'll TL;DR it here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;OS X Terminal Improvements&lt;/strong&gt;: An &lt;code&gt;.inputrc&lt;/code&gt; file for improving the user experience on OS X terminals. This includes making Ctrl+arrows skip entire words, tab-insensitive command/folder completion, and so on and so forth. The source of this file is a &lt;a rel=&quot;nofollow&quot; href=&quot;https://gist.github.com/gregorynicholas/1812027&quot;&gt;gist from Gregory Nicholas&lt;/a&gt;, whom I do not know but greatly appreciate his existence.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PowerShell Scripts&lt;/strong&gt; — These ones were all me and I adore them. For the most part, they’re a variety of aliases for commands that I’ll never remember but use often. The sample profile, however, also scans the &lt;code&gt;cmdlets&lt;/code&gt; subfolder for all self-contained PowerShell scripts (any command with some amount of complexity) and adds it to your toolset whenever you load PowerShell. Yay!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://images.squarespace-cdn.com/content/v1/6837dd32e0d4765d46376796/1094ee9d-1adc-4d30-94b4-9aeee07abf6a/rk5n13vr.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Cmder&lt;/p&gt;
&lt;p&gt;We had some good times together old friend.&lt;/p&gt;
&lt;h4 id=&quot;steel-hunters-version-control-iteration-one&quot;&gt;&lt;em&gt;Steel Hunters&lt;/em&gt; Version Control: Iteration One&lt;/h4&gt;
&lt;p&gt;I like git; it’s a great VCS with an intuitive workflow and command set. That said, Perforce has always been the go-to solution for games as it handles binary files (especially large binary files) incredibly well. I’m not a huge fan of Perforce’s GUI client, but it’s workable. That all said: I like git. And Perforce has &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.perforce.com/products/helix4git&quot;&gt;Helix4Git&lt;/a&gt;, which works with Perforce’s standard version control as well as git. It just maintains two separate databases that it mirrors based on your workflow.&lt;/p&gt;
&lt;p&gt;You may have already figured out the issue with this: it &lt;em&gt;mirrors your repository contents on your hard drive&lt;/em&gt;. And since I never had the money to upgrade to the desktop computer I spec’d out in January, my storage space on my development laptop is precious.&lt;/p&gt;
&lt;p&gt;That quickly made it a no-go.&lt;/p&gt;
&lt;h4 id=&quot;steel-hunters-version-control-iteration-two&quot;&gt;&lt;em&gt;Steel Hunters&lt;/em&gt; Version Control: Iteration Two&lt;/h4&gt;
&lt;p&gt;Okay, this time we’re going straight-up Perforce. I setup a server on Amazon AWS EC2, installed the necessary Perforce server components and all was right with the world.&lt;/p&gt;
&lt;p&gt;Except for the fact that Amazon AWS EC2 server costs add up. Quickly. Especially when you have a project that was, at the time, 100 GB without any local versioning whatsoever. The server-side storage costs increased rapidly.&lt;/p&gt;
&lt;p&gt;And since I’m working on &lt;em&gt;Steel Hunters&lt;/em&gt; and it brings in negative dollars, I have always had a job (I now have a contract gig or two for moneydollars). I simply did not have time to manage server maintenance on top of everything else. Also: I know nothing about server maintenance, so whenever I needed to do something, I ended up in a google rabbit hole with fifty Chrome tabs open, each of which solved one aspect of a series of problems I was dealing with.&lt;/p&gt;
&lt;p&gt;So: no-go.&lt;/p&gt;
&lt;h4 id=&quot;steel-hunters-version-control-iteration-three&quot;&gt;&lt;em&gt;Steel Hunters&lt;/em&gt; Version Control: Iteration Three&lt;/h4&gt;
&lt;p&gt;git (I refuse to capitalize this for some reason) doesn’t handle binary files incredibly well; especially, it doesn’t handle large binary files well. That’s why &lt;a rel=&quot;nofollow&quot; href=&quot;https://git-lfs.github.com/&quot;&gt;git-lfs&lt;/a&gt; was introduced, which I started using shortly after it was introduced and found its feature set lacking and its general usability poor.&lt;/p&gt;
&lt;p&gt;GitHub, while I love it more than I love most sites on the internet, has a limit on the size of the repositories it supports. It’s rough 2gb; so, I could store source files and key binary content files on it, but it still seemed risky.&lt;/p&gt;
&lt;p&gt;So: no-go.&lt;/p&gt;
&lt;h4 id=&quot;steel-hunters-version-control-iteration-four&quot;&gt;&lt;em&gt;Steel Hunters&lt;/em&gt; Version Control: Iteration Four&lt;/h4&gt;
&lt;p&gt;Someone on Twitter told me about &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.assembla.com/home/&quot;&gt;Assembla&lt;/a&gt; and it sounded absolutely perfect. git and Perforce support for projects. YES. LIFE WAS COMPLETE. I could store source files on git (which I believe had no size limitations) and content files on Perforce (which had a size limitation, but it worked for me).&lt;/p&gt;
&lt;p&gt;When I started adding some contractors to my team — contractors whom, due to some miracle of the universe (or simply being great people), were willing to work for free/deferred payment — this dual-VCS setup was confusing, hard to setup, hard to manage properly, and generally just bad mojo.&lt;/p&gt;
&lt;p&gt;This was not aided by some issues I was experiencing with Assembla itself; their Perforce setup was actually fairly difficult to reconcile with how Perforce is generally configured. The server-side git support (including git-LFS which I reluctantly used after being told it was much-improved since I last used it) was not up-to-date with recent releases of git and git-lfs. And this led to some incredibly bizarre errors that were fairly time-consuming and difficult to figure out.&lt;/p&gt;
&lt;p&gt;So: no-go.&lt;/p&gt;
&lt;h4 id=&quot;steel-hunters-version-control-iteration-five&quot;&gt;&lt;em&gt;Steel Hunters&lt;/em&gt; Version Control: Iteration Five&lt;/h4&gt;
&lt;p&gt;I then gave &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.visualstudio.com/team-services/&quot;&gt;Visual Studio Team Services&lt;/a&gt; a shot; it was a git-based VCS and it has &lt;em&gt;no limit&lt;/em&gt; on repository size. It is also free unless you want to bolt-on some Azure-based continuous integration or other fanciness. I didn’t believe the lack of size limitations, so I contacted customer support and explained that my project was large. Very large. They said: yup, no limit, don’t worry about. “And it’s free?” “Yes, for your purposes it is completely free of charge.”&lt;/p&gt;
&lt;p&gt;I’ve been using VSTS for the last five months without a single issue. Its user management is a complete pain, but that’s such an uncommon task that I just accepted it.&lt;/p&gt;
&lt;p&gt;The problem that I ran into a couple days ago was absolutely no fault of VSTS. It was great in every way, minus the variety of tools and utilities and integrations that are entirely reliant on the use of GitHub specifically. I still actively recommend it for mid-sized projects.&lt;/p&gt;
&lt;p&gt;The problem was that I kept running out of space on my hard drive. And, since I am not smart, it took me until a couple days ago to finally run a disk drive space analysis tool (&lt;a rel=&quot;nofollow&quot; href=&quot;https://windirstat.net/&quot;&gt;WinDirStat&lt;/a&gt;) on the disk with my &lt;em&gt;Steel Hunters&lt;/em&gt; repository on it.&lt;/p&gt;
&lt;p&gt;It totaled 380 GB. Of which 140 GB was the project itself, and 240 GB was the &lt;code&gt;.git&lt;/code&gt;folder itself.&lt;/p&gt;
&lt;p&gt;I spent the next day trying everything I could find on the &lt;em&gt;entire internet&lt;/em&gt; to try and prune now-irrelevant large files in the history of the repository using &lt;a rel=&quot;nofollow&quot; href=&quot;https://stackoverflow.com/questions/1904860/how-to-remove-unreferenced-blobs-from-my-git-repo&quot;&gt;git-based commands&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery&quot;&gt;other git-based commands&lt;/a&gt;, and even &lt;a rel=&quot;nofollow&quot; href=&quot;https://rtyley.github.io/bfg-repo-cleaner/&quot;&gt;BFG&lt;/a&gt;. I think I ended up shaving off about 10–20 GB of data from the &lt;code&gt;.git&lt;/code&gt; folder. And when I attempted to push the rewritten history to VSTS &lt;a rel=&quot;nofollow&quot; href=&quot;https://confluence.atlassian.com/stashkb/git-push-fails-fatal-the-remote-end-hung-up-unexpectedly-282988530.html&quot;&gt;it would fail&lt;/a&gt;. It would fail every time. And there was no combination of solutions that I could find (including the one on that page) that would cause it not to fail.&lt;/p&gt;
&lt;h4 id=&quot;steel-hunters-version-control-now&quot;&gt;&lt;em&gt;Steel Hunters&lt;/em&gt; Version Control: Now&lt;/h4&gt;
&lt;p&gt;I approached this problem from an entirely different perspective yesterday. git and git-lfs remain my favorite form of VCS that doesn’t bring with it the cost of Perforce.&lt;/p&gt;
&lt;h3 id=&quot;a-quick-aside-on-git-lfs&quot;&gt;A Quick Aside on git-lfs&lt;/h3&gt;
&lt;p&gt;git-lfs is now included in the Windows installer for git and that is not made obvious anywhere and can lead to multiple installs of git-lfs on your system.&lt;/p&gt;
&lt;h3 id=&quot;where-was-i-&quot;&gt;Where Was I…&lt;/h3&gt;
&lt;p&gt;I wanted to stick with git and git-lfs and, more than that, I wanted to go back to using GitHub. I bought a few “packs” of git-lfs storage on GitHub, which wasn’t ideal, but it wasn’t going to kill my bank account (on top of another aspect of this plan below) since I’ll just give up a few meals a week. And I came up with a new solution for managing our entire project-base:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Steel Hunters&lt;/em&gt; Project&lt;/strong&gt; — All source code, unique DLLs (those necessary to build aspects of the project), and select content files (game data files and, as of this morning, UMAP files due to the importance of versioning for them despite their large size). Yay, happy Trent. Back on GitHub!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Joy Engine (Unreal Engine 4 Custom Fork)&lt;/strong&gt; — This too would go on GitHub, because it was never a problem child in the first place.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Steel Hunters&lt;/em&gt; Source Asset Files&lt;/strong&gt; — This repository is for managing the source content files that are imported into the &lt;em&gt;Steel Hunters&lt;/em&gt; UE4 project. This includes files like PNGs, TGAs, PSDs, FBXs, and so on and so forth. These files are more critical to the project than any UASSET in the game project, which is why I sprung for the additional git-lfs storage packs, as I want them versioned. They aren’t as numerous and heavy as the game project’s content folder, as that folder contains a number of Unreal Engine asset packages that I don’t generally care about exporting the source files of, save special circumstances.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;steel-hunters-project-content-folder&quot;&gt;&lt;strong&gt;&lt;em&gt;Steel Hunters&lt;/em&gt; Project Content Folder&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;This was the elephants-stacked-on-elephants-stacked-on-giant-cubes-of-solid-lead of the whole dilemma. In general: most of these content files do not change with any frequency. And, if they do change, it’s generally a fairly trivial alteration of a flag, property, or minor edits. Since I always note what changes I make in fair detail in my git commit messages, if anything ever went bad, I could really just read back in the commit history and re-make the changes if need be (through downloading the original asset package or re-importing the source the file).&lt;/p&gt;
&lt;p&gt;The solution I ended up with is this: an Amazon AWS S3 bucket for syncing the &lt;em&gt;Steel Hunters&lt;/em&gt; Content directory to whenever any files are changed. This folder is &lt;a rel=&quot;nofollow&quot; href=&quot;http://www.febooti.com/products/&quot;&gt;managed through a tool&lt;/a&gt; that monitors a folder for any modifications and syncs them to the S3 bucket.&lt;/p&gt;
&lt;p&gt;Is this absolutely ideal? No. It is, however, the most time-effective way for me to maintain the project until it gets funded properly and I can bring on a team and someone with more experience than me in managing servers (which would make switching to Perforce a viable option, if the need arises).&lt;/p&gt;
&lt;p&gt;Since this whole plan was put into effect yesterday, time will tell how well everything works out.&lt;/p&gt;
&lt;h4 id=&quot;working-with-git-like-a-rockstar&quot;&gt;Working with git Like a Rockstar&lt;/h4&gt;
&lt;p&gt;I don’t pretend to be a git expert, but at this point I’ve gotten so comfortable with my command line-based workflow and built up a fair amount of shortcuts, tools, and utilities to make my day-to-day work effortless. And I don’t keep those a secret.&lt;/p&gt;
&lt;p&gt;But first: git GUI applications are universally bad. All of them lack the full set of functionality that you really want for properly managing a repository, for one. And some of the applications themselves are just… bad.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.sourcetreeapp.com/&quot;&gt;SourceTree&lt;/a&gt;, for instance, should be avoided at all costs. I’ve found it buggy, slow, completely lacking the ability to handle large projects, and just a general disappointment. I’m not even going to link it nor give it bold text. &lt;em&gt;That’s what I think of it&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.gitkraken.com/&quot;&gt;&lt;strong&gt;GitKraken&lt;/strong&gt;&lt;/a&gt; will be good some day. It’s just not there yet. It has issues with large projects, its interface, while pretty, is non-intuitive, and it’s lacking some very necessary features for properly managing a repository. As I said, though: I think it’s promising.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/apps/desktop&quot;&gt;&lt;strong&gt;GitHub Desktop&lt;/strong&gt;&lt;/a&gt; is an electron app I just found last night and… I like it? I wouldn’t use it for management of a repository or anything, but if I ever want to quickly analyze all of the various local repositories on my computer, I can open it, see some quick diffs, and then close it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://www.git-tower.com/&quot;&gt;&lt;strong&gt;Tower&lt;/strong&gt;&lt;/a&gt; is thoroughly decent, but I’ve encountered a fair amount of issues with it when working at scale.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That said: GUIs for performing diff and merge operations are absolutely crucial. And while &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.perforce.com/products/helix-apps/merge-diff-tool-p4merge&quot;&gt;P4Merge&lt;/a&gt; gets the job done adequately, what you &lt;em&gt;really&lt;/em&gt; want is &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.scootersoftware.com/&quot;&gt;Beyond Compare&lt;/a&gt;. Just… trust me. For one thing, Beyond Compare not only does diff and merge operations on git repositories, but it can also do folder/file diff and merge operations even on things that aren’t managed by any sort of version control. It’s &lt;em&gt;wonderful&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;NOTE&lt;/em&gt;: This is an archive article that I’m updating; the information here may be out of date. GitHub Desktop, for instance, is pretty good. And I’m looking at giving GitKraken another go in a few minutes.&lt;/p&gt;
&lt;h3 id=&quot;but-just-work-with-the-command-line-except-the-diff-merge-thing-&quot;&gt;But Just Work with the Command Line (Except the diff/merge Thing)&lt;/h3&gt;
&lt;p&gt;I really can’t emphasize how useful the git command line is (by the way, when you install on Windows, ensure you install both bash and standard Windows compatibility). It’s powerful, it gives you all the information you need, it does a better job of informing you what is and isn’t managed by git-lfs, it lets you easily pick-and-choose what you include in a given commit, and so on and so forth.&lt;/p&gt;
&lt;p&gt;That doesn’t mean it’ll be instantly obvious how to work with it, but that’s why I have some handy files on &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/trentpolack/joymachine-public/tree/master/git&quot;&gt;my repo’s git folder&lt;/a&gt; to help out:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[README](https://github.com/trentpolack/joymachine-public/blob/master/git/README.md)&lt;/code&gt; — Some general information about what the templates do as well as some general git information to help out.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[gitconfig](https://github.com/trentpolack/joymachine-public/blob/master/git/gitconfig.template)&lt;/code&gt; — A whole lot of aliases that make common operations a bit quicker to execute as well as aliases for operations that are not at all trivial to execute. &lt;code&gt;git state&lt;/code&gt;, &lt;code&gt;git lard&lt;/code&gt;, &lt;code&gt;git prettylog&lt;/code&gt;, and &lt;code&gt;git last&lt;/code&gt; are my favorites.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Also: I added output colors for some git operations. It was necessary.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[gitattributes](https://github.com/trentpolack/joymachine-public/blob/master/git/gitattributes.template)&lt;/code&gt; — Rules for files that I absolutely want stored as text (CPP/H/CS) and some general rules for files I want managed by git-lfs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[gitignore](https://github.com/trentpolack/joymachine-public/blob/master/git/gitignore.template)&lt;/code&gt; — A list of files and extensions that I commonly ignore (focused on UE4 projects).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;And that’s my story about version control. &lt;em&gt;fin&lt;/em&gt;&lt;/p&gt;
</description>
<category>PowerShell with Git</category>
<guid isPermaLink="true">https://coderlegion.com/4061/working-with-git-on-large-projects-with-large-binary-assets</guid>
<pubDate>Wed, 16 Jul 2025 04:55:21 +0000</pubDate>
</item>
</channel>
</rss>