<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~files/feed-premium.xsl"?>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:feedpress="https://feed.press/xmlns" xmlns:media="http://search.yahoo.com/mrss/" xmlns:podcast="https://podcastindex.org/namespace/1.0" version="2.0">
  <channel>
    <feedpress:locale>en</feedpress:locale>
    <atom:link rel="via" href="https://feeds.git-tower.com/tower-blog"/>
    <title>Tower Blog</title>
    <link>https://www.git-tower.com/blog</link>
    <lastBuildDate>Fri, 10 Apr 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://feeds.git-tower.com/tower-blog" rel="self" type="application/rss+xml"/>
    <description>Tower Blog - About Web and Software Development, Marketing and Design</description>
    <item>
      <title>Tower 16 for Mac (Beta) — Introducing AI Commits ✨</title>
      <link>https://feeds.git-tower.com/link/3463/17309542/tower-mac-16</link>
      <guid>https://www.git-tower.com/blog/tower-mac-16</guid>
      <pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>Say goodbye to writing commit messages from scratch! Tower 16 for Mac is now in beta, and it introduces AI Commits, allowing you to generate commit messages and descriptions with the help of AI directly from your favorite Git client.</p> <p>This has been one of our most requested features, and we're excited to finally bring it to you. We get it: writing commit messages takes you out of your flow. Tower 16 uses AI to handle that for you, so you can stay focused on shipping.</p>
<div class="framed-content"><p>☝️ Tower 16 is currently in Beta. To try it out, simply change the Release Channel to "Beta" under Settings &gt; Updates in the Tower for Mac application.</p></div>
<p>Let's see how it works! 😎</p>
<h2>The New "Working Copy" View</h2>
<p>The first thing you will notice when opening the "Working Copy" view is that the Commit Composing area has been redesigned with a few handy additions.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-16/214ab9074e-1775825494/TOM16-new-working-copy.avif" type="image/avif"><img alt="Tower 16 for Mac – New Working Copy View" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-16/427ae5d952-1775825494/TOM16-new-working-copy.png"></source></picture><figcaption>Tower 16 for Mac – New Working Copy View</figcaption></figure>
<p>On the left side, three new icons give you quick access to options that were previously harder to reach:</p>
<ol>
<li>Expanded Body View: keep the description field visible at all times.</li>
<li>Commit Templates: apply a previously saved template to the subject and description fields with one click.</li>
<li>Hard Line Wrap: toggle automatic line wrapping for your commit descriptions.</li>
</ol>
<p>But the real star of the show is on the right side — let's take a closer look! ✨</p>
<h2>AI Commits in Action!</h2>
<p>You will easily spot a colorful, brand new "✨ Generate" button in the Commit Composing area. Simply stage your changes, click the button, and Tower will instantly generate a commit message and description for you — it's that simple!</p>
<div class="framed-content"><p>☝️ For the AI Commits feature to work, make sure you already have either Claude Code or OpenAI Codex installed on your system.</p></div>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-16/e0928b6d37-1775825494/TOM16-generate-commit-message.mp4" type="video/mp4"></source></video><figcaption>Tower 16 for Mac – AI Commits in Action!</figcaption></figure>
<p><br /></p>
<p>You will also find a dropdown next to it that allows you to pick from a selection of preset prompts. </p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-16/433dbf325e-1775825494/TOM16-ai-commits-dropdown.avif" type="image/avif"><img alt="Tower 16 for Mac – AI Commits Preset Prompts dropdown" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-16/b4ab0c549c-1775825494/TOM16-ai-commits-dropdown.png"></source></picture><figcaption>Tower 16 for Mac – Preset Prompts dropdown</figcaption></figure>
<p><br /></p>
<p>This makes it easy to switch between different styles of commit messages depending on the situation — for example, a short one-liner versus a detailed, thorough commit.</p>
<h2>New "AI" Tab in the Settings</h2>
<p>To configure AI Commits, head over to Tower's "Settings" panel where you will find a brand new "AI" tab. </p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-16/2e04e3e514-1775825494/TOM16-ai-settings.avif" type="image/avif"><img alt='Tower 16 for Mac – New "AI" tab in Settings' src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-16/5824ffd770-1775825494/TOM16-ai-settings.png"></source></picture><figcaption>Tower 16 for Mac – New "AI" tab in Tower's Settings</figcaption></figure>
<p><br /></p>
<p>Here you can:  </p>
<ol>
<li>Select the AI provider for generating commit messages. Tower currently supports two AI providers: Claude Code and OpenAI's Codex. To use this feature, please ensure that you have one of these services installed on your system. You also have the option to disable this feature entirely.</li>
<li>Add or delete custom prompt presets to fine-tune the output to your liking.  </li>
</ol>
<p>That's right; you can create your own custom prompts to ensure that every generated message follows your preferred format and style. This is especially useful for teams that follow specific commit conventions (like Conventional Commits), or those who require certain prefixes, scopes, or formatting rules (like the usage of <a href="https://www.git-tower.com/blog/gitmoji">Gitmoji!</a>).</p>
<p>If you need some inspiration, here are a few prompt suggestions for you to consider:</p>
<div class="framed-content"><p><strong>1. Quick &amp; Simple</strong><br>
"Summarize the following code changes in a single short commit message (under 72 characters). Be direct and describe what changed, not why."</p>
<p><strong>2. Gitmoji</strong><br>
"Write a commit message for the following changes using the gitmoji convention. Start the subject line with the most appropriate gitmoji (e.g. ✨ for a new feature, 🐛 for a bug fix, ♻️ for refactoring, 🎨 for style/structure improvements). Keep the subject under 72 characters."</p>
<p><strong>3. Conventional Commits</strong><br>
"Write a commit message following the Conventional Commits specification. Use the format <code>type(scope): description</code>. Choose the appropriate type (feat, fix, refactor, chore, docs, style, test, perf, ci, build). Include a body paragraph explaining the motivation and what changed if the diff is non-trivial."</p></div>
<h2>Improvements and Bug Fixes</h2>
<p>As usual, we also took some time to implement improvements across the board:</p>
<ul>
<li><strong>License View:</strong> URLs in the license window are now clickable.</li>
<li><strong>Graphite:</strong> Performance with large numbers of branches has been significantly improved.</li>
<li><strong>Working Copy:</strong> "Show File" and "Blame" actions are now correctly disabled for untracked files.</li>
<li><strong>Workflows:</strong> The Git-Flow tab in repository settings is now hidden when a non-Git-Flow workflow is active.</li>
<li><strong>Diff/Merge Tools:</strong> Tower now validates the tool configuration before launching and provides better error feedback on failure.</li>
<li><strong>Partial Stash:</strong> You can now drag individual files from the Working Copy onto Stashes to create a partial stash, including untracked files.</li>
</ul>
<p>We also seized this opportunity to fix some bugs! Here is what we addressed:</p>
<ul>
<li><strong>Startup:</strong> Fixed a crash during app initialization that could prevent users from registering or using Tower.</li>
<li><strong>Worktrees:</strong> Fixed an issue where worktree repositories could lose their connection to the main repository.</li>
<li><strong>Performance:</strong> Fixed unnecessary UI updates in repositories with Graphite or worktrees that could cause sluggish performance.</li>
<li><strong>History:</strong> Fixed a crash that could occur when reloading history. The fully merged badge and history banner now also update correctly after fetch.</li>
<li><strong>macOS 26:</strong> Fixed a crash related to the sidebar in tabbed windows, an incorrect separator at the toolbar's second split view divider, and disabled full-size content scrolling for list and detail views to work around a system bug.</li>
</ul>
<p>We hope you enjoy this release! Happy committing! 😊</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>Not a Tower user yet? <strong>Download our 30-day free trial</strong> and experience a better way to work with Git!</p>
<p><br /></p>
<div style="text-align: center;"><a href="https://www.git-tower.com" class="button" target="_blank">Try Tower 16 Now</a></div>
<p><br /></p>
<p>PS: Did you know? Tower Pro is now <a href="https://www.git-tower.com/students" rel="noopener noreferrer" target="_blank">free for students</a> as well as <a href="https://www.git-tower.com/education" rel="noopener noreferrer" target="_blank">teachers and educational institutions!</a></p><img src="https://feeds.git-tower.com/link/3463/17309542.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Automate Your Code with GitHub Actions #2: Events and Triggers in GitHub Actions</title>
      <link>https://feeds.git-tower.com/link/3463/17309541/github-actions-events-and-triggers</link>
      <guid>https://www.git-tower.com/blog/github-actions-events-and-triggers</guid>
      <pubDate>Mon, 30 Mar 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>In this chapter, we're going to explore the core components of GitHub Actions that make up a workflow — from push and pull request events to scheduled workflows and dispatch triggers.</p> <p>Understanding these components is essential to creating effective automation pipelines and customizing workflows to meet your specific requirements.</p>
<div class="framed-content bio"><figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/github-actions-events-and-triggers/56f0150687-1775825494/bas-steins.avif" type="image/avif"><img alt="" src="https://www.git-tower.com/blog/media/pages/posts/github-actions-events-and-triggers/b9185ec1d7-1775825494/bas-steins.jpg" width="80"></source></picture></figure><div>
<h4>Who is Bas Steins?</h4>
<p><a href="https://bas.codes" target="_blank">Bas</a> is a software developer and technology trainer based in the triangle between the Netherlands, Germany, and Belgium. For almost two decades, he has been helping people turn their ideas into software and helping other developers write better code. This series is based on his mini-guide "<a href="https://bascodes.kit.com/gha-guide" target="_blank">Automate Your Code with GitHub Actions</a>".</p>
</div></div>
<h2>Triggers for Events</h2>
<p>An event is a specific activity that triggers a workflow. GitHub Actions supports a wide range of events, such as code pushes, pull requests, issue comments, and more. You can configure workflows to run on one or more events, allowing you to automate various tasks based on specific activities in your repository.</p>
<p>In our <a href="https://www.git-tower.com/blog/github-actions-fundamentals">first workflow</a>, we've already seen the <code>push</code> and the <code>pull_request</code> event:</p>
<pre><code class="language-yaml">on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main</code></pre>
<p>Each event can have additional configuration options, such as filtering by branches, paths, or tags. Here are some common event types and their use cases:</p>
<ul>
<li><strong>Push:</strong> Triggers the workflow on code pushes to the repository. Useful for running tests, linting, or deploying changes.</li>
<li><strong>Pull Request:</strong> Triggers the workflow when a pull request is opened, synchronized, or closed. Ideal for running tests, code analysis, or notifying team members.</li>
<li><strong>Issue Comment:</strong> Triggers the workflow when a comment is added to an issue or pull request. Great for automating issue triage, labeling, or closing stale issues.</li>
<li><strong>Schedule:</strong> Triggers the workflow at specific times or intervals. Perfect for running maintenance tasks, generating reports, or sending reminders.</li>
<li><strong>Repository Dispatch:</strong> Triggers the workflow via an external event using the GitHub API. Enables integration with external services, custom webhooks, or manual triggers.</li>
<li><strong>Workflow Dispatch:</strong> Triggers the workflow manually from the Actions tab in the repository. Useful for ad-hoc runs, debugging, or triggering complex workflows.</li>
<li><strong>Workflow Call:</strong> Triggers the workflow when another workflow calls it. This event is useful for creating reusable workflows or modularizing complex workflows.</li>
</ul>
<p>Since GitHub Actions is deeply integrated into the whole GitHub ecosystem, there are tons of other events that can trigger a workflow. You can find the full list of supported events in the <a href="https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows" rel="noopener noreferrer" target="_blank">official documentation</a>.</p>
<p>Here are some examples:</p>
<ul>
<li><strong>Gollum:</strong> Triggers the workflow when a Wiki page is created or updated. Useful for tracking documentation changes or updating a website.</li>
<li><strong>Project:</strong> Triggers the workflow when a project card is created, updated, moved, or deleted. Great for automating project management tasks or tracking progress.</li>
<li><strong>Release:</strong> Triggers the workflow when a new release is published. Ideal for automating release notes, versioning, or deployment tasks.</li>
<li><strong>Security Advisory:</strong> Triggers the workflow when a security advisory is published or updated. Critical for automating security checks, vulnerability scanning, or compliance tasks.</li>
</ul>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Series: "Automate Your Code with GitHub Actions"</h2>    <p></p>
<p>This is part 2 of our series titled "<b>Automate Your Code with GitHub Actions</b>", based on the mini-guide by <a href="https://bas.codes" target="_blank">Bas Steins</a>. Be sure to check out the rest of the series:</p>
<ol>
  <li><a href="https://www.git-tower.com/blog/github-actions-fundamentals">Fundamentals of GitHub Actions</a></li>
  <li>Events and Triggers in GitHub Actions <small>← you are here!</small>
</li>
  <li>Jobs, Actions, and the Marketplace <small>(soon!)</small>
</li>
  <li>Creating Custom GitHub Actions <small>(soon!)</small>
</li>
  <li>Examples: DevContainers, GitHub Pages, and Cloudflare Workers <small>(soon!)</small>
</li>
  <li>Examples: Data Automation, Linting, and Package Publishing <small>(soon!)</small>
</li>
  <li>Repository Splitting and Quick Reference <small>(soon!)</small>
</li>
</ol>
<p class="signup-cta">Sign up for our newsletter to get notified about the next episode!</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Series: "Automate Your Code with GitHub Actions" <p>This is part 2 of our series titled "<b>Automate Your Code with GitHub Actions</b>", based on the mini-guide by <a href="https://bas.codes" target="_blank">Bas Steins</a>. Be sure to check out the rest of the series:</p>
<ol>
  <li><a href="https://www.git-tower.com/blog/github-actions-fundamentals">Fundamentals of GitHub Actions</a></li>
  <li>Events and Triggers in GitHub Actions <small>← you are here!</small>
</li>
  <li>Jobs, Actions, and the Marketplace <small>(soon!)</small>
</li>
  <li>Creating Custom GitHub Actions <small>(soon!)</small>
</li>
  <li>Examples: DevContainers, GitHub Pages, and Cloudflare Workers <small>(soon!)</small>
</li>
  <li>Examples: Data Automation, Linting, and Package Publishing <small>(soon!)</small>
</li>
  <li>Repository Splitting and Quick Reference <small>(soon!)</small>
</li>
</ol>
<p class="signup-cta">Sign up for our newsletter to get notified about the next episode!</p></label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/github-actions-events-and-triggers">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div>
<h2>Contexts</h2>
<p>Each event provides a set of contexts that contain information about the event, such as the event type, the repository, the commit, the pull request, and more. You can use these contexts to access data related to the event and make decisions in your workflow.</p>
<p>For example, the <code>push</code> event provides the following contexts:</p>
<ul>
<li><code>github.event_name</code>: The name of the event that triggered the workflow.</li>
<li><code>github.repository</code>: The repository where the event occurred.</li>
<li><code>github.ref</code>: The Git reference (branch or tag) that triggered the workflow.</li>
<li><code>github.sha</code>: The commit SHA that triggered the workflow.</li>
<li><code>github.actor</code>: The username of the user that triggered the workflow.</li>
<li><code>github.head_ref</code>: The head branch of the pull request.</li>
<li><code>github.base_ref</code>: The base branch of the pull request.</li>
</ul>
<p>You can access these contexts in your workflow using the <code>github</code> object. For example, to print the commit SHA that triggered the workflow, you can use the following step:</p>
<pre><code class="language-yaml">- name: Print commit SHA
  run: echo ${{ github.sha }}</code></pre>
