search blog

Git CLI

Why use the Git CLI?

Using the git CLI at first was difficult, going from using the built-in tab in VS Code to GitHub Desktop and then the CLI was a step and a half. While GitHub Desktop has some neat features and a nice visualisation for repos, the fine grain control that using the CLI brings is unmatched.

Something that has saved me a lot of time is using aliases such as gll for logging. These have saved me a huge amount of time and I don't have to remember the specific flags of every command I most commonly use.

Benefits of the CLI

  • Fine grain control
  • Add by hunks
  • Rebase/Merge
  • Accessable on most machines

Drawbacks of the CLI

  • Have to memorize commands
  • Learning curve

My Common Commands

git add <.|-A|-i|-p>

Using -i or -p flag will put you in patch mode or interactive mode where you have a wizard to help what hunks/files you want to stage. The -A or . flag will add the current directory or all files.

git checkout <-b> 

Checkout is a command that switches branches, using - will switch to the previous branch. Using the -b flag will create a branch.

git commit -m "" -m "<body>"<!----></code></pre><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><p><!----><!--[--><!--[--><!--[--><!--[!--><!--[--><!--[!--><!--[!--><!----><!----><!--[!-->Commiting it using the staged files and creating a commit out of them along with
some meta information such as title, date, etc. You can drop the <!--]--><!----><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><code class="inline-block bg-zinc-100 px-1 py-0.5 dark:bg-zinc-800">-m</code><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><!----><!--[!-->s and it
will open up a file to write the commit message in an editor.<!--]--><!----><!----><!--]--><!--]--><!--]--><!--]--><!----><!--]--><!--]--><!----><!--]--><!----></p><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><pre><code class="hljs"><!---->git log --decorate --oneline --graph<!----></code></pre><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><p><!----><!--[--><!--[--><!--[--><!--[!--><!--[--><!--[!--><!--[!--><!----><!----><!--[!-->Logging is one of the most useful commands, this allows you to see a graph of
the repo history, If you have branches it will show them visually as different
nodes. If shows the SHA and a commit title. A really useful tool for locating
branches splitting or joining and just to see a general history of the repo.<!--]--><!----><!----><!--]--><!--]--><!--]--><!--]--><!----><!--]--><!--]--><!----><!--]--><!----></p><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><pre><code class="hljs"><!---->git rebase -i HEAD~10<!----></code></pre><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><p><!----><!--[--><!--[--><!--[--><!--[!--><!--[--><!--[!--><!--[!--><!----><!----><!--[!-->Rebasing is a useful tool for editing the commit history. The interactive flag
allows for a file to open in your editor to edit commits. The <!--]--><!----><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><code class="inline-block bg-zinc-100 px-1 py-0.5 dark:bg-zinc-800">HEAD~10</code><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><!----><!--[!--> in this
is to get the last 10 commits from the head. In the editor you have the choice
to reword, reorder, squash, etc commits, afterwards the CLI will rebase the
commits and you can push - or sometimes force push - to remote.<!--]--><!----><!----><!--]--><!--]--><!--]--><!--]--><!----><!--]--><!--]--><!----><!--]--><!----></p><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><pre><code class="hljs"><!---->git merge <branch><!----></code></pre><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><p><!----><!--[--><!--[--><!--[--><!--[!--><!--[--><!--[!--><!--[!--><!----><!----><!--[!-->Merging is taking two branches and merging them into one using a new commit.
There are other ways to merge and flags you can pass in, but the one I most
commonly use to merge a branch is this. This is a good way to keep a feature
branch up to date with the main branch.<!--]--><!----><!----><!--]--><!--]--><!--]--><!--]--><!----><!--]--><!--]--><!----><!--]--><!----></p><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><pre><code class="hljs"><!---->git stash <list> <-m "<message>"> <pop> <drop><!----></code></pre><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><p><!----><!--[--><!--[--><!--[--><!--[!--><!--[--><!--[!--><!--[!--><!----><!----><!--[!-->Stashing is taking files and stashing them away for later. Stashing takes on the
style of a stack, first in is last out (unless using the index flag). Using the
<!--]--><!----><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><code class="inline-block bg-zinc-100 px-1 py-0.5 dark:bg-zinc-800">-m</code><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><!----><!--[!--> flag adds a message to the stash so you can easily see them in the list.<!--]--><!----><!----><!--]--><!--]--><!--]--><!--]--><!----><!--]--><!--]--><!----><!--]--><!----></p><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><pre><code class="hljs"><!---->git tag -a <tag name> <commit sha> -m "<title>"<!----></code></pre><!----><!--]--><!--]--><!--]--><!--]--><!----><!--[!--><!--[!--><!--]--><!--]--><!----><!--[!--><!--[--><!--[!--><!--[!--><!----><p><!----><!--[--><!--[--><!--[--><!--[!--><!--[--><!--[!--><!--[!--><!----><!----><!--[!-->This will create a tag for the given commit, tags are really useful for creating
checkpoints in your code that you can come back to later on and easily identify.<!--]--><!----><!----><!--]--><!--]--><!--]--><!--]--><!----><!--]--><!--]--><!----><!--]--><!----></p><!----><!--]--><!--]--><!--]--><!--]--><!----><!--]--><!--]--><!----> <hr> <div class="flex flex-wrap items-center justify-between"><ul class="flex flex-wrap gap-2"><!--[--><li><p><a tabindex="0" href="/blog?tags=git" class="text-accent-600 ring-on-focus-visible hover:underline">#git</a></p></li><li><p><a tabindex="0" href="/blog?tags=cli" class="text-accent-600 ring-on-focus-visible hover:underline">#cli</a></p></li><!--]--></ul> <p>Published 12/26/2024</p></div></article></div><!----><!----></main> <footer class="bg-white dark:bg-zinc-900"><div class="wrap container flex items-center justify-between"><div class="flex items-center gap-2"><a target="_blank" href="https://www.github.com/bobbymannino/bobbymannino" class="hover:text-accent-600 text-zinc-800 dark:text-zinc-100" title="See this repo on GitHub"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" class="size-6"><path fill="currentColor" fill-rule="evenodd" d="M16 2a14 14 0 0 0-4.43 27.28c.7.13 1-.3 1-.67v-2.38c-3.89.84-4.71-1.88-4.71-1.88a3.7 3.7 0 0 0-1.62-2.05c-1.27-.86.1-.85.1-.85a2.94 2.94 0 0 1 2.14 1.45a3 3 0 0 0 4.08 1.16a2.93 2.93 0 0 1 .88-1.87c-3.1-.36-6.37-1.56-6.37-6.92a5.4 5.4 0 0 1 1.44-3.76a5 5 0 0 1 .14-3.7s1.17-.38 3.85 1.43a13.3 13.3 0 0 1 7 0c2.67-1.81 3.84-1.43 3.84-1.43a5 5 0 0 1 .14 3.7a5.4 5.4 0 0 1 1.44 3.76c0 5.38-3.27 6.56-6.39 6.91a3.33 3.33 0 0 1 .95 2.59v3.84c0 .46.25.81 1 .67A14 14 0 0 0 16 2"></path></svg><!----></a> <p><small>© bobman.dev 2024</small></p></div> <div class="not-hoverable:hidden"><kbd>Ctrl</kbd> <kbd>K</kbd></div></div></footer><!----><!----><!--]--> <!--[!--><!--]--><!--]-->
			
			<script>
				{
					__sveltekit_vgwgvq = {
						base: new URL("..", location).pathname.slice(0, -1)
					};

					const element = document.currentScript.parentElement;

					Promise.all([
						import("../_app/immutable/entry/start.BVwhMn29.js"),
						import("../_app/immutable/entry/app.C9vs7aB6.js")
					]).then(([kit, app]) => {
						kit.start(app, element, {
							node_ids: [0, 4],
							data: [{"type":"data","data":{posts:[{content:"\n# What is ACID?\n\nACID is an acronym that stands for Atomicity, Consistency, Isolation, and\nDurability. These are the four key properties of a transaction in a database\nsystem. A transaction is a sequence of operations that are executed as a single\n'action'. The ACID properties ensure that the database remains in a consistent\nstate even in the presence of failures.\n\n## Atomicity\n\nAtomicity is treating a transaction (multiple 'actions') as a single action, so\nif one fails they all fail and revert back. This ensures that the database stays\nconsistent.\n\n```sql\nupdate users set balance = balance - 100 where id = 1;\nupdate users set balance = balance + 100 where id = 2;\n```\n\nIf user 1 doesn't have the balance (balance cannot be below 0) nothing will be\nadded to the balance of user 2.\n\n## Consistency\n\nThis means that transactions must be kept valid from one state to another.\n\n```sql\ncreate table users (\n    id serial primary key,\n    balance int not null default 0 check(balance >= 0)\n);\n\nupdate users set balance = -100 where id = 1;\n```\n\nThe above statement wouldn't work as the balance has to be above or equal to 0.\n\n## Isolation\n\nIsolation ensures that the execution of transactions does not interfere with\neach other. This means that transactions are executed independently of each\nother and if there are 2 transactions trying to access/modify the same data\nat the same time, only one can do so at once. This ensures there are no\n'dirty reads'.\n\n## Durability\n\nOnce a transaction is committed, it will remain in the system even if there is a\nsystem failure. This means that the changes made by the transaction are\npermanent.\n",meta:{title:"ACID Databases",slug:"acid-databases",publishedOn:new Date(1734912000000),tagline:"Atomicity, Consistency, Isolation and Durability",tags:["database","acid"]}},{content:"\n# Box Testing\n\n## Black Box Testing\n\nBlack box testing is a technique used to test a system/application's\nfunctionality without knowing the internal code base. This focuses on inputs and\noutputs to ensure a system behaves as expected.\n\nYou would use this type of testing for things like validating user interfaces\nand external functions. It is particularly useful when you do not have access to\na function (like an external API).\n\n## White Box Testing\n\nWhite box testing is a method used to test the structures/workings of an\napplication as opposed to its functionality. A white box tester has access to\nall the internal code and can test the application at a much deeper level. White\nbox testers can test things like internal algorithms and data structures.\n\nThis type of tester can be applied at the unit, integration, and system levels.\n\n## Gray Box Testing\n\nGray box testing is a combination of white box and black box, it takes a hybrid\napproach where the testers have limited knowledge of internal code, but enough\nto define test cases. Gray box testers are allowed all the documentation linked\nto the functions.\n",meta:{title:"Box Testing",slug:"box-testing",publishedOn:new Date(1738627200000),tagline:"What is white/black/gray box testing?",tags:["tests"]}},{content:"\n# Config Files\n\nI have taken the time to look in more details about config files, how they are\nstored and where they are stored. It turns out nearly every service uses a\ndifferent format or location so how can i save them all in one place for peace\nof mind? if anything were to happen how would i get back to where i am now? well\ni decided to create a script to backup as many config files as i find relevent.\nI have backed up 5 config files;\n\n- Git\n- GitHub\n- Zed\n- homebrew\n- Zsh\n\nThe script i built is written in shell and essentially takes each file, copes it\ninto a git repo and commits the changes, then the restore script takes those\nfiles and copies them back into the places they belog to be used. Its very\nsimple but allows me to take my config anywhere with ease.\n",meta:{title:"Config Files",slug:"config-files",publishedOn:new Date(1734393600000),tagline:"Backing up every config file",tags:["config","backup","shell"]}},{content:"\n# GitHub CLI\n\n## What is the GitHub CLI?\n\nThe GitHub CLI is useful for things like cloning repos but also making actions\nthat you would otherwise make on GitHub, such as cloning a repo, creating\nan issue, viewing a pull request, creating labels and much more.\n\n## My Favorite Commands\n\n```sh\ngh repo create --private \u003Cname>\n```\n\nThis one is self explanatory. It creates a new private repo on GitHub. This\nsaves me a huge amount of time, normally you would have to go onto GitHub >\nRepos > Create, but with the CLI, it's much much quicker.\n\n```sh\ngh pr create -e\n```\n\nThis opens up an editor where you enter information about a pull request you are\ncreating.\n\n```sh\ngh issue list -a \"@me\"\n```\n\nThis lists all open issues that are assigned to you.\n\n```sh\ngh browse -b $(git branch --show-current)\n```\n\nThis opens the current repo on the current branch in your browser.\n",meta:{title:"GitHub CLI",slug:"github-cli",publishedOn:new Date(1735171200000),tagline:"Practicing the GitHub CLI",tags:["github","cli"]}},{content:"\n# Git CLI\n\n## Why use the Git CLI?\n\nUsing the git CLI at first was difficult, going from using the built-in tab in\nVS Code to GitHub Desktop and then the CLI was a step and a half. While GitHub\nDesktop has some neat features and a nice visualisation for repos, the fine\ngrain control that using the CLI brings is unmatched.\n\nSomething that has saved me a lot of time is using aliases such as `gll` for\nlogging. These have saved me a huge amount of time and I don't have to remember\nthe specific flags of every command I most commonly use.\n\n### Benefits of the CLI\n\n- Fine grain control\n- Add by hunks\n- Rebase/Merge\n- Accessable on most machines\n\n### Drawbacks of the CLI\n\n- Have to memorize commands\n- Learning curve\n\n## My Common Commands\n\n```sh\ngit add \u003C.|-A|-i|-p>\n```\n\nUsing `-i` or `-p` flag will put you in patch mode or interactive mode where you\nhave a wizard to help what hunks/files you want to stage. The `-A` or `.` flag\nwill add the current directory or all files.\n\n```sh\ngit checkout \u003C-b> \u003Cbranch|->\n```\n\nCheckout is a command that switches branches, using `-` will switch to the\nprevious branch. Using the `-b` flag will create a branch.\n\n```sh\ngit commit -m \"\u003Ctitle>\" -m \"\u003Cbody>\"\n```\n\nCommiting it using the staged files and creating a commit out of them along with\nsome meta information such as title, date, etc. You can drop the `-m`s and it\nwill open up a file to write the commit message in an editor.\n\n```sh\ngit log --decorate --oneline --graph\n```\n\nLogging is one of the most useful commands, this allows you to see a graph of\nthe repo history, If you have branches it will show them visually as different\nnodes. If shows the SHA and a commit title. A really useful tool for locating\nbranches splitting or joining and just to see a general history of the repo.\n\n```sh\ngit rebase -i HEAD~10\n```\n\nRebasing is a useful tool for editing the commit history. The interactive flag\nallows for a file to open in your editor to edit commits. The `HEAD~10` in this\nis to get the last 10 commits from the head. In the editor you have the choice\nto reword, reorder, squash, etc commits, afterwards the CLI will rebase the\ncommits and you can push - or sometimes force push - to remote.\n\n```sh\ngit merge \u003Cbranch>\n```\n\nMerging is taking two branches and merging them into one using a new commit.\nThere are other ways to merge and flags you can pass in, but the one I most\ncommonly use to merge a branch is this. This is a good way to keep a feature\nbranch up to date with the main branch.\n\n```sh\ngit stash \u003Clist> \u003C-m \"\u003Cmessage>\"> \u003Cpop> \u003Cdrop>\n```\n\nStashing is taking files and stashing them away for later. Stashing takes on the\nstyle of a stack, first in is last out (unless using the index flag). Using the\n`-m` flag adds a message to the stash so you can easily see them in the list.\n\n```sh\ngit tag -a \u003Ctag name> \u003Ccommit sha> -m \"\u003Ctitle>\"\n```\n\nThis will create a tag for the given commit, tags are really useful for creating\ncheckpoints in your code that you can come back to later on and easily identify.\n",meta:{title:"Git CLI",slug:"git-cli",publishedOn:new Date(1735171200000),tagline:"Learning the git CLI, and why it's better then a GUI",tags:["git","cli"]}},{content:"\n# Postgres Current Setting\n\nUsing `current_setting` in postgres is a way of obtaining session/transaction\nvariables. This is incredibly useful for debugging and understanding the\nenvironment in which your queries are running.\n\n## Setting a Variable\n\n`set_config` is a way to store a text value in the postgres connection. This\nfunction takes in 3 arguments:\n\n`setting_name` [text], The key of what you want to store.\n\n`new_value` [text], The value of what you want to store.\n\n`is_local` [boolean], If true the value will only persist for the current\ntransaction, otherwise will persist for as long as the current session is alive.\n\nThe function will return what is entered into `new_value`.\n\nIn practice, it would look like this:\n\n```sql\nSELECT set_config('auth.uid', '1234', false);\n```\n\n## Getting a Variable\n\n`current_setting` takes in two arguments (the second being optional):\n\n`setting_name` [text], This is the key of the value you want to get.\n\n`missing_ok` [boolean?] If false or undefined then will throw an error if the\nkey does not exist, otherwise will return the value.\n\nUsing the function would look like this:\n\n```sql\nSELECT current_setting('auth.uid', true);\n```\n",meta:{title:"Postgres Current Setting",slug:"postgres-current-setting",publishedOn:new Date(1735948800000),tagline:"Session/transaction variables in postgres",tags:["sql","postgres"]}},{content:"\n# Postgres Window Functions\n\n## What is a Window Function?\n\nA window function is a function that in SQL that is used to perform calculations\non a set of rows that are related to the current row, for example ordering by\nrow number. These functions are particularly useful when you need to perform\ncalculations such as getting the rank of a row compared to others or grouping\nand then ordering by rank.\n\nA window function is made up of 2 parts:\n\n- A function. The function is the actual calculation that is performed on the\n  set of rows\n- The window. The window is the set of rows that are related to the current row\n  and are used to perform the calculation\n\n## Window Functions in Postgres\n\nPostgres supports window functions in the form of `OVER` clauses. The `OVER`\nclause is used to specify the window that the function should be applied to.\n\nThe syntax for a window function in postgres is:\n\n```sql\n\u003Cfunction>() OVER ([PARTITION BY xx, xx] [ORDER BY xx, xx])\n```\n\nIn use it would look something like\n\n```sql\nselect\n    id, name, score,\n    row_number() over (order by score desc) as rank\nfrom\n    scores;\n```\n\nThis would return all the rows, and with each row a rank column which will be\nfilled with the row index ordered by their score descending, which means the\nfirst row (highest scorer) will have rank 1, the second row, rank 2 and so on.\n\n## `RANK` vs `DENSE_RANK` vs `ROW_NUMBER`\n\nThere are 3 common window functions in postgres:\n\n### `ROW_NUMBER`\n\nTakes each row - regardless of ties - and assigns a unique number to it,\nstarting and 1 and ending at n. This is useful for when you need a unique value\nfor every row.\n\n| id  | score | rank |\n| --- | ----- | ---- |\n| 1   | 12    | 1    |\n| 5   | 10    | 2    |\n| 4   | 10    | 3    |\n| 2   | 8     | 4    |\n| 3   | 7     | 5    |\n\n### `RANK`\n\nRank takes each row like `ROW_NUMBER` but in the event of a tie, it will give both\nrows the lower rank and then skip the higher rank.\n\n| id  | score | rank |\n| --- | ----- | ---- |\n| 1   | 12    | 1    |\n| 5   | 10    | 2    |\n| 4   | 10    | 2    |\n| 2   | 8     | 4    |\n| 3   | 7     | 5    |\n\n### `DENSE_RANK`\n\nThis is similar to `RANK` except it will not skip the next number on a tie,\nuseful if you do not wants gaps in the rank.\n\n| id  | score | rank |\n| --- | ----- | ---- |\n| 1   | 12    | 1    |\n| 5   | 10    | 2    |\n| 4   | 10    | 2    |\n| 2   | 8     | 3    |\n| 3   | 7     | 4    |\n\n## Examples\n\n### Top 3 Scorers\n\nGiven the schema below, find the top 3 scorers for both male and female. If\nthere is a tie, treat that as one rank.\n\n```sql\ncreate table scores (\n    id serial primary key,\n    name text not null, -- for this example don't worry about duplicate handling\n    gender text not null check (gender in ('m', 'f')),\n    score int not null, check (score >= 0)\n);\n\ninsert into scores (name, gender, score) values\n    ('Alice', 'f', 10),\n    ('Bob', 'm', 12),\n    ('Charlie', 'm', 8),\n    ('Diana', 'f', 7),\n    ('Eve', 'f', 10),\n    ('Frank', 'm', 10),\n    ('Grace', 'f', 8),\n    ('Hank', 'm', 7),\n    ('Ivy', 'f', 12),\n    ('Jack', 'm', 10);\n```\n\nThe answer:\n\n```sql\nwith ranked_scores as (\n    select\n        name, gender, score,\n        dense_rank() over (partition by gender order by score desc) as rank\n    from scores\n)\nselect *\nfrom ranked_scores\nwhere rank \u003C= 3;\n```\n\n| name    | gender | score | rank |\n| ------- | ------ | ----- | ---- |\n| Ivy     | f      | 12    | 1    |\n| Alice   | f      | 10    | 2    |\n| Eve     | f      | 10    | 2    |\n| Grace   | f      | 8     | 3    |\n| Bob     | m      | 12    | 1    |\n| Jack    | m      | 10    | 2    |\n| Frank   | m      | 10    | 2    |\n| Charlie | m      | 8     | 3    |\n\nIn the answer we use a CTE, this is beacuse the `where` clause is executed\nbefore the `select` so we would get `rank not defined`. The way to solve this is\nto execute the `select` before the `where` by use of a CTE. We also have chosen\nto use `dense_rank` instead or `rank` or `row_number`, this is because we want\nthe top 3 ranks, so we include all people whos ranks are 1, 2 or 3.\n\n### Running Total\n\nGiven the schema below find the running total of sales for each product over\ntime.\n\n```sql\ncreate table sales (\n    id serial primary key,\n    product_id int not null,\n    sale_date date not null,\n    amount numeric not null\n);\n\ninsert into sales (product_id, sale_date, amount) values\n    (1, '2024-01-01', 100),\n    (2, '2024-01-01', 200),\n    (3, '2024-01-02', 150),\n    (2, '2024-01-02', 250),\n    (1, '2024-01-03', 200),\n    (2, '2024-01-03', 300),\n    (3, '2024-01-03', 250),\n    (1, '2024-01-04', 300),\n    (2, '2024-01-04', 400),\n    (3, '2024-01-04', 350),\n    (4, '2024-01-05', 200);\n```\n\nThe answer:\n\n```sql\nselect\n    product_id,\n    sale_date,\n    amount,\n    sum(amount) over (partition by product_id order by sale_date) as running_total\nfrom sales\norder by product_id, sale_date;\n```\n\n| product_id | sale_date  | amount | running_total |\n| ---------- | ---------- | ------ | ------------- |\n| 1          | 2024-01-01 | 100    | 100           |\n| 1          | 2024-01-03 | 200    | 300           |\n| 1          | 2024-01-04 | 300    | 600           |\n| 2          | 2024-01-01 | 200    | 200           |\n| 2          | 2024-01-02 | 250    | 450           |\n| 2          | 2024-01-03 | 300    | 750           |\n| 2          | 2024-01-04 | 400    | 1150          |\n| 3          | 2024-01-02 | 150    | 150           |\n| 3          | 2024-01-03 | 250    | 400           |\n| 3          | 2024-01-04 | 350    | 750           |\n| 4          | 2024-01-05 | 200    | 200           |\n\nIn this example we have used a different function to get the running total:\n`sum`. This is the right function as we want ot get the total (sum) of the\ncurrent row + the rows before it. We partition it by the `product_id` so we can\nsee per product the sales, and then we order it by `sale_date` so we can see\neach sale how much the running total goes up by. As we are not using a `where`\nclause there is no need to use a CTE, we can use the window function in the\nregular query.\n",meta:{title:"Postgres Window Functions",slug:"postgres-window-functions",publishedOn:new Date(1735603200000),tagline:"Learning what is and how to use window functions in postgres",tags:["database","postgres","sql"]}},{content:"\n# Regex is Really Useful\n\nRegex is a really useful tool that I have not utilised enough, hopefully with\nthis post as a guide I can incorporate it more into my workflow.\n\n## What is Regex?\n\nRegex is short for \"regular expressions\". It is a powerful tool for matching\npatterns in text. It is used in many programming languages and text editors to\nsearch for and manipulate text. It can also be used for replacing strings within\na string.\n\n## How does Regex Work?\n\nRegex works by using a pattern to match text. The pattern is made up of special\ncharacters that represent different types of characters. For example, `\\s` would\nmatch a single whitespace character, and `\\d` would match a single digit\ncharacter.\n\n## Patterns\n\nWhat I mean by patterns is what you can use to identify a string.\n\n### Start & End\n\nThere are 2 really important characters that you should be aware of: `^` and\n`$`. The caret `^` matches the start of a string and the dollar sign `$` matches\nthe end of a string. This is useful for when you want to match a string that\nstarts with a certain character or ends with a certain character.\n\n```typescript\nconst xp = new RegExp(/^word$/);\n\nconst str = \"word\";\n\nconst doesMatch = xp.test(str);\n// doesMatch = true\n```\n\n### Brackets\n\nThere are 3 types of brackets to be aware of:\n\n`{}` - These are used to quantify the preceding expression\n\n`[]` - These are used to match a single character from a list of characters\n\n`()` - These are used to group expressions together\n\n```typescript\nconst xp = new RegExp(/^[a-z]{3}$/);\n// This will match any 3 lowercase English letters\n\nconst xp = new RegExp(/^(a|b)c$/);\n// This will match:\n// - \"ac\"\n// - \"bc\"\n```\n\n### Negation\n\nNegation is used to match any character that is not in a list of characters.\nThis can be done using the caret, For example, `[^a]` will match any character\nthat is not `a`.\n\n```typescript\nconst xp = new RegExp(/^[^a]$/);\n// This will match any single character that is not \"a\"\n```\n\n### Quantifiers\n\nQuantifiers are used to match a certain number of characters.\n\n`?` Matches the preceding pattern 0 or 1 times\n\n`*` Matches the preceding pattern 0 or more times\n\n`+` Matches the preceding pattern 1 or more times\n\n`{n}` Matches the preceding pattern exactly n times\n\n`{n,}` Matches the preceding pattern n or more times\n\n`{n,m}` Matches the preceding pattern between n and m times\n\nBy default all matches have to pass for a test to return true, think of it using\nthe and operator, to use the or operator you can use the `|` character.\n\n```typescript\nconst xp = new RegExp(/^(bob){2}(tom)?$/);\n// will match\n// - \"bobbob\"\n// - \"bobbobtom\"\n\nconst str = \"bobbob\";\n\nconst doesMatch = xp.test(str);\n// doesMatch = true\n```\n\n### Sinlge Characters\n\nSingle characters are the most basic type of pattern. They match a single\ncharacter in the text. For example, `a` would match `a` and `a` only. There are\nspecial cases where you can apply a range to a character. For example, `A-Z`\nwhich will match all upper case english letters. The same will apply for numbers.\n\n```typescript\nconst xp = new RegExp(/^[a-z]{2}A$/);\n// will match any two lowercase English characters followed by an uppercase \"A\"\n```\n\n### Special Characters\n\nSpecial characters are characters that have a special meaning in regex. For\nexample, the dot `.` will match any character except a newline character. The\nbackslash `\\` is used to escape special characters. For example, `\\\\` will match\na single backslash character. Important ones to learn are:\n\n`\\b` Word boundary (start or end of a word)\n\n`\\B` Non-word boundary\n\n`\\w` Word character (alphanumeric & underscore)\n\n`\\W` Non-word character\n\n`\\d` Digit character (0-9)\n\n`\\D` Non-digit character\n\n`\\s` Whitespace character ( )\n\n`\\S` Non-whitespace character\n\n`.` Any character except a newline character\n\n```typescript\nconst xp = new RegExp(/\\bword\\b/);\n// will match the word \"word\" but not \"words\"\n\nconst xp = new RegExp(/\\d{3}/);\n// will match any 3 digit number\n\nconst xp = new RegExp(/(\\s)*/);\n// will match any number of whitespace characters\n\nconst xp = new RegExp(/(\\w){3,18}/);\n// will match any word that is between 3 and 18 characters long\n// this would be quite useful for something like a username\n```\n\n### Flags\n\nFlags are used to change the behavior of a regular expression. There are 6 flags\nthat can be used:\n\n`g` Global - Matches all occurrences of the pattern\n\n`i` Case-insensitive - Matches the pattern regardless of case\n\n`m` Multiline - Matches the pattern across multiple lines\n\n`u` Unicode - Matches the pattern as a Unicode string\n\n`y` Sticky - Matches the pattern only at the start of the string\n\n`s` Dotall - Matches the pattern across multiple lines\n\n```typescript\nconst xp = new RegExp(/word/g);\n// will match all occurrences of the word \"word\"\n\nconst xp = new RegExp(/word/i);\n// will match the word \"word\" regardless of case\n```\n\n### Lookaround\n\nLookaround is used to match a pattern only if it is followed or preceded by\nanother pattern. There are 4 types of lookaround:\n\n`(?=...)` Positive lookahead\n\n`(?!...)` Negative lookahead\n\n`(?\u003C=...)` Positive lookbehind\n\n`(?\u003C!...)` Negative lookbehind\n\n```typescript\nconst xp = new RegExp(/^a(?=b{1,2})$/);\n// This will match the single letter `a` if it is followed by 1 or 2 occurrences\n// of the letter `b`\n```\n\nSomething like positive lookhead is really useful for doing complex find and\nreplace where you would want to keep the center of something the same.\n\nIn this example we are replacing the bad words if the name they are being called\nis 'bob' or 'Bob'\n\n```typescript\nconst str =\n  \"Bob is bad. Will is naughty, Tom is naughty, Tom is bad, Bob is good, bob is naughty.\";\n\nconst xp = new RegExp(/(?\u003C=(B|b)ob\\sis\\s)(bad|naughty)/, \"g\");\n\nconst newStr = str.replace(xp, \"good\");\n\nconsole.log(newStr);\n// \"Bob is good. Will is naughty, Tom is naughty, Tom is bad, Bob is good, bob is good.\"\n```\n\nIn this example we want to return all the names that come before 'BAD'\n\n```typescript\nconst names = `Bob BAD\nTom BAD\nWill GOOD\nBob GOOD\nGreg BAD`;\n\nconst xp = new RegExp(/\\w+(?=\\sBAD)/, \"g\");\n\nconst matches = names.match(xp);\n// [\"Bob\", \"Tom\", \"Greg\"]\n```\n\nNote that if there are no matches it will return `null`\n",meta:{title:"Regex is Really Useful",slug:"regex-is-really-useful",publishedOn:new Date(1736380800000),tagline:"Is regex worth learning about? Yes.",tags:["regex"]}},{content:"\n# Sets and Maps\n\n## Sets\n\n### What is a Set?\n\nA set is a collection (list) of unique values. Each element in a set can only\ncontain one item, but it can be of any type, such as an object, number, string,\netc. Sets are built into most languages by default.\n\n```javascript\nconst mySet = new Set();\nmySet.add(1);\nmySet.add(2);\nmySet.add(3);\nmySet.add(4);\nmySet.add(3);\n// mySet = Set { 1, 2, 3, 4 }\n```\n\n### Why use Sets?\n\nSets are often more performant than arrays when you need to check if a value\nexists in a collection. This is because sets are optimized for this operation.\nSets are also useful when you need to ensure that a value is unique in a\ncollection.\n\nSets also have to have a lookup time complexity of better then O(N) by default.\nDepending on the language and the set type (number, record, etc) the time\ncomplexity for `mySet.has()` can be as low as O(log(N)).\n\n### Example\n\nOften sets are used in JavaScript to create seperate duplicates from an array\nlike so:\n\n```javascript\nconst arr = [1, 2, 3, 3, 2];\nconst uniqueArr = [...new Set(arr)];\n// uniqueArr = [1, 2, 3]\n```\n\n## Maps\n\n### What is a Map?\n\nA map is a datatype that holds key value pairs (similar to a record/object) but\nwith a few key differences. A key for a map can be any primivte data type or\nobject. Each key must be unique still.\n\nSimilar to sets, maps must also feature lookup time complexity of better then\nO(N).\n\n### Map vs Object\n\n- A map has 0 keys by default, it only contains what you put into it\n- A map's key type can be any value, such as a function, object, etc\n- A map is ordered by insertion order, so you can create a history\n- A map has a `.size` property so you can get the number of elements\n- A map is iterable by default\n- Maps are safe to use with user provided keys, whereas objects may allow object inection attacks\n- Maps are optimized for adding/removing key value pairs\n- Maps do not have built in serialization/parsing like objects do, but it is simple to create your own\n\n### Example\n\n```javascript\nconst myMap = new Map();\nmyMap.set(1, { name: \"Bob\" });\nmyMap.set(2, { name: \"Alice\" });\nmyMap.set(3, { name: \"Charlie\" });\n// myMap = Map { 1 => { name: \"Bob\" }, 2 => { name: \"Alice\" }, 3 => { name: \"Charlie\" } }\n\nconst size = myMap.size;\n// size = 3\n\nmyMap.delete(2);\n\nfor (const [key, value] of myMap) {\n  console.log(key, value);\n  // 1, { name: \"Bob\" }\n  // 3, { name: \"Charlie\" }\n}\n\nconst hasTwo = myMap.has(2);\n// hasTwo = false\n```\n",meta:{title:"Sets And Maps",slug:"sets-and-maps",publishedOn:new Date(1736899200000),tagline:"What are sets and maps? And when to use them?",tags:["maps","sets"]}},{content:"\n# Why use a VPS?\n\nBefore I was aware of VPS's I used netlify and Vercel to host any sites, I also\nused things like Supabase and Firebase for databases. It didn't cost much\nbecause I wasn't actually using a lot, bandwidth wasn't a worry, storage was not\na worry, nor was speed.\n\nOnce I had started using more resources up it was clear to me I needed a\nsolution that works for me, not too expensive as i'm still not using that much\nbut more then the free version, and with more freedom to do what I want.\n\nAnd then I stumbled upon [Digital Ocean\nDroplets](https://www.digitalocean.com/products/droplets). They seemed to solve\nall the issues I was having. A Virtual Private Server (VPS) is essentially a\ncomputer that you have access to, but it is stored elsewhere (like cloud\nstorage). You can then access the computer via ssh and do with it as you please.\nDepending on the provider you can have a linux OS or a window OS - usually\ncosting a bit more for windows.\n\nOnce I had my linux VPS spun up I installed [Coolify](https://coolify.io) and\nfrom there it was as easy a 3 clicks to get a new postgres instance, or connect\nmy GitHub account to build and deploy a SvelteKit application on each repo push.\n\nThe bandwidth is more then enough, it costs next to nothing, and I am not\nlimited to a certain vendor. I have the choice to install whatever software I\nwould like, if analytics are what i'm after, I can start a\n[Umami](https://umami.is) and there are no limits, even docker containers can be\nran. A VPS is exactly what I need.\n",meta:{title:"Why use a VPS?",slug:"why-use-a-vps",publishedOn:new Date(1735516800000),tagline:"Why you should use a VPS",tags:["vps","hosting","postgres"]}},{content:"\n# Which Editor\n\n## VS Code\n\n### Advantages\n\n- Cross-platform\n- Stable\n- Vast amount of extensions\n- Ease of use\n- Intergrated into GitHub, head to a repo and click period on your keyboard\n- Supports basically every language\n- Intergrated Git control\n\n### Disadvantages\n\n- Slow due to being electron based\n- Crowded, this can be a plus but for me I prefer a minimal IDE\n\n## Vim\n\n### Advantages\n\n- Cross-platform\n- Stable\n- Quickest\n- No need to install anything\n- On every machine\n\n### Disadvantages\n\n- Learning curve\n\n## Zed\n\n### Advantages\n\n- Cross-platform\n- Quick as it's rust based\n- Minimal\n\n### Disadvantages\n\n- Doesn't support too many extensions (at the time of writing it is still in\n  beta)\n\n## What Do I Use?\n\nI personally use Zed with vim mode enabled, this way I get the best of both\nworlds. I end up with a nice and fast GUI using Zed, but also the quick keyboard\nshortcuts using vim. There are many extensions for vim that can enable what Zed\ndo but for me I prefer the ease of zed, the extension store being one click, and\nI always know how to exit Zed.\n",meta:{title:"Which Editor?",slug:"which-editor",publishedOn:new Date(1735257600000),tagline:"Learning the git CLI, and why it's better then a GUI",tags:["zed","vscode","vim","editor"]}}]},"uses":{}},{"type":"data","data":{post:{content:"\n# Git CLI\n\n## Why use the Git CLI?\n\nUsing the git CLI at first was difficult, going from using the built-in tab in\nVS Code to GitHub Desktop and then the CLI was a step and a half. While GitHub\nDesktop has some neat features and a nice visualisation for repos, the fine\ngrain control that using the CLI brings is unmatched.\n\nSomething that has saved me a lot of time is using aliases such as `gll` for\nlogging. These have saved me a huge amount of time and I don't have to remember\nthe specific flags of every command I most commonly use.\n\n### Benefits of the CLI\n\n- Fine grain control\n- Add by hunks\n- Rebase/Merge\n- Accessable on most machines\n\n### Drawbacks of the CLI\n\n- Have to memorize commands\n- Learning curve\n\n## My Common Commands\n\n```sh\ngit add \u003C.|-A|-i|-p>\n```\n\nUsing `-i` or `-p` flag will put you in patch mode or interactive mode where you\nhave a wizard to help what hunks/files you want to stage. The `-A` or `.` flag\nwill add the current directory or all files.\n\n```sh\ngit checkout \u003C-b> \u003Cbranch|->\n```\n\nCheckout is a command that switches branches, using `-` will switch to the\nprevious branch. Using the `-b` flag will create a branch.\n\n```sh\ngit commit -m \"\u003Ctitle>\" -m \"\u003Cbody>\"\n```\n\nCommiting it using the staged files and creating a commit out of them along with\nsome meta information such as title, date, etc. You can drop the `-m`s and it\nwill open up a file to write the commit message in an editor.\n\n```sh\ngit log --decorate --oneline --graph\n```\n\nLogging is one of the most useful commands, this allows you to see a graph of\nthe repo history, If you have branches it will show them visually as different\nnodes. If shows the SHA and a commit title. A really useful tool for locating\nbranches splitting or joining and just to see a general history of the repo.\n\n```sh\ngit rebase -i HEAD~10\n```\n\nRebasing is a useful tool for editing the commit history. The interactive flag\nallows for a file to open in your editor to edit commits. The `HEAD~10` in this\nis to get the last 10 commits from the head. In the editor you have the choice\nto reword, reorder, squash, etc commits, afterwards the CLI will rebase the\ncommits and you can push - or sometimes force push - to remote.\n\n```sh\ngit merge \u003Cbranch>\n```\n\nMerging is taking two branches and merging them into one using a new commit.\nThere are other ways to merge and flags you can pass in, but the one I most\ncommonly use to merge a branch is this. This is a good way to keep a feature\nbranch up to date with the main branch.\n\n```sh\ngit stash \u003Clist> \u003C-m \"\u003Cmessage>\"> \u003Cpop> \u003Cdrop>\n```\n\nStashing is taking files and stashing them away for later. Stashing takes on the\nstyle of a stack, first in is last out (unless using the index flag). Using the\n`-m` flag adds a message to the stash so you can easily see them in the list.\n\n```sh\ngit tag -a \u003Ctag name> \u003Ccommit sha> -m \"\u003Ctitle>\"\n```\n\nThis will create a tag for the given commit, tags are really useful for creating\ncheckpoints in your code that you can come back to later on and easily identify.\n",meta:{title:"Git CLI",slug:"git-cli",publishedOn:new Date(1735171200000),tagline:"Learning the git CLI, and why it's better then a GUI",tags:["git","cli"]}}},"uses":{"params":["slug"],"parent":1}}],
							form: null,
							error: null
						});
					});
				}
			</script>
		</div>
  </body>
</html>