<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Git on Nelson Figueroa</title><link>https://nelson.cloud/categories/git/</link><description>Recent content in Git on Nelson Figueroa</description><image><title>Nelson Figueroa</title><url>https://nelson.cloud/apple-touch-icon.png</url><link>https://nelson.cloud/categories/git/</link></image><language>en</language><lastBuildDate>Thu, 18 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://nelson.cloud/categories/git/index.xml" rel="self" type="application/rss+xml"/><item><title>.gitignore Isn’t the Only Way To Ignore Files in Git</title><link>https://nelson.cloud/.gitignore-isnt-the-only-way-to-ignore-files-in-git/?ref=rss</link><pubDate>Thu, 18 Jun 2026 00:00:00 +0000</pubDate><guid>https://nelson.cloud/.gitignore-isnt-the-only-way-to-ignore-files-in-git/?ref=rss</guid><description>You can ignore files in .gitignore, .git/info/exclude, and ~/.config/git/ignore</description><content:encoded><![CDATA[<p>I&rsquo;ve been using Git for so long and I just realized you can ignore files at three different levels and not just with <code>.gitignore</code>. The three files you can use to ignore files are:</p>
<ul>
<li><code>.gitignore</code></li>
<li><code>.git/info/exclude</code></li>
<li><code>~/.config/git/ignore</code></li>
</ul>
<h2 id="gitignore">.gitignore</h2>
<p><code>.gitignore</code> is the usual file where you write files you want to ignore. It&rsquo;s checked into Git along with the rest of the code. Whatever files you add to it will not get taken into account when running <code>git</code> commands.</p>
<h2 id="gitinfoexclude">.git/info/exclude</h2>
<p>The <code>exclude</code> file lives in the <code>.git</code> directory of every Git repository but changes to it are not checked into Git. It usually has a few comment lines on a fresh Git repository. This file is useful for ignoring things on a per-repo basis. For example, you may have a personal <code>notes.txt</code> file in a repository that you don&rsquo;t want to check into git but you also don&rsquo;t want to add to <code>.gitignore</code> because it&rsquo;s unique to your workflow. In that case you would add <code>notes.txt</code> to <code>.git/info/exclude</code>.</p>
<h2 id="configgitignore">~/.config/git/ignore</h2>
<p>The <code>ignore</code> file lives in your machine&rsquo;s home directory in <code>~/.config/git/ignore</code>. Whatever filenames are added to this file are ignored globally at a machine-level. This file is not checked into Git and isn&rsquo;t associated with any particular repository. It&rsquo;s a great place to add files that you want to ignore in every git repository on your computer. For example, if you&rsquo;re on macOS, adding <code>.DS_Store</code> here would be ideal.</p>
<p>You can customize the global ignore file to be a different file. For example, if you want your global git ignore file to be <code>.gitignore_global</code> you would run the command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git config --global core.excludesFile ~/.gitignore_global</span></span></code></pre></div><p>And if you ever want to return to the default setting, run:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git config --global --unset core.excludesFile</span></span></code></pre></div><h2 id="checking-which-file-is-ignoring-a-specific-file">Checking Which File Is Ignoring a Specific File</h2>
<p>When adding filenames to any of these, you can use this command to check how a filename is being ignored. For example, if you want to check how <code>.DS_Store</code> is being ignored, run <code>git check-ignore -v .DS_Store</code> in any Git repository.</p>
<p>Here is the output when the repository&rsquo;s <code>.gitignore</code> is ignoring <code>.DS_Store</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git check-ignore -v .DS_Store
</span></span><span class="line"><span class="cl"><span class="go">.gitignore:1:.DS_Store	.DS_Store
</span></span></span></code></pre></div><p>Here is the output when the repository&rsquo;s <code>.git/info/exclude</code> is ignoring <code>.DS_Store</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git check-ignore -v .DS_Store
</span></span><span class="line"><span class="cl"><span class="go">.git/info/exclude:7:.DS_Store	.DS_Store
</span></span></span></code></pre></div><p>Here is the output when the global <code>~/.config/git/ignore</code> file is ignoring <code>.DS_Store</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git check-ignore -v .DS_Store
</span></span><span class="line"><span class="cl"><span class="go">/Users/nelson/.config/git/ignore:2:.DS_Store	.DS_Store
</span></span></span></code></pre></div><p>And here is the output when a custom global ignore file <code>.gitignore_global</code> is ignoring <code>.DS_Store</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git check-ignore -v .DS_Store
</span></span><span class="line"><span class="cl"><span class="go">/Users/nelson/.gitignore_global:1:.DS_Store	.DS_Store
</span></span></span></code></pre></div><p>If there is nothing ignoring a file, the <code>git check-ignore -v</code> command produces no output.</p>
<hr>
<p>This post received a lot of attention on Hacker News! Check it out here: 