<p>By using contexts, you can create dynamic workflows that respond to specific events and conditions in your repository.</p>
<h2>The <code>push</code> Event</h2>
<p>The <code>push</code> event triggers the workflow when a commit is pushed to the repository. This event is useful for running tests, linting, or deploying changes. You can configure the <code>push</code> event to run on specific branches, tags, or paths.</p>
<p>Here is an example workflow that triggers on the <code>push</code> event:</p>
<pre><code class="language-yaml">name: Push Event
on:
  push:
    branches:
      - main
      - feature/*
    tags:
      - v1.*
    paths:
      - 'src/**'</code></pre>
<p>In this workflow, the <code>push</code> event is configured to run on the <code>main</code> branch, any branch that starts with <code>feature/</code>, tags that match the pattern <code>v1.*</code>, and changes in the <code>src/</code> directory.</p>
<p>You can use the <code>push</code> event to automate tasks such as: running tests on every commit, deploying changes to a staging environment, notifying team members of new commits, and generating release notes based on commit messages.</p>
<h3>The <code>push</code> Context</h3>
<p>When the <code>push</code> event triggers a workflow, it provides a set of contexts that contain information about the event. You can use these contexts to access data related to the push event and make decisions in your workflow.</p>
<p>Here are some common contexts provided by the <code>push</code> event:</p>
<ul>
<li><code>github.event_name</code>: The name of the event that triggered the workflow (<code>push</code>).</li>
<li><code>github.repository</code>: The repository where the event occurred.</li>
<li><code>github.ref</code>: The Git reference (branch or tag) that triggered the workflow.</li>
<li><code>github.sha</code>: The commit SHA that triggered the workflow.</li>
<li><code>github.actor</code>: The username of the user that triggered the workflow.</li>
<li><code>github.head_ref</code>: The head branch of the push event.</li>
<li><code>github.base_ref</code>: The base branch of the push event.</li>
</ul>
<h2>The <code>pull_request</code> Event</h2>
<p>The <code>pull_request</code> event triggers the workflow when a pull request is opened, synchronized, or closed. This event is ideal for running tests, code analysis, or notifying team members. You can configure the <code>pull_request</code> event to run on specific branches, paths, or labels.</p>
<p>Here is an example workflow that triggers on the <code>pull_request</code> event:</p>
<pre><code class="language-yaml">name: Pull Request Event
on:
  pull_request:
    branches:
      - main
      - feature/*
    paths:
      - 'src/**'
      - '!src/experimental/**'</code></pre>
<p>In this workflow, the <code>pull_request</code> event is configured to run on the <code>main</code> branch, any branch that starts with <code>feature/</code>, and changes in the <code>src/</code> directory excluding the <code>src/experimental/</code> directory.</p>
<p>You can use the <code>pull_request</code> event to automate tasks such as: running tests on every pull request, code analysis and linting, notifying team members of new pull requests, and automatically labeling pull requests based on changes.</p>
<h3>The <code>pull_request</code> Context</h3>
<p>When the <code>pull_request</code> event triggers a workflow, it provides a set of contexts that contain information about the event. You can use these contexts to access data related to the pull request event and make decisions in your workflow.</p>
<p>Here are some common contexts provided by the <code>pull_request</code> event:</p>
<ul>
<li><code>github.event_name</code>: The name of the event that triggered the workflow (<code>pull_request</code>).</li>
<li><code>github.repository</code>: The repository where the event occurred.</li>
<li><code>github.ref</code>: The Git reference (branch or tag) that triggered the workflow.</li>
<li><code>github.sha</code>: The commit SHA that triggered the workflow.</li>
<li><code>github.actor</code>: The username of the user that triggered the workflow.</li>
<li><code>github.head_ref</code>: The head branch of the pull request.</li>
<li><code>github.base_ref</code>: The base branch of the pull request.</li>
</ul>
<h2>The <code>schedule</code> Event</h2>
<p>The <code>schedule</code> event triggers the workflow at specific times or intervals. This event is perfect for running maintenance tasks, generating reports, or sending reminders. You can configure the <code>schedule</code> event to run on a cron schedule or at specific times.</p>
<p>Here is an example workflow that triggers on the <code>schedule</code> event:</p>
<pre><code class="language-yaml">name: Scheduled Event
on:
  schedule:
    - cron: '0 0 * * *'</code></pre>
<p>In this workflow, the <code>schedule</code> event is configured to run every day at midnight (00:00 UTC).</p>
<p>You can use the <code>schedule</code> event to automate tasks such as: running daily backups, generating weekly reports, sending monthly reminders, and cleaning up stale data.</p>
<div class="framed-content">
<p>☝️ The cron schedule needs to follow the POSIX cron syntax. You can use online tools like <a href="https://crontab.guru" target="_blank">crontab.guru</a> to generate cron expressions for your desired schedule. Shortcuts like <code>@daily</code>, <code>@weekly</code>, <code>@monthly</code>, and <code>@yearly</code> are not supported.</p>
</div>
<p>To understand the cron syntax, here is a quick reference:</p>
<pre><code>┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of the month (1 - 31)
│ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
│ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
* * * * *</code></pre>
<h3>The <code>schedule</code> Context</h3>
<p>When the <code>schedule</code> event triggers a workflow, it provides a set of contexts that contain information about the event. Here are some common contexts provided by the <code>schedule</code> event:</p>
<ul>
<li><code>github.event_name</code>: The name of the event that triggered the workflow (<code>schedule</code>).</li>
<li><code>github.repository</code>: The repository where the event occurred.</li>
<li><code>github.ref</code>: The Git reference (branch or tag) that triggered the workflow.</li>
<li><code>github.sha</code>: The commit SHA that triggered the workflow.</li>
<li><code>github.actor</code>: The username of the user that triggered the workflow.</li>
</ul>
<h2>The <code>issues</code> Event</h2>
<p>The <code>issues</code> event triggers the workflow when an issue is opened, edited, deleted, transferred, pinned, unpinned, closed, reopened, assigned, unassigned, labeled, unlabeled, locked, unlocked, milestoned, or demilestoned. This event is ideal for automating issue triage, labeling, or closing stale issues. You can configure the <code>issues</code> event to run on specific labels, assignees, or milestone changes.</p>
<p>Here is an example workflow that triggers on the <code>issues</code> event:</p>
<pre><code class="language-yaml">name: Issue Event
on:
  issues:
    types: [opened, edited, closed]
    branches:
      - main
    labels:
      - bug
      - enhancement</code></pre>
<p>In this workflow, the <code>issues</code> event is configured to run on the <code>main</code> branch when an issue is opened, edited, or closed with the labels <code>bug</code> or <code>enhancement</code>.</p>
<p>You can use the <code>issues</code> event to automate tasks such as: labeling issues based on content, assigning issues to team members, closing stale or resolved issues, and notifying team members of new or updated issues.</p>
<h3>The <code>issues</code> Context</h3>
<p>When the <code>issues</code> event triggers a workflow, it provides a set of contexts that contain information about the event. Here are some common contexts provided by the <code>issues</code> event:</p>
<ul>
<li><code>github.event_name</code>: The name of the event that triggered the workflow (<code>issues</code>).</li>
<li><code>github.repository</code>: The repository where the event occurred.</li>
<li><code>github.ref</code>: The Git reference (branch or tag) that triggered the workflow.</li>
<li><code>github.sha</code>: The commit SHA that triggered the workflow.</li>
<li><code>github.actor</code>: The username of the user that triggered the workflow.</li>
<li><code>github.head_ref</code>: The head branch of the issue event.</li>
<li><code>github.base_ref</code>: The base branch of the issue event.</li>
</ul>
<h2>Dispatch Events</h2>
<h3>The <code>repository_dispatch</code> Event</h3>
<p>The <code>repository_dispatch</code> event triggers the workflow when a repository dispatch event is sent to the repository. This event is ideal for triggering workflows from external systems or services. You can configure the <code>repository_dispatch</code> event to run on specific types of events or with custom payloads.</p>
<p>Here is an example workflow that triggers on the <code>repository_dispatch</code> event:</p>
<pre><code class="language-yaml">name: Repository Dispatch Event
on:
  repository_dispatch:
    types: [my-event-type]</code></pre>
<p>In this workflow, the <code>repository_dispatch</code> event is configured to run when a repository dispatch event of type <code>my-event-type</code> is sent to the repository.</p>
<p>You can use the <code>repository_dispatch</code> event to automate tasks such as: triggering deployments from external systems, running tests from external services, notifying team members of external events, and integrating with third-party services.</p>
<h3>The <code>repository_dispatch</code> Context</h3>
<p>When the <code>repository_dispatch</code> event triggers a workflow, it provides a set of contexts that contain information about the event. Here are some common contexts:</p>
<ul>
<li><code>github.event_name</code>: The name of the event that triggered the workflow (<code>repository_dispatch</code>).</li>
<li><code>github.repository</code>: The repository where the event occurred.</li>
<li><code>github.ref</code>: The Git reference (branch or tag) that triggered the workflow.</li>
<li><code>github.sha</code>: The commit SHA that triggered the workflow.</li>
<li><code>github.actor</code>: The username of the user that triggered the workflow.</li>
</ul>
<p>To trigger a repository dispatch event, you can use the GitHub API or the GitHub CLI. Here is an example to trigger a repository dispatch event from another workflow:</p>
<pre><code class="language-yaml">name: Trigger Repository Dispatch
on:
  push:
    branches:
      - main
jobs:
  trigger_dispatch:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Repository Dispatch
        run: |
          curl -X POST \
            -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
            -H "Accept: application/vnd.github.v3+json" \
            https://api.github.com/repos/owner/repo/dispatches \
            -d '{"event_type": "my-event-type", "client_payload": {"key": "value"}}'</code></pre>
<h3>The <code>workflow_dispatch</code> Event</h3>
<p>The <code>workflow_dispatch</code> event triggers the workflow manually from the Actions tab in the GitHub repository. This event is perfect for running workflows on-demand, testing changes, or deploying specific versions. You can configure the <code>workflow_dispatch</code> event with input parameters to customize the workflow run.</p>
<p>Here is an example workflow that triggers on the <code>workflow_dispatch</code> event:</p>
<pre><code class="language-yaml">name: Workflow Dispatch Event
on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Environment to deploy to'
        required: true
        default: 'production'</code></pre>
<p>In this workflow, the <code>workflow_dispatch</code> event is configured to run with an input parameter <code>environment</code> that specifies the deployment environment. The input parameter is required and has a default value of <code>production</code>.</p>
<p>You can use the <code>workflow_dispatch</code> event to automate tasks such as: deploying specific versions of the application, running manual tests or validations, triggering custom actions or integrations, and performing maintenance tasks on-demand.</p>
<h3><code>repository_dispatch</code> vs. <code>workflow_dispatch</code></h3>
<p>The <code>repository_dispatch</code> and <code>workflow_dispatch</code> events are both manual triggers for workflows, but they have different use cases and configurations.</p>
<ul>
<li><strong><code>repository_dispatch</code>:</strong> Triggered by external systems or services using the GitHub API or GitHub CLI. Can be configured to run on specific event types.</li>
<li><strong><code>workflow_dispatch</code>:</strong> Triggered manually from the Actions tab in the GitHub repository. Can be configured with input parameters to customize the workflow run.</li>
</ul>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>In the next article, we'll explore how jobs and actions work together to form the backbone of your workflows. See you there!</p><img src="https://feeds.git-tower.com/link/3463/17309541.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Automate Your Code with GitHub Actions #1: Fundamentals of GitHub Actions</title>
      <link>https://feeds.git-tower.com/link/3463/17299013/github-actions-fundamentals</link>
      <guid>https://www.git-tower.com/blog/github-actions-fundamentals</guid>
      <pubDate>Fri, 13 Mar 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>This guide provides a foundational understanding of GitHub Actions, its unique advantages, and its role in modern software development—while critically examining its place in the broader CI/CD and automation landscape.</p> <p><a href="https://github.com/features/actions" rel="noopener noreferrer" target="_blank">GitHub Actions</a> is a powerful automation platform integrated directly into GitHub, enabling developers to create workflows that respond to events within their repositories. </p>
<p>Most often the use case of CI/CD is associated with GitHub Actions, but it can be used for much more than that. For advanced software developers, GitHub Actions offers a flexible, event-driven framework to automate complex tasks, streamline development processes, and enforce best practices across teams. </p>
<div class="framed-content bio"><figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/github-actions-fundamentals/133c5d2694-1775825494/bas-steins.avif" type="image/avif"><img alt="" src="https://www.git-tower.com/blog/media/pages/posts/github-actions-fundamentals/0194f761dc-1775825494/bas-steins.jpg" width="80"></source></picture></figure><div>
<h4>Who is Bas Steins?</h4>
<p><a href="https://bas.codes" target="_blank">Bas</a> is a software developer and technology trainer based in the triangle between the Netherlands, Germany, and Belgium. For almost two decades, he has been helping people turn their ideas into software and helping other developers write better code. This series is based on his mini-guide "<a href="https://bascodes.kit.com/gha-guide" target="_blank">Automate Your Code with GitHub Actions</a>".</p>
</div></div>
<h2>What Is GitHub Actions?</h2>
<p>At its core, GitHub Actions is an automation platform that enables developers to define workflows—sequences of tasks—triggered by specific events in a GitHub repository. These events can range from code pushes and pull requests to issue comments, scheduled times, or even external triggers through webhooks. Each workflow is composed of jobs, which run in parallel or sequentially, and each job consists of steps that execute specific commands or reusable actions.</p>
<p>For advanced developers, the true power of GitHub Actions lies in its deep integration with GitHub's ecosystem. Unlike standalone CI/CD tools (like Jenkins), GitHub Actions is inherently tied to repository events, enabling highly contextual automation. This means workflows can be tailored to respond to precise conditions, such as a pull request from a specific branch or a comment containing a particular keyword. Additionally, GitHub Actions supports both GitHub-hosted and self-hosted runners, providing flexibility for organizations with unique infrastructure needs or compliance requirements.</p>
<p>However, it's essential to recognize that GitHub Actions isn't a one-size-fits-all solution. While it excels in scenarios tightly coupled with GitHub's features, it may not fully replace more mature CI/CD platforms such as Jenkins or CircleCI for certain use cases—particularly those requiring extensive plugin ecosystems or complex orchestration across multiple repositories.</p>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Series: "Automate Your Code with GitHub Actions"</h2>    <p></p>
<p>This is part 1 of our series titled "<b>Automate Your Code with GitHub Actions</b>", based on the mini-guide by <a href="https://bas.codes" target="_blank">Bas Steins</a>. Be sure to check out the rest of the series:</p>
<ol>
  <li>Fundamentals of GitHub Actions <small>← you are here!</small>
</li>
  <li><a href="https://www.git-tower.com/blog/github-actions-events-and-triggers">Events and Triggers in GitHub Actions</a></li>
  <li>Jobs, Actions, and the Marketplace <small>(soon!)</small>
</li>
  <li>Creating Custom GitHub Actions <small>(soon!)</small>
</li>
  <li>Examples: DevContainers, GitHub Pages, and Cloudflare Workers <small>(soon!)</small>
</li>
  <li>Examples: Data Automation, Linting, and Package Publishing <small>(soon!)</small>
</li>
  <li>Repository Splitting and Quick Reference <small>(soon!)</small>
</li>
</ol>
<p class="signup-cta">Sign up for our newsletter to get notified about the next episode!</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Series: "Automate Your Code with GitHub Actions" <p>This is part 1 of our series titled "<b>Automate Your Code with GitHub Actions</b>", based on the mini-guide by <a href="https://bas.codes" target="_blank">Bas Steins</a>. Be sure to check out the rest of the series:</p>
<ol>
  <li>Fundamentals of GitHub Actions <small>← you are here!</small>
</li>
  <li><a href="https://www.git-tower.com/blog/github-actions-events-and-triggers">Events and Triggers in GitHub Actions</a></li>
  <li>Jobs, Actions, and the Marketplace <small>(soon!)</small>
</li>
  <li>Creating Custom GitHub Actions <small>(soon!)</small>
</li>
  <li>Examples: DevContainers, GitHub Pages, and Cloudflare Workers <small>(soon!)</small>
</li>
  <li>Examples: Data Automation, Linting, and Package Publishing <small>(soon!)</small>
</li>
  <li>Repository Splitting and Quick Reference <small>(soon!)</small>
</li>
</ol>
<p class="signup-cta">Sign up for our newsletter to get notified about the next episode!</p></label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/github-actions-fundamentals">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div>
<h2>Pricing</h2>
<p>GitHub Actions comes with a generous free tier that allows you to run up to 2,000 minutes per month on the GitHub Free plan. If you need more minutes, you can upgrade to a paid plan, such as GitHub Pro or GitHub Team, which offer 3,000 minutes per month. For larger organizations, GitHub Enterprise Cloud provides 50,000 minutes per month.</p>
<p>As of the date of writing, these are the current pricing tiers. <a href="https://docs.github.com/en/billing/concepts/product-billing/github-actions#included-storage-and-minutes" rel="noopener noreferrer" target="_blank">Please check this link for the most up-to-date pricing</a>.</p>
<table>
<thead>
<tr>
<th>Plan</th>
<th>Storage</th>
<th>Minutes (per month)</th>
</tr>
</thead>
<tbody>
<tr>
<td>GitHub Free</td>
<td>500 MB</td>
<td>2,000</td>
</tr>
<tr>
<td>GitHub Pro</td>
<td>1 GB</td>
<td>3,000</td>
</tr>
<tr>
<td>GitHub Free for organizations</td>
<td>500 MB</td>
<td>2,000</td>
</tr>
<tr>
<td>GitHub Team</td>
<td>2 GB</td>
<td>3,000</td>
</tr>
<tr>
<td>GitHub Enterprise Cloud</td>
<td>50 GB</td>
<td>50,000</td>
</tr>
</tbody>
</table>
<p>The free minutes are based on a Linux virtual machine with 2 Cores and 7 GB of RAM. If you need more resources, you can choose from different virtual machine configurations, such as Windows, macOS, or ARM64. Each configuration has a different pricing model based on the resources provided.</p>
<p>In general, a Windows virtual machine costs twice as much as a Linux virtual machine, while a macOS virtual machine costs ten times as much as a Linux virtual machine. The ARM64 virtual machine is currently in public preview and has a different pricing model.</p>
<h2>Our First Workflow</h2>
<p>A workflow in GitHub Actions is defined using a YAML file stored in the <code>.github/workflows</code> directory of your repository. Yes, that's a directory and that means you can define multiple workflows for a single repository.</p>
<p>Let's look at an example and break it down:</p>
<pre><code class="language-yaml">name: CI/CD Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '14'
      - name: Install dependencies
        run: npm install
      - name: Run tests
        run: npm test

  deploy:
    runs-on: ubuntu-latest
    needs: build-and-test
    if: github.ref == 'refs/heads/main' &amp;&amp; github.event_name == 'push'
    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: echo "Deploying to production"  # Replace with actual deployment command</code></pre>
<h3>Explanation</h3>
<p>The workflow above is a CI/CD pipeline that builds and tests a project on pull requests and deploys it to production on pushes to the main branch. Here's a breakdown of the key components:</p>
<ul>
<li><strong>Triggers:</strong> The workflow runs on both <code>push</code> and <code>pull_request</code> events for the <code>main</code> branch.</li>
<li><strong>Jobs:</strong><ul>
<li><code>build-and-test</code>: This job checks out the code, sets up Node.js, installs dependencies, and runs tests. It runs on both pushes and pull requests.</li>
<li><code>deploy</code>: This job depends on the successful completion of <code>build-and-test</code> (via <code>needs: build-and-test</code>) and only runs on pushes to the <code>main</code> branch (enforced by the <code>if</code> condition). It simulates a deployment step.</li>
</ul>
</li>
<li><strong>Conditional Execution:</strong> The <code>if</code> statement in the <code>deploy</code> job ensures that deployment only occurs when code is pushed directly to <code>main</code>, not on pull requests.</li>
<li><strong>Steps:</strong> Each job consists of a series of steps that execute commands or actions. In this example, we use the <code>actions/checkout</code> action to fetch the code, and a placeholder command to simulate deployment.</li>
<li><strong>Actions:</strong> The <code>uses</code> keyword is used to invoke reusable actions from the GitHub Marketplace. In this case, we use the <code>actions/checkout</code> action to fetch the code.</li>
<li><strong>Runners:</strong> The <code>runs-on</code> keyword specifies the runner environment for each job. In this case, both jobs run on an <code>ubuntu-latest</code> virtual machine.</li>
</ul>
<p>To put it simple, a workflow is triggered by an event and consists of one or more jobs that run on runners. Each job contains a series of steps that execute commands or actions.</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>In the next article, we will dive deeper into each component. See you there!</p><img src="https://feeds.git-tower.com/link/3463/17299013.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Exploring the .git Directory – How Git Stores Your Code</title>
      <link>https://feeds.git-tower.com/link/3463/17278711/exploring-the-git-directory</link>
      <guid>https://www.git-tower.com/blog/exploring-the-git-directory</guid>
      <pubDate>Wed, 18 Feb 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>We all use Git every day, but how many of us truly understand what's happening behind the scenes? Today, we're going to bravely venture inside the <code>.git</code> directory, unpack its most important contents, and demystify how Git actually works.</p> <p>There's a mysterious <code>.git</code> folder at the root of every repository. You probably know that this folder serves as the brain, heart, and engine room of your project's version control system, even though it is often ignored and sometimes feared.</p>
<p>If you've ever wondered what types of files and folders exist inside this magical folder, then this tour is for you.</p>
<p>Ready for some enlightenment? Let's dive in!</p>
<h2>1. What is the <code>.git</code> directory for?</h2>
<p>At its core, Git is a content-addressable filesystem, and the <code>.git</code> directory is where all that content (and the pointers to it) lives. It's the repository itself, containing everything Git needs to know about your project's history, branches, configuration, and more. Your working directory (where your actual files are) is just one projection of what's inside <code>.git</code>.</p>
<p>Let's start by listing its contents. Navigate to the root of any Git repository in your terminal and type <code>ls -F .git/</code>. You'll see something like this:</p>
<pre><code class="language-bash">branches/        HEAD        hooks/        logs/        objects/        refs/        config        description        index        info/</code></pre>
<p>The exact contents might vary slightly depending on your Git version and repository state. Please note that the <code>branches/</code> directory is a legacy remnant from older versions of Git and is no longer used in modern repositories. </p>
<p>You may also notice a <code>COMMIT_EDITMSG</code> file in the listing, which stores the message from your most recent commit that Git uses when you run <code>git commit --amend</code>.</p>
<p>Each of these files and directories plays a crucial role. Let's break them down.</p>
<h2>2. The <code>HEAD</code> File (Your Current Position)</h2>
<p>One of the most fundamental files in <code>.git</code> is <code>HEAD</code>. It's usually a simple text file that contains a reference to your current branch.</p>
<pre><code class="language-bash"># Example content of .git/HEAD when on the 'main' branch
cat .git/HEAD
# Output: ref: refs/heads/main</code></pre>
<p>This tells Git that your current <code>HEAD</code> (your "current commit") is the latest commit on the <code>main</code> branch.</p>
<h3>What about a "Detached HEAD"?</h3>
<p>When you <code>git checkout &lt;commit-hash&gt;</code>, the <code>HEAD</code> file changes to point directly to a commit hash, rather than a branch.</p>
<pre><code class="language-bash"># Example content of .git/HEAD in a detached HEAD state
cat .git/HEAD
# Output: 8b0e7a2b... (40-character SHA-1 hash)</code></pre>
<p>This is a "detached HEAD" state. It means you're directly on a commit, not on a branch. This simple file's content is the key to understanding a concept that often confuses new users!</p>
<div class="download-tower-framed">  <div class="download-tower-framed-info">  <h3>Not a Tower user yet?</h3>  <p>Download our 30-day free trial and experience a better way to work with Git!</p>  <div><a href="https://www.git-tower.com?utm_source=blog&amp;utm_medium=cta&amp;utm_content=post&amp;utm_campaign=exploring-the-git-directory" target="_blank">Try Tower Now</a></div>  </div>  <div class="app-icon"><picture><source type="image/avif" srcset="https://www.git-tower.com/blog/assets/img/icons/downloads-modal-app-icon.avif"><img class="tower-icon" src="https://www.git-tower.com/blog/assets/img/icons/downloads-modal-app-icon.png" alt="Tower app icon"></source></picture></div></div>
<h2>3. The <code>config</code> File (Your Project's Local Settings)</h2>
<p>You've likely used <code>git config</code> from the command line. <a href="https://www.git-tower.com/blog/the-ultimate-guide-to-git-config">This is Git&#039;s configuration system, which is immensely customizable</a> — and if you want a quick way to build your own, try Tower's <a href="https://www.git-tower.com/free-tools/git-config-generator">Git Config Generator</a>.</p>
<p>The <code>config</code> file is where your local, repository-specific configurations are stored.</p>
<pre><code class="language-ini"># Example content of .git/config
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    ignorecase = true
    precomposeunicode = true
[remote "origin"]
    url = https://github.com/your-org/your-repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
    remote = origin
    merge = refs/heads/main</code></pre>
<p>This file contains settings like remote URLs, branch tracking information, and any specific overrides for this particular repository. It's neatly organized into <code>[sections]</code>.</p>
<h2>4. The <code>index</code> File (Staging Area)</h2>
<p>The <code>index</code> file is a crucial binary file that represents your "staging area" or "cache". It is a dynamic snapshot of your project's state that is waiting to be committed.</p>
<p>When you run <code>git add &lt;file&gt;</code>, Git takes the current version of that file from your working directory, computes its hash, stores it in the <code>objects</code> directory, and updates the <code>index</code> file to record that this new version of the file is now staged for the next commit.</p>
<h2>5. The <code>objects</code> Directory (The Heart of Git)</h2>
<p>This is where the magic truly happens. The <code>objects</code> directory is Git's content-addressable database. Every piece of content — every file, every directory state, every commit message — is stored here as an "object", identified by its SHA-1 hash.</p>
<p>Inside <code>objects/</code>, you'll find subdirectories named after the first two characters of the SHA-1 hash. This helps distribute the objects more evenly across the filesystem. The remaining 38 characters form the filename itself, so a full object path looks like <code>.git/objects/8b/0e7a2b9d1f3c5e7a9b2d4f6e8c0a1b3d5f7e9a</code>.</p>
<p>There are three main types of objects:</p>
<ul>
<li><strong>Blob Objects:</strong> These store the actual content of your files. If two files have identical content, Git only stores one blob object and points to it twice.</li>
<li><strong>Tree Objects:</strong> These represent the state of a directory at a given point in time. They contain a list of pointers to blob objects (for files) and other tree objects (for subdirectories). This is how Git stores directory structures efficiently.</li>
<li><strong>Commit Objects:</strong> These are the commits you create. Each commit object stores:<ul>
<li>A pointer to the top-level tree object for that commit (the root directory snapshot).</li>
<li>Pointers to its parent commit(s).</li>
<li>Author and committer information.</li>
<li>The commit message.</li>
</ul>
</li>
</ul>
<p>This elegant system means Git doesn't store "diffs" between file versions. Instead, it stores full snapshots, and computes the differences on the fly when you ask for them.</p>
<p>That said, you may also notice a <code>pack/</code> subdirectory inside <code>objects/</code>. For efficiency, Git periodically compresses objects into binary pack files using delta compression — so while conceptually Git stores full snapshots, on disk it optimizes storage behind the scenes (you can trigger this manually with <code>git gc</code>).</p>
<h2>6. The <code>refs</code> Directory (The Pointers)</h2>
<p>The <code>refs</code> directory is where Git stores simple pointers to specific commit objects. This is where your branches and tags truly live.</p>
<ul>
<li>
<p><code>refs/heads/</code>: Contains one file for each local branch (e.g., <code>refs/heads/main</code>, <code>refs/heads/feature/login</code>). Each file contains the SHA-1 hash of the commit that branch currently points to.</p>
<pre><code class="language-bash"># Example content of .git/refs/heads/main
cat .git/refs/heads/main
# Output: 8b0e7a2b9d1f3c5e... (the latest commit on 'main')</code></pre>
<p>This means that a branch is nothing more than a movable pointer to a commit. Moving a branch (e.g., with <code>git commit</code> or <code>git reset</code>) simply means updating the SHA-1 hash in this file.</p>
</li>
<li>
<p><code>refs/tags/</code>: Similar to heads, but for tags. Each file contains the SHA-1 hash of the commit (or tag object) that the tag points to. Tags are generally immutable pointers.</p>
</li>
<li>
<p><code>refs/remotes/</code>: Tracks the state of branches on remote repositories (e.g., <code>refs/remotes/origin/main</code>).</p>
</li>
</ul>
<h2>7. <code>hooks</code> and <code>logs</code> (Automate and Observe)</h2>
<p>Finally, two more important directories:</p>
<ul>
<li>
<p><code>hooks/</code>: This directory contains sample scripts (e.g., <code>pre-commit.sample</code>, <code>post-merge.sample</code>) that you can rename and activate. These are your Git Hooks, allowing you to run custom scripts before or after certain Git events. They're powerful for enforcing code quality, running tests, or deploying code. <a href="https://www.git-tower.com/learn/git/faq/git-hooks">You can learn more about Git Hooks here</a>.</p>
</li>
<li>
<p><code>logs/</code>: This is where Git keeps its <code>reflog</code> (reference logs). The <code>reflog</code> is an incredibly useful safety net that records every time your <code>HEAD</code> (or a branch) has been updated. This means you can almost always recover "lost" commits or branches, as we discussed in our <a href="https://www.git-tower.com/blog/posts/force-push-in-git">article on Force Push disaster recovery</a>.</p>
</li>
</ul>
<h2>Final Words</h2>
<p>If you've made it this far, congratulations! You're not <em>just using</em> Git anymore; you're truly understanding it!</p>
<p>By taking this guided tour of the <code>.git</code> directory, you now realize that Git is not a complex, magical black box, but an elegant and robust system built upon simple, interconnected objects and pointers. Now, if something goes wrong, you'll have a better intuition for troubleshooting.</p>
<p>For more in-depth guides, don't forget to sign up for our newsletter below and follow Tower on <a href="https://x.com/gittower" rel="noopener noreferrer" target="_blank">Twitter</a> and <a href="https://www.linkedin.com/company/gittower" rel="noopener noreferrer" target="_blank">LinkedIn</a>!</p>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Join Over 100,000 Developers &amp; Designers</h2>    <p>Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Join Over 100,000 Developers &amp; Designers Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/exploring-the-git-directory">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div><img src="https://feeds.git-tower.com/link/3463/17278711.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Tower 11 for Windows — Commit Templates</title>
      <link>https://feeds.git-tower.com/link/3463/17268456/tower-windows-11</link>
      <guid>https://www.git-tower.com/blog/tower-windows-11</guid>
      <pubDate>Mon, 02 Feb 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>We are thrilled to announce the release of Tower 11 for Windows! This version introduces a feature that many of you have been waiting for: Commit Templates!</p>
<p>Get ready to craft better commits and bring more consistency to your project's history! 😎</p> <p>Clear and descriptive commit messages are the backbone of a healthy Git repository. They make it easier to understand changes, review code, and track down bugs. But maintaining a high standard for commit messages across a whole team and over the long run is a tough challenge. </p>
<p>That's where Git's "Commit Templates" come to the rescue! And with Tower 11 for Windows, using them is now incredibly simple.</p>
<p>Let's dive in and see how you can start using this feature today.</p>
<h2>Your Command Center for Commit Templates</h2>
<p>You can manage all your commit templates in Tower's Preferences, under the new "Templates" tab. We've included a default template to get you started, but the real power comes from creating your own.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/ad102f45aa-1775825494/tow11-manage-commit-templates.avif" type="image/avif"><img alt="Tower 11 for Windows – Managing Commit Templates" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/23f7695859-1775825494/tow11-manage-commit-templates.png"></source></picture><figcaption>Tower 11 for Windows – Managing Commit Templates</figcaption></figure>
<p><br /></p>
<p>To create a new template, just click the "+" button and fill in the details. If you're not sure what to include in your commit template, <a href="https://www.git-tower.com/blog/how-to-write-the-perfect-commit-message">this blog post can teach you all the fundamentals on how to write a compelling commit message</a>.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/9fc06cad96-1775825494/tow11-create-commit-template.avif" type="image/avif"><img alt="Tower 11 for Windows – Creating a new Commit Template" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/d194be9815-1775825494/tow11-create-commit-template.png"></source></picture><figcaption>Tower 11 for Windows – Creating a new Commit Template</figcaption></figure>
<p><br /></p>
<p>You can set a global default template that will be used for all your repositories. Or, for more fine-grained control, you can define a specific template for a particular repository in its settings.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/28cf9c82cf-1775825494/tow11-repository-settings.avif" type="image/avif"><img alt="Tower 11 for Windows – Repository Settings" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/d43c82eb29-1775825494/tow11-repository-settings.png"></source></picture><figcaption>Tower 11 for Windows – Repository Settings</figcaption></figure>
<h2>Inserting a Template When Committing</h2>
<p>When you're ready to commit, you'll find a new "Commit template" button in the commit composer. Clicking it will reveal all your saved templates.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/20735e6bb4-1775825494/tow11-commit-template-button.avif" type="image/avif"><img alt="Tower 11 for Windows — Commit Template button" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/cf67600f9f-1775825494/tow11-commit-template-button.png"></source></picture><figcaption>Tower 11 for Windows — Commit Template button</figcaption></figure>
<p><br /></p>
<p>For the keyboard ninjas out there, we've got you covered too! Simply type "t:" or "/" in the commit subject field to bring up the template list and select the one you need without ever leaving the keyboard.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/9c81d73951-1775825494/tow11-insert-commit-template.avif" type="image/avif"><img alt="Tower 11 for Windows – Insert a Commit Template using the keyboard." src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/340d33f612-1775825494/tow11-insert-commit-template.png"></source></picture><figcaption>Tower 11 for Windows – Insert a Commit Template using the keyboard.</figcaption></figure>
<h2>ARM-Native Version for Windows</h2>
<p>We are also excited to announce that, starting with this release, Tower for Windows will be available as an ARM-native application! </p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/80f5c7a18a-1775825494/tow11-arm-ready.avif" type="image/avif"><img alt="Tower 11 for Windows — ARM-Native Version" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-11/1b1f77d8bc-1775825494/tow11-arm-ready.png"></source></picture><figcaption>Tower 11 for Windows — ARM-Native Version</figcaption></figure>
<p><br /></p>
<p>If you are using a Windows device with an ARM processor, you can now enjoy a faster and more energy-efficient experience. This native ARM version ensures that Tower runs with the best possible performance on these devices.</p>
<p>The best part? If you're using a device with an ARM processor, you will automatically receive the ARM-native version when you update to version 11. There's no need to switch manually!</p>
<h2>Other Improvements</h2>
<p>As usual, we took some time to implement improvements across the board. Here's what's new:</p>
<ul>
<li><strong>Branch Naming:</strong> Spaces in branch names are now automatically replaced with dashes for improved consistency.</li>
<li><strong>Bookmarks:</strong> The default path when adding a new repository is now synchronized with the default clone path defined in Preferences.</li>
<li><strong>Licensing:</strong> Evaluation of license expiration dates has been improved.</li>
<li><strong>GPG Configuration:</strong> Improved GPG configuration handling by providing system environment variables for the GPG config binary.</li>
<li><strong>Portable Git:</strong> Updated to version <strong>2.52.0</strong> for improved compatibility and performance. Please note that <code>git-flow</code> was removed in version 2.51.2. To maintain compatibility, do not remove previous versions of Embedded Git and select version <strong>2.51.0</strong> in <strong>Preferences → Git Config → Git Binary</strong>.</li>
</ul>
<p>We also fixed some bugs! Here is what we addressed:</p>
<ul>
<li><strong>Preferences:</strong> Fixed a crash that could occur when switching the SSH implementation to OpenSSH.</li>
<li><strong>GPG:</strong> Fixed an issue with retrieving the GPG binary version.</li>
<li><strong>Commit:</strong> Fixed string encoding issues when committing changes.</li>
<li><strong>Working Tree:</strong> Addressed a potential crash when refreshing the working tree.</li>
<li><strong>Rebase:</strong> Fixed an issue where running an interactive rebase could result in intermittent errors.</li>
<li><strong>Remote Branches:</strong> Fixed parsing issues with remote branch names.</li>
</ul>
<p>We can't wait for you to try Tower 11 for Windows! <strong>If you already have a Tower account, update to version 11 today!</strong></p>
<p>Happy committing! 😊</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>Not a Tower user yet? <strong>Download our 30-day free trial</strong> and experience a better way to work with Git!</p>
<p><br /></p>
<div style="text-align: center;"><a href="https://www.git-tower.com" class="button" target="_blank">Try Tower Now</a></div>
<p><br /><br />
PS: Did you know? Tower Pro is now <a href="https://www.git-tower.com/students" rel="noopener noreferrer" target="_blank">free for students</a> as well as <a href="https://www.git-tower.com/education" rel="noopener noreferrer" target="_blank">teachers and educational institutions!</a></p><img src="https://feeds.git-tower.com/link/3463/17268456.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>The Ultimate Guide to Git Config: Fine-Tuning Your Git Experience</title>
      <link>https://feeds.git-tower.com/link/3463/17267049/the-ultimate-guide-to-git-config</link>
      <guid>https://www.git-tower.com/blog/the-ultimate-guide-to-git-config</guid>
      <pubDate>Fri, 30 Jan 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>You've probably used <code>git config</code> to set your name and email, but have you ever explored its other capabilities? </p>
<p>Git's configuration system is a treasure trove of settings that can dramatically improve your productivity and tailor Git to your exact needs. It’s like having a secret control panel for the world's most popular version control system!</p> <p>But with dozens of options, where do you even start? Don't worry — we've got you covered. </p>
<p>In this comprehensive guide, we'll explore the ins and outs of <code>git config</code>, from the foundational settings to the "hidden gems" that will make you a Git power user. </p>
<p>Ready to customize your Git experience? Let's get started!</p>
<h2>1. The What, Where, and How of Git Config</h2>
<p>Before we dive into the cool stuff, let's get the basics right. Understanding how <code>git config</code> works is the foundation for everything else.</p>
<h3>What is <code>git config</code>?</h3>
<p>At its heart, <code>git config</code> is the command that lets you get and set configuration variables that control all aspects of Git's appearance and operation. These configurations can be as simple as setting your username or as complex as rewriting Git's core behaviors for diffing and merging.</p>
<h3>The Three Levels of Configuration</h3>
<p>Git provides three levels of configuration, each overriding the previous one:</p>
<ol>
<li><strong>System (<code>--system</code>):</strong> These settings apply to every user on the entire machine. You'll rarely need to touch this. The file is typically located at <code>/etc/gitconfig</code>.</li>
<li><strong>Global (<code>--global</code>):</strong> This is where you'll set your personal preferences. These settings apply to all of your repositories. The file is located in your user's home directory (<code>~/.gitconfig</code> on Linux/macOS, <code>C:\Users\&lt;YourName&gt;\.gitconfig</code> on Windows). This is where the magic happens for most users!</li>
<li><strong>Local (<code>--local</code>):</strong> These settings are specific to the repository you are currently in. They are stored in the <code>.git/config</code> file inside your repository and are perfect for project-specific overrides.</li>
</ol>
<p>This layered system gives you incredible flexibility. You can set a global preference and then override it for a specific project that has different needs.</p>
<div class="framed-content" style="text-align:center"><h4>Free Tool: Git Config Generator</h4><figure><a href="https://www.git-tower.com/free-tools/git-config-generator"><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/the-ultimate-guide-to-git-config/69bddaa620-1775825494/git-config-generator.avif" type="image/avif"><img alt="" src="https://www.git-tower.com/blog/media/pages/posts/the-ultimate-guide-to-git-config/0235d8b70e-1775825494/git-config-generator.png"></source></picture></a></figure><div><p>Create your own personalized .gitconfig file interactively using Tower's <a href="https://www.git-tower.com/free-tools/git-config-generator">Git Config Generator</a>!</p></div></div>
<h3>Basic Commands</h3>
<p>Interacting with these settings is straightforward. Here are the commands you'll use most often:</p>
<pre><code class="language-bash"># View all settings (from all levels)
git config --list

# View a specific setting
git config user.name

# Set a global setting
git config --global user.name "Your Name"

# Set a local setting for the current repository
git config --local user.email "your-email@example.com"

# Remove a setting
git config --global --unset user.signingkey</code></pre>
<h3>The Config File Syntax</h3>
<p>While using <code>git config --set</code> is great, sometimes it's easier to open the <code>.gitconfig</code> file with your favorite text editor and edit it directly. </p>
<p>The syntax is simple and intuitive:</p>
<pre><code>[section]
    key = value

# This is a comment
; This is also a comment

[alias]
    co = checkout
    st = status

[user]
    name = Bruno Brito
    email = bruno@git-tower.com</code></pre>
<p>Sections are denoted by square brackets (e.g., <code>[user]</code>), followed by key-value pairs.</p>
<h3>Modularizing Your Config with <code>include</code></h3>
<p>As your <code>.gitconfig</code> file grows, it can become a bit unwieldy. A fantastic feature for staying organized is <code>include.path</code>. It allows you to split your configuration into multiple files.</p>
<p>For example, you could keep all your <a href="https://www.git-tower.com/learn/git/faq/how-to-set-up-git-aliases">Git aliases</a> in a separate <code>~/.gitconfig-aliases</code> file:</p>
<pre><code class="language-ini"># In ~/.gitconfig
[include]
    path = ~/.gitconfig-aliases</code></pre>
<p>Then, in <code>~/.gitconfig-aliases</code>:</p>
<pre><code class="language-ini">[alias]
    co = checkout
    st = status
    br = branch
    lg = log --oneline --graph --decorate</code></pre>
<p>This keeps your main config file clean and makes your settings easier to manage or even share!</p>
<h2>2. The Essentials: Your Identity and Core Settings</h2>
<p>In this section, we will cover the essential settings that every developer should configure.</p>
<ul>
<li>
<p><strong>Setting Your Identity:</strong> This is the first thing you should do on a new machine. It ensures all your work is properly attributed to you.</p>
<pre><code class="language-bash">git config --global user.name "Your Name"
git config --global user.email "your-email@example.com"</code></pre>
</li>
<li>
<p><strong>Choosing Your Default Branch Name:</strong> The default branch name in new repositories used to be <code>master</code>. The community has since shifted towards <code>main</code>. You can make <code>main</code> your default for all new projects:</p>
<pre><code class="language-bash">git config --global init.defaultBranch main</code></pre>
</li>
<li>
<p><strong>The Core Editor:</strong> When Git needs you to enter a message (like for a commit or a merge), it opens an editor. You should tell Git which one to use:</p>
<pre><code class="language-bash"># For VS Code
git config --global core.editor "code --wait"</code></pre>
</li>
<li>
<p><strong>Handling Line Endings:</strong> To prevent issues when collaborating with people on different operating systems (Windows vs. Mac/Linux), it's a good practice to configure how Git handles line endings.</p>
<pre><code class="language-bash"># For macOS/Linux
git config --global core.autocrlf input
# For Windows
git config --global core.autocrlf true</code></pre>
</li>
<li>
<p><strong>Ignoring File Permissions:</strong> Have you ever seen a file show up as "modified" when you only changed its executable permissions? This can be annoying. If you don't need to track file permissions, you can tell Git to ignore these changes:</p>
<pre><code class="language-bash">git config --global core.fileMode false</code></pre>
</li>
</ul>
<h2>3. Productivity Boosters for Smoother Workflows</h2>
<p>With the basics out of the way, let's look at some settings that will save you time and make Git more enjoyable to use.</p>
<h3>Aliases: Your Personal Git Shortcuts</h3>
<p>Aliases are one of the most powerful features in <code>git config</code>. They let you create your own shortcuts for longer commands.</p>
<pre><code class="language-ini">[alias]
    # Simple shortcuts
    co = checkout
    st = status
    br = branch

    # A more complex log format
    lg = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&lt;%an&gt;%Creset' --abbrev-commit

    # Run a shell command!
    purge = "!git branch --merged | egrep -v '(^\\*|main|develop)' | xargs git branch -d"</code></pre>
<p>With the <code>lg</code> alias above, <code>git lg</code> gives you a beautifully formatted history. The <code>purge</code> alias lets you clean up all your merged local branches with a single command!</p>
<h3>Controlling Your Git Output Color Palette</h3>
<p>Since version 1.8.4, Git's output has become colorful, making it easier to read at a glance. However, if you prefer a more monochromatic appearance, you can adjust the settings by typing the following:</p>
<pre><code class="language-bash">git config --global color.ui false</code></pre>
<p>This single command disables color for Git's output (like <code>diff</code>, <code>status</code>, and <code>branch</code>) when you're using a terminal.</p>
<h3>The Pager</h3>
<p>Sometimes, a command's output is too long to fit on your screen (like <code>git log</code>). Git uses a "pager" (like <code>less</code>) to let you scroll through it but you can control this behavior. </p>
<p>For example, to disable the pager for <code>git branch</code>:</p>
<pre><code class="language-bash">git config --global pager.branch false</code></pre>
<p>With this setting, all branches will print directly to the terminal.</p>
<h3>Rebase by Default</h3>
<p>If you prefer a clean, linear history, you might favor <code>git pull --rebase</code> over a merge commit every time you pull. You can make this the default:</p>
<pre><code class="language-bash">git config --global pull.rebase true</code></pre>
<p>This is a game-changer for many developers who love a tidy commit history.</p>
<div class="download-tower-framed">  <div class="download-tower-framed-info">  <h3>Not a Tower user yet?</h3>  <p>Download our 30-day free trial and experience a better way to work with Git!</p>  <div><a href="https://www.git-tower.com?utm_source=blog&amp;utm_medium=cta&amp;utm_content=post&amp;utm_campaign=the-ultimate-guide-to-git-config" target="_blank">Try Tower Now</a></div>  </div>  <div class="app-icon"><picture><source type="image/avif" srcset="https://www.git-tower.com/blog/assets/img/icons/downloads-modal-app-icon.avif"><img class="tower-icon" src="https://www.git-tower.com/blog/assets/img/icons/downloads-modal-app-icon.png" alt="Tower app icon"></source></picture></div></div>
<h2>4. More Powerful Features and Hidden Gems</h2>
<p>Now for the really fun stuff! These are some of the lesser-known settings that can solve common frustrations and make you look like a Git wizard.</p>
<ul>
<li>
<p><strong><code>--force-with-lease</code>: The Safer <a href="https://www.git-tower.com/blog/force-push-in-git">Force Push</a></strong>. You probably already know <code>git push --force</code> is dangerous. A safer alternative is <code>--force-with-lease</code>, which will fail if someone else has pushed to the branch in the meantime. Make it an easy-to-use alias:</p>
<pre><code class="language-ini">[alias]
  pf = push --force-with-lease</code></pre>
</li>
<li>
<p><strong>Better Diffs:</strong> You can tell Git to use a different algorithm for calculating diffs, which can sometimes produce more readable results.</p>
<pre><code class="language-ini">git config --global diff.algorithm patience</code></pre>
<p>These are the available algorithms:</p>
<ul>
<li>myers: The default algorithm (fast, but may produce confusing diffs).</li>
<li>patience: Slower, but often more human-readable.</li>
<li>minimal: Aims to generate the smallest possible diff.</li>
<li>histogram: An improvement over patience (faster, with similar quality).</li>
</ul>
</li>
<li>
<p><strong><code>blame.ignoreRevsFile</code>: Ignoring Formatting Commits:</strong> Ever run <code>git blame</code> only to find that a massive reformatting commit is "blamed" for every line? <a href="https://www.git-tower.com/blog/how-to-exclude-commits-from-git-blame">As explained in more detail here</a>, you can tell Git to ignore these commits! Create a file named <code>.git-blame-ignore-revs</code> with the commit hashes to ignore, and then run:</p>
<pre><code class="language-bash">git config blame.ignoreRevsFile .git-blame-ignore-revs</code></pre>
</li>
<li>
<p><strong><code>help.autocorrect</code>: For the Typo-Prone Developer:</strong> Do you ever type <code>git chekcout</code>? Git can automatically correct your typos and run the right command for you. In the example below, the value of 10 represents 10 deciseconds, which is equivalent to 1 second.</p>
<pre><code class="language-bash"># Waits 1 second (10 deciseconds) before running the corrected command
git config --global help.autocorrect 10</code></pre>
</li>
<li>
<p><strong><code>rerere</code>: Reuse Recorded Resolution:</strong> If you find yourself resolving the same merge conflicts over and over (especially in long-lived feature branches), <code>rerere</code> is your new best friend. <a href="https://www.git-tower.com/blog/5-advanced-git-features">It stands for &quot;Reuse Recorded Resolution&quot; and you can learn more about it in this blog post</a>.</p>
<pre><code class="language-bash">git config --global rerere.enabled true</code></pre>
<p>Once enabled, Git will remember how you resolved a conflict. The next time it sees the <em>exact same conflict</em>, it will resolve it for you automatically!</p>
</li>
</ul>
<h2>5. Performance Tuning for Large Repositories</h2>
<p>Working in a massive monorepo? Does <code>git status</code> take forever? These performance-oriented settings, many of which are covered in our <a href="https://www.git-tower.com/blog/git-performance">detailed guide to Git performance</a>, can make a world of difference.</p>
<ul>
<li>
<p><strong>The Commit Graph:</strong> This feature dramatically speeds up history-traversing operations like <code>git log</code>.</p>
<pre><code class="language-bash">git config --global core.commitGraph true
git config --global gc.writeCommitGraph true
git config --global fetch.writeCommitGraph true</code></pre>
</li>
<li>
<p><strong>Filesystem Monitor (<code>fsmonitor</code>):</strong> This is perhaps the biggest performance booster for large repos. It uses a background process to watch for file changes, making commands like <code>git status</code> nearly instantaneous.</p>
<pre><code class="language-bash">git config --global core.fsmonitor true</code></pre>
</li>
<li>
<p><strong>The Untracked Cache:</strong> Works with <code>fsmonitor</code> to speed up how Git finds new, untracked files.</p>
<pre><code class="language-bash">git config --global core.untrackedCache true</code></pre>
</li>
</ul>
<p>For more tips on repository performance, you should <em>really</em> consider reading <a href="https://www.git-tower.com/blog/git-performance">our in-depth article on the topic</a>.</p>
<h2>6. Security and Best Practices</h2>
<p>Finally, let's look at some settings that enhance security and help you manage different contexts.</p>
<ul>
<li>
<p><strong>Signing Your Commits:</strong> You can sign your commits with a GPG key or SSH to verify your identity. This is great for open-source work and corporate environments.</p>
<pre><code class="language-bash">git config --global user.signingkey &lt;YourGPGKeyID&gt;
git config --global commit.gpgSign true</code></pre>
</li>
<li>
<p><strong>Conditional Includes:</strong> This is one of the most powerful "hidden gems". <code>includeIf</code> lets you use different configurations based on the repository's path. This is perfect for managing work and personal projects.</p>
</li>
</ul>
<p>For example, you can use your work email for all repositories inside <code>~/work/</code>:</p>
<pre><code class="language-ini"># In ~/.gitconfig
[user]
    name = Bruno Brito (Personal)
    email = bruno.personal@gmail.com

[includeIf "gitdir:~/work/"]
    path = ~/.gitconfig-work</code></pre>
<p>Then, in <code>~/.gitconfig-work</code>:</p>
<pre><code class="language-ini">[user]
    name = Bruno Brito (Tower)
    email = bruno@git-tower.com</code></pre>
<p>Now, Git will automatically use the correct name and email depending on where your repository is located!</p>
<h3>A Recommended <code>.gitconfig</code> Template</h3>
<p>Feeling inspired? Here’s a template you can use as a starting point for your own awesome <code>.gitconfig</code>:</p>
<pre><code class="language-ini">[user]
    name = Your Name
    email = you@example.com

[init]
    defaultBranch = main

[core]
    editor = code --wait
    autocrlf = input
    fileMode = false
    fsmonitor = true
    untrackedCache = true

[color]
    ui = auto

[pull]
    rebase = true

[rerere]
    enabled = true

[help]
    autocorrect = 10

[alias]
    co = checkout
    ci = commit
    st = status
    br = branch
    lg = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all
    pf = push --force-with-lease

# Use work email for repos in the ~/work/ directory
[includeIf "gitdir:~/work/"]
    path = ~/.gitconfig-work</code></pre>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<h2>Final Words</h2>
<p>And there you have it! From simple aliases to powerful performance tuning, you're now equipped to create a Git configuration that works for you, not against you. </p>
<p>Don't be afraid to experiment and find the settings that best fit your workflow. A well-crafted <code>.gitconfig</code> is a sign of a true Git artisan! 😎</p>
<p>For more tips, don't forget to sign up for our newsletter below and follow Tower on <a href="https://x.com/gittower" rel="noopener noreferrer" target="_blank">Twitter</a> and <a href="https://www.linkedin.com/company/gittower" rel="noopener noreferrer" target="_blank">LinkedIn</a>!</p>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Join Over 100,000 Developers &amp; Designers</h2>    <p>Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Join Over 100,000 Developers &amp; Designers Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/the-ultimate-guide-to-git-config">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div><img src="https://feeds.git-tower.com/link/3463/17267049.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Tower 15 for Mac — Automatic Branch Management</title>
      <link>https://feeds.git-tower.com/link/3463/17199687/tower-mac-15</link>
      <guid>https://www.git-tower.com/blog/tower-mac-15</guid>
      <pubDate>Thu, 20 Nov 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>Tower 15 for Mac is here! This update introduces Automatic Branch Management, making it easier than ever to keep your repository tidy and clutter-free. We've also added significant improvements to the "History" view for better visualization of your work 😎</p> <p>If you’ve ever felt overwhelmed by a cluttered sidebar full of old, merged, or long-forgotten branches, this release is for you! We know that managing a growing number of branches can be a real headache, distracting you from your main task: committing great code.</p>
<p>Tower 15 takes the burden of branch hygiene off your shoulders, allowing you to automatically or manually archive branches that are no longer needed.</p>
<p>All right, let's dive into what's new!</p>
<p><strong>For a quick walkthrough of what's new, check out our 3-minute video tour below:</strong></p>
<div class="video-container"><iframe width="100%" height="315" src="https://www.youtube.com/embed/xTrxb2dJP8M?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
<h2>New "Fully Merged" and "Stale" Badges and Hint Views</h2>
<p>The first thing you will likely notice after updating Tower is a new set of badges in the "Branches" section of the sidebar.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/6719591692-1775825494/tom15-fully-merged-stale-badges.avif" type="image/avif"><img alt='Tower 15 – New "Fully Merged" and "Stale" badges' src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/b029333a88-1775825494/tom15-fully-merged-stale-badges.png"></source></picture><figcaption>Tower 15 – New "Fully Merged" and "Stale" badges</figcaption></figure>
<p><br /></p>
<p>You will see new badges next to branches indicating if they are <strong>"Fully Merged"</strong> (meaning all their commits have been integrated into a primary branch) or the time they were last updated when they became <strong>"Stale"</strong> (meaning they haven't seen any activity for a while).</p>
<p>These badges are complemented by a helpful hint view that appears when you select a fully merged or stale branch. This view provides a quick, one-click option to delete the branch, making the cleanup process a breeze!</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/ad4d9f161b-1775825494/tom15-fully-merged-hint-view.avif" type="image/avif"><img alt='Tower 15 – "Fully Merged" and "Stale" Badges with Hint View' src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/154abd191b-1775825494/tom15-fully-merged-hint-view.png"></source></picture><figcaption>Tower 15 – "Fully Merged" and "Stale" Hint Views for quick deletion</figcaption></figure>
<h2>Automatic Branch Management</h2>
<p>While deleting a stale or fully merged branch is often a good choice, sometimes all you want is to hide a branch from sight.</p>
<p>This is now possible with Tower 15 for Mac. You will notice a new "Archived Branches" view where you can:</p>
<ul>
<li>drag and drop any branch into this section.</li>
<li>add any branch to this section by clicking on the context menu.</li>
</ul>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/e672fcc205-1775825494/tom15-archive-branches-manually.mp4" type="video/mp4"></source></video><figcaption>Tower 15 – Archive Branches</figcaption></figure>
<p><br /></p>
<p>You can perform this process manually (you can even select multiple branches at once!) or allow Tower to automatically identify and handle them for you.</p>
<p>If you choose the latter, you have two options: either click on the notification number in the footer, as shown in the example below…</p>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/c0f93fa038-1775825494/tom15-archive-branches-automatically.mp4" type="video/mp4"></source></video><figcaption>Tower 15 – Automatically Archive Branches</figcaption></figure>
<p><br /></p>
<p>…or enable this option by going to the Settings. In the "General" tab, you will find a new option labeled "Automatically archive stale and fully merged branches."</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/b0f96c12e1-1775825494/tom15-automatically-archive-settings.avif" type="image/avif"><img alt="Tower 15 – Automatically Archive Branches in Tower's Settings" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/ab8454a4ee-1775825494/tom15-automatically-archive-settings.png"></source></picture><figcaption>Tower 15 – Automatically Archive Branches in Tower's Settings</figcaption></figure>
<p><br /></p>
<p>At any time, you can move a branch from the "Archived Branches" view back to the main "Branches" view by right-clicking on it and selecting the "Unarchive [BRANCH]" option.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/31853d00f6-1775825494/tom15-unarchive-branch.avif" type="image/avif"><img alt='Tower 15 – "Unarchive Branch" option' src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/74b18ac30d-1775825494/tom15-unarchive-branch.png"></source></picture><figcaption>Tower 15 – "Unarchive Branch" option</figcaption></figure>
<p><br /></p>
<p>As you can see in the screenshot above, we've also added a "Skips Auto-Archiving" flag that allows you to keep a branch and prevents it from being automatically archived. This will also be the case for branches that you have pinned.</p>
<h2>Fork Point: See What's Unique</h2>
<p>Tower 15 also introduces a key visualization enhancement to help you understand your branch structure instantly.</p>
<p>The "History" view now clearly shows the <strong>Fork Point</strong>, which is the exact commit where a branch diverged from its parent. Commits prior to this divergence will be shown grayed out.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/bac99b2552-1775825494/tom15-fork-point.avif" type="image/avif"><img alt='Tower 15 – New "Fork Point"' src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/babb025735-1775825494/tom15-fork-point.png"></source></picture><figcaption>Tower 15 – New "Fork Point"</figcaption></figure>
<p><br /></p>
<p>If there are no exclusive commits to a branch yet, this will also be easily noticeable by the "No new commits on this branch" message.</p>
<figure><img alt='Tower 15 – "No new commits on this branch" message' src="https://www.git-tower.com/blog/tom15-fork-point.png-no-new-commits"><figcaption>Tower 15 – "No new commits on this branch" message</figcaption></figure>
<p><br /></p>
<p>This visual improvement makes it much clearer to see exactly which commits were introduced by the branch you are currently viewing relative to its parent branch. No more guessing — just a clean, visual representation of your branch's scope.</p>
<h2>macOS 26 Tahoe Support</h2>
<p>As you know, we are always dedicated to offering the best experience on the Mac platform. We're happy to report that Tower 15 is fully compatible with the new operating system, <strong>macOS 26 Tahoe</strong>.</p>
<p>Here it is in all its glory!</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/777954a463-1775825494/tom15-tahoe.avif" type="image/avif"><img alt="Tower 15 in macOS 26 Tahoe" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/47dc56ba29-1775825494/tom15-tahoe.jpg"></source></picture><figcaption>Tower 15 in macOS 26 Tahoe</figcaption></figure>
<p><br /></p>
<p>With Tahoe, a new theming system has been implemented. This means Tower 15 now includes a set of shiny new icons!</p>
<p>To try them out, go to macOS's "System Settings &gt; Appearance" and have a look at the "Icon &amp; Widget style" section.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/03c01b0e5d-1775825494/tom15-new-icons-tahoe.avif" type="image/avif"><img alt="New Tower 15 icons in macOS 26 Tahoe" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/317edc717a-1775825494/tom15-new-icons-tahoe.png"></source></picture><figcaption>New Tower 15 icons in macOS 26 Tahoe</figcaption></figure>
<h2>Other Improvements</h2>
<p>As usual, we took some time to implement improvements across the board. We revamped the sidebar footer, which now features a collapsible filter field and allows you to choose from several view settings.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/778b90079d-1775825494/tom15-revamped-footer.avif" type="image/avif"><img alt="Tower 15 – Revamped Footer" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-15/fed06e9c69-1775825494/tom15-revamped-footer.jpg"></source></picture><figcaption>Tower 15 – Revamped Footer</figcaption></figure>
<p><br /></p>
<p>There is also a long list of other enhancements, most notably around the <strong>Pinned Branches</strong> feature to make it more robust and convenient:</p>
<ul>
<li><strong>Pinned Branches:</strong> Pinned branches are now stored in the Git config and should not unpin anymore, ensuring your favorites always stay put.</li>
<li><strong>Pinned Branches:</strong> You can now pin and unpin multiple branches at once, saving you time.</li>
<li><strong>Pinned Branches:</strong> The "Pinned Branches" section in the sidebar is now automatically expanded for quick access.</li>
<li><strong>Pinned Branches:</strong> Undoing a branch delete now correctly restores the pinned flag.</li>
<li><strong>Sorting:</strong> Text is now sorted in many views using a localized standard compare to match system behavior across your Mac.</li>
<li><strong>Commit Signing:</strong> Tower now correctly handles SSH keys without a comment.</li>
<li><strong>Settings:</strong> Ref related view settings have been moved into the View menu.</li>
</ul>
<p>We also fixed some bugs! Here is what we addressed:</p>
<ul>
<li><strong>Merge/Rebase:</strong> Tower could crash when using Quick Merge or Rebase. This has been fixed.</li>
<li><strong>History:</strong> A crash could occur when searching for whitespaces. This is fixed now.</li>
<li><strong>Worktrees:</strong> In some cases Tower could crash when accessing worktrees. It's working now.</li>
<li><strong>git-flow-next:</strong> Updating the workflow would crash in bare repositories. Not anymore.</li>
<li><strong>Working Copy:</strong> Some actions would crash when finishing, which is fixed now.</li>
<li><strong>Main Window:</strong> Tower could crash in certain cases when switching to a different repository in the same window. This has been fixed.</li>
<li><strong>Reset Revision:</strong> The text field did not allow entering arbitrary revisions anymore. It does allow them again now.</li>
<li><strong>Merge Conflict:</strong> The merge conflict wizard now allows resolving a "both deleted" conflict again.</li>
<li><strong>Merge Conflict:</strong> A crash has been fixed that sometimes occurred when a merge tool finished.</li>
</ul>
<p>We hope you enjoy this release! Happy committing! 😊</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>Not a Tower user yet? <strong>Download our 30-day free trial</strong> and experience a better way to work with Git!</p>
<p><br /></p>
<div style="text-align: center;"><a href="https://www.git-tower.com" class="button" target="_blank">Try Tower 15 Now</a></div>
<p><br /></p>
<p>PS: Did you know? Tower Pro is now <a href="https://www.git-tower.com/students" rel="noopener noreferrer" target="_blank">free for students</a> as well as <a href="https://www.git-tower.com/education" rel="noopener noreferrer" target="_blank">teachers and educational institutions!</a></p><img src="https://feeds.git-tower.com/link/3463/17199687.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Tower 10 for Windows — Introducing Graphite Support</title>
      <link>https://feeds.git-tower.com/link/3463/17202346/tower-windows-10</link>
      <guid>https://www.git-tower.com/blog/tower-windows-10</guid>
      <pubDate>Thu, 20 Nov 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>The wait is over: Tower 10 has arrived! For enthusiasts of Stacked Pull Requests, this release is a game-changer. We're excited to announce comprehensive support for <a href="https://graphite.dev" rel="noopener noreferrer" target="_blank">Graphite</a>, integrating its most powerful features directly into Tower. You can now handle your stacked branches and craft Pull Requests seamlessly within our Git client ✌️</p> <p>With our <a href="https://www.git-tower.com/blog/tower-windows-8">Tower 8.0  update</a>, we set the stage for incorporating advanced Git workflows. Features like Branch Dependency and the "Restack" action were introduced, and the response from our user community has been overwhelmingly positive.</p>
<p>Building on that foundation, Tower 10 now offers full support for Graphite's toolset, empowering you to merge changes into your projects faster than ever.</p>
<p>This article will guide you through the essentials of Graphite and how it integrates with Tower 10.</p>
<h2>About Graphite</h2>
<p>If you want to enhance your team's Pull Request process and are unfamiliar with <a href="https://www.git-tower.com/blog/graphite">Graphite</a>, you're in for a treat!</p>
<p>Graphite employs a stack-based methodology that allows developers to work on several features in parallel by layering changes. This is often called the <a href="https://www.git-tower.com/blog/stacked-prs">Stacked Pull Requests workflow</a>.</p>
<p>The idea is straightforward: by linking smaller, incremental Pull Requests, you reduce the amount of code to be reviewed. This leads to quicker integration and minimizes the chances of significant merge conflicts or bugs.</p>
<p>Effective branch management is key to this approach, and this is where Graphite excels. Even if you are the sole user of this workflow in your team, it works flawlessly from the get-go. There's every reason to give it a shot! 😉</p>
<p>Graphite not only simplifies branch management but also provides a dedicated interface for code reviews (be sure to check out <a href="https://graphite.dev/features/ai-reviews" rel="noopener noreferrer" target="_blank">AI Reviews</a>!) and complements GitHub by extending its functionality.</p>
<p>In addition to its Web UI, Graphite provides:</p>
<ul>
<li>A <a href="https://graphite.dev/docs/install-the-cli" rel="noopener noreferrer" target="_blank">CLI tool</a></li>
<li>A <a href="https://marketplace.visualstudio.com/items?itemName=Graphite.gti-vscode" rel="noopener noreferrer" target="_blank">VS Code extension</a></li>
</ul>
<p>You can <a href="https://www.git-tower.com/blog/graphite">discover more about Graphite in this article</a>. We believed that integrating these capabilities into a Git client would be a great advantage, so we went ahead and did just that.</p>
<p>Let's start the tour!</p>
<h2>Setting Up Graphite in Tower 10</h2>
<p>To begin, simply click the "Workflows" button in the toolbar and select the new Graphite.dev entry. You will need a <a href="https://graphite.dev/" target="_blank">Graphite.dev</a> account and the <a href="https://graphite.dev/docs/install-the-cli" target="_blank">Graphite CLI tool (version 1.5.3 or higher)</a> installed.</p>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/836d4ef1aa-1775825494/enable-graphite-workflow.mp4" type="video/mp4"></source></video><figcaption>Tower 10 – Enabling the Graphite Workflow</figcaption></figure>
<div class="framed-content"><p>☝️ You may find the "Configure Workflow" button grayed out if you haven't configured Graphite yet. <strong>Make sure you install the CLI tool and configure the Graphite token by accessing Tower's terminal ("File -&gt; Open in Terminal").</strong></p></div>
<p>You'll be asked to specify the "Trunk" branch (typically <code>main</code>) and your <a href="https://graphite.dev/docs/install-the-cli" rel="noopener noreferrer" target="_blank">Graphite token</a>, which should be detected automatically by Tower. We recommend installing the Graphite binary via <code>npm</code> , the standard package manager for Node.js.</p>
<p>You'll notice the "Workflows" icon has changed to Graphite. Clicking it gives you quick access to popular Graphite commands and opens the Graphite dashboard in your browser.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/a7e3083c17-1775825494/graphite-toolbar.avif" type="image/avif"><img alt="Tower 10 – Graphite Workflow in Toolbar" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/ac536bc355-1775825494/graphite-toolbar.png"></source></picture><figcaption>Tower 10 – Graphite Workflow in Toolbar</figcaption></figure>
<p><br /></p>
<h2>Working with Graphite in Tower 10</h2>
<p>Now is a great time to explore the Graphite commands you can run effortlessly in Tower!</p>
<h3>Working Copy</h3>
<p>With the Graphite workflow active, you'll see new options in the "Working Copy" view.</p>
<p>We've introduced a "Create" action that lets you instantly make a new branch with your staged changes (equivalent to <code>gt create</code> in the Graphite CLI). This is a best practice in the Graphite workflow, which recommends treating each branch as a small, atomic changeset with a single commit initially.</p>
<p>The "Commit" action is similar to the <code>gt modify --commit</code> command in Graphite: it adds a new commit to the current branch and automatically restacks if there are no conflicts.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/9bd4e9732d-1775825494/graphite-working-copy.avif" type="image/avif"><img alt='Tower 10 — "Working Copy" view' src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/850b5fd9b0-1775825494/graphite-working-copy.png"></source></picture><figcaption>Tower 10 — "Working Copy" view</figcaption></figure>
<div class="framed-content"><p>☝️ Tower's "Quick Amend" feature is also compatible with the Graphite workflow. To amend the current branch's commit, hold down (<span class="kbd-shortcut">Left Alt + CTRL</span>), and the "Commit" button will change to "Modify". This is the same as running <code>gt modify</code> in the Graphite CLI.</p></div>
<h3>Creating a Stacked Branch</h3>
<p>Graphite is centered around Stacked Branches, and creating a new one is simple: right-click on any branch to create a new stacked branch based on it.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/82ef0a967d-1775825494/graphite-create-new-stacked-branch.avif" type="image/avif"><img alt="Tower 10 — Create New Stacked Branch" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/c9b9f82eb0-1775825494/graphite-create-new-stacked-branch.png"></source></picture><figcaption>Tower 10 — Create New Stacked Branch</figcaption></figure>
<p><br /></p>
<p>In the following dialog, you can choose its parent branch for straightforward integration and opt to check it out right away.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/ea790b1652-1775825494/create-new-stacked-branch-options.avif" type="image/avif"><img alt="Tower 10 — Create New Stacked Branch Dialog" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/164f96c3f3-1775825494/create-new-stacked-branch-options.png"></source></picture><figcaption>Tower 10 — Create New Stacked Branch Dialog</figcaption></figure>
<p><br /></p>
<p>From the context menu, you can also perform all other standard Graphite operations, like renaming, merging, squashing, or deleting branches.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/a6d9e1851e-1775825494/graphite-context-menu-options.avif" type="image/avif"><img alt="Tower 10 – Additional Context Menu Options" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/64f4a16431-1775825494/graphite-context-menu-options.png"></source></picture><figcaption>Tower 10 – Additional Context Menu Options</figcaption></figure>
<h3>Setting the Parent Branch</h3>
<p>You can change a branch's parent at any time, just as you would with Stacked Branches, by using the context menu and selecting "Track Parent Branch."</p>
<p>In Graphite's terminology, this is known as "tracking" (<code>gt track</code>) and "untracking" (<code>gt untrack</code>) a stacked branch.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/5ac43defaa-1775825494/graphite-track-parent-branch.avif" type="image/avif"><img alt="Tower 10 – Setting the Parent Branch" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/754270501b-1775825494/graphite-track-parent-branch.png"></source></picture><figcaption>Tower 10 – Setting the Parent Branch</figcaption></figure>
<h3>Restacking</h3>
<p>Restacking syncs all changes by rebasing each child branch onto its parent. Tower shows an icon in the sidebar for branches that need restacking. You can perform this action by right-clicking the branch and choosing "Restack [Branch]".</p>
<p>In the branch's history, a yellow banner will also inform you that the branch needs to be restacked.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/f571de7d21-1775825494/tower-restack-branch.avif" type="image/avif"><img alt="Tower 10 — Restack Branch" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/0591a24842-1775825494/tower-restack-branch.png"></source></picture><figcaption>Tower 10 — Restack Branch</figcaption></figure>
<p><br /></p>
<p>In the "Restack Branch" dialog, you'll see a "Restack Full Stack" option. If this is not checked, Tower/Graphite will restack the selected branch and its parents. If checked, the branch's children will also be restacked (hence "full stack").</p>
<p>Tower will let you know if any conflicts occur during the restack.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/89d11be3c2-1775825494/graphite-restack-branch-dialog.avif" type="image/avif"><img alt="Tower 10 — Restack Branch Dialog" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/85ce0e6529-1775825494/graphite-restack-branch-dialog.png"></source></picture><figcaption>Tower 10 — Restack Branch Dialog</figcaption></figure>
<h3>Syncing a Branch</h3>
<p>Right-clicking any branch also lets you "sync" it. This synchronizes all branches in the stack, much like the <code>gt get</code> command.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/470bd63218-1775825494/graphite-sync-branch.avif" type="image/avif"><img alt="Tower 10 — Sync Branch Dialog" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/79a15dad46-1775825494/graphite-sync-branch.png"></source></picture><figcaption>Tower 10 — Sync Branch Dialog</figcaption></figure>
<p><br /></p>
<p>Tower also offers extra options, like restacking all branches in your repository.</p>
<h3>Submitting a Branch (To Create a Pull Request)</h3>
<p>You can submit a branch to create a PR by right-clicking it and selecting the option from the context menu.</p>
<p>More options are available by clicking the drop-down arrow, such as updating only branches with existing open PRs.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/c7d7d021f0-1775825494/graphite-submit-branch.avif" type="image/avif"><img alt="Tower 10 — Submit Branch to Graphite" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/366e996215-1775825494/graphite-submit-branch.png"></source></picture><figcaption>Tower 10 — Submit Branch to Graphite</figcaption></figure>
<p><br /></p>
<p>All open Pull Requests are accessible in Tower's "Pull Requests" view, in the sidebar or via the shortcut <span class="kbd-shortcut">CTRL + 4</span>.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/a50116ac05-1775825494/graphite-pull-requests.avif" type="image/avif"><img alt="Tower 10 — Pull Requests" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/d947ed2a83-1775825494/graphite-pull-requests.png"></source></picture><figcaption>Tower 10 — Pull Requests</figcaption></figure>
<p><br /></p>
<p>This view lets you inspect, merge, close, comment on, or check out pull requests without opening a browser.</p>
<h3>Merge Queue</h3>
<p>Graphite includes a <a href="https://graphite.dev/docs/graphite-merge-queue" rel="noopener noreferrer" target="_blank">Merge Queue</a> feature that avoids semantic merge conflicts by automating the rebase process during merges. This keeps the trunk branch "green" and helps development teams move faster with fewer interruptions.</p>
<p>In Tower, if a merge is possible, the Graphite branch is added to the merge queue. The merge is asynchronous, so you'll need to manually refresh and sync the branch to see if it has been merged.</p>
<p>When a Graphite branch is sent to the merge queue, it's validated remotely. If it can be merged, it is; otherwise, the process fails.</p>
<p>To do this, right-click the branch and choose "Add [BRANCH] to Merge Queue…" from Tower's context menu.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/659899a312-1775825494/graphite-merge-queue.avif" type="image/avif"><img alt="Tower 10 — Graphite's Merge Queue" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/5c1f8b004b-1775825494/graphite-merge-queue.png"></source></picture><figcaption>Tower 10 — Graphite's Merge Queue</figcaption></figure>
<h3>Warning Messages</h3>
<p>While using Tower, you might accidentally disrupt Graphite's state with certain Git operations, like a <code>git push</code>.</p>
<p>Tower will warn you when this might happen before you proceed.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/8963c15d0e-1775825494/graphite-warning-message.avif" type="image/avif"><img alt="Tower 10 — Warning Message" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/fab2d392f1-1775825494/graphite-warning-message.png"></source></picture><figcaption>Tower 10 — Warning Message</figcaption></figure>
<p><br /></p>
<p>You can enable or disable these prompts in the "Integration" tab of Tower's Settings.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/8fc17b0428-1775825494/tower-settings-integration.avif" type="image/avif"><img alt="Tower 10 — Integration Settings" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-10/a49335b0ea-1775825494/tower-settings-integration.png"></source></picture><figcaption>Tower 10 — Integration Settings</figcaption></figure>
<h2>Other Improvements</h2>
<p>As always, we've also made some other improvements under the hood.</p>
<p>Here's a list of the improvements and bug fixes we've addressed:</p>
<ul>
<li>System Menu: The <span class="kbd-shortcut">Alt + SPACE</span> shortcut now works as expected.</li>
<li>Submodules: Navigation through nested submodules has been refined.</li>
<li>Portable Git has been updated to version 2.51.2 for improved compatibility and performance.</li>
</ul>
<p>We hope you enjoy this release! Happy stacking! 😊</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>Not a Tower user yet? <strong>Download our 30-day free trial</strong> and see a better way to work with Git!</p>
<p><br /></p>
<div style="text-align: center;"><a href="https://www.git-tower.com" class="button" target="_blank">Try Tower 10 Now</a></div>
<p><br /><br />
PS: Did you know? Tower Pro is now <a href="https://www.git-tower.com/students" rel="noopener noreferrer" target="_blank">free for students</a> and <a href="https://www.git-tower.com/education" rel="noopener noreferrer" target="_blank">teachers and educational institutions!</a></p><img src="https://feeds.git-tower.com/link/3463/17202346.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Version Control in the Age of AI: The Complete Guide</title>
      <link>https://feeds.git-tower.com/link/3463/17217327/version-control-in-the-age-of-ai</link>
      <guid>https://www.git-tower.com/blog/version-control-in-the-age-of-ai</guid>
      <pubDate>Wed, 12 Nov 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>With the rise of AI coding assistants like Claude Code and Gemini CLI, our development workflows are changing at a rapid pace. These tools can be incredibly powerful, but they also introduce new challenges. How do we maintain a clean, understandable, and efficient version control history when a significant portion of our code is generated by AI?</p> <p>This article will provide a practical guide for developers to effectively use Git and version control in the age of AI. Whether you're a "vibe-coder" or a seasoned software engineer or web developer, we believe this guide can teach you something valuable to apply to your daily workflow.</p>
<p>We will first cover the fundamentals of Git and then explore some more advanced techniques, such as Git Worktrees, to help you maintain control of your project's advancements and keep your version control history clean and organized.</p>
<p>Along the way, we will also explain how <a href="https://www.git-tower.com">Tower, our Git client</a>, can assist you!</p>
<h2>The Importance of Creating Snapshots of Your Project</h2>
<p>When working with AI-generated code, it's easy to get carried away and end up with large, monolithic changes. This is where the discipline of creating frequent, small commits becomes your best friend.</p>
<p>Think of each commit as a snapshot of your work — a safety net that you can always go back to. If an AI-generated change introduces a bug or takes you down the wrong path, you can easily revert to a previous state. Tiny, atomic commits make it much easier to pinpoint where things went wrong.</p>
<p>In the upcoming chapters, we will explore a variety of techniques — both basic and advanced — that will help you keep track of your code developments.</p>
<h2>The Fundamentals of Git</h2>
<p>Let's start by revisiting some core Git best practices that are more important than ever in the age of AI: crafting effective commit messages and efficiently managing branches.</p>
<div class="framed-content"><p>☝️ If you're just getting started with Git, we recommend exploring our <a href="https://www.git-tower.com/learn">Learn section</a>, where you'll find a variety of free resources to help you become confident with version control, including ebooks and videos.</p></div>
<h3>Crafting the Perfect Commit Message</h3>
<p>A well-crafted commit message is a love letter to your future self and your teammates. When working with AI, it's crucial to explain the "why" behind a change, not just the "what". The AI can generate the code, but it can't (yet) understand the business context or the problem you're trying to solve.</p>
<p>A good commit message should be clear, concise, and descriptive. It should explain the intent behind the change and any trade-offs that were made.</p>
<p>This is such an important topic that <a href="https://www.git-tower.com/blog/how-to-write-the-perfect-commit-message">we have dedicated an entire article to it</a>!</p>
<h4>How Tower Can Help 🔥</h4>
<p>Tower has lots of features to help you create better commits. Here are some tips!</p>
<ol>
<li>While writing a commit in the "Working Copy" view, press <span class="kbd-shortcut">/</span> to easily reference files, commits, or even insert an emoji (<a href="https://www.git-tower.com/blog/gitmoji">Tower supports Gitmoji</a>). If you have a service account like GitHub connected, you can also easily address an issue.</li>
</ol>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/68c20459c6-1775825494/tower-commit-composing.mp4" type="video/mp4"></source></video><figcaption>Composing Commits in Tower</figcaption></figure>
<p><br /></p>
<ol start="2">
<li>If your team follows specific guidelines, adhering to <a href="https://www.git-tower.com/blog/tower-mac-11">commit templates</a> will make a lot of sense. The tip mentioned above allows you to follow a commit template, and you can also click the button next to the character counter to insert a template. To create, edit, or delete commit templates, visit the "Templates" tab in the Settings.</li>
</ol>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/14b1725f6a-1775825494/tower-create-commit-template.mp4" type="video/mp4"></source></video><figcaption>Managing Commit Templates in Tower</figcaption></figure>
<h3>Branching Strategies</h3>
<p>Feature branches are the cornerstone of a healthy Git workflow. They allow you to work on new features or bug fixes in isolation without affecting the main branch. This is especially important when experimenting with AI-generated code.</p>
<p>Create a new branch for each new task, and only merge it back into the main branch when you're confident that the code is working as expected.</p>
<h4>How Tower Can Help 🔥</h4>
<p>With its visualization capabilities, Tower lets you quickly explore any branch by viewing the list of branches in the sidebar. But a lot more can be achieved here!</p>
<ol>
<li>Tower is aware of the parent branch; therefore, if the <code>main</code> branch has received an update, you can quickly update your feature branch to incorporate the latest changes.</li>
</ol>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/df934b6c0f-1775825494/tom14-update-branch.avif" type="image/avif"><img alt="Tower's &quot;Update Branch&quot; feature" src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/a67f0775a5-1775825494/tom14-update-branch.png"></source></picture><figcaption>Tower's "Update Branch" feature</figcaption></figure>
<p><br /></p>
<ol start="2">
<li>The "Fork Point" feature in Tower will display the precise commit at which a branch split from its parent. Commits that occurred before this divergence will appear grayed out.</li>
</ol>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/27c711b5d2-1775825494/tom15-fork-point.avif" type="image/avif"><img alt="Tower's &quot;Fork Point&quot;" src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/837df06733-1775825494/tom15-fork-point.png"></source></picture><figcaption>Tower's "Fork Point"</figcaption></figure>
<p><br /></p>
<ol start="3">
<li>Our newly released <a href="https://www.git-tower.com/features/workflows">Tower Workflows feature</a> allows you to easily create new branches and merge/clean them up when you're finished. It was designed with flexibility in mind, enabling you to customize how the feature works to suit your needs.</li>
</ol>
<div class="video-container"><iframe width="100%" height="315" src="https://www.youtube.com/embed/WYhtxBAzOB0?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
<h2>Advanced Git Techniques for AI-Powered Development</h2>
<p>Now that we've covered the basics, let's explore some advanced Git techniques that are particularly well-suited for working with AI.</p>
<h3>Staging Chunks and Lines for Granular Commits</h3>
<p>AI-generated code often comes in large blocks. Instead of committing the entire block at once, it's a good practice to review the changes and stage them in smaller, logical chunks.</p>
<h4>How Tower Can Help 🔥</h4>
<p>Tower's "Changeset" view allows you to do just that. Instead of typing <code>git add -p</code> in the command line, you can stage individual lines or chunks of code with a single click.</p>
<p>This gives you granular control over what goes into each commit, helping you create those small, atomic commits we talked about earlier.</p>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/498649e879-1775825494/tower-single-line-staging.mp4" type="video/mp4"></source></video><figcaption>Tower's single-line staging feature</figcaption></figure>
<h3>Interactive Rebase for a Clean History</h3>
<p>AI assistants can sometimes be a bit "chatty," generating a lot of small, incremental changes. While this is great for experimentation, it can lead to a cluttered commit history.</p>
<p>This is where interactive rebase comes into play. Interactive rebase allows you to rewrite your commit history before merging a branch. You can reorder, squash, and edit commits to create a clean and logical history.</p>
<p>Before pushing your changes to the remote repository, it is always advisable to take some time to organize your commits — for your future self and your team!</p>
<p>Squashing is great if you prefer to move forward carefully in small steps. You can continuously add small commits labeled as "WIP" (Work in Progress) and then combine them all into a single commit when the feature is complete.</p>
<h4>How Tower Can Help 🔥</h4>
<p>Instead of using the command line (<code>git rebase -i</code>), Tower makes interactive rebase as easy as dragging and dropping:</p>
<ol>
<li>You can reorder commits by dragging them up or down in the "History" view. Tower's <a href="https://www.git-tower.com/features/drag-and-drop">drag and drop feature</a> is very capable!</li>
<li>You can edit commit messages or the content of the commits by right-clicking a commit and selecting "Edit commit message of [COMMIT]" or "Edit [COMMIT]," respectively.</li>
</ol>
<p>If you choose the latter option, Tower will check out that commit and allow you to make any desired changes, such as staging additional files or removing existing ones.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/9c243ea169-1775825494/tower-edit-commit.avif" type="image/avif"><img alt="Editing a Commit in Tower" src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/e2036db547-1775825494/tower-edit-commit.png"></source></picture><figcaption>Editing a Commit in Tower</figcaption></figure>
<p><br /></p>
<ol start="3">
<li>You can also simply drag one commit onto another to squash them together (hold <span class="kbd-shortcut">⌥</span> to fixup commits instead).</li>
</ol>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/28880a85fe-1775825494/tower-squash-fixup.mp4" type="video/mp4"></source></video><figcaption>Tower – Interactive Rebase with Drag and Drop</figcaption></figure>
<p><br /></p>
<p>And speaking of "fixup," you can also make amendments by typing <code>fixup!</code> followed by the appropriate commit in the commit message area. After that, you can access the branch view to use the "autofixup" feature.</p>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/6e3cfb90f5-1775825494/tower-fixup-auto.mp4" type="video/mp4"></source></video><figcaption>Tower – Autofixup</figcaption></figure>
<h3>Git Worktrees for Running AI Agents in Parallel</h3>
<p>In the AI coding landscape, it's common to work on multiple features in parallel with your preferred coding agent. If that describes you, then <a href="https://www.git-tower.com/learn/git/faq/git-worktree">Git worktrees</a> are the way to go! ✌️</p>
<p>A worktree is a separate working directory linked to your main repository. This allows you to have multiple branches checked out simultaneously, each in its own directory.</p>
<p>For example, you can have your main feature branch checked out in one worktree and a hotfix branch in another. You can switch between them seamlessly without needing to stash or commit your changes, making it ideal for running multiple AI coding agents simultaneously.</p>
<h4>How Tower Can Help 🔥</h4>
<p>In Tower, working with worktrees is a breeze. You can create a new worktree by right-clicking on any branch in the sidebar and selecting "Check out [BRANCH] in New Worktree...".</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/48adbb3d26-1775825494/create-new-worktree-context-menu.avif" type="image/avif"><img alt="Creating a New Worktree from a Branch" src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/3fa0afde1d-1775825494/create-new-worktree-context-menu.jpg"></source></picture><figcaption>Creating a New Worktree from a Branch</figcaption></figure>
<p><br /></p>
<p>The "Worktrees" section in the sidebar will help you keep track of all your worktrees.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/43cd9e2619-1775825494/tower-worktree-section.avif" type="image/avif"><img alt="Worktrees in Tower's Sidebar" src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/c2b7cf0d42-1775825494/tower-worktree-section.jpg"></source></picture><figcaption>Worktrees in Tower's Sidebar</figcaption></figure>
<h3>Stacked Branches for Incremental Work</h3>
<p>Stacked branches are useful for organizing incremental work with AI agents. For example, instead of creating multiple independent branches for a feature (such as the model and the UI), you can use stacked branches to easily update the dependent branch with any changes.</p>
<p>This approach also makes the final review process easier, aligning with its intended design. This is also known as the <a href="https://www.git-tower.com/blog/stacked-prs">Stacked Pull Requests workflow</a>.</p>
<h4>How Tower Can Help 🔥</h4>
<p>Tower allows you to create stacked branches from any branch by simply right-clicking on a branch and selecting the appropriate option from the context menu.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/ab3cfeaed0-1775825494/tower-create-new-stacked-branch.avif" type="image/avif"><img alt="Tower – Create New Stacked Branch" src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/2444652ff5-1775825494/tower-create-new-stacked-branch.png"></source></picture><figcaption>Tower – Create New Stacked Branch</figcaption></figure>
<p><br /></p>
<p>Since Tower tracks the parent branch, you will be prompted to restack the child branch whenever the parent undergoes changes, ensuring that they remain in sync. You will also be notified if any merge conflicts arise while integrating the new changes.</p>
<p>This even works if you are a <a href="https://www.git-tower.com/blog/graphite">Graphite</a> user.</p>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/version-control-in-the-age-of-ai/fc3783c879-1775825494/tower-restack-branch.mp4" type="video/mp4"></source></video><figcaption>Branch Restacking in Tower</figcaption></figure>
<h2>Conclusion</h2>
<p>AI is transforming the way we write software. With code generation now possible in seconds, having a clear understanding of your project's history is more important than ever.</p>
<p>By adopting the principles discussed — such as making frequent, atomic commits and utilizing advanced techniques like interactive rebase and Git Worktrees — you can make your version control system the most reliable component of your AI-powered workflow.</p>
<p>We hope you found this guide useful! For more Git tips and tricks, don't forget to sign up for our newsletter below and follow Tower on <a href="https://twitter.com/gittower" rel="noopener noreferrer" target="_blank">Twitter / X</a> and <a href="https://www.linkedin.com/company/gittower/" rel="noopener noreferrer" target="_blank">LinkedIn</a>! ✌️</p>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Join Over 100,000 Developers &amp; Designers</h2>    <p>Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Join Over 100,000 Developers &amp; Designers Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/version-control-in-the-age-of-ai">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div><img src="https://feeds.git-tower.com/link/3463/17217327.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>7 CLI Tools Every Developer Should Install</title>
      <link>https://feeds.git-tower.com/link/3463/17187634/7-cli-tools-every-developer-should-install</link>
      <guid>https://www.git-tower.com/blog/7-cli-tools-every-developer-should-install</guid>
      <pubDate>Wed, 15 Oct 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>In this post, we will have a look at 7 essential command-line tools that I believe every developer should consider adding to their arsenal. I will share why I think they're useful and provide some tips and commands to help you get the most out of them.</p> <p>All right, get your terminal ready and let's get right into it! 😎</p>
<div class="framed-content">In a hurry? Watch our brief <a href="https://youtube.com/shorts/_3hCuxhv3aQ?feature=share" target="_blank">2-minute vertical video</a> that introduces all the tools listed below.
  <div class="video-container"><iframe width="100%" height="315" src="https://www.youtube.com/embed/_3hCuxhv3aQ?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
</div>
<h2>1. btop: A Beautiful System Resource Monitor</h2>
<p>When you need to keep an eye on your system's performance, <a href="https://github.com/aristocratos/btop" rel="noopener noreferrer" target="_blank">btop</a> is my go-to tool. It's similar to programs like <code>htop</code> and <code>atop</code>, but in my opinion, it's much more pleasing to the eye!</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/4deeb0c163-1775825494/btop.avif" type="image/avif"><img alt="Btop - A Beautiful System Resource Monitor" src="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/9ea8a7e128-1775825494/btop.png"></source></picture><figcaption>Btop - A Beautiful System Resource Monitor</figcaption></figure>
<p><br /></p>
<p>Btop provides a comprehensive overview of your CPU, memory, disk I/O, network usage, and running processes. It is great to spot resource hogs, as it allows you to quickly sort processes by various metrics (CPU usage, memory usage, PID, etc.).</p>
<p>You can use the arrow keys to navigate between different sorting columns, such as memory or CPU, and then press <span class="kbd-shortcut">r</span> to sort them by that column. You can also filter a process by pressing <span class="kbd-shortcut">f</span> and then typing its name.</p>
<p>Btop comes bundled with dozens of themes as well! Just press <span class="kbd-shortcut">Esc</span> to access the options, where you can customize many visual aspects of the application.</p>
<h2>2. Ncdu: Your Disk Usage Detective</h2>
<p>Ever found yourself wondering where all your disk space went? <a href="https://dev.yorhel.nl/ncdu" rel="noopener noreferrer" target="_blank">Ncdu</a> is a really fast disk usage analyzer that will quickly pinpoint the culprits.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/6bd2058c2f-1775825494/ncdu.avif" type="image/avif"><img alt="Ncdu: Your Disk Usage Detective" src="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/42b09b991e-1775825494/ncdu.png"></source></picture><figcaption>Ncdu: Your Disk Usage Detective</figcaption></figure>
<p><br /></p>
<p>Ncdu scans your directories and presents a hierarchical view of disk usage, making it incredibly easy to identify large files and folders. More importantly, it allows you to delete unnecessary items directly from its interface, saving you precious disk space and time. This is particularly handy for cleaning up large <code>node_modules</code> folders, old logs, or forgotten project artifacts.</p>
<p>Navigating through directories is easy: just use the arrow keys to move up and down. When you find a file or directory to delete, simply press the <span class="kbd-shortcut">D</span> key. Keep in mind that Ncdu will ask for confirmation before deletion, but once it's gone, you won't find the files in the Trash!</p>
<p>BTW, you can exclude folders with many files to speed things up. Simply type <code>ncdu --exclude ~/Sites</code> to exclude the "Sites" directory, for example.</p>
<h2>3. fd: The Lightning-Fast File Finder</h2>
<p><code>find</code> is powerful, but <a href="https://github.com/sharkdp/fd" rel="noopener noreferrer" target="_blank">fd</a> is fast, user-friendly, and often exactly what you need. It's a simpler, quicker alternative for finding files in your filesystem.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/c1fab107d2-1775825494/fd.avif" type="image/avif"><img alt="fd: The Lightning-Fast File Finder" src="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/e9f0f16061-1775825494/fd.png"></source></picture><figcaption>fd: The Lightning-Fast File Finder</figcaption></figure>
<p><br /></p>
<p><code>fd</code> is designed for speed and convenience. You can run it from a high-level directory without waiting, making it perfect for large codebases or for quickly locating a file when you know its name, even partially, but have no idea which folder it is in.</p>
<p>You can easily filter by file type using the command: <code>fd --extension psd</code>. In this example, you will see a list of available Photoshop files.</p>
<h2>4. git-flow-next: Supercharging Your Git Workflow</h2>
<p>If you enjoy branching workflows like Gitflow, then <a href="https://git-flow.sh/" rel="noopener noreferrer" target="_blank">git-flow-next</a> is worth exploring. It is fully compatible with the original Gitflow but includes powerful features, such as the ability to:</p>
<ul>
<li>Create custom branching configurations from scratch.</li>
<li>Keep branches in sync with their parent branches by simply typing <code>git flow update</code>.</li>
</ul>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/5bd869942e-1775825494/git-flow-next.avif" type="image/avif"><img alt="git-flow-next: Supercharging Your Git Workflow" src="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/d9efe2f439-1775825494/git-flow-next.png"></source></picture><figcaption>git-flow-next: Supercharging Your Git Workflow</figcaption></figure>
<p><br /></p>
<p>Once you define your own branching configuration (or use a preset — you can choose between the classic Gitflow, GitHub Flow, and GitLab Flow and then customize them), you can quickly start and finish branches to integrate their changes and delete fully merged branches.</p>
<p>Oh, BTW: `git-flow-next is an open-source project <a href="https://www.git-tower.com/blog/git-flow-next">developed by the Tower team</a> 😉</p>
<h2>5. z: The Smart Directory Jumper</h2>
<p>Tired of typing out long paths to frequently accessed directories? <a href="https://github.com/rupa/z" rel="noopener noreferrer" target="_blank">z</a> is a brilliant tool that learns your habits and lets you jump to any directory with just a few keystrokes.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/b874e09eea-1775825494/z.avif" type="image/avif"><img alt="z: The Smart Directory Jumper" src="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/30d41646d3-1775825494/z.png"></source></picture><figcaption>z: The Smart Directory Jumper</figcaption></figure>
<p><br /></p>
<p><code>z</code> keeps track of the directories you visit most often (based on "frecency" - a combination of frequency and recency). Instead of typing <code>cd ~/projects/my-awesome-app/src/components</code>, you can simply type <code>z components</code> or <code>z my-awesome</code>. </p>
<p>It's a massive time-saver for anyone who navigates their filesystem frequently!</p>
<h2>6. Zellij: The Customizable Terminal Multiplexer</h2>
<p>In an age where AI assistants like Claude and Gemini CLI are often used directly in the terminal, a robust terminal multiplexer is non-negotiable. </p>
<p>Terminal multiplexers allow you to run multiple terminal sessions within a single window, detach from them, and reattach later. This means you can keep your development environment running even if you close your terminal or lose your SSH connection.</p>
<p>While <a href="https://github.com/tmux/tmux" rel="noopener noreferrer" target="_blank">tmux</a> is way more popular, <a href="https://zellij.dev" rel="noopener noreferrer" target="_blank">Zellij</a> offers a fantastic out-of-the-box experience with incredible customization. Zellij provides a clean, well-designed interface for managing panes and tabs, and its plugin system allows for powerful extensions.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/c2d6e75925-1775825494/zellij.avif" type="image/avif"><img alt="Zellij: The Customizable Terminal Multiplexer" src="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/573e045081-1775825494/zellij.png"></source></picture><figcaption>Zellij: The Customizable Terminal Multiplexer</figcaption></figure>
<p><br /></p>
<p>To get started, simply type <code>zellij -s your-saved-session</code> to create a new session. If you detach from the session, you can later resume it by typing <code>zellij attach your-saved-session</code>. </p>
<p>You can also view your entire list of sessions by typing <code>zellij list-sessions</code>.</p>
<h2>7. ASDF: The Universal Runtime Version Manager</h2>
<p>Managing multiple versions of Node.js, Python, Ruby, or any other runtime can be a headache. <a href="https://asdf-vm.com/">ASDF</a> simplifies this by providing a single, consistent interface for managing all your runtime versions.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/b35a3ddedb-1775825494/asdf.avif" type="image/avif"><img alt="ASDF: The Universal Runtime Version Manager" src="https://www.git-tower.com/blog/media/pages/posts/7-cli-tools-every-developer-should-install/e465775293-1775825494/asdf.png"></source></picture><figcaption>ASDF: The Universal Runtime Version Manager</figcaption></figure>
<p><br /></p>
<p>Instead of installing separate version managers (like <code>nvm</code> for Node.js, <code>rbenv</code> for Ruby, <code>pyenv</code> for Python), ASDF consolidates them all. You can easily switch between different versions globally or on a per-project basis, preventing conflicts and ensuring your projects run with the correct dependencies.</p>
<p>To get started, install a plugin (such as Node.js or Ruby) by typing, for example, <code>asdf plugin add nodejs</code>. Then, you can easily install a specific version of a runtime by typing something like <code>asdf install nodejs 22.14.0</code>.</p>
<p>To set a global default version for a runtime, type <code>asdf global &lt;plugin-name&gt; &lt;version&gt;</code>. For a project-specific version, type <code>asdf local &lt;plugin-name&gt; &lt;version&gt;</code> instead; a <code>.tool-versions</code> file will be created in your current directory.</p>
<p>Finally, you can type <code>asdf list</code> to see a list of all the installed versions for the runtimes of your choosing.</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>We hope you enjoyed this list of CLI tools! Once you take some time to familiarize yourself with them, I think your experience using the terminal will be much more enjoyable!</p>
<p>For more tips and tricks, be sure to sign up for our newsletter below and follow Tower on <a href="https://twitter.com/gittower" rel="noopener noreferrer" target="_blank">Twitter / X</a> and <a href="https://www.linkedin.com/company/gittower/" rel="noopener noreferrer" target="_blank">LinkedIn</a>! ✌️</p>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Join Over 100,000 Developers &amp; Designers</h2>    <p>Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Join Over 100,000 Developers &amp; Designers Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/7-cli-tools-every-developer-should-install">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div><img src="https://feeds.git-tower.com/link/3463/17187634.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>git-flow-next: The Next Iteration of Advanced Git Workflows</title>
      <link>https://feeds.git-tower.com/link/3463/17165838/git-flow-next</link>
      <guid>https://www.git-tower.com/blog/git-flow-next</guid>
      <pubDate>Thu, 18 Sep 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>Today, we're excited to introduce <a href="https://git-flow.sh/" rel="noopener noreferrer" target="_blank">git-flow-next</a>, a brand-new, open-source command-line tool that reimagines the popular <code>git-flow</code> model. It's designed to give you the agility and advanced capabilities needed for modern, demanding Git workflows.</p> <p>As the creators of <a href="https://www.git-tower.com">Tower</a>, we worked closely with a lot of teams using <code>git-flow</code>. We understood why it was so popular, but we couldn't ignore the friction and frustration it often caused.</p>
<p>Instead of merely working around these problems, we decided to address them directly. While developing the <a href="https://www.git-tower.com/blog/tower-mac-14">Tower 14 for Mac</a> release, which enables you to <a href="https://www.git-tower.com/blog/tower-mac-14">create custom branching workflows of any kind</a>, we considered whether we could extend similar functionality to CLI users.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/git-flow-next/dad85fab7b-1775825494/tower14-branch-workflow-configuration.avif" type="image/avif"><img alt="Tower 14 for Mac – Branch Workflow Configuration" src="https://www.git-tower.com/blog/media/pages/posts/git-flow-next/1e320b3665-1775825494/tower14-branch-workflow-configuration.png"></source></picture><figcaption>Tower 14 for Mac – Branch Workflow Configuration</figcaption></figure>
<p><br /></p>
<p>With <code>git-flow-next</code>, we're doing just that! We're giving back to the development community a tool that adapts to the Git workflow you're seeking – regardless of complexity and the level of flexibility you require.</p>
<p><strong>Here's a 5-minute video that will guide you through all the capabilities of git-flow-next:</strong></p>
<div class="video-container"><iframe width="100%" height="315" src="https://www.youtube.com/embed/AFBUnYj6YfA?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
<h2>Core Features</h2>
<p><code>git-flow-next</code> was built on top of the original <a href="https://nvie.com/posts/a-successful-git-branching-model/" rel="noopener noreferrer" target="_blank">git-flow</a> and <a href="https://github.com/petervanderdoes/gitflow-avh" rel="noopener noreferrer" target="_blank">gitflow-avh</a> projects (both of which are now discontinued), paving the way forward with a strong emphasis on improving the developer experience and making it much more customizable.</p>
<p>In short, our aim is to deliver a tool that is:</p>
<ul>
<li>Engineered for stability and flexibility.</li>
<li>Written in Go for exceptional speed and efficiency.</li>
<li>Fully compatible with your existing <code>git-flow</code> setups.</li>
<li>Able to provide clearer guidance through complex merges.</li>
<li>Designed to seamlessly integrate with today's diverse Git practices.</li>
</ul>
<p>That is the TL;DR version. Below is a more in-depth look at what makes it stand out.</p>
<h3>1. Written in Go for Better Performance</h3>
<p>At its heart, <code>git-flow-next</code> is a complete rebuild using <a href="https://go.dev/" rel="noopener noreferrer" target="_blank">Go</a>. This choice ensures exceptional reliability, resource efficiency, and provides a highly responsive experience.</p>
<p>Go's concurrent capabilities and strong type system contribute to a remarkably stable and predictable tool, while its efficient compilation delivers impressive performance.</p>
<p>This modern architecture guarantees <code>git-flow-next</code> can evolve alongside the dynamic world of software development and Git.</p>
<h3>2. Improved Conflict Resolution</h3>
<p>Merge conflicts are an unavoidable reality in collaborative projects.</p>
<p>While Git's core merge mechanism remains intact, <code>git-flow-next</code> offers more intuitive strategies and clear instructions during the resolution process, enabling teams to navigate merges with newfound confidence and minimal disruption.</p>
<h3>3. Your Workflow, Your Way</h3>
<p>Understanding that no two development teams are alike, <code>git-flow-next</code> offers unparalleled configuration flexibility. This is a big step compared to the conventional workflow imposed by the original git-flow model.</p>
<p>You can come up with your own branch naming conventions to match your team's preferences and current infrastructure. Beyond that, you can take control of merge strategies, fine-tuning how branches are integrated based on your project's unique needs.</p>
<p>This adaptability ensures <code>git-flow-next</code> fits perfectly into a wide spectrum of development workflows.</p>
<h3>4. Smooth Adoption</h3>
<p>Adopting new tools shouldn't force a complete overhaul. <code>git-flow-next</code> is meticulously crafted for full compatibility with your existing <code>git-flow</code> repositories.</p>
<p>You can effortlessly switch to <code>git-flow-next</code> without re-initializing repositories or disrupting your team's established processes. This backward compatibility guarantees a smooth adoption and empowers teams to incrementally embrace the advantages of <code>git-flow-next</code>.</p>
<h3>5. Clear Guidance Through Any Hurdle</h3>
<p>Not everyone is a Git nerd, and we're OK with that. <code>git-flow-next</code> prioritizes a frictionless developer experience by providing clear and actionable error messages.</p>
<p>When issues arise, the tool offers clear guidance and practical solutions for recovery, ensuring you spend less time troubleshooting and more time coding.</p>
<h2>Get Started… and Get Involved!</h2>
<p>We're incredibly enthusiastic about <code>git-flow-next</code> and believe it will become a great tool for developers seeking a modern, flexible approach to their Git workflows.</p>
<p>We encourage you to test it out and see for yourself! To get started, simply follow the <a href="https://git-flow.sh/docs/installation/" rel="noopener noreferrer" target="_blank">installation steps in the official documentation</a>.</p>
<p>As an open-source project, you can find the <code>git-flow-next</code> repository on <a href="https://github.com/gittower/git-flow-next/" rel="noopener noreferrer" target="_blank">GitHub</a>. We'd love to see you contribute and take this project even further!</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>To stay updated on the latest <code>git-flow-next</code> and Tower releases, be sure to sign up for our newsletter below and follow Tower on <a href="https://twitter.com/gittower" rel="noopener noreferrer" target="_blank">Twitter / X</a> and <a href="https://www.linkedin.com/company/gittower/" rel="noopener noreferrer" target="_blank">LinkedIn</a>! ✌️</p>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Join Over 100,000 Developers &amp; Designers</h2>    <p>Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Join Over 100,000 Developers &amp; Designers Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/git-flow-next">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div><img src="https://feeds.git-tower.com/link/3463/17165838.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Tower 14 for Mac — Custom Git Workflows</title>
      <link>https://feeds.git-tower.com/link/3463/17105667/tower-mac-14</link>
      <guid>https://www.git-tower.com/blog/tower-mac-14</guid>
      <pubDate>Tue, 19 Aug 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>Tower 14 for Mac is here! This update allows you to create custom Git workflows, enabling you to define and enforce the exact workflow that meets your project's needs.</p> <p>We have spoken with many teams and learned that most struggle to develop their own ideal Git workflows. As a result, they often end up adapting generic solutions or creating systems that are difficult for everyone to follow.</p>
<p>If that resonates with you, you will definitely love this release! Tower 14 for Mac puts you in the driver's seat, allowing you to define trunk, base, and topic branches, as well as set merge strategies and various other options.</p>
<p>Think of this as creating your own system — such as <code>git-flow</code> — but with limitless possibilities! 😎</p>
<p>All right, let's take a look at what's new – but first, let's recap why you should consider using a Git workflow if you don't have one already.</p>
<p><strong>For a quick walkthrough of what's new, check out our 5-minute video tour below:</strong></p>
<div class="video-container"><iframe width="100%" height="315" src="https://www.youtube.com/embed/WYhtxBAzOB0?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
<h2>Why Workflows Matter</h2>
<p>It is important to standardize your branching and merging practices so that you can create a <em>predictable</em> development environment. We feel this is key for a productive, enjoyable experience with Git, especially when collaborating with teams!</p>
<p>This standardization and predictability offer many advantages.</p>
<ol>
<li>Every team member can easily understand the repository's state and the purpose of each branch if you use clear naming conventions and well-defined merge behaviors.</li>
<li>New colleagues can quickly grasp the project's specific Git conventions, leading to quicker onboarding.</li>
<li>The entire team will become less prone to errors.</li>
</ol>
<p>Workflows can (and should!) be automated, making this process even more beneficial to everyone — and this is exactly where Tower 14 comes in.</p>
<h2>Setting Up a Custom Git Workflow</h2>
<p>The heart of Custom Git Workflows lies in its flexibility. You can create a workflow tailored to your project, team size, and development methodology. They can be as simple or complex as you'd like!</p>
<p>The magic begins by clicking on the "Workflows" icon, now conveniently located on the left-hand side next to the "Services" and "Bookmarks" views.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/b6b02b15ec-1775825494/tower14-workflows-icon-toolbar.avif" type="image/avif"><img alt='Tower 14 – "Workflows" icon in the Toolbar' src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/1cbff1be99-1775825494/tower14-workflows-icon-toolbar.png"></source></picture><figcaption>Tower 14 – "Workflows" icon in the Toolbar</figcaption></figure>
<p><br /></p>
<p>Here, you can set your preferred workflow by choosing from the following options:</p>
<ul>
<li>Predefined workflows, such as <code>git-flow</code> or GitHub/GitLab Flow.</li>
<li>Other workflows like Graphite or GitFlow CLI.</li>
<li>The option to create any custom Git workflow you can imagine from scratch.</li>
</ul>
<p>If your project already has a workflow in place, Tower will attempt to auto-detect it based on the existing branches.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/c3d327695b-1775825494/tower14-select-workflow.avif" type="image/avif"><img alt="Tower 14 – Select your Workflow" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/fab38b5de4-1775825494/tower14-select-workflow.png"></source></picture><figcaption>Tower 14 – Select your Workflow</figcaption></figure>
<p><br /></p>
<p>To understand the power of this feature, let's explore an existing workflow — we will use <code>git-flow</code>— and break down the extensive customization options available in Tower Workflows.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/ca6d666a0a-1775825494/tower14-branch-workflow-configuration.avif" type="image/avif"><img alt="Tower 14 — Branch Workflow Configuration" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/4b06ac845e-1775825494/tower14-branch-workflow-configuration.png"></source></picture><figcaption>Tower 14 — Branch Workflow Configuration</figcaption></figure>
<p><br /></p>
<p>Look at all those options! Let's explore what they can do.</p>
<p>The first step is to define your core branches, i.e., your "trunk" (e.g., <code>main</code>, <code>master</code>) and "base" (e.g., <code>develop</code>, <code>dev</code>) branches so that you can establish the foundational structure of your repository.</p>
<div class="framed-content"><p>☝️ If you want to learn more about "trunk", "base", and "topic" branches, we recommend reading <a href="https://www.git-tower.com/blog/base-topic-parent-branches">this article</a>.</p></div>
<p>Afterwards, you should define your "topic" branch types (e.g., <code>feature</code>, <code>hotfix</code>, <code>release</code>). For each topic branch type, you can set specific branch prefixes (e.g., <code>feature/</code>, <code>hotfix/</code>). This clarifies intent and ensures consistency across your team and can be used for automated checks and organization.</p>
<p>In the example below, we've added <code>bugfix</code> to our Workflow, which is not part of <code>git-flow</code> by default — a prime example of the customizability of this feature.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/f8861e037e-1775825494/tower14-topic-branch-configuration.avif" type="image/avif"><img alt="Tower 14 – Topic Branch Configuration" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/334ef7482f-1775825494/tower14-topic-branch-configuration.png"></source></picture><figcaption>Tower 14 – Topic Branch Configuration</figcaption></figure>
<p><br /></p>
<p>Next, you can take full control of how changes flow through your branches. You can now define distinct downstream merge strategies (merging the parent into your topic branch to keep it up to date) and upstream merge strategies (merging a branch into its parent to finalize topic branches).</p>
<p>Whether you prefer merge, rebase, or squash, Tower 14 lets you dictate the exact behavior for each merge scenario.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/75094829ac-1775825494/tower14-merge-strategy-configuration.avif" type="image/avif"><img alt="Tower 14 — Merge Strategy Configuration" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/9925e7d6cd-1775825494/tower14-merge-strategy-configuration.png"></source></picture><figcaption>Tower 14 — Merge Strategy Configuration</figcaption></figure>
<p><br /></p>
<p>When merging upstream, you can also create a tag, which can be useful for releases or significant milestones. This makes sure critical points in your project's history are always marked.</p>
<p>Finally, you have the option to create a merge commit when integrating branches, ensuring a complete and traceable record of all integrations. For those who prefer a cleaner, linear history, you can opt out.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/0505136941-1775825494/tower14-merge-commit-and-tag.avif" type="image/avif"><img alt="Tower 14 – Configuring Merge Commit and Tag Creation" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/6cefea96ea-1775825494/tower14-merge-commit-and-tag.png"></source></picture><figcaption>Tower 14 – Configuring Merge Commit and Tag Creation</figcaption></figure>
<h2>Starting and Finishing a Feature/Hotfix/…</h2>
<p>Once your workflow is configured, you can easily get started with your work by clicking the "Workflows" button and choosing the appropriate option.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/1555bf9591-1775825494/tower14-start-feature.avif" type="image/avif"><img alt='Tower 14 – "Start Feature"' src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/eb64f6c7db-1775825494/tower14-start-feature.png"></source></picture><figcaption>Tower 14 – "Start Feature"</figcaption></figure>
<p><br /></p>
<p>Once the task is complete, you can either click the "Workflows" button again to finish the feature, or access the branch's context menu by right-clicking the mouse.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/5789a7cf03-1775825494/tower14-finish-feature.avif" type="image/avif"><img alt='Tower 14 – "Finish Feature" in the Context Menu' src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/cb2906b960-1775825494/tower14-finish-feature.png"></source></picture><figcaption>Tower 14 – "Finish Feature" in the Context Menu</figcaption></figure>
<h2>Updating Branches</h2>
<p>While you are working on a new feature, it's normal for the parent branch to receive new commits from other team members. To minimize the chance of encountering merge conflicts, you should integrate those changes frequently.</p>
<p>We have good news here: this is very easy when using Tower ✌️</p>
<p>Since Tower establishes a parent/child relationship between branches, you will see a banner reminding you that you should update your child branches since there have been updates to the parent branch.</p>
<p>This feature is extremely useful for smoothly integrating your changes when you finish working on a feature or bug fix, so we recommend that you update your child branches often!</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/04727be33e-1775825494/tower14-update-branch.avif" type="image/avif"><img alt='Tower 14 – "Update Branch" notification' src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/236eaac302-1775825494/tower14-update-branch.png"></source></picture><figcaption>Tower 14 – "Update Branch" notification</figcaption></figure>
<p><br /></p>
<p>In the update process, Tower will always inform you if there are any merge conflicts that need to be resolved.</p>
<figure><img alt='Tower 14 – "Update Branch with Merge Conflicts" notification' src="https://www.git-tower.com/blog/tower14-update-branch.png-merge-conflicts"><figcaption>Tower 14 – "Update Branch with Merge Conflicts" notification</figcaption></figure>
<p><br /></p>
<p>You will also be notified of any conflicts in the "Update branch" dialog.</p>
<figure><img alt='Tower 14 – "Update Branch" dialog' src="https://www.git-tower.com/blog/tower14-update-branch.png-dialog"><figcaption>Tower 14 – "Update Branch" dialog</figcaption></figure>
<p><br /></p>
<p><strong>TIP:</strong> Don't forget to establish dependencies between branches so that child branches receive updates from their parent branches when changes occur. You can right-click any branch at any time and set a different "Upstream" or "Parent Branch" to track.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/f52d9d3e3f-1775825494/tower14-track-parent-branch.avif" type="image/avif"><img alt="Tower 14 – Track Parent Branch" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-14/2b4256c32e-1775825494/tower14-track-parent-branch.png"></source></picture><figcaption>Tower 14 – Track Parent Branch</figcaption></figure>
<p><br /></p>
<p>We hope you enjoy this release! Happy committing! 😊</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>Not a Tower user yet? <strong>Download our 30-day free trial</strong> and experience a better way to work with Git!</p>
<p><br /></p>
<div style="text-align: center;"><a href="https://www.git-tower.com" class="button" target="_blank">Try Tower 14 Now</a></div>
<p><br /><br />
PS: Did you know? Tower Pro is now <a href="https://www.git-tower.com/students" rel="noopener noreferrer" target="_blank">free for students</a> as well as <a href="https://www.git-tower.com/education" rel="noopener noreferrer" target="_blank">teachers and educational institutions!</a></p><img src="https://feeds.git-tower.com/link/3463/17105667.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Git Branching Explained: Base, Topic, and Parent Branches</title>
      <link>https://feeds.git-tower.com/link/3463/17105666/base-topic-parent-branches</link>
      <guid>https://www.git-tower.com/blog/base-topic-parent-branches</guid>
      <pubDate>Tue, 29 Jul 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>How do you integrate new features without breaking existing functionality? How do multiple developers work concurrently without conflicts? The answer lies in mastering Git's powerful branching capabilities.</p>
<p>Within Git's powerful arsenal, branches are its absolute superpower. They let you, and your team, work on new ideas, fix bugs, and experiment without causing chaos in your main codebase.</p> <p>In this post, we'll take a deep dive into core Git branching concepts, showcasing why they are absolutely indispensable for stress-free software development.</p>
<p>Let's jump right in by first identifying and distinguishing the key branch types, so you can clearly understand their role and value for any development team:</p>
<ol>
<li>Base Branches</li>
<li>Topic Branches</li>
<li>Parent Branches</li>
</ol>
<h2>1. The Foundation: Base Branches</h2>
<p>Imagine your project's main development path as the sturdy trunk of a tree, or the main highway in a bustling city. In Git, this is what we call a base branch.</p>
<p>A base branch is a long-lived, stable branch that represents the primary line of development for your project. You'll most commonly encounter branches named <code>main</code> (the modern default, replacing the older <code>master</code>) or <code>develop</code>. Think of it as the source of truth – the code that is either currently deployed to production, or is always in a deployable state.</p>
<p>You can have multiple base branches: a typical example is a development branch where work is done and then at some point merged into <code>main</code>, representing your production state that can be deployed.</p>
<div class="framed-content"><p>💡 <strong>In a nutshell</strong>: The "Base Branch" is the long-lived, stable branch (e.g., <code>main</code>, <code>develop</code>) from which new features or fixes originate. It's the "source of truth" for the project's current state.</p></div>
<p>The base branch serves as your project's unwavering foundation. It provides a consistent and reliable reference point for everyone on the team, ensuring that there's always a known good version of the code. This stability is crucial, as you don't want experimental or unfinished features breaking what's already working.</p>
<p>As the main line of work lives in your base branches, they serve as essential reference points for many functionalities that determine whether work has been integrated and whether it is safe to delete a topic branch. When using commands like <code>git branch --merged &lt;BRANCH&gt;</code> or <code>git branch --no-merged &lt;BRANCH&gt;</code>, it is important to run these for every base branch to gain an overview of which branches have been merged upstream and which have not.</p>
<p>In an upcoming version of Tower, this information will be used to automatically identify branches that have been merged.</p>
<h2>2. Feature Focus: Topic Branches</h2>
<p>Now, let's say you're building a new feature, such as a user authentication system, or maybe fixing a tricky bug. You definitely don't want to mess with the stable base branch while you're experimenting!</p>
<p>This is where topic branches come into play.</p>
<p>A topic branch is a short-lived branch that you create to work on a specific feature, bug fix, or experiment. When you type something like <code>git checkout -b new-auth-feature main</code>, you're essentially saying, "Hey Git, create a new branch called <code>new-auth-feature</code> based on the current state of <code>main</code>, and then switch me over to it!"</p>
<p>The lifecycle of a topic branch is straightforward: you create it, do your work, test it, and once it's complete and reviewed, you merge it back into your base branch. After the merge, the topic branch is typically deleted, keeping your repository tidy.</p>
<div class="framed-content"><p>💡 <strong>In a nutshell</strong>: If <code>main</code> is the main road, a topic branch is a temporary detour you take to work on something specific. Once you're done, you merge your changes back onto the main road.</p></div>
<p>Topic branches allow you to work on your changes in a completely isolated environment, which is clearly the main advantage of working this way. If your new feature introduces unexpected bugs or doesn't pan out as planned, it's contained within the topic branch. You can fix it there or simply discard the branch without ever affecting the stable <code>main</code> branch.</p>
<p>Topic branches also provide a sensible way to collaborate. Multiple developers can work on different features simultaneously, creating their own topic branches so they don't step on each other's toes. This approach also has its advantages when it's time to review the code before merging, often through creating pull requests. Your teammates can review your changes, offer feedback, and approve them before they become part of the main codebase.</p>
<p>As a bonus, this approach contributes to a clean project history, as your base branch maintains a clear, understandable, and linear history of integrated features rather than a jumbled mess of individual commits.</p>
<h2>3. The Lineage: Parent Branches</h2>
<p>Every branch has a history, and part of that history is its parent branch. Simply put, the parent branch is the branch from which another branch was created. It's the immediate ancestor, defining the starting point and initial state of the new branch.</p>
<p>Most often, when you create a topic branch like <code>feature/shopping-cart</code>, its parent branch will be your base branch, <code>main</code> or <code>develop</code>. The new <code>feature/shopping-cart</code> branch inherits all the commits and files that were present in <code>main</code> at the moment it was created.</p>
<div class="framed-content"><p>💡 <strong>In a nutshell</strong>:  The parent branch is the "origin" of a child branch. It's the branch whose history the new branch inherits at the moment of its creation.</p></div>
<p>This relationship determines which changes will be exclusive to your topic branch compared to its parent branch. With <a href="https://www.git-tower.com/blog/tower-mac-14">Tower 14 for Mac</a>, the parent branch is selected by default when using the "Compare" view, allowing you to see only the unique commits introduced by this feature branch.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/9aaf004feb-1775825494/tower14-branch-comparison.avif" type="image/avif"><img alt="Tower 14 — Branch Comparison" src="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/d126f708ea-1775825494/tower14-branch-comparison.png"></source></picture><figcaption>Tower 14 — Branch Comparison</figcaption></figure>
<p><br /></p>
<p>If you have multiple base branches, a base branch can also have another base branch as a parent. Consider our example from above (in the "Base Branches" section): your develop’s branch parent would be <code>main</code>, as work ultimately always flows upwards to your <code>main</code> branch. The other way around, if <code>main</code> would receive changes from e.g. hotfix branches, <code>develop</code> would need those changes from <code>main</code> in order to stay in sync.</p>
<p>Tower 14 makes it easy to stay uptodate with the new "Update Branch" action.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/ee4725c8a4-1775825494/tower14-update-branch.avif" type="image/avif"><img alt='Tower 14 — "Update Branch" Action' src="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/a02c6dca5d-1775825494/tower14-update-branch.png"></source></picture><figcaption>Tower 14 — "Update Branch" Action</figcaption></figure>
<p><br /></p>
<p>The parent branch is usually the branch that your topic branch will be merged back into, unless you are using stacked branches (see below). In that case, the stacked branch will ultimately be merged back into the trunk branch after all stacked parents have been merged.</p>
<h2>The Stacked Branches Workflow</h2>
<p>While a new branch typically sprouts directly from your base branch, sometimes your work is so extensive, or involves multiple interdependent logical changes, that it benefits from a more layered approach.</p>
<p>This is where <a href="https://www.git-tower.com/blog/stacked-prs">stacked branches, also known as &quot;stacked pull requests&quot;</a>, come into play.</p>
<p>These are a series of dependent topic branches. Instead of each new branch directly diverging from the base, they form a chain of dependencies.</p>
<p>It looks something like this:</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/432944663a-1775825494/stacked-branches-graph.avif" type="image/avif"><img alt="The Stacked Branches Workflow" src="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/7b1bdfd1c4-1775825494/stacked-branches-graph.png"></source></picture><figcaption>The Stacked Branches Workflow</figcaption></figure>
<p><br /></p>
<p>In this scenario:</p>
<ul>
<li><code>refactor-payment-gateway</code>'s parent is <code>main</code>.</li>
<li><code>implement-stripe-integration</code>'s parent is <code>refactor-payment-gateway</code>.</li>
<li><code>add-subscription-plans</code>'s parent is <code>implement-stripe-integration</code>.</li>
</ul>
<p>Each branch in the stack represents a distinct, logically isolated chunk of work, but they are built upon, and thus dependent on, the changes introduced in the "parent" branch below them in the stack.</p>
<h3>Stacked Branches: Pros and Cons</h3>
<p>Let's start with the good: Stacked Branches are a great solution when you're working on large features that can be overwhelming to review. By breaking them into a stack, each pull request (PR) for a branch in the stack is smaller and easier to understand, speeding up code reviews.</p>
<p>This allows for faster, uninterrupted development since you don't have to wait for the first part of a large feature to be reviewed and merged before starting work on related parts. This also enables you to ship parts of a larger feature incrementally, delivering value sooner.</p>
<p>Stacked branches can present some challenges, most notably the need for frequent rebasing to keep them up to date with the base branch. For this reason, additional tools are often recommended.</p>
<p>Good news — <a href="https://www.git-tower.com">Tower</a> not only supports Stacked Branches but can do the restacking automatically for you! This was introduced in <a href="https://www.git-tower.com/blog/tower-mac-12">Tower 12 for Mac</a> and <a href="https://www.git-tower.com/blog/tower-windows-8">Tower 8 for Windows</a>.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/6317b14392-1775825494/tower12-restack-branch.avif" type="image/avif"><img alt="Restacking in Tower for Mac" src="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/bf49b01f58-1775825494/tower12-restack-branch.png"></source></picture><figcaption>Restacking in Tower for Mac</figcaption></figure>
<p><br /></p>
<p>Specialized tools like <a href="https://www.git-tower.com/blog/graphite">Graphite</a> can simplify the management of stacked pull requests. <a href="https://www.git-tower.com/blog/tower-mac-13">Tower is the only Git client with Graphite support</a>, allowing for Stacked PR management without the need of using the Graphite CLI or the browser.</p>
<p>You can learn all about this integration in the 5-minute video below:</p>
<div class="video-container"><iframe width="100%" height="315" src="https://www.youtube.com/embed/2hjLn9mq9fY?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
<h2>Best Practices for Branching</h2>
<p>To maximize the benefits of branching, we would like to share some advice with you, along with some helpful Tower tips!</p>
<ul>
<li>
<p><strong>Keep Topic Branches small:</strong> Focus each topic branch on a single, logical change. Smaller branches are easier to review and manage.</p>
</li>
<li>
<p><strong>Descriptive naming is recommended:</strong> Make an effort to use meaningful names for your branches, such as <code>feature/user-profile-edits</code>, <code>bugfix/login-form-validation</code>, or <code>hotfix/critical-api-issue</code>.</p>
</li>
<li>
<p><strong>Merge or Rebase frequently:</strong> Regularly update your topic branch with the latest changes from its parent (usually the base branch) to minimize complex merge conflicts later on.</p>
</li>
</ul>
<p>With Tower, merging is as simply as dragging and dropping!</p>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/9dcbb98885-1775825494/tower-merge-drag-and-drop.mp4" type="video/mp4"></source></video><figcaption>Merging a branch in Tower with Drag and Drop</figcaption></figure>
<p><br /></p>
<p>Keeping topic branches up to date has become even easier with the release of <a href="https://www.git-tower.com/blog/tower-mac-14">Tower 14 for Mac</a>. By setting up parent/child relationships, Tower will notify you whenever your branch needs updating; When this occurs, you can simply click the "Update Branch" action instead of manually merging or rebasing branches.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/7328fd65d8-1775825494/tower14-track-parent-branch.avif" type="image/avif"><img alt="Tower 14 – Track Parent Branch" src="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/c3b5fb41b0-1775825494/tower14-track-parent-branch.png"></source></picture><figcaption>Tower 14 – Track Parent Branch</figcaption></figure>
<p><br /></p>
<ul>
<li><strong>Always use pull requests for code review and integration:</strong> This ensures a thorough review process before changes hit the base branch.</li>
</ul>
<p>With Tower, you can create a pull request by simply dragging and dropping the desired branch onto the "Pull Requests" workspace view.</p>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/023b48a629-1775825494/tower-create-pr-drag-and-drop.mp4" type="video/mp4"></source></video><figcaption>Creating a pull request in Tower with Drag and Drop</figcaption></figure>
<p><br /></p>
<p>And if you are an adopter of the Stacked Branches workflow, remember to always restack to keep your branches in sync by restacking often.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/770bfe59ff-1775825494/graphite-restack-branch-dialog.avif" type="image/avif"><img alt="Tower 13 for Mac — Restack Branch Dialog" src="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/fc927c2631-1775825494/graphite-restack-branch-dialog.png"></source></picture><figcaption>Tower 13 for Mac — Restack Branch Dialog</figcaption></figure>
<p><br /></p>
<ul>
<li><strong>Delete branches after merging:</strong> Once a topic branch is merged into your base branch, delete it from your local and remote repositories to keep things clean.</li>
</ul>
<p>In Tower's "Branches Review" view, you can filter by "Fully Merged" to pinpoint the branches that can be removed without hesitation.</p>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/base-topic-parent-branches/3d5f0a77b6-1775825494/tower-clean-up-branches.mp4" type="video/mp4"></source></video><figcaption>Cleaning up fully merged branches in Tower</figcaption></figure>
<h2>Final Words</h2>
<p>By embracing the foundational stability of your Base Branch, the focused isolation of Topic Branches, and the logical structure provided by Parent Branches (even in complex stacked scenarios), you are setting yourself and your team up for safe experimentation, parallel feature development, and clear code reviews.</p>
<p>Follow these guidelines and our branching best practices to enjoy a development workflow that is more efficient, less stressful, and ultimately more productive.</p>
<p>For more Git tips and tricks, don't forget to sign up for our newsletter below and follow Tower on <a href="https://twitter.com/gittower" rel="noopener noreferrer" target="_blank">Twitter / X</a> and <a href="https://www.linkedin.com/company/gittower/" rel="noopener noreferrer" target="_blank">LinkedIn</a>! ✌️</p>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Join Over 100,000 Developers &amp; Designers</h2>    <p>Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Join Over 100,000 Developers &amp; Designers Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/base-topic-parent-branches">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div><img src="https://feeds.git-tower.com/link/3463/17105666.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Tower 9.1 for Windows — Gitea and Gitmoji Support</title>
      <link>https://feeds.git-tower.com/link/3463/17062420/tower-windows-91</link>
      <guid>https://www.git-tower.com/blog/tower-windows-91</guid>
      <pubDate>Tue, 01 Jul 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>With the release of Tower 9.1 for Windows, we're bringing the power of <a href="https://gitea.com/" rel="noopener noreferrer" target="_blank">Gitea</a> directly to our Git client! This means that you can now add your Gitea accounts and manage your precious repositories and pull requests without ever leaving Tower 😊</p>
<p>Gitea isn't the only star of the show; this release also introduces support for Gitmoji, allowing you to create more meaningful and expressive commits!</p> <p>In an age where cloud services reign supreme, the idea of hosting your own code might seem a bit old-school. But for many, privacy, control, and performance are paramount. This is where self-hosted Git solutions truly shine, offering a robust alternative to public cloud providers. And among these, <a href="https://gitea.com/" rel="noopener noreferrer" target="_blank">Gitea</a> has emerged as a fantastic candidate.</p>
<p>Gitea is a lightweight, open-source, self-hosted Git service that provides everything you need for Git hosting, code review, team collaboration, and more, all within your own infrastructure.</p>
<p>This means complete control over your data, enhanced security, and, often, better performance tailored to your specific needs. It's also very popular among teams that simply want to avoid vendor lock-in.</p>
<div class="framed-content"><p>☝️ If you're new to Gitea, we have prepared a <a href="https://www.git-tower.com/blog/how-to-install-gitea">quick tutorial to help you get started with Gitea on a VPS</a> 😎</p></div>
<p>All right, let's see how you can add Gitea as a remote service to Tower and get started! <strong>If you prefer, you can also watch the 5-minute video tour below:</strong></p>
<div class="video-container"><iframe width="100%" height="315" src="https://www.youtube.com/embed/4pNRUz0bNIU?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
<h2>Adding a Gitea Account to Tower</h2>
<p>Getting your Gitea account set up in Tower is a breeze and it works like adding any other remote service, like GitHub, BitBucket, or GitLab.</p>
<p>To add a new Gitea service account, simply follow these steps:</p>
<ol>
<li>Navigate to the "Remote Services" view by clicking the cloud icon in the toolbar, selecting "View &gt; Show Services," or pressing <span class="kbd-shortcut">Alt + S</span>.</li>
</ol>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/377de051f1-1775825494/tower-services-toolbar.avif" type="image/avif"><img alt='Tower 9.1 for Windows — "Services" in the Toolbar' src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/830dab7963-1775825494/tower-services-toolbar.png"></source></picture><figcaption>Tower — "Services" in the Toolbar</figcaption></figure>
<p><br /></p>
<ol start="2">
<li>Click on the "Gitea" or "Gitea Self-Hosted" option in the Service Accounts list, or click the "+" button in the bottom-left corner to add a new Gitea account.</li>
</ol>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/069b7ee10c-1775825494/tower-gitea-service-accounts.avif" type="image/avif"><img alt='Tower 9.1 for Windows — "Gitea" and "Gitea Self-Hosted" options' src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/f9ecb5ad37-1775825494/tower-gitea-service-accounts.png"></source></picture><figcaption>Tower — "Gitea" and "Gitea Self-Hosted" options</figcaption></figure>
<p><br /></p>
<ol start="3">
<li>Tower will then prompt you for your Gitea instance URL and your credentials. Enter the full URL of your Gitea server (if self-hosted) and then provide your username and password (or better yet, a personal access token for more secure authentication).</li>
</ol>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/cc6730e943-1775825494/tower-add-gitea-account.avif" type="image/avif"><img alt="Tower 9.1 for Windows — Add Gitea Account" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/3cc6516e53-1775825494/tower-add-gitea-account.png"></source></picture><figcaption>Tower — Add Gitea Account</figcaption></figure>
<p><br /></p>
<ol start="4">
<li>Once you've entered your details, click "Add Account". Tower will verify your credentials; if successful, your Gitea account will appear in your Services list.</li>
</ol>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/7ce581cde7-1775825494/tower-gitea-repositories.avif" type="image/avif"><img alt="Tower 9.1 for Windows — Gitea Repositories" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/cf038b06fa-1775825494/tower-gitea-repositories.png"></source></picture><figcaption>Tower — Gitea Repositories</figcaption></figure>
<p><br /></p>
<p>And just like that, you're connected! All your Gitea repositories will now be accessible, ready for you to clone, fetch, and manage! 🎉</p>
<h2>Inspecting Gitea Pull Requests in Tower</h2>
<p>One of the most powerful features of Git is the ability to collaborate through pull requests. Gitea enables you to easily create pull requests directly in the browser, as shown below.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/c2417fff96-1775825494/gitea-pull-request-browser.avif" type="image/avif"><img alt="Creating a Pull Request in Gitea" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/f3dadd16f0-1775825494/gitea-pull-request-browser.png"></source></picture><figcaption>Creating a Pull Request in Gitea</figcaption></figure>
<p><br /></p>
<p>However, Tower allows you to seamlessly manage your Gitea pull requests, making code review and collaboration even more efficient — no need to open browser windows!</p>
<p>Once your Gitea account is added (as described in the previous chapter),  open any repository and navigate to the "Pull Requests" section in Tower's sidebar, found under the "Workspace" heading.</p>
<p>Tower will display a list of all open pull requests for that repository. You'll see key information such as the pull request title, author, and status.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/7a9e76df93-1775825494/tower-gitea-pull-request.avif" type="image/avif"><img alt="Tower — Gitea Pull Requests" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/d14aeb6eee-1775825494/tower-gitea-pull-request.png"></source></picture><figcaption>Tower — Gitea Pull Requests</figcaption></figure>
<p><br /></p>
<p>Click on any pull request in the list to open its detailed view. You will find 3 tabs:</p>
<ol>
<li><strong>Conversation</strong>: View comments from your team members and reply.</li>
<li><strong>Commits</strong>: Browse the commit history and inspect individual file changes.</li>
<li><strong>Changeset</strong>: View the full diff of changes.</li>
</ol>
<p>At the bottom, you will also have the option to check out, close, or merge the pull request, assuming you have the necessary permissions.</p>
<p>This functionality eliminates the constant context switching between your Git client and the Gitea web interface — it's all about staying in the flow 😎</p>
<h2>Gitmoji Support</h2>
<p><a href="https://github.com/carloscuesta/gitmoji" rel="noopener noreferrer" target="_blank">Gitmoji</a> is an open-source project that aims to standardize the use of emojis in commit messages. <a href="https://www.git-tower.com/blog/gitmoji">You can learn more about it in this blog post.</a></p>
<p>While you can manually enter the necessary emojis when creating a commit, the recommended method is to use the <a href="https://github.com/carloscuesta/gitmoji-cli" rel="noopener noreferrer" target="_blank">Gitmoji CLI tool</a> or… the latest release of Tower for Windows! 😎</p>
<p>Let's see it in action.</p>
<h3>Crafting a Commit with Gitmoji</h3>
<p>Tower supports Gitmoji without the need to install any additional tools. This feature was first introduced in <a href="https://www.git-tower.com/blog/gitmoji#getting-started-the-easy-way">Tower 10.5 for Mac</a> and is now also available on Tower for Windows.</p>
<p>To include emojis in your commit message, just type <span class="kbd-shortcut">::</span> in the "Commit Subject" field. A list of emojis will show up, along with descriptions of their meanings. You can also have a look at the <a href="https://gitmoji.dev" rel="noopener noreferrer" target="_blank">complete list of emojis available here</a>.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/da93c75b99-1775825494/tower-add-gitmoji.avif" type="image/avif"><img alt="Tower 9.1 for Windows — Add Gitmoji" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/980a16c5d2-1775825494/tower-add-gitmoji.jpg"></source></picture><figcaption>Tower 9.1 for Windows — Add Gitmoji</figcaption></figure>
<p><br /></p>
<p>Gitmoji is also available in our Commit Composing tools, which you can access by simply typing <span class="kbd-shortcut">/</span>.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/f5c4cae309-1775825494/gitmoji-commit-composing.avif" type="image/avif"><img alt="Tower 9.1 for Windows — Commit Composing with Gitmoji" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/bc25adeeca-1775825494/gitmoji-commit-composing.jpg"></source></picture><figcaption>Tower 9.1 for Windows — Commit Composing with Gitmoji</figcaption></figure>
<p><br /></p>
<p>That's it! As you can see, adding the right emoji to your commit messages is quite simple.</p>
<p>Tower will also display the emojis in any "History" view, as shown below.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/4cf22037d6-1775825494/gitmoji-history-view.avif" type="image/avif"><img alt="Tower 9.1 for Windows — History View with Gitmoji" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-91/6d8bdf110e-1775825494/gitmoji-history-view.jpg"></source></picture><figcaption>Tower 9.1 for Windows — History View with Gitmoji</figcaption></figure>
<h2>Other Improvements</h2>
<p>As is tradition, we've also addressed some other small improvements and bug fixes, such as:</p>
<ul>
<li><strong>LFS:</strong> Pulling LFS repositories now works as expected.</li>
<li><strong>Sidebar:</strong> Remote names are now accurately updated after renaming.</li>
<li><strong>Network Paths:</strong> Fixed a potential crash when handling network paths.</li>
<li><strong>Services:</strong> Enhanced logic for matching repositories to their configured services.</li>
<li><strong>UI:</strong> Increased separator visibility in Dark Mode and improved visualization of parent-child branch relationships.</li>
<li><strong>Portable Git:</strong> Updated to version 2.50.0 for improved compatibility and performance and upgraded the zip utility to support the latest compression formats.</li>
<li><strong>Shortcuts:</strong> Reassigned the <span class="kbd-shortcut">Ctrl + Shift + Backspace</span> shortcut to the "Reset" action and removed it from "Discard All Changes", ensuring more intuitive shortcut behavior.</li>
<li><strong>Stacked branches:</strong> Fixed an issue where the restack context menu item was incorrectly enabled, as well as an issue where, under certain conditions, the restack dialog validation could run indefinitely.</li>
</ul>
<p>For the complete changelog, please have a look at the <a href="https://www.git-tower.com/release-notes/windows?show_tab=release-notes">Release Notes</a>.</p>
<p>We hope you enjoy our latest Windows release. Happy committing! 😊</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>New to Tower? Download our 30-day free trial and discover a more efficient way to work with Git!</p>
<p><br /></p>
<div style="text-align: center;"><a href="https://www.git-tower.com" class="button" target="_blank">Try Tower 9.1 Now</a></div>
<p><br /><br />
PS: Did you know? Tower Pro is now <a href="https://www.git-tower.com/students" rel="noopener noreferrer" target="_blank">free for students</a> as well as <a href="https://www.git-tower.com/education" rel="noopener noreferrer" target="_blank">teachers and educational institutions!</a></p><img src="https://feeds.git-tower.com/link/3463/17062420.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>How to Install Gitea (with SQLite3 and HTTPS!) on a VPS</title>
      <link>https://feeds.git-tower.com/link/3463/17062419/how-to-install-gitea</link>
      <guid>https://www.git-tower.com/blog/how-to-install-gitea</guid>
      <pubDate>Tue, 24 Jun 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>Setting up your own Gitea instance on a VPS might sound daunting, but trust me, it's more straightforward than you think! By following this guide, you'll have your private Git server up and running in no time.</p> <p>This is quite a fun project that offers significant benefits! By the end of this tutorial, you will have unparalleled control over your source code, your data, and your team's collaboration workflow.</p>
<p>Here is the plan for today:</p>
<ul>
<li>Install Gitea on a VPS with a fresh Ubuntu 24.04 installation</li>
<li>Configure Gitea with SQLite 3</li>
<li>Set up HTTPS with Nginx and Let's Encrypt</li>
</ul>
<p>So, grab your terminal, pour yourself a cup of coffee, and let's get started on bringing your Git hosting in-house.</p>
<div class="framed-content"><p>📣 We are celebrating the <a href="https://www.git-tower.com/blog/tower-windows-91">Tower 9.1 for Windows release, which brings full Gitea support</a>. This means that you can now manage your repositories and pull requests directly in our Git client!</p></div>
<h2>Preparing Your VPS: The Groundwork</h2>
<p>Before we install Gitea, we need to ensure our VPS is ready. For this tutorial, we'll assume you're using a fresh Ubuntu 24.04 LTS instance, which is a popular and stable choice.</p>
<h3>1. Connect to Your VPS via SSH</h3>
<p>First things first: open your terminal and connect to your VPS. Replace <code>your_username</code> and <code>your_vps_ip</code> with your actual login details:</p>
<pre><code class="language-bash">ssh your_username@your_vps_ip</code></pre>
<p>If this is your first time connecting, you might be prompted to confirm the host's authenticity. Type <code>yes</code> and press Enter.</p>
<h3>2. Update Your System</h3>
<p>It's always a good practice to update your package lists and upgrade any existing packages to their latest versions:</p>
<pre><code class="language-bash">sudo apt update &amp;&amp; sudo apt upgrade -y</code></pre>
<h3>3. Install Required Dependencies</h3>
<p>Gitea requires Git, a database, and a few other packages. We'll use SQLite3 for simplicity in this tutorial, but for larger deployments, you might consider PostgreSQL or MySQL.</p>
<pre><code class="language-bash">sudo apt install git sqlite3 -y</code></pre>
<h3>4. Create a Git User for Gitea</h3>
<p>Gitea runs best under its own dedicated user. This enhances security by isolating the Gitea process.</p>
<pre><code class="language-bash">adduser \
   --system \
   --shell /bin/bash \
   --gecos 'Git Version Control' \
   --group \
   --disabled-password \
   --home /home/git \
   git</code></pre>
<p>This command creates a new system user named <code>git</code> with a home directory at <code>/home/git</code>.</p>
<h2>Installing Gitea</h2>
<p>Now that the groundwork is laid, let's get Gitea onto your server! We'll download the official binary, which is the easiest way to get up and running.</p>
<h3>1. Download the Gitea Binary</h3>
<p>First, please check the <a href="https://docs.gitea.com/installation/install-from-binary" rel="noopener noreferrer" target="_blank">official Gitea documentation</a> for the latest stable release. Look for the Linux AMD64 static binary. As of writing, the latest stable version is <code>1.23.8</code>.</p>
<pre><code class="language-bash">wget -O gitea https://dl.gitea.com/gitea/1.23.8/gitea-1.23.8-linux-amd64</code></pre>
<p>Now, we will make the binary executable and copy it to a more appropriate folder: <code>/usr/local/bin/gitea</code></p>
<pre><code class="language-bash">chmod +x gitea
cp gitea /usr/local/bin/gitea</code></pre>
<h3>2. Create Necessary Directories</h3>
<p>Gitea needs specific directories for its configuration, logs, and repositories.</p>
<pre><code class="language-bash">mkdir -p /var/lib/gitea/{custom,data,log}
chown -R git:git /var/lib/gitea/
chmod -R 750 /var/lib/gitea/
mkdir /etc/gitea
chown root:git /etc/gitea
chmod 770 /etc/gitea</code></pre>
<p>⚠️ Please note that <code>/etc/gitea</code> is temporarily set with write permissions so that the web installer can write the configuration file. After the installation is finished, we should change these permissions to read-only using:</p>
<pre><code class="language-bash">chmod 750 /etc/gitea
chmod 640 /etc/gitea/app.ini</code></pre>
<h3>3. Create a Systemd Service for Gitea</h3>
<p>Running Gitea as a <code>systemd</code> service ensures it starts automatically on boot and can be managed easily.</p>
<p>Create a new service file:</p>
<pre><code class="language-bash">sudo nano /etc/systemd/system/gitea.service</code></pre>
<p>Paste the following content into the file. Pay close attention to the <code>WorkingDirectory</code> and <code>ExecStart</code> paths:</p>
<pre><code class="language-ini">[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target network.target

[Service]
RestartSec=2s
Type=simple
User=git
Group=git
WorkingDirectory=/var/lib/gitea/
ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini
Restart=always
Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea

[Install]
WantedBy=multi-user.target</code></pre>
<p>Save and exit (<span class="kbd-shortcut">Ctrl + X</span>, <span class="kbd-shortcut">Y</span>, Enter).</p>
<h3>4.. Enable and Start the Gitea Service</h3>
<pre><code class="language-bash">sudo systemctl enable gitea
sudo systemctl start gitea
sudo systemctl status gitea</code></pre>
<p>You should see output indicating that the Gitea service is <code>active (running)</code>. If not, check the logs with <code>journalctl -u gitea</code>.</p>
<h2>Initial Gitea Configuration (Web Interface)</h2>
<p>Gitea is now running! You can access its web installer to complete the setup.</p>
<h3>1. Access the Web Installer</h3>
<p>By default, Gitea listens on port 3000. Open your web browser and navigate to <code>http://your_vps_ip:3000</code>.</p>
<p>You'll be greeted by the Gitea installation page. Feel free to review each field, but there's only one key setting that you should change: the Database type.</p>
<ul>
<li><strong>Database Type</strong>: SQLite3</li>
</ul>
<p>Click <strong>"Install Gitea"</strong>. This process will create the <code>app.ini</code> configuration file in <code>/etc/gitea</code>.</p>
<p>After the installation, it's time to register your first user, which will be the administrator account. Simply click on "Register Now" and enter a username, email address, and password.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/how-to-install-gitea/286fd2ff21-1775825494/gitea-user-registration.avif" type="image/avif"><img alt="Gitea – User Registration" src="https://www.git-tower.com/blog/media/pages/posts/how-to-install-gitea/e1ceb3b7c8-1775825494/gitea-user-registration.png"></source></picture><figcaption>Gitea – User Registration</figcaption></figure>
<p><br /></p>
<p>Success! You should now have access to the Gitea dashboard! 🎉</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/how-to-install-gitea/114b706a5c-1775825494/gitea-dashboard.avif" type="image/avif"><img alt="Gitea – Dashboard" src="https://www.git-tower.com/blog/media/pages/posts/how-to-install-gitea/3878f593f3-1775825494/gitea-dashboard.png"></source></picture><figcaption>Gitea – Dashboard</figcaption></figure>
<h2>Setting Up HTTPS with Nginx and Let's Encrypt</h2>
<p>Having Gitea running is great, but accessing it via <code>http://your_vps_ip:3000</code> isn't very secure or user-friendly. We want to access it via <code>https://gitea.mywebsite.com</code>. This requires a web server (Nginx) acting as a reverse proxy and an SSL certificate (from Let's Encrypt).</p>
<h3>1. Point Your Domain to Your VPS</h3>
<p>Before proceeding, make sure your domain's DNS records are set up. Create an A record for <code>gitea.mywebsite.com</code> that points to your VPS's public IP address. DNS changes can take some time to propagate.</p>
<h3>2. Install Nginx</h3>
<p>Nginx will be our web server that handles incoming requests on port 80 and 443 and forwards them to Gitea running on port 3000.</p>
<pre><code class="language-bash">sudo apt install nginx -y</code></pre>
<h3>3. Configure Nginx as a Reverse Proxy</h3>
<p>Create a new Nginx configuration file for your Gitea site:</p>
<pre><code class="language-bash">sudo nano /etc/nginx/sites-available/gitea.conf</code></pre>
<p>Paste the following configuration. Replace <code>gitea.mywebsite.com</code> with your actual domain.</p>
<pre><code class="language-ini">server {
    listen 80;
    server_name gitea.mywebsite.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}</code></pre>
<p>Save and exit.</p>
<h3>4. Enable the Nginx Site and Test Configuration</h3>
<p>Create a symbolic link to enable the site:</p>
<pre><code class="language-bash">sudo ln -s /etc/nginx/sites-available/gitea.conf /etc/nginx/sites-enabled/</code></pre>
<p>Test your Nginx configuration for syntax errors:</p>
<pre><code class="language-bash">sudo nginx -t</code></pre>
<p>If it reports "syntax is ok" and "test is successful", reload Nginx to apply the changes:</p>
<pre><code class="language-bash">sudo systemctl reload nginx</code></pre>
<p>Now, if you navigate to <code>http://gitea.mywebsite.com</code> (without the <code>:3000</code> port), you should see your Gitea instance!</p>
<h3>5. Install Certbot (for Let's Encrypt SSL)</h3>
<p>Time for SSL! Let's install Certbot, a tool that automates obtaining and renewing <a href="https://letsencrypt.org" rel="noopener noreferrer" target="_blank">Let&#039;s Encrypt</a> SSL certificates.</p>
<pre><code class="language-bash">sudo apt install certbot python3-certbot-nginx -y</code></pre>
<h3>6. Obtain and Install SSL Certificate</h3>
<p>Now run this command, once again replacing <code>gitea.mywebsite.com</code> with your own domain.</p>
<pre><code class="language-bash">sudo certbot --nginx -d gitea.selfhostfun.win</code></pre>
<p>Certbot will guide you through the process interactively. It will ask for your email and require you to agree to the terms of service.</p>
<p>Once that is done, Certbot will automatically modify your Nginx configuration to include the SSL certificates and force HTTPS.</p>
<h3>7. Update Gitea's Base URL in <code>app.ini</code></h3>
<p>Finally, we need to tell Gitea that it's now accessible via HTTPS. Edit Gitea's main configuration file:</p>
<pre><code class="language-bash">sudo nano /etc/gitea/app.ini</code></pre>
<p>Find the <code>[server]</code> section and change the <code>ROOT_URL</code> to your HTTPS domain:</p>
<pre><code class="language-ini">[server]
PROTOCOL = http
DOMAIN = gitea.mywebsite.com
ROOT_URL = https://gitea.mywebsite.com/
HTTP_PORT = 3000</code></pre>
<p><em>Note</em>: Keep <code>PROTOCOL = http</code> and <code>HTTP_PORT = 3000</code> because Nginx is handling the HTTPS part and forwarding to Gitea's internal HTTP port. The <code>ROOT_URL</code> is what Gitea uses for generating links internally.</p>
<p>Save and exit.</p>
<h3>8. Restart Gitea to Apply Changes</h3>
<pre><code class="language-bash">sudo systemctl restart gitea</code></pre>
<h2>All Done!</h2>
<p>Congratulations! You should now have your very own Gitea instance running securely on your VPS, accessible via <code>https://gitea.mywebsite.com</code>!</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/how-to-install-gitea/10dcc657e2-1775825494/gitea-installation-with-https.avif" type="image/avif"><img alt="Gitea — Installation Complete with HTTPS" src="https://www.git-tower.com/blog/media/pages/posts/how-to-install-gitea/eb53bb8837-1775825494/gitea-installation-with-https.png"></source></picture><figcaption>Gitea — Installation Complete with HTTPS</figcaption></figure>
<p><br /></p>
<p>You've taken full control of your Git hosting, providing a private, powerful, and efficient platform for your team's code collaboration. No more relying solely on public cloud services when you have the power to host your code exactly how you want it!</p>
<p>With your Gitea instance up and running, you can now seamlessly integrate it with <a href="https://www.git-tower.com/blog/tower-windows-91">Tower for Windows 9.1</a>, bringing all the power of your self-hosted Git repositories and pull requests right to your desktop 😎</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/how-to-install-gitea/0c800613a5-1775825494/tower-gitea-service-accounts.avif" type="image/avif"><img alt='Tower — "Gitea" and "Gitea Self-Hosted" options' src="https://www.git-tower.com/blog/media/pages/posts/how-to-install-gitea/2651f277e6-1775825494/tower-gitea-service-accounts.png"></source></picture><figcaption>Tower — "Gitea" and "Gitea Self-Hosted" options</figcaption></figure>
<p><br /></p>
<p>We hope you found this post helpful. For more Git tips and tricks, don't forget to sign up for our newsletter below and follow Tower on <a href="https://twitter.com/gittower" rel="noopener noreferrer" target="_blank">Twitter / X</a> and <a href="https://www.linkedin.com/company/gittower/" rel="noopener noreferrer" target="_blank">LinkedIn</a>! ✌️</p>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Join Over 100,000 Developers &amp; Designers</h2>    <p>Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Join Over 100,000 Developers &amp; Designers Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/how-to-install-gitea">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div><img src="https://feeds.git-tower.com/link/3463/17062419.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Tower 13 for Mac — Introducing Graphite Support</title>
      <link>https://feeds.git-tower.com/link/3463/17018237/tower-mac-13</link>
      <guid>https://www.git-tower.com/blog/tower-mac-13</guid>
      <pubDate>Tue, 24 Jun 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>Tower 13 is here! If you are a fan of Stacked Pull Requests, "13" is indeed your lucky number! This update introduces seamless <a href="https://graphite.dev" rel="noopener noreferrer" target="_blank">Graphite</a> support for all the most popular actions, allowing you to manage your stacked branches and create Pull Requests without ever leaving our Git client.</p> <p>Our <a href="https://www.git-tower.com/blog/tower-mac-12">previous major release</a> laid the groundwork for adding popular Git workflows by introducing Branch Dependency capabilities and the "Restack" action — and many Tower users have embraced this new workflow with open arms.</p>
<p>Now, Tower 13 takes full advantage of this foundation to support Graphite tooling, enabling you to integrate changes into your project at a rapid pace.</p>
<p>In this blog post, you will learn more about Graphite and its integration into Tower 13. <strong>If you prefer, you can also watch the 5-minute video tour below:</strong></p>
<div class="video-container"><iframe width="100%" height="315" src="https://www.youtube.com/embed/2hjLn9mq9fY?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
<h2>About Graphite</h2>
<p>If you're looking to improve the Pull Request approval process in your organization and haven't heard about <a href="https://graphite.dev" rel="noopener noreferrer" target="_blank">Graphite</a> yet, we think you're missing out!</p>
<p>Graphite provides a stack-based workflow that enables developers to work on multiple features simultaneously by stacking changes on top of each other. This approach is commonly referred to as the <a href="https://www.git-tower.com/blog/stacked-prs">Stacked Pull Requests workflow</a>.</p>
<p>The concept is simple: by chaining incremental Pull Requests, there is less code to review, leading to faster code integration and a reduced likelihood of introducing bugs or running into major merge conflicts.</p>
<p>For this approach to be successful, managing branches efficiently is paramount – and that's where Graphite shines! Even if you're the first (or only) person on your team to adopt this workflow, everything will work perfectly right away, so there's absolutely no reason not to give it a try 😉</p>
<p>In addition to effortless branch management, Graphite also provides its own interface for code reviews (check out <a href="https://diamond.graphite.dev" rel="noopener noreferrer" target="_blank">Diamond</a> — hot off the press!) and works alongside GitHub, enhancing its functionality.</p>
<p>Apart from the Web UI, Graphite also offers:</p>
<ul>
<li>A <a href="https://graphite.dev/docs/install-the-cli" rel="noopener noreferrer" target="_blank">CLI tool</a></li>
<li>A <a href="https://marketplace.visualstudio.com/items?itemName=Graphite.gti-vscode" rel="noopener noreferrer" target="_blank">VS Code extension</a></li>
</ul>
<p>You can <a href="https://www.git-tower.com/blog/graphite">learn more about Graphite in this blog post</a>. We thought it would be nice to integrate these features into a Git client, so we rolled up our sleeves and built just that.</p>
<p>Let's begin the guided tour!</p>
<h2>Working with Graphite in Tower 13</h2>
<p>To get started, click the "Workflow" button available in the toolbar and pick the new entry: Graphite.dev!</p>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/2b9ac46860-1775825494/enable-graphite-workflow.mp4" type="video/mp4"></source></video><figcaption>Tower 13 – Enabling the Graphite Workflow</figcaption></figure>
<p><br /></p>
<div class="framed-content"><p>☝️ Please note that you need to have a <a href="https://graphite.dev/" target="_blank">Graphite.dev</a> account and the <a href="https://graphite.dev/docs/install-the-cli" target="_blank">Graphite CLI tool installed (version 1.5.3 or higher)</a>.</p></div>
<p>You will then be prompted to define the "Trunk" branch (usually <code>main</code>) and enter your Graphite token (more info <a href="https://graphite.dev/docs/install-the-cli" rel="noopener noreferrer" target="_blank">here</a>) and the path to the Graphite binary.</p>
<p>We recommend installing the Graphite binary using <code>homebrew</code>, as Tower should automatically detect it. That said, Tower also supports detection via <code>npm</code> (the standard package manager for Node.js), so it should pick it up as well.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/172390a525-1775825494/graphite-configure-workflow.avif" type="image/avif"><img alt="Tower 13 — Configure Graphite Workflow" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/a5c1e875b0-1775825494/graphite-configure-workflow.png"></source></picture><figcaption>Tower 13 — Configure Graphite Workflow</figcaption></figure>
<p><br /></p>
<p>With everything set up, Tower will automatically load the branch information from Graphite by executing the command that CLI Graphite users recognize as <code>gt state</code> in the background.</p>
<p>You may have noticed that the "Workflow" icon has switched to Graphite. By clicking the button, you will be able to quickly access some of Graphite's most popular commands and open the Graphite dashboard in your browser.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/c3954dc432-1775825494/graphite-toolbar.avif" type="image/avif"><img alt="Tower 13 – Graphite Workflow in Toolbar" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/c291101d17-1775825494/graphite-toolbar.png"></source></picture><figcaption>Tower 13 – Graphite Workflow in Toolbar</figcaption></figure>
<p><br /></p>
<p>All right, this is the perfect time to explore the Graphite commands that you can effortlessly run in Tower!</p>
<h3>Working Copy</h3>
<p>With the Graphite workflow enabled, the first thing you will notice is that there are new options available in the "Working Copy" view.</p>
<p>We've added a new "Create" action that allows you to instantly create a new branch with the staged changes (the equivalent of <code>gt create</code> in Graphite's CLI tool). This is a good practice within the Graphite workflow, as it is recommended to treat each branch as an atomic changeset containing, at least initially, a single commit.</p>
<p>The "Commit" action functions like the <code>gt modify --commit</code> command in Graphite: it adds a new commit to the currently checked-out branch and automatically restacks if necessary, provided there are no conflicts.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/cafa6cf58d-1775825494/graphite-working-copy.avif" type="image/avif"><img alt='Tower 13 — "Working Copy" view' src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/42b13a8a3d-1775825494/graphite-working-copy.png"></source></picture><figcaption>Tower 13 — "Working Copy" view</figcaption></figure>
<div class="framed-content"><p>☝️ Tower's "Quick Amend" feature also works with the Graphite workflow. To modify the current branch by amending its commit, hold the Option key (<span class="kbd-shortcut">⌥</span>) and the "Commit" button will be renamed to "Modify". This is the equivalent of running <code>gt modify</code> in Graphite's CLI tool.</p></div>
<h3>Creating a Stacked Branch</h3>
<p>Graphite is all about Stacked Branches, and creating a new one couldn't be easier: just right-click on the "Branches" view in the sidebar to create a new stacked branch.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/6fe5727a09-1775825494/graphite-create-new-stacked-branch.avif" type="image/avif"><img alt="Tower 13 — Create New Stacked Branch" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/09664c6b00-1775825494/graphite-create-new-stacked-branch.png"></source></picture><figcaption>Tower 13 — Create New Stacked Branch</figcaption></figure>
<p><br /></p>
<p>In the next dialog, you can select its parent branch for easy integration and choose to pin it and/or check it out immediately.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/5b49019c25-1775825494/create-new-stacked-branch-options.avif" type="image/avif"><img alt="Tower 13 — Create New Stacked Branch Dialog" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/326d29849f-1775825494/create-new-stacked-branch-options.png"></source></picture><figcaption>Tower 13 — Create New Stacked Branch Dialog</figcaption></figure>
<h3>Managing Branches</h3>
<p>You can also create a new stacked branch by right-clicking on any branch and selecting the preferred option from the context menu.</p>
<p>Additionally, you can perform all other common Graphite operations, such as renaming, merging, squashing, or deleting branches.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/977b279b72-1775825494/graphite-context-menu.avif" type="image/avif"><img alt="Tower 13 – Graphite Commands in Context Menu" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/04960c935b-1775825494/graphite-context-menu.png"></source></picture><figcaption>Tower 13 – Graphite Commands in Context Menu</figcaption></figure>
<h3>Setting the Parent Branch</h3>
<p>At any moment, you can change the parent branch of a branch; this works in the same way as you would for Stacked Branches — by accessing the context menu and clicking on "Track Parent Branch."</p>
<p>In Graphite terminology, you may know this as "tracking" (<code>gt track</code>) and "untracking" (<code>gt untrack</code>) a stacked branch.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/462a5ce404-1775825494/tower-set-parent-branch.avif" type="image/avif"><img alt="Tower 13 – Setting the Parent Branch" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/399bc85ff2-1775825494/tower-set-parent-branch.png"></source></picture><figcaption>Tower 13 – Setting the Parent Branch</figcaption></figure>
<h3>Restacking</h3>
<p>Restacking synchronizes all changes by rebasing each child branch onto its parent branch. Tower will display an icon in the sidebar for the branches that require restacking, and you can easily perform this action by right-clicking the desired branch and selecting "Restack [Branch]".</p>
<p>In the branch's history view, you will also notice a yellow banner informing you that the branch needs restacking.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/7467fb82e2-1775825494/tower-restack-branch.avif" type="image/avif"><img alt="Tower 13 — Restack Branch" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/b63a877334-1775825494/tower-restack-branch.png"></source></picture><figcaption>Tower 13 — Restack Branch</figcaption></figure>
<p><br /></p>
<p>In the "Restack Branch" dialog, you will notice a "Restack Full Stack" option. If this option is not active, Tower/Graphite will restack the selected branch and all its parent branches. If the option is selected, the children of the branch will also be restacked (hence the name "full stack").</p>
<p>Tower will notify you of any conflicts that may arise during the restacking operation.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/2c38a1bbe1-1775825494/graphite-restack-branch-dialog.avif" type="image/avif"><img alt="Tower 13 — Restack Branch Dialog" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/b03a329d44-1775825494/graphite-restack-branch-dialog.png"></source></picture><figcaption>Tower 13 — Restack Branch Dialog</figcaption></figure>
<h3>Syncing a Branch</h3>
<p>Right-clicking any branch will also give you the option to "sync" it. As the name suggests, this will synchronize all the branches in the stack, similar to running the <code>gt get</code> command.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/05c6693333-1775825494/graphite-sync-branch.avif" type="image/avif"><img alt="Tower 13 — Sync Branch Dialog" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/41bc162b71-1775825494/graphite-sync-branch.png"></source></picture><figcaption>Tower 13 — Sync Branch Dialog</figcaption></figure>
<p><br /></p>
<p>Tower also provides you with additional options, such as the ability to restack all branches in your repository.</p>
<h3>Submitting a Branch (To Create a Pull Request)</h3>
<p>You can submit a branch (effectively creating a PR) by right-clicking the branch and choosing the appropriate option from the context menu.</p>
<p>You can access additional options by clicking the drop-down arrow, such as updating only the branches that already have open PRs.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/559127aadb-1775825494/graphite-submit-branch.avif" type="image/avif"><img alt="Tower 13 — Submit Branch to Graphite" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/cd2dd2f187-1775825494/graphite-submit-branch.png"></source></picture><figcaption>Tower 13 — Submit Branch to Graphite</figcaption></figure>
<p><br /></p>
<p>All available Pull Requests can be quickly accessed in Tower's "Pull Requests" view, located in the sidebar or by using the shortcut <span class="kbd-shortcut">⌘ + 4</span>.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/baface2550-1775825494/graphite-pull-requests.avif" type="image/avif"><img alt="Tower 13 — Pull Requests" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/e284da0504-1775825494/graphite-pull-requests.png"></source></picture><figcaption>Tower 13 — Pull Requests</figcaption></figure>
<p><br /></p>
<p>This view enables you to inspect, merge, close, comment on, or check out pull requests without the need to open a browser window.</p>
<h3>Merge Queue</h3>
<p>Graphite offers a <a href="https://graphite.dev/docs/graphite-merge-queue" rel="noopener noreferrer" target="_blank">Merge Queue</a> feature that prevents semantic merge conflicts by automating the rebase process during merges. This ensures that the trunk branch remains "green", allowing development teams to progress more quickly with fewer disruptions.</p>
<p>In Tower, if merging is possible, the Graphite branch is added to the merge queue. The merge is performed asynchronously, so be sure to manually refresh and sync the branch afterwards to check if it has been merged.</p>
<p>When a Graphite branch is submitted to the merge queue, it is validated remotely to determine if it can be merged. If merging is possible, it is merged; if not, the process fails.</p>
<p>To run this operation, simply right-click the branch and select "Add [BRANCH] to Merge Queue…" from Tower's context menu.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/7c8475bce5-1775825494/graphite-merge-queue.avif" type="image/avif"><img alt="Tower 13 — Graphite's Merge Queue" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/4fab7694b8-1775825494/graphite-merge-queue.png"></source></picture><figcaption>Tower 13 — Graphite's Merge Queue</figcaption></figure>
<h3>Warning Messages</h3>
<p>While using Tower, you may inadvertently disrupt Graphite's state by performing certain Git operations, such as a <code>git push</code>, shown below.</p>
<p>Tower will alert you whenever this situation may arise before you continue.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/dc526d3aa1-1775825494/graphite-warning-message.avif" type="image/avif"><img alt="Tower 13 — Warning Message" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/2f3e0503c7-1775825494/graphite-warning-message.png"></source></picture><figcaption>Tower 13 — Warning Message</figcaption></figure>
<p><br /></p>
<p>These prompts can be enabled and disabled by visiting the "Integration" tab in Tower's Settings.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/bf9c650c6b-1775825494/tower-settings-integration.avif" type="image/avif"><img alt="Tower 13 — Integration Settings" src="https://www.git-tower.com/blog/media/pages/posts/tower-mac-13/3fa11525fa-1775825494/tower-settings-integration.png"></source></picture><figcaption>Tower 13 — Integration Settings</figcaption></figure>
<h2>Other Improvements</h2>
<p>As usual, we have also taken the time to make some other enhancements behind the scenes.</p>
<p>Here is the list of improvements and bugs that we have worked on:</p>
<ul>
<li>Rounded Avatars: Tower now displays rounded avatars for authors and committers.</li>
<li>Working Copy: Tower could crash if a user profile referenced an invalid signing key. This has been fixed.</li>
<li>History View improvements: Enhanced commit loading performance with signature verification enabled. Fixed issues with scroll position reset and empty list display . Resolved high CPU usage problem caused by GPG key server interactions.</li>
</ul>
<p>We hope you enjoy this release! Happy stacking! 😊</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>Not a Tower user yet? <strong>Download our 30-day free trial</strong> and experience a better way to work with Git!</p>
<p><br /></p>
<div style="text-align: center;"><a href="https://www.git-tower.com" class="button" target="_blank">Try Tower 13 Now</a></div>
<p><br /><br />
PS: Did you know? Tower Pro is now <a href="https://www.git-tower.com/students" rel="noopener noreferrer" target="_blank">free for students</a> as well as <a href="https://www.git-tower.com/education" rel="noopener noreferrer" target="_blank">teachers and educational institutions!</a></p><img src="https://feeds.git-tower.com/link/3463/17018237.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Meet Graphite – The AI Developer Productivity Platform</title>
      <link>https://feeds.git-tower.com/link/3463/17019109/graphite</link>
      <guid>https://www.git-tower.com/blog/graphite</guid>
      <pubDate>Wed, 30 Apr 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>As developers, we love building things. What we don't enjoy as much is <em>waiting</em>: waiting for code reviews, getting blocked on merges, and the general friction that can sometimes slow down the development process.</p>
<p>If this resonates with you, then you'll want to hear about <a href="https://graphite.dev/" target="_blank" rel="noopener">Graphite</a>, a platform designed to tackle these very challenges head-on.</p> <p>Graphite positions itself as an AI developer productivity platform, aiming to help engineering teams create, review, and merge smaller code changes more efficiently, stay unblocked, and ultimately ship faster. </p>
<p>In this post, let's find out how Graphite can help you accomplish just that.</p>
<h2>Giving Time Back to Your Engineering Team</h2>
<p>The folks at Graphite understand a core pain point for many engineering teams: code review can be a significant time sink. In fact, they point out that many engineers spend a day or more each week either reviewing code or stuck waiting for their own reviews to come through. That's a substantial chunk of valuable engineering time!</p>
<p>But Graphite believes it doesn't have to be this way. The team behind Graphite has a strong background, with many founding members hailing from tech giants like Meta and Google. These companies have, in many cases, <a href="https://sback.it/publications/icse2018seip.pdf" rel="noopener noreferrer" target="_blank">developed their own internal code review tools</a> to optimize their engineers' workflows. The Graphite team missed the power of these internal systems, particularly the <a href="https://stacking.dev" rel="noopener noreferrer" target="_blank">stacked diffs workflow</a>, which they initially leveraged in an internal tool.</p>
<p>The internal tool proved so effective that the team decided to pivot and focus entirely on developing it into the platform we now know as Graphite. Their mission is to bring the power of stacked pull requests – the very workflow that underpins best-in-class internal code review tools like Phabricator and Critique – to every software company.</p>
<h2>Diamond – Embracing AI</h2>
<p>Beyond just stacked PRs, Graphite also recognized the potential of AI early on, culminating in the release of <a href="https://diamond.graphite.dev" rel="noopener noreferrer" target="_blank">Diamond</a> (formerly known as Graphite Reviewer).</p>
<p>As a codebase-aware AI code review companion, it provides developers with immediate, actionable feedback on their pull requests, significantly reducing the number of review cycles. While other AI bots hallucinate and create noisy comments, Diamond is calibrated to catch real bugs and deliver smarter, targeted feedback with fewer false positives.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/graphite/fb7f405850-1775825494/graphite-diamond.avif" type="image/avif"><img alt="Diamond – Agentic AI Code Review" src="https://www.git-tower.com/blog/media/pages/posts/graphite/f40ff28afa-1775825494/graphite-diamond.png"></source></picture><figcaption>Diamond – Agentic AI Code Review</figcaption></figure>
<p><br /></p>
<p>Diamond allows you to:</p>
<ul>
<li><strong>Merge PRs faster:</strong> Diamond automatically catches bugs and errors before human reviewers, letting your team spend less time on code review, and more time on building.</li>
<li><strong>Enforce quality &amp; consistency:</strong> Customize Diamond with repo-specific AI prompts and regex rules to enforce best practices across your entire team.</li>
<li><strong>Keep your code private &amp; secure:</strong> Diamond doesn't store or train on your team's code - your data remains yours.</li>
</ul>
<h2>The Results</h2>
<p>The impact of Graphite speaks for itself. Tens of thousands of engineers at leading companies like Asana, Ramp, Tecton, and Vercel rely on Graphite daily to improve their development workflows.</p>
<p>Across these companies and many others, the average engineer using Graphite has seen some impressive results:</p>
<ul>
<li><strong>1.3x's the number of PRs in flight:</strong> Engineers can manage and work on more changes concurrently.</li>
<li><strong>Saves ~10 hours a week waiting to merge PRs:</strong> Less time spent blocked means more time spent building.</li>
<li><strong>Merges 26% more PRs:</strong> A more efficient review process leads to a higher throughput of merged code.</li>
<li><strong>Ships 20% more code (despite decreasing median per-PR size by 8%):</strong> Smaller, more frequent merges contribute to a higher overall shipping velocity.</li>
</ul>
<p>These statistics highlight the tangible benefits that Graphite brings to engineering teams, translating directly into increased productivity and faster delivery cycles.</p>
<h2>A Comprehensive Toolkit</h2>
<p>Graphite isn't just about stacked PRs and AI; it's a comprehensive platform packed with features designed to streamline the entire software development lifecycle. </p>
<p>The platform includes:</p>
<ul>
<li>CLI tool: For seamless integration with your existing Git workflow and powerful control over stacked PRs.</li>
<li>AI Code Review Companion: Providing intelligent, automated feedback directly on your pull requests.</li>
<li>VS Code Extension: Bringing the power of Graphite directly into your code editor.</li>
<li>Pull Request Inbox: A centralized hub for managing and prioritizing code reviews.</li>
<li>Code Review Tool: Offering a focused and efficient interface for reviewing code changes.</li>
<li>Workflow Automation Engine: Allowing teams to customize and automate their code review and merge processes.</li>
<li>Merge Queue: Ensuring smooth and automated merging of pull requests once they're approved.</li>
<li>Developer Productivity Insights: Providing valuable data and analytics to help teams understand and improve their development process.</li>
</ul>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/graphite/86d769cf08-1775825494/graphite-developer-insights.avif" type="image/avif"><img alt="Graphite – Developer Insights" src="https://www.git-tower.com/blog/media/pages/posts/graphite/df1035d065-1775825494/graphite-developer-insights.png"></source></picture><figcaption>Graphite – Developer Insights</figcaption></figure>
<p><br /></p>
<p>All these components are thoughtfully designed to make the software development process as streamlined and effortless as possible.</p>
<h2>How to Get Started with Graphite</h2>
<p>Ready to experience the benefits of Graphite for yourself? The platform offers a free tier for small teams, making it easy to get started. Simply <a href="https://app.graphite.dev/signup" rel="noopener noreferrer" target="_blank">create your account</a> by signing up with your email or GitHub account.</p>
<p>Give Graphite a try and see how it can help your team unlock new levels of productivity and efficiency in your development workflow!</p><img src="https://feeds.git-tower.com/link/3463/17019109.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Celebrating 20 Years of Git: 20 Interesting Facts From its Creator</title>
      <link>https://feeds.git-tower.com/link/3463/17012174/git-turns-20</link>
      <guid>https://www.git-tower.com/blog/git-turns-20</guid>
      <pubDate>Thu, 17 Apr 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>On April 7, 2005, a seemingly simple tool emerged that would fundamentally reshape the landscape of software development. Git, created by Linus Torvalds, was initially designed to solve a very specific problem: managing Linux kernel development after the departure of BitKeeper.</p>
<p>While many in the tech world might be aware of the remarkable speed at which Git's core functionalities were conceived – famously within a mere 10 days – the full story behind its creation and evolution is rich with surprising details and fascinating insights.</p> <p>To celebrate this milestone, Linus was recently featured on <a href="https://www.youtube.com/@GitHub" rel="noopener noreferrer" target="_blank">GitHub&#039;s official YouTube channel</a> (you can watch the video below or <a href="https://github.blog/open-source/git/git-turns-20-a-qa-with-linus-torvalds" rel="noopener noreferrer" target="_blank">read the full interview with Taylor Blau</a>). We thought this would be a great opportunity to present this conversation to the Tower community.</p>
<p>In this insightful conversation, Torvalds reflects on:</p>
<ul>
<li>the origins of his groundbreaking project</li>
<li>his initial expectations (or lack thereof)</li>
<li>the key decisions that shaped Git into the ubiquitous version control system we know today.</li>
</ul>
<div class="video-container"><iframe width="560" height="315" src="https://www.youtube.com/embed/sCr_gb8rdEI?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
<p><br /></p>
<p>Join us as we celebrate two decades of Git by exploring these engaging tidbits straight from the mind of its legendary creator! </p>
<p>Here are 20 interesting (and fun) facts about the early days of Git.</p>
<p><em>The original transcript has been lightly edited for the purpose of this blog post.</em></p>
<h2>20 Facts About Git</h2>
<h3>1. Git was born out of necessity to solve a specific problem.</h3>
<p>Linus Torvalds didn't embark on creating Git with the goal of global domination in mind. His primary motivation was to solve his own immediate problem: the need for a better version control system for the Linux kernel development. He had a strong negative opinion of existing systems like CVS and even felt his initial, raw version of Git was already an improvement.</p>
<blockquote>
<p>"I saw it as a solution to my problems, and I obviously thought it was superior. Even literally 20 years ago to the day, I thought that first version, which was pretty raw — to be honest, even that version was superior to CVS."</p>
</blockquote>
<h3>2. The initial version of Git was developed in approximately 10 days.</h3>
<p>While the groundwork and conceptualization took longer, the intensive coding period to get a working version of Git for kernel use was remarkably short, highlighting Linus's deep understanding of the requirements.</p>
<blockquote>
<p>"It was actually fewer than — well, it was about 10 days until I could use it for the kernel, yes. But to be fair, the whole process started like December or November the year before, so 2004."</p>
</blockquote>
<h3>3. The reverse engineering of BitKeeper ultimately led to Linus creating Git.</h3>
<p>The commercial nature of BitKeeper and the restrictions it placed on reverse engineering caused friction within the open-source kernel community. When this led to the loss of free BitKeeper usage, Linus felt compelled to create an open-source alternative.</p>
<blockquote>
<p>"What did come up was that Tridge in Australia basically reverse engineered BitKeeper, which wasn’t that hard because BitKeeper internally was basically a good wrapper around SCCS, which goes back to the 60s. SCCS is almost worse than CVS. But that was explicitly against the license rules for BitKeeper. BitKeeper was like, you can use this for open source, but you can’t reverse engineer it. And you can’t try to clone BitKeeper. And that made for huge issues."</p>
</blockquote>
<h3>4. Linus spent about four months mentally planning the design of Git before writing the initial code.</h3>
<p>The ten-day coding sprint was preceded by a significant period of thinking through the problems he wanted to solve and how Git could improve upon existing systems without infringing on BitKeeper's licensing.</p>
<blockquote>
<p>"So by the time I started writing Git, I had actually been thinking about the issue for four months and thinking about what worked for me and thinking about “How do I do something that does even better than BitKeeper does but doesn’t do it the way BitKeeper does it?” I did not want to be in the situation where Larry would say, “Hey, you did the one thing you were not supposed to do.” So yes, the writing part was maybe 10 days until I started using Git for the kernel, but there was a lot of mental going over what the ideas should be."</p>
</blockquote>
<h3>5. For Linus, programming Git in userspace felt easier than dealing with the complexities of kernel development.</h3>
<p>Working on a userspace tool allowed Linus to focus on higher-level logic without the low-level memory management and hardware considerations inherent in kernel development.</p>
<blockquote>
<p>"And it was kind of interesting because it was — one of my reactions was how much easier it is to do programming in the userspace. There’s so much less you need to care about. You don’t need to worry about memory allocations. You don’t need to worry about a lot of things. And debugging is so much easier when you have all this infrastructure that you’re writing when you’re doing a kernel. So it was actually somewhat — I mean, I wouldn’t say relaxing, but it was fun to do something userspace-y where I had a fairly clear goal of what I wanted. I mean, a clear goal in the sense I knew the direction. I didn’t know the details."</p>
</blockquote>
<h3>6. A primary design goal for Git was performance, particularly in efficiently applying large series of patches.</h3>
<p>Linus wanted Git to handle the numerous patches involved in kernel development quickly, aiming for operations that wouldn't even require a coffee break.</p>
<blockquote>
<p>"But for me, one of the goals was that I could apply a patch series in basically half a minute, even when it was like 50, 100 patches. It’s one of those things where if things are just instant, some mistake happens, you see the result immediately and you just go on and you fix it. And some of the other projects I had been looking at took like half a minute per patch, which was not acceptable to me. And that was because the kernel is a very large project and a lot of these SCMs were not designed to be scalable."</p>
</blockquote>
<h3>7. The use of SHA-1 hashes in Git was primarily for detecting data corruption and ensuring stability, rather than for security purposes.</h3>
<p>While SHA-1 provides a level of cryptographic security, Linus's main concern was data integrity, learning from issues encountered with BitKeeper's approach to data protection.</p>
<blockquote>
<p>"And people kind of think that using the SHA-1 hashes was a huge mistake. But to me, SHA-1 hashes were never about the security. It was about finding corruption. Because we’d actually had some of that during the BitKeeper things, where BitKeeper used CRCs and MD5s, right, but didn’t use it for everything. So one of the early designs for me was absolutely everything was protected by a really good hash."</p>
</blockquote>
<h3>8. Git's low-level design is intentionally simple.</h3>
<p>Linus drew a parallel to Unix's design philosophy, where a few fundamental ideas underpin a powerful and versatile system.</p>
<blockquote>
<p>"Unix has like a core philosophy of everything is a process, everything is a file, you pipe things between things. And then the reality is it’s not actually simple. I mean, there’s the simple concepts that underlie the philosophy, but then all the details are very complicated. I think that’s what made me appreciate Unix in the first place. And I think Git has some of the same kind of, there’s a fundamental core simplicity to the design and then there’s the complexity of implementation."</p>
</blockquote>
<h3>9. Linus believes that the effort to support SHA-256 in addition to SHA-1 was largely a waste of time and resources, driven by unnecessary worry.</h3>
<p>While understanding the concerns, he felt there wasn't a genuine need for the dual-hashing approach and that it led to "pointless churn."</p>
<blockquote>
<p>"Well, I mean, SHA-1 I regret in the sense that I think it caused a lot of pointless churn with the whole “trying to support SHA-256 as well as SHA-1.” And I understand why it happened, but I do think it was mostly pointless. I don’t think there was a huge, real need for it, but people were worried, so it was short. So I think there’s a lot of wasted effort there."</p>
</blockquote>
<h3>10. During the initial development, Linus had a clear vision for the immediate steps but wasn't entirely certain about how all the pieces would ultimately fit together.</h3>
<p>While he quickly achieved the ability to apply patches, other core functionalities like merging took more time and he wasn't always sure he would reach his goals.</p>
<blockquote>
<p>"I had a clear idea of the initial stages but I wasn’t sure how it would work in the long run. So honestly, after the first week, I had something that was good for applying patches, but not so much for everything else. I had the basics for doing merges, and the data structures were in place for that, but it actually took, I think it took an additional week before I did my first merge. There were a number of things where I had kind of the big picture and result in mind, but I wasn’t sure if I’d get there."</p>
</blockquote>
<h3>11. The very first versions of Git were rudimentary because there was a more important project to prioritize.</h3>
<p>The initial focus was on getting the core functionality working for kernel development, with robustness and more advanced features added over time.</p>
<blockquote>
<p>"Yeah, the first steps, I mean the first week or two, I mean, you can go and look at the code — and people have — and it is not complicated code. I think the first version was 10,000 lines or something. You can more or less read it in a single sitting. Yeah, and it’s fairly straightforward and doesn’t do a lot of error checking and stuff like that. It’s really a, “Let’s get this working because I have another project that I consider to be more important that I need to get back to.” It really was."</p>
</blockquote>
<h3>12. Early Git usage involved direct manipulation of low-level "plumbing commands" and manual editing of files.</h3>
<p>Basic operations like committing required arcane sequences of commands that directly interacted with Git's underlying object store.</p>
<blockquote>
<p>"I mean, the first week when I was using it for the kernel, I was literally using the raw, what are now called “plumbing commands” by hand. Of course. Because there was no so-called porcelain. There was nothing above that to make it usable. So to make a commit, you’d do these very arcane things. Set your index, commit-tree. Yeah, commit-tree, write, and that just returns an SHA that you write by hand into the head file and that was it."</p>
</blockquote>
<h3>13. The <code>hash-object</code> command, fundamental for Git's content-addressable storage, was one of the earliest binary utilities Linus created.</h3>
<p>This allowed him to verify the core hashing mechanism by manually hashing data and checking the output.</p>
<blockquote>
<p>"I think that was one of the first binaries that I had where I could just check that I could hash everything by hand and it would return the hash to standard out, then you could do whatever you wanted to it."</p>
</blockquote>
<h3>14. The initial user interface "porcelain" for Git consisted of shell scripts written by Linus to wrap the difficult-to-use plumbing commands.</h3>
<p>Making Git accessible required building higher-level tools on top of the core commands. Linus's initial attempts were in the form of simple scripts, which weren't particularly user-friendly.</p>
<blockquote>
<p>"But it was like the early porcelain was me scripting shell scripts around these very hard-to-use things. And honestly, it wasn’t easy to use even with my shell scripts."</p>
</blockquote>
<h3>15. The first target audience for Git was the hardcore kernel developers who were already familiar with some of the concepts from using BitKeeper.</h3>
<p>Their prior experience with a more advanced VCS made them more receptive to Git's underlying ideas.</p>
<blockquote>
<p>"But to be fair, the first initial target audience for this were pretty hardcore kernel people who had been using BitKeeper. They at least knew a lot of the concepts I was aiming for. People picked it up."</p>
</blockquote>
<h3>16. Linus handed over the maintainership of Git to Junio Hamano relatively early in the project.</h3>
<p>After only three or four months of his own stewardship, Linus recognized the need to focus on the kernel and trusted Junio's capabilities to lead Git's further development.</p>
<blockquote>
<p>"I mean, to be honest, I maintained Git for like three or four months. I think I handed it off in August [of 2005] or something like that. And when I handed it off, I truly just handed it off. I was like, “I’m still around.” I was still reading the Git mailing list, which I don’t do anymore. Junio wanted to make sure that if he asked me anything, I’d be okay. But at the same time, I was like, this is not what I want to do."</p>
</blockquote>
<h3>17. Linus's criteria for choosing Junio as the maintainer was largely based on his "taste" in code.</h3>
<p>He valued Junio's judgment and his understanding of the project's direction.</p>
<blockquote>
<p>"But to be honest I’ll take credit for having worked with people on the internet for long enough that I was like — during the four months I was maintaining Git, I was pretty good at picking up who has got the good taste to be a good maintainer. That’s what it’s about — taste — for you. For me, it’s hard to describe. You can see it in patches, you can see it in how they react to other people’s code, “how they think” kind of things."</p>
</blockquote>
<h3>18. Git's distributed nature, where every repository is a full copy with complete history, was a key design principle.</h3>
<p>This architecture made local work and later sharing incredibly easy. It also differentiated it from most previous centralized version control systems and contributed to its widespread adoption.</p>
<blockquote>
<p>"So the distributed nature really ends up making so many things so easy and that was one big part that set Git apart from pretty much all SCMs before, was… I mean there had been distributed SCMs, but there had, as far as I know, never been something where it was like the number one design goal — I mean, along with the other number one design goals — where it means that you can work with Git purely locally and then later if you want to make it available in any other place it’s so easy. And that’s very different from, say, CVS where you have to set up this kind of repository and if you ever want to move it anywhere else it’s just very very painful and you can’t share it with somebody else without losing track of it."</p>
</blockquote>
<h3>19. Linus believes that Git's fundamental design, emphasizing easy copying and the equality of all repositories, made services like GitHub "trivial" at their core.</h3>
<p>The underlying architecture of Git facilitated the creation of centralized hosting platforms.</p>
<blockquote>
<p>"And the fact that Git didn’t do that, and very much by design didn’t do that, I mean that’s what made services like GitHub trivial. I mean I’m trivializing GitHub because I realized there’s a lot of work in making all the infrastructure around Git, but at the same time the basic Git hosting site is basically nothing because the whole design of Git is designed around making it easy to copy, and every repository is the same and equal."</p>
</blockquote>
<h3>20. Linus was amused by the initial wave of complaints about Git's user interface, particularly the naming of commands, as he sometimes deliberately chose different names than CVS simply because he disliked it.</h3>
<p>The transition from older systems led to confusion and criticism, but Linus had his own reasons for some of the seemingly arbitrary choices.</p>
<blockquote>
<p>"Oh, the complaints kept coming. Tell me about it. Oh, I mean, it’s more like I can’t point to details. You’d have to Google it. But the number of people who sent me, “Why does it do this?” And the flame wars over my choice of names. For example, I didn’t have git status, which actually is one of the commands I use fairly regularly now... So I just remember the first few years, the complaints about why the names of the subcommands are different for no good reason. And the main reason was I just didn’t like CVS very much, so I did things differently on purpose sometimes."</p>
</blockquote>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<h2>Final Words</h2>
<p>So there you have it: 20 interesting facts about the early days of Git!</p>
<p>Here at <a href="https://www.git-tower.com">Tower</a>, as passionate fans and dedicated users of Git ourselves, we join the global community in celebrating this remarkable 20-year milestone. We recognize and appreciate the profound influence Git has had on our daily work and the collaborative spirit of software development as a whole.</p>
<p>Here's to many more years of Git! 🥂</p>
<p>We hope you found this post helpful. For more Git tips and tricks, don't forget to sign up for our newsletter below and follow Tower on <a href="https://twitter.com/gittower" rel="noopener noreferrer" target="_blank">Twitter / X</a> and <a href="https://www.linkedin.com/company/gittower" rel="noopener noreferrer" target="_blank">LinkedIn</a>! ✌️</p>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Join Over 100,000 Developers &amp; Designers</h2>    <p>Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Join Over 100,000 Developers &amp; Designers Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/git-turns-20">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div><img src="https://feeds.git-tower.com/link/3463/17012174.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>How to Exclude Commits from Git Blame</title>
      <link>https://feeds.git-tower.com/link/3463/17008462/how-to-exclude-commits-from-git-blame</link>
      <guid>https://www.git-tower.com/blog/how-to-exclude-commits-from-git-blame</guid>
      <pubDate>Wed, 16 Apr 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>Ah, <code>git blame</code>! The detective of Git-land, diligently pointing its finger at the author of each line of code. But sometimes, the blame game can get a little… <em>noisy</em>. </p>
<p>What if you're trying to understand the evolution of a critical piece of logic, but all you see are commits related to code formatting or a massive refactoring that touched almost every file? These commits, while important in their own right, can sometimes obscure the more granular history you're trying to uncover.</p>
<p>Thankfully, there are ways to tell <code>git blame</code> to politely ignore certain commits, allowing you to focus on the changes that truly matter. This is what this article is all about.</p> <p>Today, we will explore the situations in which it makes sense to exclude commits and examine our options. </p>
<p>But first, here's a brief overview of the purpose of <code>git blame</code>.</p>
<h2>About the "Git Blame" Command</h2>
<p>At its core, <code>git blame</code> is a Git command that displays the author and revision information for each line of a file. </p>
<p>The primary purpose of this command is to understand the history of a specific piece of code. It helps you answer questions like:</p>
<ul>
<li>Who wrote this line of code?</li>
<li>When was this line last changed?</li>
<li>Why was this change made (by examining the commit message)?</li>
</ul>
<p>It works by traversing the commit history of a file; starting from the current version of the file, it looks back through the commits that have modified it, line by line. For each line, it identifies the commit that introduced or last changed that particular line.</p>
<p>Git cleverly tracks line movements across commits. So, if a line of code is moved to a different location within the same file or even to another file (in some cases), <code>git blame</code> can often still trace its original author and commit. </p>
<p>This makes it a powerful tool for understanding the evolution of your codebase — way more reliable than your colleague John!</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/how-to-exclude-commits-from-git-blame/b48c0822b1-1775825494/john-snitch-git-blame.avif" type="image/avif"><img alt="John versus Git Blame!" src="https://www.git-tower.com/blog/media/pages/posts/how-to-exclude-commits-from-git-blame/ed4cf53d57-1775825494/john-snitch-git-blame.jpg"></source></picture><figcaption>John versus Git Blame!</figcaption></figure>
<p><br /></p>
<p>Jokes aside, for every line in the specified file, <code>git blame</code> shows:</p>
<ul>
<li>The commit hash of the last commit that modified that line.</li>
<li>The author of that commit.</li>
<li>The date and time of that commit.</li>
<li>The actual line of code.</li>
</ul>
<p>This information is essential for debugging, understanding legacy code, and collaborating effectively within a team.</p>
<h2>Why Exclude Commits From Git Blame?</h2>
<p>While <code>git blame</code> is incredibly useful, there are scenarios where certain types of commits can clutter the output and make it harder to find the information you're really looking for. </p>
<p>Imagine the following situations:</p>
<ul>
<li><strong>Massive Code Formatting</strong>: Your team decides to adopt a stricter code style and runs an automated formatter across the entire codebase. This results in a commit that touches almost every line of every file, but doesn't change any functional logic.<br />
Running <code>git blame</code> after this commit might show the formatter as the author of large sections of the code, obscuring the original authors and the actual evolution of the logic.</li>
<li><strong>Large-Scale Refactoring</strong>: A significant refactoring effort might involve moving code around, renaming variables, or restructuring directories without fundamentally changing the behavior of the code. These commits can also dominate the <code>git blame</code> history, making it difficult to see the more fine-grained changes.</li>
<li><strong>Automated Script Changes</strong>: Commits generated by automated scripts, such as dependency updates or generated code, might not provide much useful context when you're trying to understand the human-written parts of the code.</li>
<li><strong>Cherry-Picks and Merges</strong>: Sometimes, cherry-picking or merging commits can result in changes that don't accurately reflect the original authorship in the target branch's history. Excluding the merge commit itself might provide a cleaner view of the individual contributions.</li>
</ul>
<p>This is where the ability to exclude commits comes in handy. So let's have a look at how it works in practice.</p>
<h2>How to Exclude Commits from Git Blame</h2>
<p>Git provides a couple of powerful ways to exclude specific commits from the <code>git blame</code> output:</p>
<ul>
<li><strong>Option 1:</strong> Creating a <code>.git-blame-ignore-revs</code> File</li>
<li><strong>Option 2:</strong> Command-Line Options for <code>git blame</code></li>
</ul>
<p>Let's explore both methods.</p>
<h3>Option 1: Creating a <code>.git-blame-ignore-revs</code> File</h3>
<p>The <code>.git-blame-ignore-revs</code> file is a configuration file that allows you to specify a list of commit hashes (or SHAs — Secure Hash Algorithm) that <code>git blame</code> should ignore.</p>
<div class="framed-content">
  <p>💡 Please note that <code>.git-blame-ignore-revs</code> is merely a convention; Git does not automatically use this file in the same manner as it does with the <code>.gitignore</code> file.</p>
  <p>However, we recommend using this file name, as popular code hosting platforms like <a href="https://docs.github.com/en/repositories/working-with-files/using-files/viewing-and-understanding-files#ignore-commits-in-the-blame-view" target="_blank" rel="noopener noreferrer">GitHub</a> and <a href="https://about.gitlab.com/releases/2025/03/20/gitlab-17-10-released/#ignore-specific-revisions-in-git-blame" target="_blank" rel="noopener noreferrer">GitLab</a> look for and support this file.</p>
</div>
<h4>1. Creating and Using the File</h4>
<p>To use this feature, you first need to create a file named <code>.git-blame-ignore-revs</code> at the root of your Git repository. This file should contain a list of commit hashes/SHAs, with one hash per line.</p>
<p>For example, your <code>.git-blame-ignore-revs</code> file might look like this:</p>
<pre><code># Removed semi-colons from the entire codebase
a1b2c3d4e5f678901234567890abcdef01234567
# Converted all JavaScript to TypeScript
fedcba9876543210fedcba9876543210fedcba98</code></pre>
<p>Each line in this file represents a commit that you want <code>git blame</code> to skip over when tracing the history of a file. Comments are optional but recommended.</p>
<h4>2. Syntax for Listing Commits to Ignore</h4>
<p>The syntax for the <code>.git-blame-ignore-revs</code> file is straightforward: simply list one full commit hash per line. You can obtain these hashes using commands like <code>git log</code> or by inspecting your Git history in Tower.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/how-to-exclude-commits-from-git-blame/39897cbedc-1775825494/commit-hash-in-tower.avif" type="image/avif"><img alt="Finding the Commit Hash in Tower" src="https://www.git-tower.com/blog/media/pages/posts/how-to-exclude-commits-from-git-blame/331d9ee0b1-1775825494/commit-hash-in-tower.png"></source></picture><figcaption>Finding the Commit Hash in Tower</figcaption></figure>
<p><br /></p>
<p>It is important to use the full SHA-1 hash to ensure Git correctly identifies the commits to ignore.</p>
<h4>3. Configuring Git to Use the File</h4>
<p>Once you've created and populated the <code>.git-blame-ignore-revs</code> file, you need to tell Git to actually use it. You can do this by setting the <code>blame.ignoreRevsFile</code> configuration option.</p>
<p>To enable this for your current repository, run the following command in your terminal:</p>
<pre><code class="language-bash">git config blame.ignoreRevsFile .git-blame-ignore-revs</code></pre>
<p>To enable it globally for all your Git repositories, use the <code>--global</code> flag:</p>
<pre><code class="language-bash">git config --global blame.ignoreRevsFile .git-blame-ignore-revs</code></pre>
<p>With this configuration in place, whenever you run <code>git blame</code> on a file in your repository (or any repository if you used the <code>--global</code> option), Git will automatically skip over the commits listed in your <code>.git-blame-ignore-revs</code> file. </p>
<p>If a line's last modification was in an ignored commit, <code>git blame</code> will continue to trace the history back to the commit <em>before</em> the ignored one.</p>
<h3>Option 2: Command-Line Options for <code>git blame</code></h3>
<p>For more ad-hoc or one-off exclusions, <code>git blame</code> also provides command-line options to ignore specific commits or an ignore file.</p>
<h4>1. The <code>--ignore-rev</code> Option</h4>
<p>The <code>--ignore-rev</code> option allows you to specify one or more commit hashes/SHAs directly in your <code>git blame</code> command. </p>
<p>To ignore a single commit, you would use:</p>
<pre><code class="language-bash">git blame --ignore-rev &lt;commit-sha&gt; &lt;file&gt;</code></pre>
<p>To ignore multiple commits, you can use the option multiple times:</p>
<pre><code class="language-bash">git blame --ignore-rev &lt;commit-sha-1&gt; --ignore-rev &lt;commit-sha-2&gt; &lt;file&gt;</code></pre>
<p>This option is useful when you quickly want to exclude a specific commit without modifying the <code>.git-blame-ignore-revs</code> file.</p>
<h4>2. The <code>--ignore-revs-file</code> Option</h4>
<p>If you have a file containing the list of commits to ignore (which doesn't necessarily have to be named <code>.git-blame-ignore-revs</code> or located at the repository root), you can explicitly tell <code>git blame</code> to use it with the <code>--ignore-revs-file</code> option:</p>
<pre><code class="language-bash">git blame --ignore-revs-file &lt;path/to/ignore-file&gt; &lt;file&gt;</code></pre>
<p>This can be helpful if you want to maintain different ignore lists for different purposes or if you prefer to keep the ignore list in a non-standard location.</p>
<h2>Best Practices for Excluding Commits</h2>
<p>While the ability to exclude commits from <code>git blame</code> is powerful, it's important to use it judiciously and follow some best practices.</p>
<p>Here are 4 tips you should keep in mind.</p>
<h3>1. Maintaining the Ignore List</h3>
<p>If you choose to use the <code>.git-blame-ignore-revs</code> file, it's important to maintain it over time. As your project evolves, you might encounter new formatting or refactoring commits that you want to add to the ignore list.</p>
<p>Consider keeping the ignore list relatively concise and focused on truly disruptive commits. A very long ignore list might indicate a broader issue with your commit history or development practices.</p>
<h3>2. Communicating Excluded Commits to the Team</h3>
<p>If you are using the repository-specific <code>.git-blame-ignore-revs</code> file (i.e., you configured <code>blame.ignoreRevsFile</code> without the <code>--global</code> flag), it's a good idea to communicate to your team that this file exists and what types of commits are being ignored. This ensures that everyone on the team is aware of the potential differences in their <code>git blame</code> output.</p>
<p>Since <code>.git-blame-ignore-revs</code> is typically committed to the repository, it automatically shares the ignore list with everyone who clones the project. However, it's still helpful to mention its existence in your project's documentation or during team meetings.</p>
<h3>3. Balancing Exclusion with Accountability</h3>
<p>While excluding certain commits can improve the clarity of <code>git blame</code> output, it's important to maintain accountability. Don't use commit exclusion as a way to hide authorship of problematic code. The primary goal is to improve the signal-to-noise ratio, not to rewrite history or evade responsibility.</p>
<p>Remember that the excluded commits are still part of the Git history and can be examined using other Git commands like <code>git log</code>. <code>git blame</code> with exclusions simply provides a filtered view.</p>
<h3>4. Integrating Exclusion into Your Workflow</h3>
<p>Consider integrating the creation or updating of the <code>.git-blame-ignore-revs</code> file as part of your team's workflow when performing large-scale formatting or refactoring. For example, the script that performs the formatting could also generate or append to the ignore list.</p>
<p>Using a repository-specific <code>.git-blame-ignore-revs</code> file and enabling it via <code>git config</code> within the repository ensures that the ignore rules are automatically applied for everyone working on that project. This provides a consistent and cleaner <code>git blame</code> experience for the entire team. Speaking of <code>git config</code>, if you want an easy way to build and customize your <code>.gitconfig</code> interactively, check out Tower's free <a href="https://www.git-tower.com/free-tools/git-config-generator">Git Config Generator</a>.</p>
<h2>Final Words</h2>
<p>We've journeyed through the ins and outs of excluding commits from <code>git blame</code>, from understanding its purpose to mastering the techniques for filtering out noise. </p>
<p>Whether you choose to use the <code>.git-blame-ignore-revs</code> file for persistent exclusions or the command-line options for more targeted filtering, you now have the tools to make your code history investigations more focused and efficient. So go ahead and use these techniques wisely!</p>
<p>We hope you found this post helpful. For more Git tips and tricks, don't forget to sign up for our newsletter below and follow Tower on <a href="https://twitter.com/gittower" rel="noopener noreferrer" target="_blank">Twitter / X</a> and <a href="https://www.linkedin.com/company/gittower" rel="noopener noreferrer" target="_blank">LinkedIn</a>! ✌️</p>
<div class="signup--block">  <div class="signup--block__join--email">    <h2>Join Over 100,000 Developers &amp; Designers</h2>    <p>Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</p>
<form class="newsletter-form analytics--submit" autocomplete="off" novalidate>
          <input type="hidden" name="lists[]" value="tower-newsletter">

    <div class="newsletter-form__groups">
        <div class="row" style="display:none">
      <label for="signup-tag__tower_newsletter"><input class="signup-tag__item consent__text" name="tags[]" type="checkbox" value="tower_newsletter" checked id="signup-tag__tower_newsletter">Join Over 100,000 Developers &amp; Designers Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.</label>
    </div>
      </div>

  <div class="newsletter-form__signup">
    <label for="newsletter-form__email" class="sr-only">Email address</label>
    <input type="email" id="newsletter-form__email" name="email" placeholder="Your email address" aria-required="true" autocomplete="email">
    <input type="submit" value="Subscribe" class="newsletter-form__signup-button">
  </div>

    <div class="newsletter-form__consent">
        <label for="consent--legal"><input type="checkbox" id="consent--legal" class="consent__item consent__text" data-required="1" aria-required="true">I have read and accept the <a href="https://www.git-tower.com/legal/privacy-policy" target="_blank">Privacy Policy</a>. I understand that I can unsubscribe at any time by clicking on the unsubscribe link in any email.</label>
      </div>

    <input type="hidden" name="signup[medium]" value="tower-blog">
      <input type="hidden" name="signup[URI]" value="posts/how-to-exclude-commits-from-git-blame">
      <input type="hidden" name="signup[OS]" value="">
    <div class="request-notice" role="status" aria-live="polite"> </div>
</form>
  </div></div><img src="https://feeds.git-tower.com/link/3463/17008462.gif" height="1" width="1"/>]]></description>
    </item>
    <item>
      <title>Tower 9.0 for Windows — Git Worktree Support</title>
      <link>https://feeds.git-tower.com/link/3463/16995598/tower-windows-9</link>
      <guid>https://www.git-tower.com/blog/tower-windows-9</guid>
      <pubDate>Mon, 31 Mar 2025 00:00:00 +0000</pubDate>
      <description><![CDATA[<p>For those of you eagerly awaiting Git Worktree support in Tower, your patience has paid off! We're thrilled to announce that Tower 9.0 for Windows brings this powerful feature directly to your favorite Git client.</p> <p>After bringing <a href="https://www.git-tower.com/blog/tower-mac-125">Git Worktree support to Tower for Mac</a> earlier this year, it's now Windows' turn! With this release, you can easily create, check out, and manage Worktrees right from within Tower!</p>
<p>Let's first explore what makes <code>git-worktree</code> so useful and then see how easy it is to perform all Worktree operations in Tower.</p>
<h2>The Power of "Git Worktree"</h2>
<p>In short, <code>git-worktree</code> allows you to simultaneously work on different branches without the usual conflicts and disruptions. This is a game-changer when you need to switch gears for urgent tasks, like a hotfix, without interrupting your current work. </p>
<p>Traditionally, you might have resorted to:</p>
<ul>
<li>Stashing your changes, which can be cumbersome and prone to forgotten details.</li>
<li>Creating incomplete commits, which require later edits and can clutter your history.</li>
</ul>
<p>With worktrees, you can seamlessly transition between branches or pull requests, maintaining a clean and organized workflow 😎</p>
<p>Another significant advantage is handling long-running processes. You can execute time-consuming operations like builds or tests in one worktree while continuing development in another, ensuring uninterrupted productivity.</p>
<p>Worktrees differ from branches in their directory structure. Each worktree has its own distinct working directory — which is why it is recommended to create worktrees outside your main project folder, to avoid redundancy.</p>
<p>Furthermore, worktrees are resource-efficient. They share the underlying Git repository data (objects and refs), minimizing disk space usage compared to multiple clones and offering faster performance.</p>
<h2>Worktrees in Tower for Windows</h2>
<p>Tower provides an intuitive interface for managing and switching between worktrees. </p>
<p>With this new update, you will notice a dedicated "Worktrees" section conveniently located in the sidebar, following "Submodules".</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/f608fab2c0-1775825494/worktree-section.avif" type="image/avif"><img alt="Tower 9.0 – Worktrees in the sidebar" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/0cd466317d-1775825494/worktree-section.png"></source></picture><figcaption>Tower 9.0 – Worktrees in the sidebar</figcaption></figure>
<h3>Creating a New Worktree</h3>
<p>There are several ways to create a new worktree in Tower. One method is to right-click on any branch and select "Check out [BRANCH] in New Worktree..." from the context menu.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/d72e95ac9f-1775825494/create-new-worktree-context-menu.avif" type="image/avif"><img alt="Tower 9.0 – Creating a New Worktree from the Context Menu" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/405a078ea8-1775825494/create-new-worktree-context-menu.png"></source></picture><figcaption>Tower 9.0 – Creating a New Worktree from the Context Menu</figcaption></figure>
<p><br /></p>
<p>Alternatively, you can use the "+" button at the bottom of the sidebar or navigate to "Repository" &gt; "Add New Worktree…" in the main menu.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/4e0f7ed8d7-1775825494/create-new-worktree-footer.avif" type="image/avif"><img alt='Tower 9.0 – Creating a New Worktree by clicking the "+" button' src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/cd7fdc6cbc-1775825494/create-new-worktree-footer.png"></source></picture><figcaption>Tower 9.0 – Creating a New Worktree by clicking the "+" button</figcaption></figure>
<p><br /></p>
<p>In the dialog box, specify the desired location for the worktree and the branch to use as a starting point.</p>
<p>Upon clicking "Create Worktree", a new worktree will be generated and automatically checked out, ready for use!</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/36cf0853e0-1775825494/add-worktree.avif" type="image/avif"><img alt="Tower 9.0 – Creating a New Worktree dialog" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/0299d919ee-1775825494/add-worktree.png"></source></picture><figcaption>Tower 9.0 – Creating a New Worktree dialog</figcaption></figure>
<p><br /></p>
<p>Fans of drag-and-drop actions will appreciate that you can easily drag a branch to the "worktree" section to instantly create a worktree based on that branch. By the way, this also works with commits, not just branches 😉</p>
<figure><video preload="metadata" playsinline="playsinline" muted="muted" loop="loop" autoplay><source src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/e2a62e5b4f-1775825494/create-worktree-drag-and-drop.mp4" type="video/mp4"></source></video><figcaption>Creating a New Worktree with Drag and Drop</figcaption></figure>
<h3>Managing Worktrees in Tower</h3>
<p>Tower visually distinguishes worktrees with a unique icon within the "Branches" section, making them easily identifiable.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/45436b4edb-1775825494/worktree-icon.avif" type="image/avif"><img alt='Tower 9.0 – Worktrees in the "Branches" section' src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/4f83eb4800-1775825494/worktree-icon.png"></source></picture><figcaption>Tower 9.0 – Worktrees in the "Branches" section</figcaption></figure>
<p><br /></p>
<p>Right-clicking on a worktree provides options to remove it, relocate it, or open it in the terminal or Explorer, offering comprehensive control.</p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/1f89542113-1775825494/worktree-options-context-menu.avif" type="image/avif"><img alt="Tower 9.0 – Worktree options" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/39a55a6aa6-1775825494/worktree-options-context-menu.png"></source></picture><figcaption>Tower 9.0 – Worktree options</figcaption></figure>
<p><br /></p>
<h2>A New Compact Top Bar Layout</h2>
<p>With this release, we've also introduced a new compact top bar layout for a cleaner appearance. </p>
<figure><picture><source srcset="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/671a6f15a7-1775825494/tow-9-compact-bar.avif" type="image/avif"><img alt="Tower 9.0 – Compact Top Bar Layout" src="https://www.git-tower.com/blog/media/pages/posts/tower-windows-9/0b1c379f2f-1775825494/tow-9-compact-bar.png"></source></picture><figcaption>Tower 9.0 – Compact Top Bar Layout</figcaption></figure>
<p><br /></p>
<p>To try it out, enable "Use compact top bar layout" in "Preferences &gt; General." Changes will be applied after restarting Tower.</p>
<figure><img alt="Tower 9.0 – Enabling the Compact Top Bar Layout" src="https://www.git-tower.com/blog/tow-9-compact-bar.png-settings"><figcaption>Tower 9.0 – Enabling the Compact Top Bar Layout</figcaption></figure>
<p><br /></p>
<h2>Other Improvements</h2>
<p>As always, we've also taken a moment to address some other small improvements and bug fixes, such as:</p>
<ul>
<li>SSH Keys: Fixed retrieval from 1Password.  </li>
<li>Rebase: Fixed commit message editing during rebase operations.  </li>
<li>Services: Fixed issues with adding custom accounts and GitLab authentication issues.  </li>
<li>Ignore &amp; Exclude Files: Fixed an issue where these files did not open correctly. They now function as expected.  </li>
<li>Cherry-Picking: Fixed the issue where commits were applied in the wrong order, ensuring they now follow the expected sequence.  </li>
</ul>
<p>For the complete changelog, please have a look at the <a href="https://www.git-tower.com/release-notes/windows?show_tab=release-notes">Release Notes</a>.</p>
<p>We hope you enjoy our latest Windows release. Happy committing! 😊</p>
<div style="height:5px; width:200px; margin:55px auto 50px auto; border-bottom:3px solid #E2E6E9"></div>
<p>New to Tower? Download our 30-day free trial and discover a more efficient way to work with Git!</p>
<p><br /></p>
<div style="text-align: center;"><a href="https://www.git-tower.com" class="button" target="_blank">Try Tower 9.0 Now</a></div>
<p><br /><br />
PS: Did you know? Tower Pro is now <a href="https://www.git-tower.com/students" rel="noopener noreferrer" target="_blank">free for students</a> as well as <a href="https://www.git-tower.com/education" rel="noopener noreferrer" target="_blank">teachers and educational institutions!</a></p><img src="https://feeds.git-tower.com/link/3463/16995598.gif" height="1" width="1"/>]]></description>
    </item>
  </channel>
</rss>
