
    
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
                
        
        
        
            
{"version":"https:\/\/jsonfeed.org\/version\/1","title":"mathspp.com feed","home_page_url":"https:\/\/mathspp.com\/blog\/tags\/git","feed_url":"https:\/\/mathspp.com\/blog\/tags\/git.json","description":"Stay up-to-date with the articles on mathematics and programming that get published to mathspp.com.","author":{"name":"Rodrigo Gir\u00e3o Serr\u00e3o"},"items":[{"title":"Automatically pushing code changes during live coding with uv","date_published":"2025-05-14T10:25:00+02:00","id":"https:\/\/mathspp.com\/blog\/automatically-pushing-code-changes-during-live-coding-with-uv","url":"https:\/\/mathspp.com\/blog\/automatically-pushing-code-changes-during-live-coding-with-uv","content_html":"<p>This article shows the small script I use to automatically push code changes while live coding in talks or classes, improved with uv.<\/p>\n\n<p>One year ago I <a href=\"\/blog\/til\/automatically-push-code-changes-during-live-coding\">wrote a short TIL article where I showed how I automatically push code changes while I'm live-coding<\/a>.\nThe code I shared looked like this:<\/p>\n<pre><code class=\"language-py\">from pathlib import Path\nfrom time import sleep\n\nfrom git import Repo\n\nrepo = Repo(Path(__file__).parent)\n\nwhile True:\n    repo.index.add(\"*\")\n    repo.index.commit(\"Auto sync commit\")\n    repo.remote().push()\n    sleep(60)<\/code><\/pre>\n<p>This code uses <code>GitPython<\/code> to add all files in the folder that contains this script, adds a generic commit message, and pushes.\nThe script does this every minute, so when I'm teaching or doing any sort of live-coding, the repo I'm working off of gets updated every minute and participants can keep tabs on what I'm writing.<\/p>\n<p>Having used this for a while, there are two disadvantages to it:<\/p>\n<ol>\n<li>I need to install <code>GitPython<\/code> in a virtual environment in each repo I want to use this on; and<\/li>\n<li>the script itself gets pushed to the repo, polluting it a bit.<\/li>\n<\/ol>\n<p>(As I write this, I realised, I could fix 2. by adding the script to a file <code>.gitignore<\/code>!)<\/p>\n<p>To fix 1. and 2., and to improve my user experience a bit, I <a href=\"\/blog\/til\/standalone-executable-python-scripts-with-uv\">started using uv to inline the dependency on <code>GitPython<\/code> and to turn it into a standalone executable<\/a>.<\/p>\n<p>Assuming the script was called <code>gitsync.py<\/code>, by doing <code>uv add GitPython --script gitsync.py<\/code> and by <a href=\"\/link-blog\/simonwillison-net-2024-aug-21-usrbinenv-uv-run\">adding the uv shebang<\/a>, the top of the script now looks like this:<\/p>\n<pre><code class=\"language-py\">#!\/usr\/bin\/env -S uv run\n\n# \/\/\/ script\n# requires-python = \"&gt;=3.13\"\n# dependencies = [\n#     \"gitpython\",\n# ]\n# \/\/\/<\/code><\/pre>\n<p>I also tweaked the script structure a bit and now I use <code>os.getcwd()<\/code> to figure out the current working directory when I run <code>gitsync.py<\/code>:<\/p>\n<pre><code class=\"language-py\">#!\/usr\/bin\/env -S uv run\n\n# \/\/\/ script\n# requires-python = \"&gt;=3.13\"\n# dependencies = [\n#     \"gitpython\",\n# ]\n# \/\/\/\n\nimport os\nfrom time import sleep\n\nfrom git import Repo\n\ndef main() -&gt; None:\n    repo_folder = os.getcwd()\n    print(f\"gitsync.py starting at {repo_folder}\")\n    repo = Repo(repo_folder)\n\n    while True:\n        repo.index.add(\"*\")\n        repo.index.commit(\"Auto sync commit\")\n        repo.remote().push()\n        sleep(60)\n\nif __name__ == \"__main__\":\n    main()<\/code><\/pre>\n<p>This makes it so that I can put <code>gitsync.py<\/code> in a directory that's in my PATH, and then use it from anywhere.\nNow, when I'm teaching, I just run <code>gitsync.py &amp;<\/code> and that starts syncing my code in the background.\nPretty cool!<\/p>","summary":"This article shows the small script I use to automatically push code changes while live coding in talks or classes, improved with uv.","date_modified":"2025-07-23T16:49:02+02:00","tags":["git","productivity","programming","python","uv"],"image":"\/user\/pages\/02.blog\/automatically-pushing-code-changes-during-live-coding-with-uv\/thumbnail.webp"},{"title":"TIL #118 \u2013 git checkout -","date_published":"2025-02-26T19:01:00+01:00","id":"https:\/\/mathspp.com\/blog\/til\/git-checkout","url":"https:\/\/mathspp.com\/blog\/til\/git-checkout","content_html":"<p>Today I learned how to quickly switch back and forth between two different git branches.<\/p>\n\n<h2 id=\"git-checkout\">git checkout -<a href=\"#git-checkout\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Suppose you're in a git branch called <code>fix-1523-very-important-high-priority<\/code> to fix issue 1523 that is very important and high priority.\nThen, you checkout the main branch to pull the most recent changes, or something like that, with <code>git checkout main<\/code>.\nYou do what you have to do on <code>main<\/code> and then you have to checkout the other branch again...<\/p>\n<p>One of two things will happen:<\/p>\n<ol>\n<li>you don't want to type the whole branch name again; or<\/li>\n<li>you don't even remember the exact branch name in the first place.<\/li>\n<\/ol>\n<p>You can solve both issues with <code>git checkout -<\/code>.\nThis will checkout the most recent branch you had checked out.\nIsn't this amazing?<\/p>\n<p>When I shared this online, someone noted this is the same with the command to change directories, <code>cd<\/code>.\nWhen you run <code>cd -<\/code>, you switch back to the previous directory you were in.<\/p>","summary":"Today I learned how to quickly switch back and forth between two different git branches.","date_modified":"2025-10-20T22:34:56+02:00","tags":["git","productivity"],"image":"\/user\/pages\/02.blog\/04.til\/118.git-checkout-\/thumbnail.webp"},{"title":"Automatic site updates with cog and pre-commit","date_published":"2024-08-09T19:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/automatic-site-updates-with-cog-and-pre-commit","url":"https:\/\/mathspp.com\/blog\/automatic-site-updates-with-cog-and-pre-commit","content_html":"<p>This article outlines how I use a pre-commit hook and cog to keep my blog stats updated automatically.<\/p>\n\n<p>Some months ago I introduced some <a href=\"\/blog\">basic stats in my blog<\/a> that show how many articles I've published, along with how many words and lines of code those articles contain.\nI <a href=\"\/blog\/adding-stats-to-my-blog\">wrote an article explaining how I wrote a script that gathers these blog stats for me<\/a> but that's a script I still need to run and then manually update the stats.<\/p>\n<p>I wanted to automate this process but I couldn't bring myself to do it.\nAnd then, I came to the silly realisation that I could use ChatGPT to help me with the set up that I was dreading to do.<\/p>\n<h2 id=\"rewriting-the-stats-with-cog\">Rewriting the stats with cog<a href=\"#rewriting-the-stats-with-cog\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p><a href=\"https:\/\/nedbatchelder.com\/code\/cog\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Cog<\/a> is &ldquo;a file generation tool&rdquo; that lets you use snippets of Python code to fill in parts of other files.\nFor this particular project, I wanted it to rewrite <a href=\"https:\/\/github.com\/mathspp\/mathspp\/blob\/876da9f7b38708f928e0940247cfa1e10ba8c68a\/pages\/02.blog\/blog.md?plain=1#L16-L18\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">the Markdown table that lists the blog stats<\/a>, that looks like this:<\/p>\n<pre><code class=\"language-markdown\">...\n\n| 364 | 401,577 | 33,251 |\n| :-: | :-: | :-: |\n| articles | words | lines of code |\n\n...<\/code><\/pre>\n<p>I already have a script <code>stats.py<\/code> that computes the stats, so I started by changing it to produce the output in this exact format.\nThen, I tweaked the markdown file to include a cog tag that runs the script and inserts its output in the markdown file.\nThe markdown file now looks like this:<\/p>\n<pre><code class=\"language-markdown\">...\n\n&lt;!--\n[[[cog\nimport cog, subprocess\nresult = subprocess.run([\"python\", \"pages\/02.blog\/stats.py\"], text=True, capture_output=True)\ncog.outl(result.stdout)\n]]]--&gt;\n| 364 | 401,577 | 33,251 |\n| :-: | :-: | :-: |\n| articles | words | lines of code |\n&lt;!--[[[end]]]---&gt;\n\n...<\/code><\/pre>\n<p>The <code>[[[cog<\/code> part tells cog where my Python code starts and the <code>]]]<\/code> tells it where it ends.\nIn my case, I'm just using the module <code>subprocess<\/code> to run the script I already have, I'm capturing its output, and I'm reemitting the output through cog.<\/p>\n<p>The output that I produce with <code>cog.outl<\/code> is then inserted between the <code>]]]<\/code> and the <code>[[[end]]]<\/code>, which is where the table ends up being.\nIn case you're wondering, for every run cog will start by clearing the previous table and then will write the new one.<\/p>\n<p>Finally, note that the cog tags are surrounded by HTML multi-line comments, so that the cog tags themselves do not show up in the final page.\nAt least, not visibly.\nIf you inspect the source code of <a href=\"\/blog\">my blog page<\/a> you will see the HTML comments with the cog tags there.<\/p>\n<h2 id=\"triggering-cog-automatically-with-pre-commit\">Triggering cog automatically with pre-commit<a href=\"#triggering-cog-automatically-with-pre-commit\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>The thing with cog is that I still have to run <code>cog -r blog.md<\/code> to update the table, so my next step is to automate the step that calls cog.\nFor that, I asked ChatGPT to help me set up <a href=\"https:\/\/pre-commit.com\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">a pre-commit hook<\/a> that is triggered when my blog pages change.<\/p>\n<p>After a couple of exchanges with ChatGPT, I ended up with <a href=\"https:\/\/github.com\/mathspp\/mathspp\/blob\/876da9f7b38708f928e0940247cfa1e10ba8c68a\/.pre-commit-config.yaml\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">the following <code>.pre-commit-config.yaml<\/code> file<\/a>...<\/p>","summary":"This article outlines how I use a pre-commit hook and cog to keep my blog stats updated automatically.","date_modified":"2025-07-23T16:49:02+02:00","tags":["git","llm","productivity","programming","python","scripting","slice of life"],"image":"\/user\/pages\/02.blog\/automatic-site-updates-with-cog-and-pre-commit\/thumbnail.webp"},{"title":"TIL #098 \u2013 Git alias for quick commit &amp; push","date_published":"2024-05-30T22:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/git-alias-for-quick-commit-and-push","url":"https:\/\/mathspp.com\/blog\/til\/git-alias-for-quick-commit-and-push","content_html":"<p>Today I learned how to create git aliases in my <code>.gitconfig<\/code> file.<\/p>\n\n<h2 id=\"git-alias-for-quick-commit-push\">Git alias for quick commit &amp; push<a href=\"#git-alias-for-quick-commit-push\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Today I learned (or was reminded, really) that you can create aliases for <code>git<\/code> commands.\nFor example, for this blog I often run these two commands in sequence:<\/p>\n<pre><code class=\"language-bash\">git commit -m \"Update\"\ngit push<\/code><\/pre>\n<p>So, I realised I could set an alias, like <code>git cp<\/code>, to do this for me!\nI first learned how to create git aliases from Adam Johnson's <a href=\"https:\/\/gumroad.com\/a\/817193683\/wlrcr\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">\u201cBoost Your Git DX\u201d<\/a>, but the very short version of one way in which this can work is by modifying the section <code>[alias]<\/code> of your <code>.gitconfig<\/code> file.<\/p>\n<p>You should place the file <code>.gitconfig<\/code> in your home directory (in case it isn't there yet) and then you can add this to its contents:<\/p>\n<pre><code>[alias]\n    cp = !git commit -m \"Update\" &amp;&amp; git push\n    facp = !git add . &amp;&amp; git cp<\/code><\/pre>\n<p>This makes it so that <code>git cp<\/code> is equivalent to running <code>git commit -m \"Update\" &amp;&amp; git push<\/code> and <code>git facp<\/code> (fast add, commit, and push) is equivalent to running <code>git add .<\/code> followed by <code>git cp<\/code>.<\/p>\n<p>By saving around three seconds every time I commit things on my blog, I expect these two aliases to save me a full minute by next month!\nMaybe in a couple of years they will have saved me enough time to make up for the time I lost creating the aliases <em>and<\/em> writing a blog article about them.<\/p>\n<p>To conclude, the diagram below contains the information of this article in a diagram:<\/p>\n<p><img alt=\"A diagram showing that a section `alias` can be added to the git configuration file `.gitconfig` in order to create command aliases.\" src=\"\/user\/pages\/02.blog\/04.til\/098.git-alias-for-quick-commit-and-push\/_diagram.webp\"><\/p>","summary":"Today I learned how to create git aliases in my .gitconfig file.","date_modified":"2025-07-23T16:49:02+02:00","tags":["git","productivity"],"image":"\/user\/pages\/02.blog\/04.til\/098.git-alias-for-quick-commit-and-push\/thumbnail.webp"},{"title":"TIL #096 \u2013 automatically push code changes during live coding","date_published":"2024-05-12T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/automatically-push-code-changes-during-live-coding","url":"https:\/\/mathspp.com\/blog\/til\/automatically-push-code-changes-during-live-coding","content_html":"<p>Today I learned how to automatically push code changes while I'm doing live coding, for example while teaching.<\/p>\n\n<h2 id=\"automatically-push-code-changes-during-live-coding\">Automatically push code changes during live coding<a href=\"#automatically-push-code-changes-during-live-coding\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>When I'm doing live coding during tutorials \/ workshops \/ webinars, I often want to push the code I'm writing to GitHub so that participants have a way to fetch my work in case they fall behind.\nI don't want to have to do this manually every time I write some code, so I wrote a short script that does this automatically for me.<\/p>\n<p>I can never find the script that automates this process and every time I do some live coding during a webinar I have to rewrite the code, so this time I decided I'd write it down in my blog so that I don't have to keep reinventing the wheel.\nHere's the script:<\/p>\n<pre><code class=\"language-py\">from pathlib import Path\nfrom time import sleep\n\nfrom git import Repo\n\nrepo = Repo(Path(__file__).parent)\n\nwhile True:\n    repo.index.add(\"*\")\n    repo.index.commit(\"Auto sync commit\")\n    repo.remote().push()\n    sleep(60)<\/code><\/pre>\n<p>It depends on <a href=\"https:\/\/gitpython.readthedocs.io\/en\/stable\/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">the module GitPython<\/a> and the script also assumes it's located at the root of the repository I want to sync.<\/p>\n<p>Whenever I'm doing live coding, all I need to do is install the GitPython dependency and start the script, which will add, commit, and push, all my changes every 60 seconds.<\/p>","summary":"Today I learned how to automatically push code changes while I&#039;m doing live coding, for example while teaching.","date_modified":"2025-07-23T16:49:02+02:00","tags":["git","modules","productivity","programming"],"image":"\/user\/pages\/02.blog\/04.til\/096.automatically-push-code-changes-during-live-coding\/thumbnail.webp"},{"title":"TIL #089 \u2013 delete merged git branches","date_published":"2023-11-22T18:00:00+01:00","id":"https:\/\/mathspp.com\/blog\/til\/delete-merged-git-branches","url":"https:\/\/mathspp.com\/blog\/til\/delete-merged-git-branches","content_html":"<p>Today I learned how to automatically delete local git branches that have been merged already.<\/p>\n\n<h2 id=\"delete-merged-git-branches\">Delete merged git branches<a href=\"#delete-merged-git-branches\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>Today I ran the command <code>git branch<\/code> and I got scared when I saw the amount of results I got:<\/p>\n<pre><code class=\"language-txt\">  codeql-on-code-change\n  docs-improvements\n  document-reactive-watch\n  early-show-root\n  escape-markup-in-md-headings\n  fkaab\/main\n  gh-pages\n  issue3637\n* main\n  opacity-component-classes\n  tree-reload-preserve-state\n  # ...<\/code><\/pre>\n<p>I had about 40 branches on me!\nHowever, most of them had been merged already and I wanted to get rid of them.<\/p>\n<h3 id=\"a-chatgpt-solution\">A ChatGPT solution<a href=\"#a-chatgpt-solution\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>I was aware of two commands that I suspected could be used as the main ingredients:<\/p>\n<ul><li><code>git branch --merged<\/code> lists branches that have been merged; and<\/li>\n<li><code>git branch -d<\/code> deletes a branch.<\/li>\n<\/ul><p>So, I opened ChatGPT and I asked it:<\/p>\n<blockquote>\n<p>How can I combine the commands <code>git branch --merged<\/code> and <code>git branch -d<\/code> to delete all of the local branches that have been merged already?<\/p>\n<\/blockquote>\n<p>ChatGPT complied to my request and gave me back this command:<\/p>\n<pre><code class=\"language-bash\">git branch --merged | grep -v \"\\*\" | xargs -n 1 git branch -d<\/code><\/pre>\n<p>It then proceeded to explain what each part does:<\/p>\n<ol><li><code>git branch --merged<\/code> lists all local branches that have been merged into the currently checked-out branch;<\/li>\n<li><code>grep -v \"\\*\"<\/code> excludes the currently checked-out branch from the list. The asterisk (*) is used to denote the currently checked-out branch in the <code>git branch<\/code> output; and<\/li>\n<li><code>xargs -n 1 git branch -d<\/code> deletes each branch listed in the output using the <code>git branch -d<\/code> command. The <code>-n 1<\/code> option specifies that <code>xargs<\/code> should pass one branch at a time to the <code>git branch -d<\/code> command.<\/li>\n<\/ol><p>I made sure to be in my branch <code>main<\/code> and then I ran this command to delete more than 30 branches that I no longer cared about.<\/p>\n<p>Then, <a href=\"https:\/\/twitter.com\/mathsppblog\/status\/1727283644493095309\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">I asked on X<\/a> if there were any issues with the approach that ChatGPT recommended.\nI explicitly tagged <a href=\"https:\/\/gumroad.com\/a\/817193683\/wlrcr\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Adam Johnson, the author of &ldquo;Boost Your Git DX&rdquo;<\/a> and a contributor to git, and I got some interesting replies.<\/p>\n<h3 id=\"a-human-solution\">A human solution<a href=\"#a-human-solution\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>When I got feedback by more experienced users, they suggested a more robust version of the command.\nThey gave me essentially two equivalent versions, so I'll show you just one:<\/p>\n<pre><code class=\"language-bash\">git switch main &amp;&amp;\ngit pull --prune &amp;&amp;\ngit branch --format '%(refname:short) %(upstream:track)' | awk '$2 == \"[gone]\" { print $1 }' | xargs -r git branch -D<\/code><\/pre>\n<p>What are we doing here?<\/p>\n<ul><li><code>git switch main<\/code> makes sure we're in the branch <code>main<\/code>;<\/li>\n<li><code>git pull --prune<\/code> updates local information about branches that have been deleted in the remote repository (e.g., branches you've deleted after merging pull requests);<\/li>\n<li><code>git branch --format '%(refname:short) %(upstream:track)'<\/code> lists all local branches with their name and information about the upstream branch. If a branch has been deleted upstream, the part <code>%(upstream:track)<\/code> will look like <code>[gone]<\/code>;<\/li>\n<li><code>awk '$2 == \"[gone]\" { print $1 }'<\/code> uses <code>awk<\/code> to look for branches that show the output <code>[gone]<\/code> and prints the names of those branches; and<\/li>\n<li><code>xargs -r git branch -D<\/code> will take the names from the previous...<\/li><\/ul>","summary":"Today I learned how to automatically delete local git branches that have been merged already.","date_modified":"2025-07-23T16:49:02+02:00","tags":["git","productivity"],"image":"\/user\/pages\/02.blog\/04.til\/089.delete-merged-git-branches\/thumbnail.webp"},{"title":"TIL #081 \u2013 find commits that affected a file","date_published":"2023-09-06T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/find-commits-that-affected-a-file","url":"https:\/\/mathspp.com\/blog\/til\/find-commits-that-affected-a-file","content_html":"<p>Today I learned how to find the commits that affected a specific file with <code>git log<\/code>.<\/p>\n\n<h2 id=\"find-commits-that-affected-a-file\">Find commits that affected a file<a href=\"#find-commits-that-affected-a-file\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>When using git, you can use the command <code>git log<\/code> to show a log of all commits (I like <code>git log --oneline<\/code> to show a terser log).<\/p>\n<p>What I learned today is that using the command <code>git log -- path\/to\/file<\/code> will filter the logs to only show commits that affected that file.<\/p>\n<h3 id=\"practical-example\">Practical example<a href=\"#practical-example\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>I was looking at <a href=\"https:\/\/github.com\/Textualize\/textual\/blob\/1b61a95c7025160cbbcb74cf9562a3b057afd3e6\/tests\/test_table.py\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">commit 1b61a95<\/a> of the <a href=\"https:\/\/github.com\/textualize\/textual\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Textual<\/a> repository, which created a file <code>tests\/test_table.py<\/code> with a test that I cared about.<\/p>\n<p>What I wanted was to figure out how that file evolved over time because the file <code>tests\/test_table.py<\/code> no longer exists and because I couldn't find the tests that existed in that file.<\/p>\n<p>So, what I did was run the command <code>git log -- tests\/test_table.py<\/code> and I got this output:<\/p>\n<pre><code class=\"language-git\">commit 12d429dbd0c9e86fb45251c17dbb9e15ad6624cf\nAuthor: Darren Burns &lt;darrenb900@gmail.com&gt;\nDate:   Tue Jan 24 11:33:35 2023 +0000\n\n    Replace DataTable row_count with property, test improvements\n\ncommit d1413ee352a79b8b5e0a8f23cee9276893896903\nAuthor: Darren Burns &lt;darrenb900@gmail.com&gt;\nDate:   Tue Jan 24 10:38:47 2023 +0000\n\n    Updating test to ensure row_key mapped data is correct\n\ncommit a45a3dca6a1513b9e64cb4b680d337ae3b75c1f8\nAuthor: Josh Karpel &lt;josh.karpel@gmail.com&gt;\nDate:   Wed Dec 21 16:57:43 2022 -0600\n\n    add option to clear columns in DataTable.clear\n\ncommit 1b61a95c7025160cbbcb74cf9562a3b057afd3e6\nAuthor: Will McGugan &lt;willmcgugan@gmail.com&gt;\nDate:   Thu Nov 10 16:22:52 2022 +0000\n\n    table tests<\/code><\/pre>\n<p>Then, using <code>git show &lt;commit&gt;<\/code> you can take a look at each commit and figure out what happened with the file.\nIf the file was deleted or renamed, then the commit at the top of the log should be the commit where said file was deleted or renamed.<\/p>\n<p>For example, in this case, running <code>git log --oneline -- tests\/test_table.py<\/code> outputs this:<\/p>\n<pre><code class=\"language-git\">12d429dbd Replace DataTable row_count with property, test improvements\nd1413ee35 Updating test to ensure row_key mapped data is correct\na45a3dca6 add option to clear columns in DataTable.clear\n1b61a95c7 table tests<\/code><\/pre>\n<p>Then, if I do <code>git show 12d429dbd<\/code> I can scroll through the commit changes and eventually hit the part of the diff that shows that the file was deleted:<\/p>\n<pre><code class=\"language-diff\">diff --git a\/tests\/test_table.py b\/tests\/test_table.py\ndeleted file mode 100644\nindex d57be5a60..000000000\n--- a\/tests\/test_table.py\n+++ \/dev\/null<\/code><\/pre>","summary":"Today I learned how to find the commits that affected a specific file with git log.","date_modified":"2025-07-23T16:49:02+02:00","tags":["git","productivity","programming"],"image":"\/user\/pages\/02.blog\/04.til\/081.find-commits-that-affected-a-file\/thumbnail.webp"},{"title":"TIL #068 \u2013 nested git repositories","date_published":"2023-07-10T00:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/nested-git-repositories","url":"https:\/\/mathspp.com\/blog\/til\/nested-git-repositories","content_html":"<p>Today I learned how to create nested git repositories through the <code>submodules<\/code> command.<\/p>\n\n<h2 id=\"the-problem\">The problem<a href=\"#the-problem\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>I'm working on my <a href=\"https:\/\/ep2023.europython.eu\/session\/build-a-terminal-todo-app-with-textual\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">Textual tutorial for EuroPython 2023<\/a> and I am saving all the tutorial materials (code, slides, instructions, etc) in a GitHub repository under my company's organisation.<\/p>\n<p>The repository lives under my company because I am giving the tutorial in their name.\nHowever, I would still like to show that tutorial on my <a href=\"https:\/\/github.com\/mathspp\/talks\" target=\"_blank\" rel=\"nofollow noopener noreferrer\" class=\"external-link no-image\">talks repository<\/a>.\nSo, I thought \u201cWouldn't it be nice if I could nest git repositories and just list the tutorial repository under my talks repository?\u201d.<\/p>\n<p>As it turns out, you <em>can<\/em> nest git repositories!<\/p>\n<h2 id=\"how-do-you-nest-two-repositories\">How do you nest two repositories?<a href=\"#how-do-you-nest-two-repositories\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<p>To nest a repository inside another one, you use the command <code>git submodule add<\/code>.\nWhen you add the nested repository, that git refers to as a \u201csubmodule\u201d, you need to specify the URL of the original repository, so that git can point to it.<\/p>\n<p>Suppose that you have two repositories, <code>parent<\/code> and <code>child<\/code>, and you want to nest <code>child<\/code> inside <code>parent<\/code>.\nHere is how you could do this:<\/p>\n<pre><code class=\"language-bash\">## Open the `parent` folder.\n~:$ cd parent\n\n## Clone the `child` inside the parent.\n## This will create a folder `child` inside `parent`.\n## (The child sub-repo can be inside a folder with a different name.)\n~\/parent:$ git clone https:\/\/github.com\/xxx\/child\n\n## Add that folder as a submodule linked to a repo at a given URL.\n## (This creates a new file `.gitmodules`.)\n~\/parent:$ git submodule add https:\/\/github.com\/xxx\/child child\n##             repository URL ^    local path for the repo ^^^^^\n\n## Commit &amp; push the submodule.\n~\/parent:$ git commit -m \"Add child submodule.\"\n~\/parent:$ git push<\/code><\/pre>\n<p>That's all it takes!\nQuite neat, hun?\nIf I learn other useful things about submodules I will let you know.<\/p>\n<p>That's it for now! <a href=\"\/subscribe\">Stay tuned<\/a> and I'll see you around!<\/p>","summary":"Today I learned how to create nested git repositories through the `submodules` command.","date_modified":"2025-07-23T16:49:02+02:00","tags":["git","productivity"],"image":"\/user\/pages\/02.blog\/04.til\/068.nested-git-repositories\/thumbnail.webp"},{"title":"TIL #060 \u2013 how to rename a git branch","date_published":"2023-04-21T16:00:00+02:00","id":"https:\/\/mathspp.com\/blog\/til\/rename-a-git-branch","url":"https:\/\/mathspp.com\/blog\/til\/rename-a-git-branch","content_html":"<p>Today I learned how to rename a git branch from the CLI.<\/p>\n\n<h2 id=\"rename-a-git-branch\">Rename a git branch<a href=\"#rename-a-git-branch\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h2>\n<h3 id=\"how-to-rename-a-local-git-branch\">How to rename a local git branch<a href=\"#how-to-rename-a-local-git-branch\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>To rename a <em>local<\/em> git branch, you can use the command <code>git branch<\/code> with the option <code>-m<\/code>.<\/p>\n<p>If you're in the branch you want to rename, just do<\/p>\n<pre><code class=\"language-bash\">git branch -m new-name<\/code><\/pre>\n<p>If you are in another branch, you can do<\/p>\n<pre><code class=\"language-bash\">git branch -m old-name new-name<\/code><\/pre>\n<h3 id=\"how-to-rename-a-remote-git-branch\">How to rename a remote git branch<a href=\"#how-to-rename-a-remote-git-branch\" class=\"toc-anchor after\" data-anchor-icon=\"#\" aria-label=\"Anchor\"><\/a><\/h3>\n<p>If you want to rename a remote git branch, you can just delete the old branch and push the new one.<\/p>\n<p>I also found the command<\/p>\n<pre><code class=\"language-bash\">git push origin :old-name new-name<\/code><\/pre>\n<p>but I have never used this command and when I quickly scanned the documentation for <code>git push<\/code> I couldn't find out what the <code>:old-name new-name<\/code> really does.\n(Comment below if you know!)<\/p>\n<p>That's it for now! <a href=\"\/subscribe\">Stay tuned<\/a> and I'll see you around!<\/p>","summary":"Today I learned how to rename a git branch from the CLI.","date_modified":"2025-07-23T16:49:02+02:00","tags":["git","productivity"],"image":"\/user\/pages\/02.blog\/04.til\/060.rename-a-git-branch\/thumbnail.webp"}]}