<a href="https://news.ycombinator.com/item?id=48583356" target="_blank" rel="noopener">https://news.ycombinator.com/item?id=48583356</a></p>
]]></content:encoded></item><item><title>How to Clone a Specific Git Branch Without Other Branches</title><link>https://nelson.cloud/how-to-clone-a-specific-git-branch-without-other-branches/?ref=rss</link><pubDate>Thu, 27 Feb 2025 00:00:00 +0000</pubDate><guid>https://nelson.cloud/how-to-clone-a-specific-git-branch-without-other-branches/?ref=rss</guid><description>Clone a single Git branch using &amp;ndash;single-branch and &amp;ndash;depth for faster cloning.</description><content:encoded><![CDATA[<h2 id="cloning-a-specific-branch">Cloning a Specific Branch</h2>
<p>To clone a specific branch of a git repository without cloning all other branches, use the following command formula:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git clone --single-branch --branch &lt;branch_name&gt; &lt;repo_URL.git&gt;</span></span></code></pre></div><p>For example, if you want to clone the <code>release-1.28</code> branch of the 

<a href="https://github.com/kubernetes/kubernetes/tree/release-1.28" target="_blank" rel="noopener">Kubernetes GitHub repository</a>, run:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git clone --single-branch --branch release-1.28 https://github.com/kubernetes/kubernetes.git</span></span></code></pre></div><h2 id="cloning-the-latest-commit-of-a-specific-branch">Cloning the Latest Commit of a Specific Branch</h2>
<p>If you only want to clone the latest commit of a specific branch (which results in a faster and smaller cloning operation) use <code>--depth 1</code>. The command formula looks like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git clone --single-branch --branch &lt;branch_name&gt; --depth <span class="m">1</span> &lt;repo_URL.git&gt;</span></span></code></pre></div><p>And here is another example using the <code>release-1.28</code> branch of the 

<a href="https://github.com/kubernetes/kubernetes/tree/release-1.28" target="_blank" rel="noopener">Kubernetes GitHub repository</a>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git clone --single-branch --branch release-1.28 --depth <span class="m">1</span> https://github.com/kubernetes/kubernetes.git</span></span></code></pre></div><h2 id="references">References</h2>
<ul>
<li>

<a href="https://www.freecodecamp.org/news/git-clone-branch-how-to-clone-a-specific-branch/" target="_blank" rel="noopener">https://www.freecodecamp.org/news/git-clone-branch-how-to-clone-a-specific-branch/</a></li>
<li>

<a href="https://git-scm.com/docs/git-clone" target="_blank" rel="noopener">https://git-scm.com/docs/git-clone</a></li>
</ul>
]]></content:encoded></item><item><title>Scrape Contributor Emails From Any Git Repository</title><link>https://nelson.cloud/scrape-contributor-emails-from-any-git-repository/?ref=rss</link><pubDate>Thu, 21 Jul 2022 00:00:00 +0000</pubDate><guid>https://nelson.cloud/scrape-contributor-emails-from-any-git-repository/?ref=rss</guid><description>Scraping contributor emails from git repositories using git shortlog.</description><content:encoded><![CDATA[<p>In a 

<a href="https://nelson.cloud/scraping-github-contributor-emails/">previous post</a> I wrote about how it&rsquo;s possible to scrape emails from GitHub repositories using their API.
I even wrote up a 

<a href="https://github.com/nelsonfigueroa/github-email-scraper" target="_blank" rel="noopener">Ruby script</a> to do this.
I now realize that is a very complicated way to go about it after discovering the <code>git shortlog</code> command.</p>
<p>With <code>git shortlog</code> you can list all contributor emails for any git repository, not just GitHub repos.</p>
<blockquote><p><strong>Disclaimer:</strong></p>I am writing about this to make others aware of this form of scraping and it is purely for educational purposes. I do not plan on doing anything with emails from git repos and you shouldn’t either.</blockquote>

