Prev | Contents | Next

20 Appendix: Making a Playground

In programming circles in general, a playground is a place you can go to mess with code and tech and not worry about messing up your production system.

And there are places you can go online to find these, but with Git, I find it’s just as easy to make your own local repo.

Here’s a way to make a new local repo called playground out of the current directory. (You should not be under a Git repo at this time; create the playground outside other existing repos.)

$ git init playground
  Initialized empty Git repository in /user/playground/.git/

playground isn’t a special name. You can call it foo or anything. I’ll just use it for this example.

What that command did was create a new subdirectory called playground and create a Git repo in it.

Let’s continue at the end: how do you delete the repo? You just remove the directory.

$ rm -rf playground   # delete the playground repo

And let’s create it again:

$ git init playground

We have all the power!

Note: This repo only exists on this computer; it has no remotes and no way to push. You could add that stuff later, if you wanted, but playgrounds tend to be temporary areas where you’re just trying things out.

Let’s go into the playground and check it out.

$ cd playground
$ ls -la
  total 4
  drwxr-xr-x  3 user group   18 Jul 13 14:43 .
  drwxr-xr-x 22 user group 4096 Jul 13 14:43 ..
  drwxr-xr-x  7 user group  119 Jul 13 14:43 .git

There’s a directory there called .git that has all the metadata in it.

Note: If we wanted to change this directory from a Git repo to just a normal directory, we could run this:

$ rm -rf .git       # Delete the .git directory

Again, we have all the power! But let’s show some restraint and not do that yet.

What can we do?

What can’t we do? Let’s make a file and see where we stand:

$ echo "Hello, world" > hello.txt   # Create a file

$ ls -l

  total 4
  -rw-r--r-- 1 user group 13 Jul 13 14:47 hello.txt

$ git status

  On branch main

  No commits yet

  Untracked files:
    (use "git add <file>..." to include in what will be committed)
      hello.txt

  nothing added to commit but untracked files present (use "git
  add" to track)

Now we have an untracked file.

We can git add it, we can git commit it, we can create branches, we can merge them and make conflicts and resolve them and git rebase and git reset and all kinds of stuff.

We don’t have a remote, so the only things we can’t do involving pushing and pulling.

But it turns out we can even make that happen! Let’s see how.

20.1 Cloning Bare Repos

A bare repo is one without a working tree. You can’t go in there to see files, because they don’t exist in there in a normal sense. The only thing that’s there is metadata and the commit snapshots.

You can clone, push, and pull bare repos.

Let’s make one (again, you could name it anything you want), noting the --bare command line option:

$ git init --bare origin_repo
  Initialized empty Git repository in /user/origin_repo/

If you look in there (to be clear, you have no reason to) you’ll just see metadata and directories.

Before we can use it, we’d better clone it. For ease, we’ll do this from the same directory we created it.

$ git clone origin_repo playground
  Cloning into 'playground'...
  warning: You appear to have cloned an empty repository.
  done.

It is empty, naturally. We haven’t made any commits.

Now we have two repos in this directory:

Let’s jump in there and see what’s up:

$ cd playground
$ git remote -v
  origin    /user/origin_repo (fetch)
  origin    /user/origin_repo (push)

We have remotes! Of course we do. We cloned this repo, and Git automatically sets up the origin remote.

And remember that origin is just an alias for some remote that’s identified somehow. We’re used to seeing remotes that start with https or ssh, but here’s an example of a remote that’s just another subdirectory on your disk.

Let’s make a file and commit it, and see if we can push!

$ echo "Hello, world" > hello.txt
$ git add hello.txt

$ git commit -m added
  [main (root-commit) 4a82a14] added
   1 file changed, 1 insertion(+)
   create mode 100644 hello.txt

$ git push
  Enumerating objects: 3, done.
  Counting objects: 100% (3/3), done.
  Writing objects: 100% (3/3), 907 bytes | 907.00 KiB/s, done.
  Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
  To /user/origin_repo
   * [new branch]      main -> main

$ git branch -va
  * main                4a82a14 added
    remotes/origin/main 4a82a14 added

And we’ve successfully pushed our file up to origin.

Finally, let’s make another clone. First we’ll cd back down to where origin_repo is and clone again this time into playground2:

$ git clone origin_repo playground2
  Cloning into 'playground2'...
  done.

Let’s cd in there and see what we have. It’s a clone of the repo, so we’d better see the hello.txt we pushed in there from playground earlier.

$ cd playground2 

$ ls
  hello.txt

$ cat hello.txt 
  Hello, world

Voila! It’s there!

Since playground and playground2 are both clones of the same repo, you can push from one and pull from the other to get the changes.

You can even make conflicting changes and try to git pull or git pull --rebase and see how things go wrong and how to fix them.

And if everything goes complete off the rails, you can just delete the directories and start again. It’s a playground!

20.2 Automating Playground Builds

It can be tedious to continually destroy and recreate repos that you’re trying to learn from. I suggest putting your commands in a shell script, which is just a text file that contains the commands to run.

Let’s say you make a new text file called buildrepo.sh and you put the following text in it:

rm -rf playground    # Remove old playground
git init playground  # Create a new one
cd playground
echo "Hello, world!" > hello.txt   # Create hello.txt
echo "foobar" > foobar.txt         # Create foobar.txt
git add hello.txt foobar.txt
git commit -m added
echo "foobar again" >> foobar.txt  # Append text
git add foobar.txt
git commit -m updated

That’s just a bunch of shell commands. But here’s the fun bit: if you run sh (the shell) with buildrepo.sh as an argument, it will run all those commands in order!

$ sh buildrepo.sh
  Initialized empty Git repository in /user/playground/.git/
  [main (root-commit) 2239237] added
   2 files changed, 2 insertions(+)
   create mode 100644 foobar.txt
   create mode 100644 hello.txt
  [main 0533186] updated
   1 file changed, 1 insertion(+)

Protip: If you run sh -x buildrepo.sh it will also show you the commands it is running.

After that, we can cd in there and see what happened:

$ cd playground
$ git log
  commit 05331869d77973dfbac38a31c40a44f99225e85d
  Author: User Name <user@example.com>
  Date:   Sat Jul 13 15:19:42 2024 -0700

      updated

  commit 2239237cc44d11e9479dcc610e5d02ad283766ce
  Author: User Name <user@example.com>
  Date:   Sat Jul 13 15:19:41 2024 -0700

      added

$ cat foobar.txt 
  foobar
  foobar again

By putting the initialization commands in a shell script, it’s almost like having a “saved game” at that point. You can just rerun the shell script any time you want the same playground set up.


Prev | Contents | Next