<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Laravel Git Blog - Releases</title><description>Blog posts tagged Releases: notes on Git, code review and shipping Laravel projects.</description><link>https://laravelgit.com/</link><language>en-gb</language><atom:link href="https://laravelgit.com/blog/tag/releases.xml" rel="self" type="application/rss+xml"/><item><title>Conventional Commits for a Small Team</title><link>https://laravelgit.com/blog/conventional-commits-for-a-small-team/</link><guid isPermaLink="true">https://laravelgit.com/blog/conventional-commits-for-a-small-team/</guid><description>A prefix on every commit message - feat, fix, chore - makes the log scannable and the changelog half-written. Keep the rules short or the team routes around them.</description><pubDate>Wed, 21 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Six months of commit messages that say &amp;quot;fix&amp;quot;, &amp;quot;wip&amp;quot; and &amp;quot;changes&amp;quot; tell the next developer nothing - and on a small team the next developer is usually you. Conventional Commits add one prefix to every message and turn the log into something you can actually read.&lt;/p&gt;
&lt;h2&gt;The whole format&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;type(scope): short summary
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The types that earn their keep on a Laravel app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;feat&lt;/code&gt; - new behaviour (&lt;code&gt;feat(billing): add invoice PDF download&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fix&lt;/code&gt; - a bug (&lt;code&gt;fix(queue): stop retrying permanently failed jobs&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;refactor&lt;/code&gt; - same behaviour, different code&lt;/li&gt;
&lt;li&gt;&lt;code&gt;test&lt;/code&gt; - tests only&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chore&lt;/code&gt; - dependencies, config, tooling&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docs&lt;/code&gt; - the README and friends&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The scope is optional but cheap: one word naming the part of the app (&lt;code&gt;billing&lt;/code&gt;, &lt;code&gt;queue&lt;/code&gt;, &lt;code&gt;auth&lt;/code&gt;). The summary stays imperative and under about 70 characters.&lt;/p&gt;
&lt;h2&gt;What it buys&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;git log --oneline&lt;/code&gt; becomes a changelog draft: everything user-visible is a &lt;code&gt;feat&lt;/code&gt; or &lt;code&gt;fix&lt;/code&gt;, everything else filters out. That is exactly the input the tags-to-changelog habit needs, and it makes releases a paste-and-edit job instead of an archaeology dig. Review gets faster too - a &lt;code&gt;refactor&lt;/code&gt; prefix sets expectations before the diff loads, and nobody hunts for behaviour changes in a commit that announced there are none.&lt;/p&gt;
&lt;p&gt;Breaking changes get a &lt;code&gt;!&lt;/code&gt; (&lt;code&gt;feat(api)!: drop v1 endpoints&lt;/code&gt;) or a &lt;code&gt;BREAKING CHANGE:&lt;/code&gt; footer, so they are impossible to miss at release time.&lt;/p&gt;
&lt;h2&gt;Adopt it without a fight&lt;/h2&gt;
&lt;p&gt;The failure mode is process, not spelling: a team that gets a 12-type spec and a CI gate on day one starts writing &lt;code&gt;chore: stuff&lt;/code&gt; to make the check pass. Start smaller:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Five or six types, written in the README or pull request template.&lt;/li&gt;
&lt;li&gt;Scope optional, body only when the why is not obvious from the diff.&lt;/li&gt;
&lt;li&gt;No CI enforcement at first. Squash-merge pull requests and write the conventional message on the squash commit - main stays clean even when the branch&amp;#39;s own commits are messy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If it still feels like overhead after a month, drop it. A convention the team half-follows is worse than none, because it teaches people the log cannot be trusted. The bar is not a perfect history; it is a &lt;code&gt;git log&lt;/code&gt; you can skim before a release and believe.&lt;/p&gt;
</content:encoded><category>Workflows</category><category>Releases</category></item><item><title>Keeping a Changelog From Git Tags</title><link>https://laravelgit.com/blog/keep-a-changelog-from-git-tags/</link><guid isPermaLink="true">https://laravelgit.com/blog/keep-a-changelog-from-git-tags/</guid><description>Tags mark what shipped; the log between them writes the changelog. A small habit that pays off every release.</description><pubDate>Wed, 21 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A changelog is only painful when you write it three months late. If you tag releases, most of the work is already done.&lt;/p&gt;
&lt;h2&gt;Tag what you ship&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git tag -a v1.3.0 -m &amp;quot;v1.3.0&amp;quot;
git push origin v1.3.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Annotated tags carry a message and a date, and they give you a name for &amp;quot;what is in production right now&amp;quot;.&lt;/p&gt;
&lt;h2&gt;The log between tags is your draft&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git log v1.2.0..v1.3.0 --oneline --no-merges
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That list, cleaned up, is the release note. Short, descriptive commit subjects pay off here — another reason the commit-msg habit matters.&lt;/p&gt;
&lt;h2&gt;Keep a CHANGELOG.md in the repo&lt;/h2&gt;
&lt;p&gt;Add a section per tag, newest at the top, dated. Users of your package or app read it before upgrading; future-you reads it when something breaks and the question is &amp;quot;since when&amp;quot;. For a Laravel app, note the migrations and any &lt;code&gt;.env&lt;/code&gt; keys a release adds, because those are the steps a deploy can trip on.&lt;/p&gt;
&lt;h2&gt;The habit that makes it work&lt;/h2&gt;
&lt;p&gt;Write the entry at tag time, while the diff is fresh. A changelog maintained per release is ten lines of work; reconstructed quarterly it is an afternoon of archaeology.&lt;/p&gt;
</content:encoded><category>Releases</category></item><item><title>Release Notes People Actually Read</title><link>https://laravelgit.com/blog/release-notes-people-actually-read/</link><guid isPermaLink="true">https://laravelgit.com/blog/release-notes-people-actually-read/</guid><description>A changelog generated from commits is a ledger; release notes are a letter to your users. Who you are writing for changes what you write - and what you leave out.</description><pubDate>Wed, 21 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Two artifacts get confused constantly. The changelog answers &amp;quot;what changed, exactly&amp;quot; for developers - &lt;a href=&quot;/blog/keep-a-changelog-from-git-tags/&quot;&gt;keep a changelog from git tags&lt;/a&gt; covers generating one honestly. Release notes answer a different question for a different reader: &amp;quot;what can I do now that I could not before, and did anything I rely on change?&amp;quot; Users, not maintainers. The mistake is shipping the ledger to the letter&amp;#39;s audience.&lt;/p&gt;
&lt;h2&gt;Lead with what the reader gets&lt;/h2&gt;
&lt;p&gt;Not &amp;quot;Fixed bug in invoice retry logic&amp;quot; but &amp;quot;Failed invoice payments now retry automatically - no more manual re-runs.&amp;quot; Same change, different subject. The test for each line: can a user tell whether to care in five seconds? If the change is invisible to them - refactors, dependency bumps, internal cleanup - it does not belong in release notes at all. It belongs in the changelog, which is exactly why having both frees you.&lt;/p&gt;
&lt;h2&gt;The shape that works&lt;/h2&gt;
&lt;p&gt;Three groups, in this order, skipping any that are empty:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;New&lt;/strong&gt; - capabilities, with a sentence on when you would reach for each.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved and fixed&lt;/strong&gt; - changes to things people already use, phrased from their side (&amp;quot;exports are faster&amp;quot;, not &amp;quot;optimized query&amp;quot;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Breaking and action needed&lt;/strong&gt; - the section everyone reads first even though it is last. Anything requiring a config change, a migration, or a new minimum version goes here, with the exact step to take. Hiding a breaking change in the fixed list is how release notes lose trust permanently.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The habits behind good notes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Write the note with the PR, not at release time.&lt;/strong&gt; One line in the pull request description - &amp;quot;release note: ...&amp;quot; - while the context is fresh beats reconstructing twenty changes from commit messages on release day. Your &lt;a href=&quot;/blog/pull-request-templates-that-get-filled-in/&quot;&gt;PR template&lt;/a&gt; can carry the prompt.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tie notes to the tag.&lt;/strong&gt; Notes ship when the version ships - see &lt;a href=&quot;/blog/deploy-with-tags-not-branches/&quot;&gt;deploy with tags, not branches&lt;/a&gt; - so &amp;quot;what is in production&amp;quot; and &amp;quot;what do the notes say&amp;quot; can never drift.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Keep a human pass.&lt;/strong&gt; Generated drafts are a fine start; a generated final is a ledger wearing the letter&amp;#39;s clothes. Ten minutes of editing per release is the whole cost.&lt;/p&gt;
&lt;p&gt;Users who trust your release notes read them. That trust is built line by line, and spent in one &amp;quot;everything changed, nothing says why.&amp;quot;&lt;/p&gt;
</content:encoded><category>Releases</category></item><item><title>Deploying a Laravel App With Git Push</title><link>https://laravelgit.com/blog/deploy-laravel-with-git-push/</link><guid isPermaLink="true">https://laravelgit.com/blog/deploy-laravel-with-git-push/</guid><description>A bare repo and a post-receive hook are enough for a honest small-team deploy: checkout, composer, migrate, cache.</description><pubDate>Mon, 19 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Self-hosting your git and your app on the same box has a nice property: a push can be the deploy. You need a bare repository and one hook.&lt;/p&gt;
&lt;h2&gt;The bare repo&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git init --bare /srv/git/myapp.git
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add it as a remote on your laptop and push a branch you deploy from, for example &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The post-receive hook&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;/srv/git/myapp.git/hooks/post-receive&lt;/code&gt;, made executable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#!/bin/bash
set -e
APP=/var/www/myapp
git --work-tree=$APP --git-dir=/srv/git/myapp.git checkout -f main
cd $APP
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;checkout -f&lt;/code&gt; syncs the working tree to the pushed commit. The artisan steps are the boring, repeatable part of every Laravel release.&lt;/p&gt;
&lt;h2&gt;Keep it honest&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Run the hook as a user that owns &lt;code&gt;/var/www/myapp&lt;/code&gt; but cannot sudo.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;migrate --force&lt;/code&gt; runs unattended, so only push migrations you have tested against a copy of production data.&lt;/li&gt;
&lt;li&gt;If the hook fails, the push still lands in the repo; redeploy by pushing an empty commit or rerunning the hook on the server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is one step above &amp;quot;SSH in and pull&amp;quot;. When you outgrow it — zero-downtime releases, rollbacks, multiple servers — that is the point where a real pipeline earns its keep, not before.&lt;/p&gt;
</content:encoded><category>Releases</category><category>Self-hosting</category></item><item><title>Shipping a Laravel App From Git</title><link>https://laravelgit.com/blog/shipping-laravel-from-git/</link><guid isPermaLink="true">https://laravelgit.com/blog/shipping-laravel-from-git/</guid><description>Keep deploys boring: build from a tagged commit, migrate, cache.</description><pubDate>Thu, 15 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A Laravel deploy is mostly the same few steps each time.&lt;/p&gt;
&lt;h2&gt;Build from a known commit&lt;/h2&gt;
&lt;p&gt;Deploy a tag or a commit hash, not whatever is on a branch right now.&lt;/p&gt;
&lt;h2&gt;Run migrations deliberately&lt;/h2&gt;
&lt;p&gt;Run them as a step you can see, and know how to roll back.&lt;/p&gt;
&lt;h2&gt;Warm the caches&lt;/h2&gt;
&lt;p&gt;Config, route and view caches are part of the release, not an afterthought.&lt;/p&gt;
</content:encoded><category>Releases</category><category>Workflows</category></item></channel></rss>