<blockquote><p><strong>tl;dr:</strong></p><p>You can run this command within any git repo to extract all contributor emails:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">git shortlog -sea <span class="p">|</span> grep -E -o <span class="s2">&#34;\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b&#34;</span> <span class="p">|</span> awk <span class="s1">&#39;{print tolower($0)}&#39;</span> <span class="p">|</span> sort <span class="p">|</span> uniq <span class="p">|</span> grep -wv <span class="s1">&#39;users.noreply.github.com&#39;</span></span></span></code></pre></blockquote>

<h2 id="command-break-down">Command Break Down</h2>
<p>The <code>git shortlog -sea</code> part of the command is short for <code>git shortlog --summary --email --all</code>. This command outputs the number of commits each user has made, along with their name and email, across all branches.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git shortlog -sea
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">    54  First Last &lt;FirstLast@example.com&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">   385  Another User &lt;Anotheruser@example.com&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">     2  user1 &lt;user1@example.com&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    31  first last &lt;firstlast@example.com&gt;
</span></span></span><span class="line"><span class="cl"><span class="go">    10  Someone Else &lt;1234567+someoneelse@users.noreply.github.com&gt;
</span></span></span></code></pre></div><p>The next command, <code>grep -E -o &quot;\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b&quot;</code>, extracts emails from each line using a regular expression.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git shortlog -sea <span class="p">|</span> grep -E -o <span class="s2">&#34;\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b&#34;</span>
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">FirstLast@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">Anotheruser@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">user1@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">firstlast@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">1234567+someoneelse@users.noreply.github.com
</span></span></span></code></pre></div><p>The output from the previous command is piped into <code>awk '{print tolower($0)}'</code>, which lowercases all the emails. Sometimes emails are typed in with capital letters. Lowercasing all characters will help with sorting and finding unique emails later.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git shortlog -sea <span class="p">|</span> grep -E -o <span class="s2">&#34;\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b&#34;</span> <span class="p">|</span> awk <span class="s1">&#39;{print tolower($0)}&#39;</span>
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">firstlast@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">anotheruser@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">user1@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">firstlast@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">1234567+someoneelse@users.noreply.github.com
</span></span></span></code></pre></div><p>After that, the output is piped into <code>sort</code> and <code>uniq</code>. These commands are straightforward. The emails are sorted alphabetically, then duplicates are excluded from the output.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git shortlog -sea <span class="p">|</span> grep -E -o <span class="s2">&#34;\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b&#34;</span> <span class="p">|</span> awk <span class="s1">&#39;{print tolower($0)}&#39;</span> <span class="p">|</span> sort <span class="p">|</span> uniq
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">1234567+someoneelse@users.noreply.github.com
</span></span></span><span class="line"><span class="cl"><span class="go">anotheruser@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">firstlast@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">user1@example.com
</span></span></span></code></pre></div><p>That should suffice for a lot of git repos, but I also added <code>grep -wv 'users.noreply.github.com'</code> to the end of the command to exclude noreply emails associated with GitHub.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git shortlog -sea <span class="p">|</span> grep -E -o <span class="s2">&#34;\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b&#34;</span> <span class="p">|</span> awk <span class="s1">&#39;{print tolower($0)}&#39;</span> <span class="p">|</span> sort <span class="p">|</span> uniq <span class="p">|</span> grep -wv <span class="s1">&#39;users.noreply.github.com&#39;</span>
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">anotheruser@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">firstlast@example.com
</span></span></span><span class="line"><span class="cl"><span class="go">user1@example.com
</span></span></span></code></pre></div><h2 id="extracting-emails-with-git-log">Extracting Emails With <code>git log</code></h2>
<p>It&rsquo;s possible to do something similar with the <code>git log --pretty=&quot;%ce&quot;</code> command. However, I noticed that this command does not show as many emails as <code>git shortlog</code>. I didn&rsquo;t look too much into it, but I believe it only pulls emails from one branch rather than all branches like with <code>git shortlog --all</code>.</p>
<h2 id="references">References</h2>
<p>I learned about <code>git shortlog</code> from this Stack Overflow question:</p>
<ul>
<li>

<a href="https://stackoverflow.com/questions/9597410/list-all-developers-on-a-project-in-git" target="_blank" rel="noopener">https://stackoverflow.com/questions/9597410/list-all-developers-on-a-project-in-git</a></li>
</ul>
<p>I got the email regex from here:</p>
<ul>
<li>

