{"id":437,"date":"2021-09-19T11:34:02","date_gmt":"2021-09-19T19:34:02","guid":{"rendered":"http:\/\/spacefold.com\/colin\/morethanfour\/?p=437"},"modified":"2021-09-20T14:09:09","modified_gmt":"2021-09-20T22:09:09","slug":"learning-git-4-remotes-ii-reverse-the-polarity","status":"publish","type":"post","link":"https:\/\/spacefold.com\/colin\/morethanfour\/2021\/09\/19\/learning-git-4-remotes-ii-reverse-the-polarity\/","title":{"rendered":"Learning Git &#8211; 4. Remotes II : Reverse the Polarity!"},"content":{"rendered":"\n<p>(Previously: <a href=\"https:\/\/spacefold.com\/colin\/morethanfour\/2021\/09\/19\/learning-git-3-remotes\/\">Part 3: Remotes<\/a>)<\/p>\n\n\n\n<p>In the previous chapter\/section, we learned about remotes and pushed our local source files up to a new, empty, remote repository for other developers to collaborate.<\/p>\n\n\n\n<p>This time, we&#8217;re going to do the opposite: Create an empty local repository and set it up so that we can work on an existing remote repo, our &#8220;cow-tipper&#8221; project on GitHub.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Building a local repository<\/h3>\n\n\n\n<p>I&#8217;m pretty sure I know what we need to do:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Initialize a new empty repository with git <strong>init<\/strong><\/li><li>ensure the default branch is &#8220;main&#8221; (instead of &#8220;master&#8221;)<\/li><li>add a &lt;remote&gt; referencing git@github.com:buster-kitten\/cow-tipper.git<\/li><li>fetch from that remote to populate the remote-tracking branch &#8220;&lt;remote&gt;\/main&#8221;<\/li><li>set the upstream branch on local &#8220;main&#8221; to be the &#8220;&lt;remote&gt;\/main&#8221;<\/li><\/ul>\n\n\n\n<p>In a new directory:<\/p>\n\n\n\n<pre>$ git init --initial-branch=main<\/pre>\n<pre class=\"console-output\">error: unknown option `initial-branch'<\/pre>\n\n\n\n<p>Wut? It turns out that the initial-branch option is new in Git version 2.28, and here in Linux I&#8217;m using 2.25. We&#8217;ll have to use an alternative method: I&#8217;ll create it with the default, and then re-name it:<\/p>\n\n\n\n<pre>$ git init<\/pre>\n<pre class=\"console-output\">Initialized empty Git repository in \/home\/buster\/Projects\/cow_tupper\/.git\/<\/pre>\n<pre>$ git branch -m master main<\/pre>\n<pre class=\"console-output\">error: refname refs\/heads\/master not found\nfatal: Branch rename failed<\/pre>\n\n\n\n<p>Wut!? &#8220;master&#8221; isn&#8217;t real? But:<\/p>\n\n\n\n<pre>$ git status<\/pre>\n<pre class=\"console-output\">On branch master\nNo commits yet\nnothing to commit (create\/copy files and use \"git add\" to track)<\/pre>\n\n\n\n<p>Well, then, let&#8217;s just create a &#8220;main&#8221; branch directly and worry about deleting &#8220;master&#8221; later:<\/p>\n\n\n\n<pre>$ git checkout -b main<\/pre>\n<pre class=\"console-output\">Switched to a new branch 'main'<\/pre>\n\n\n\n<p>And add the remote, which we&#8217;ll call &#8220;pluto&#8221; for fun. It&#8217;s pretty remote. Then we can fetch:<\/p>\n\n\n\n<pre>$ git remote add pluto git@github.com:buster-kitten\/cow-tipper.git\n$ git fetch pluto<\/pre>\n<pre class=\"console-output\">remote: Enumerating objects: 68, done.\nremote: Counting objects: 100% (68\/68), done.\nremote: Compressing objects: 100% (46\/46), done.\nremote: Total 68 (delta 18), reused 68 (delta 18), pack-reused 0\nUnpacking objects: 100% (68\/68), 6.90 KiB | 441.00 KiB\/s, done.\nFrom github.com:buster-kitten\/cow-tipper\n * [new branch]      main       -&gt; pluto\/main<\/pre>\n\n\n\n<p>Cool. Now we can make &#8220;main&#8221; a remote-tracking branch, right?<\/p>\n\n\n\n<pre>$ git branch --set-upstream-to pluto\/main<\/pre>\n<pre class=\"console-output\">fatal: branch 'main' does not exist<\/pre>\n\n\n\n<p>Wut!? Now &#8220;main&#8221; isn&#8217;t real? <\/p>\n\n\n\n<pre>$ git branch --verbose\n$<\/pre>\n\n\n\n<p>No results? But:<\/p>\n\n\n\n<pre>$ git status<\/pre>\n<pre class=\"console-output\">On branch main\nNo commits yet\nnothing to commit (create\/copy files and use \"git add\" to track)<\/pre>\n\n\n\n<p>So we&#8217;re &#8220;on branch main&#8221;, but &#8220;branch &#8216;main&#8217; doesn&#8217;t exist&#8221;. This is confusing&#8230; some might call it a &#8220;bug&#8221;, others &#8220;by design&#8221;. It is, for sure, unfortunate.<\/p>\n\n\n\n<p><strong>Okay, let&#8217;s not waste any more time<\/strong>: If you remember from earlier, &#8220;A <strong>branch<\/strong> in Git is just a pointer to a specific commit.&#8221; <strong>But we don&#8217;t have any commits yet<\/strong>. However, the repository metadata <strong>knows<\/strong> that the branch will be called &#8220;main&#8221;, just as soon as the first commit is made. That&#8217;s why we get the mixed messages.<\/p>\n\n\n\n<p>So what we actually need to do at this point, is this:<\/p>\n\n\n\n<pre>$ git checkout main<\/pre>\n<pre class=\"console-output\">Branch 'main' set up to track remote branch 'main' from 'pluto'.\nAlready on 'main'<\/pre>\n\n<pre>$ git status<\/pre>\n<pre class=\"console-output\">On branch main\nYour branch is up to date with 'pluto\/main'.\n\nnothing to commit, working tree clean<\/pre>\n\n<pre>$ git branch --verbose<\/pre>\n<pre class=\"console-output\">* main 92502d2 Added header comment lines<\/pre>\n\n\n\n<p>Here&#8217;s what happened, and I&#8217;m going to quote and paraphrase StackOverflow author <strong>torek<\/strong> directly because they wrote <a href=\"https:\/\/stackoverflow.com\/questions\/46915350\/got-fatal-branch-master-does-not-exist-in-git\">a great explanation<\/a>:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>&#8220;You had a repository that is in a peculiar state: it has no commits, so it has no branches. At the same time, it <em>does<\/em> have a <em>current<\/em> branch, which is <em>master<\/em>. In other words, the current branch is a branch that does not exist.<br><br>Whenever you run <strong>git checkout &lt;name&gt;<\/strong> and there is no branch named <strong>&lt;name&gt;<\/strong>, Git checks to see if there is exactly one remote-tracking branch named <strong>&lt;remote&gt;\/&lt;name&gt;<\/strong>. If so, Git creates a new branch <strong>&lt;name&gt;<\/strong> that has <strong>&lt;remote&gt;\/&lt;name&gt;<\/strong> as its upstream branch.&#8221;<\/p><cite>torek @ stack overflow<\/cite><\/blockquote>\n\n\n\n<p>This is a bit funky, and I really am not a fan of received wisdom, but it explains what we observed above.<\/p>\n\n\n\n<p>Let&#8217;s recap the necessary commands, but skip the stuff that didn&#8217;t work, the duplicate commands, and do things in the optimal sequence:<\/p>\n\n\n\n<pre>$ git init\n$ git remote add pluto git@github.com:buster-kitten\/cow-tipper.git\n$ git fetch pluto<\/pre>\n<pre class=\"console-output\">remote: Enumerating objects: 68, done.\nremote: Counting objects: 100% (68\/68), done.\nremote: Compressing objects: 100% (46\/46), done.\nremote: Total 68 (delta 18), reused 68 (delta 18), pack-reused 0\nUnpacking objects: 100% (68\/68), 6.90 KiB | 415.00 KiB\/s, done.\nFrom github.com:buster-kitten\/cow-tipper\n * [new branch]      main       -&gt; pluto\/main<\/pre>\n\n<pre>$ git checkout -b main<\/pre>\n<pre class=\"console-output\">Switched to a new branch 'main'<\/pre>\n\n<pre>$ ls -l<\/pre>\n<pre class=\"console-output\">total 0<\/pre>\n\n\n\n<p>No files? Where are my files?<\/p>\n\n\n\n<pre>$ git branch --verbose\n$<\/pre>\n\n\n\n<p>That returns nothing. Huh. Try checking out the branch a second time:<\/p>\n\n\n\n<pre>$ git checkout main<\/pre>\n<pre class=\"console-output\">Branch 'main' set up to track remote branch 'main' from 'pluto'.\nAlready on 'main'<\/pre>\n\n<pre>$ git branch -v<\/pre>\n<pre class=\"console-output\">* main 92502d2 Added header comment lines<\/pre>\n\n<pre>$ ls -l<\/pre>\n<pre class=\"console-output\">total 12\n-rw-rw-r-- 1 buster buster 152 Sep 17 13:22 cow_lib.py\n-rw-rw-r-- 1 buster buster 533 Sep 17 13:22 cow_tipper.py\n-rw-rw-r-- 1 buster buster 265 Sep 17 13:22 README.md<\/pre>\n\n\n\n<p>That&#8217;s better. <\/p>\n\n\n\n<p>I have not found an explanation of why we needed to do a second <strong>git checkout<\/strong> in order to get our working tree populated. Suggestions on a postcard, please.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Attack of the Clones<\/h3>\n\n\n\n<p>None of that stuff really matters because you&#8217;re much more likely to use a Git command that bundles all those steps together into one:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Clone<\/h4>\n\n\n\n<pre>$ git clone &lt;url&gt;<\/pre>\n\n\n\n<p>The Git <strong>clone<\/strong> command replicates a remote repository into a brand new local repository on your local file system, complete with remotes, remote-tracking branches, and a working tree of source files. Of course, it makes some choices for you:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>creates a local repository<\/li><li>creates a remote called &#8220;origin&#8221;<\/li><li>creates a remote-tracking branch called &#8220;origin\/master&#8221;<\/li><li>fetches the latest changes<\/li><li>creates a &#8220;master&#8221; branch tracking &#8220;origin\/master&#8221;<\/li><li>merges (i.e. populates) the &#8220;master&#8221; branch from &#8220;origin\/master&#8221;<\/li><\/ul>\n\n\n\n<p>Example:<\/p>\n\n\n\n<pre>$ git clone git@github.com:buster-kitten\/cow-tipper.git<\/pre>\n<pre class=\"console-output\">Cloning into 'cow-tipper'...\nremote: Enumerating objects: 68, done.\nremote: Counting objects: 100% (68\/68), done.\nremote: Compressing objects: 100% (46\/46), done.\nremote: Total 68 (delta 18), reused 68 (delta 18), pack-reused 0\nReceiving objects: 100% (68\/68), 6.92 KiB | 3.46 MiB\/s, done.\nResolving deltas: 100% (18\/18), done.<\/pre>\n\n<pre>$ cd cow-tipper\n$ ls -l<\/pre>\n<pre class=\"console-output\">total 12\n-rw-rw-r-- 1 buster buster 152 Sep 17 13:34 cow_lib.py\n-rw-rw-r-- 1 buster buster 533 Sep 17 13:34 cow_tipper.py\n-rw-rw-r-- 1 buster buster 265 Sep 17 13:34 README.md<\/pre>\n\n\n\n<p>And that&#8217;s why <strong>clone<\/strong> is typically the first Git command you&#8217;re likely to encounter, even before you learn about <strong>add<\/strong>, <strong>commit<\/strong>, <strong>push<\/strong>, <strong>fetch<\/strong>, <strong>merge<\/strong>, and <strong>pull<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How do I&#8230;?<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">Show more information about a remote<\/h4>\n\n\n\n<pre>$ git remote show &lt;alias&gt;<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Delete a remote branch<\/h4>\n\n\n\n<pre>$ git push &lt;remote&gt; --delete &lt;branch&gt;<\/pre>\n\n\n\n<p>This deletes the pointer representing &lt;branch&gt; on the &lt;remote&gt; server .<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Delete a remote reference<\/h4>\n\n\n\n<p>The <strong>remote remove<\/strong> command deletes all remote-tracking branches and config settings related to the remote:<\/p>\n\n\n\n<pre>$ git remote remove &lt;alias&gt;<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Further reading<\/h4>\n\n\n\n<ul class=\"wp-block-list\"><li><a rel=\"noreferrer noopener\" href=\"https:\/\/git-scm.com\/book\/en\/v2\/Git-Basics-Working-with-Remotes\" target=\"_blank\">https:\/\/git-scm.com\/book\/en\/v2\/Git-Basics-Working-with-Remotes<\/a><\/li><li><a rel=\"noreferrer noopener\" href=\"https:\/\/git-scm.com\/book\/en\/v2\/Distributed-Git-Contributing-to-a-Project\" target=\"_blank\">https:\/\/git-scm.com\/book\/en\/v2\/Distributed-Git-Contributing-to-a-Project<\/a><\/li><li><a href=\"https:\/\/ohshitgit.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/ohshitgit.com\/<\/a>   this is very funny and useful<\/li><\/ul>\n\n\n\n<p>And that&#8217;s all for now. I hope you enjoyed following along and maybe even found it useful. Cheers.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(Previously: Part 3: Remotes) In the previous chapter\/section, we learned about remotes and pushed our local source files up to a new, empty, remote repository for other developers to collaborate. This time, we&#8217;re going to do the opposite: Create an empty local repository and set it up so that we can work on an existing [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[15],"tags":[],"class_list":["post-437","post","type-post","status-publish","format-standard","hentry","category-source-control","post-preview"],"_links":{"self":[{"href":"https:\/\/spacefold.com\/colin\/morethanfour\/wp-json\/wp\/v2\/posts\/437","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spacefold.com\/colin\/morethanfour\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/spacefold.com\/colin\/morethanfour\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/spacefold.com\/colin\/morethanfour\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/spacefold.com\/colin\/morethanfour\/wp-json\/wp\/v2\/comments?post=437"}],"version-history":[{"count":0,"href":"https:\/\/spacefold.com\/colin\/morethanfour\/wp-json\/wp\/v2\/posts\/437\/revisions"}],"wp:attachment":[{"href":"https:\/\/spacefold.com\/colin\/morethanfour\/wp-json\/wp\/v2\/media?parent=437"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/spacefold.com\/colin\/morethanfour\/wp-json\/wp\/v2\/categories?post=437"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/spacefold.com\/colin\/morethanfour\/wp-json\/wp\/v2\/tags?post=437"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}