<a href="https://www.shellhacks.com/regex-find-email-addresses-file-grep/" target="_blank" rel="noopener">https://www.shellhacks.com/regex-find-email-addresses-file-grep/</a></li>
</ul>
]]></content:encoded></item><item><title>Scraping GitHub Contributor Emails</title><link>https://nelson.cloud/scraping-github-contributor-emails/?ref=rss</link><pubDate>Sat, 30 Oct 2021 00:00:00 +0000</pubDate><guid>https://nelson.cloud/scraping-github-contributor-emails/?ref=rss</guid><description>Scraping GitHub contributor emails, and how you can protect yourself.</description><content:encoded><![CDATA[<blockquote><p><strong>Note:</strong></p>2022-07-21 update: I discovered a better way to do this and I wrote about it in a separate blog post. Check it out here: 

<a href="https://nelson.cloud/scrape-contributor-emails-from-any-git-repository/" target="_blank" rel="noopener">Scrape Contributor Emails From Any Git Repository</a></blockquote>

<h2 id="git-emails">Git Emails</h2>
<p>When setting up Git on the command line, you are asked for your email.
When pushing commits to GitHub, the email you are using for Git gets pushed along with your code as part of the metadata.
While your GitHub email does not publicly show when viewing a repository&rsquo;s commits, it does come up when viewing commits using the GitHub API.</p>
<p>This presents a privacy risk and the potential for someone to find the email associated with your GitHub account.
I wanted to see how easily someone could do this so I created a scraper to do this for me. It turns out it&rsquo;s not hard to scrape commits for emails that are otherwise hidden from public view.</p>
<blockquote><p><strong>Disclaimer:</strong></p>I don&rsquo;t plan on doing anything malicious with this script or the emails collected. I did this out of curiosity and for demonstrational purposes.</blockquote>

<p>The scraper I created is below. Instructions can be found on the README:</p>
<ul>
<li>

<a href="https://github.com/nelsonfigueroa/github-email-scraper" target="_blank" rel="noopener">https://github.com/nelsonfigueroa/github-email-scraper</a></li>
</ul>
<h2 id="scraping-for-emails">Scraping for Emails</h2>
<p>By running the script, I can scrape for emails found in each commit for a given repository:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> ruby main.rb -u torvalds -r linux
</span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">	+-------------------+
</span></span></span><span class="line"><span class="cl"><span class="go">	|   GitHub          |
</span></span></span><span class="line"><span class="cl"><span class="go">	|       Email       |
</span></span></span><span class="line"><span class="cl"><span class="go">	|         Scraper   |
</span></span></span><span class="line"><span class="cl"><span class="go">	+-------------------+
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="err">
</span></span></span><span class="line"><span class="cl"><span class="go">Scraping https://github.com/torvalds/linux/
</span></span></span><span class="line"><span class="cl"><span class="go">Rate limit exceeded.
</span></span></span><span class="line"><span class="cl"><span class="go">Pages scraped: 1-46 out of 10449
</span></span></span><span class="line"><span class="cl"><span class="go">53 emails written to torvalds-linux.txt
</span></span></span></code></pre></div><p>Just like that, I&rsquo;ve scraped several emails. It&rsquo;s not much, and I could get a lot more if I bothered to authenticate to prevent rate limiting.
A patient scraper could simply run this periodically to get as many emails as possible.</p>
<p>So what can we do about this?</p>
<h2 id="hiding-your-email-in-github-commits">Hiding your Email in GitHub Commits</h2>
<p>You can choose to hide your email when performing Git operations on the GitHub site as well as the command line. There are two checkboxes you&rsquo;ll need to tick. Instructions are below:</p>
<ul>
<li>

<a href="https://docs.github.com/en/account-and-profile/how-tos/email-preferences/blocking-command-line-pushes-that-expose-your-personal-email-address" target="_blank" rel="noopener">Blocking command line pushes that expose your personal email address</a></li>
</ul>
<p>Next, you&rsquo;ll need to change your email Git uses on your machine to the <code>@users.noreply.github.com</code> email that GitHub provided in the previous step. Run the following:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git config --global user.email <span class="s2">&#34;00000000+yourusername@users.noreply.github.com&#34;</span>
</span></span></code></pre></div><p>Then verify that the email has been set:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-console" data-lang="console"><span class="line"><span class="cl"><span class="gp">$</span> git config --global user.email
</span></span><span class="line"><span class="cl"><span class="go">00000000+yourusername@users.noreply.github.com
</span></span></span></code></pre></div><p>Now your actual email will be hidden from Git commits that have been pushed from your machine as well as any Git operations on GitHub. Note that your email will still show up in older commits that were pushed before these changes.
However, this will still improve your privacy on GitHub going forward.</p>
]]></content:encoded></item></channel></rss>