Coding Blocks - Git from the Bottom Up – Blobs and Trees
Episode Date: August 15, 2022It's surprising how little we know about Git as we continue to dive into Git from the Bottom Up, while Michael confuses himself, Joe has low standards, and Allen tells a joke....
Transcript
Discussion (0)
You're listening to Coding Blocks, episode 191.
Subscribe to us on iTunes, Spotify, Stitcher, wherever you'd like to find your favorite
podcast apps.
Leave us a review if you can, and you're thinking, hey, wait a minute, I thought we weren't doing
this old school intro anymore, and guess what?
We went old school and did it anyways.
So hey, while we're doing the old school stuff, you can visit us at codingblocks.net.
Find all our show notes, examples, discussions, and more.
And you can send your feedback, questions, and rants to comments at codingblock.
Or you can leave one on this episode, as people did in the last episode.
So, yeah.
All right.
And blah, blah, blah.
Blocks.
Hey, what?
So, I mean, y'all missed it.
So, I had to miss it.
Okay.
Also, we got a website.
I know you like websites.
www.codingingbox.net.
We got social links at the top of that page.
With that, I'm Joe Zeck.
I'm Mike Watlow.
And I'm Alan Underwood.
All right.
Let's get into it.
See what I did there?
Oh, G-I-T.
I get it.
Okay.
Ah, yes. Very good. All right. see what i did there oh oh g-i-t i get it okay ah yes very good all right so we didn't have any
reviews this time um so sad face i guess the bag will be nice and awkward this time and then and
then also want to a little bit apologize for the last episode because it seemed like we kind of got
lost in some details and especially me because i was going by the first article that we read and it definitely confused
some things. So if I confused you guys along the way, guys and gals, I apologize. Hopefully this
will clean it up a little bit here. And also I would go check out the comments from slash episode
190 because we'll actually put up some really good stuff on that that may help clarify things for you if you were confused along the ride.
So, you know, again, hopefully this one will be a little bit better.
Yeah, a huge thanks for all the feedback, too.
We got a lot of feedback on the last episode.
A lot of people helping kind of clarify stuff and, you know, let us know what you liked and didn't like, which is all really helpful.
So it was great to hear from everybody.
So thank you very much for all that. I know we got some emails and tweets and sl which is all really helpful. It was great to hear from everybody. Thank you very much for all that.
I know we got some emails and tweets
and slacks and all those things,
all of which were helpful. Thank you very much.
We have committed it
to our index.
That's right.
Am I getting this right? I believe so.
I believe you gilded it right.
I gilded it? Wow.
That's worse. That is so much worse.
I was going along with some great puns and then like, okay, whatever.
You were speaking of something.
Well, speaking of last episode where we started talking about a book,
open source book, free, called Get From the Bottom Up.
We're going to continue on that with that.
And this is the book by, uh, I think it was Jason.
Uh,
geez,
I forget.
Uh,
Jay Weebly.
I forget what the G the J stands for,
but that's the name on GitHub.
So I'm sticking with it.
Yeah.
Yeah.
I remember,
uh,
Alan definitely,
it was John,
but,
uh,
John,
John,
uh,
and Alan had to correct me on the pronunciation of the last name.
Cause I definitely messed that up.
And now.
Oh, by the way, did you see do you know the comment I'm about to refer to?
Have you already seen it?
So I I totally messed up last episode and I gave the Internet free reign over, you know, I bastardize everybody else's names.
Have fun with mine.
And so I think it was Michelle Outlaw, I think, was the one I saw in Slack.
Nice.
All right.
I asked for it, so I got it.
Ask and you shall receive.
Yeah.
So, yeah, there you receive. Yeah. So yeah,
there you go.
Awesome.
Very nice.
Hey,
I just found a John on Twitter.
So now I'm following and clothing boxes following John weekly.
So be cool.
All right.
Hey, well,
let's start off talking a little bit about directory content tracking and
someone else should start.
All right. So maybe, maybe I can reclaim a little bit of my lost, uh, mojo from the last one. So the directory, this content tracking, they said,
it's actually pretty simple because it just keeps a snapshot of the directories contents.
And it says that get represents your files and blobs. And if you've never heard of this,
it's a binary long object, similar to a Unix directory called a tree. And this is sort of
similar to what you see like in Google or in cloud storage, right? Like everything's a blob. It's just
an object that has some content to it, right? Nothing really special about it. Um, and one of
the interesting things about these is these blobs are named by using a SHA-1 hash of the size and
the contents of the file. And this is super important. They re they reiterate this so many
times over the next several sections that because it is nothing more than the size and the contents of it.
If you create this same exact file on your system, you name it, whatever you want.
It doesn't matter because it's irrelevant.
If you put the same contents in it and it has the same length, that same hash that SHA-1
will be on your system, my system, somebody's system, you know, halfway across the world.
Again, doesn't matter about the name.
It's just the contents and the length.
And by the way, you can actually see what the hash would be.
Of course, you could just run a SHA hash one, but there's actually a command too called
get hash object and you give them a file and it'll tell you what the hash is.
And what's really cool is like for a lot of this episode, I would actually keep my dot
get folder open or kind of working with commands.
And you actually see it generating these files
and naming them various things.
And so if you look under your.git folder,
there's a folder called objects
where it's going to put your blobs.
And it's pretty cool what it does.
It takes that hash number.
It takes the first two characters
and it creates a directory
and takes the rest of the characters
for the name of the file.
So it's like, it literally feels and looks
and is like a hash table. Well, that's some of the characters for the name of the file. So it literally feels and looks and is like a hash table.
Well, that's some of the...
Remember where we ended last episode
and I was talking about if you go and poke around in there,
we had talked about optimizations related to...
I think it was the designing data intensive applications
and how you might store stuff on disk, right?
And I was referring to how the first couple characters were used
as the directory for it and i was just i was wondering if that was like some kind of a you
know optimization trick that was decided on uh as part of like they're like where do i go find this
thing and like and also to like maybe limit the number of things that might you know objects or
files that might be in a given directory because Because at least on like some older versions of Windows, that's been problematic, right?
Wait, no, I think I'm thinking of the directory name length, not the number of files.
Yeah, on Windows.
Yeah, Java was always a problem on Windows for that reason.
Well, the class paths for Java.
Right, right.
Yep.
But one of the cool things here is, and they call this out. If you have, if you have a piece of content and I think they were doing like hello world or something in a file's going to have one reference to that blob ID, and then there could be multiple trees that that that same hash always points to the same exact file.
Doesn't matter about the name.
Doesn't matter where it is on this.
Just the same contents.
Well, I believe if you were to go back to the different systems that existed prior to Git,
like go back to your TFS days or Source source safe or SVN or whatever days, you know, this, this was actually
like a key differentiator for Git compared to some of those others where like the others would track
files and directories. And so there might be multiple copies of that file, especially like
as you, if you wanted to move around do you remember do you
remember versioning in tfs like it was like you would have copies you'd have like an entire copy
tree copy of whatever that was the version right and that's been a long time ago yeah yeah and and
and that's a key key differentiator here with git and why like the repo sizes can get, or like they don't explode
in size like the other ones. And there was actually a good discussion in our Slack, which by the way,
if you're not already part of it, you should be. But there was a question about like, you know,
services like GitHub and GitLab and whatnot. Actually, I think it was, I think that,
I mean, definitely this isn't the reason, but I
think that this was like one of the many things that made it possible for those types of services
to build around Git. Because like, think about if you wanted to host something like a GitHub,
right? Like if you wanted to make GitHub, right? You're going to host all, everyone else's repos, right?
You want those things to be as small as they possibly can be, right?
And so like, you know, I'm just guessing that like the fact that Git already had this
optimization built into it, then made it also possible like, hey, you know what?
It's now foreseeable.
It's now plausible that I could like spin up a service hey you know what it's now uh foreseeable it's now plausible
that i could like spin up a service you know hosting other people's repos without it being like
a you know huge burden that it would have otherwise been in like the old days of like
a tfs or whatever yeah i mean totally just think about all the forks of popular repos up on git
right like every fork of that in old,
like if you were talking about in Visual Source Safe or whatever,
if those are truly making copies of all the files like that,
it would get...
Well, I don't want to confuse forks, though.
Well, would a fork, wouldn't that still...
I think it'd be implementation.
Like that's a GitHub maybe ded do you do it with their files?
Like,
you know,
it would kind of make sense to me cause like forks are so prevalent and
things like license files,
like with the same exact text,
it makes sense for them to do it,
but I don't know if they are.
Yeah,
that's a good point.
It's a really good point.
So I'm going to double check now.
Cause now you're making me think about the force,
but,
but as I was thinking though,
I was like,
Oh wait,
uh,
Microsoft actually did have services to do hosted TFS.
So somebody made a business model out of it.
So one of the cool things that they call out here that if you have a blob in your repository, as long as there is one link to it, like one tree that is linking to that blob, then it'll exist in the repository.
As soon as there are no links to it, then it just disappears, right?
It's no longer part of the repo.
So if you have 50 that reference, you know, the same contents of a file, then those will
all be hard linked to that same blob content.
Otherwise it'll just end up disappearing.
Yeah, it's pretty cool.
You can actually see this, uh, you like you create two files with the same contents and add them both and you can actually go watch it in the objects folder like both of
them have the same hash you can do that uh that command that i just mentioned i forgot the name
of it now um hash object and you'll see that you know this one just one file and you can actually
decode the contents with another uh content uh another command called cat file uh and or is it cat file blob there's git cat file
and then there's git cat file blob okay yeah and give it the hash and it'll actually read out the
content so this is pretty cool so if you actually go browsing uh in the that dot uh gif folder you
can actually kind of click around and see what those are but it's a kind of a weird binary format
i believe you want to do the
dash t though to find out what the type is before you know that it's the blob okay yeah okay yeah so
and then and then just to circle the loop i did go back and find like so the fork is a copy so it
would be its own because that's what i was thinking of is like you know you you i'm pretty sure that
you would see your own copy of the repo like they're not it's not sharing a dot git directory right it's creating its own copy
yeah making a copy of that git folder then i guess man now you're making me dig into the
yeah i mean i would think that like you know at a naive implementation like it would just be
like they would you know they would keep it separate. Right.
But maybe they're doing some fancy stuff.
I remember I used to work for a backup company and like D dupe was a big thing back then.
And it kind of worked the same way where basically we kind of index things by
file contents in order to kind of keep your backups in a good spot.
And that way you could have like backups from history backups from today.
And it'd be tiny because you know,
any files that didn't change would be the same so you could
essentially get differential backups that way right um but yeah i mean what github actually
does it is safe for them theoretically to to reuse the same files and to kind of only point to one
spot because the files are immutable so like once you change the file contents you've changed the
hash and so that you can't ever modify these files.
But I,
you know,
I don't know if that's what GitHub does underneath.
There's,
I don't think there's any guarantee of that or either way,
like they could do it.
They could not do it.
I mean,
if I had to guess,
and I haven't found anything yet,
but if I had to guess the way the fork would work is it is just a copy of,
of the,
of the,
whatever the source repo is, but in your fork version of
it, I would guess that it's going to add a, um, uh, Oh, what would be the term for it? Like a,
um, a remote that would tell, so that you could see what the upstream that you forked from was because then it would make it easy for
you to like pull in changes from that original remote as well as to like if you wanted to pr
back to it so that that's my guess as to what's happening behind the scenes but you know they
probably want to expose that right i'm definitely like you know calling that out there is like
that's just you know a guess as to how it might work.
It's kind of funny to think an effective way to DDoS GitHub
is basically go find the biggest repository.
I'm sure they have some rate limiting on how fast you
could do that, though. Yeah, but still, how big is the Kubernetes repository?
It's probably huge. I'm sure gig the repositories out there that are gigs
and so you know it's just like that's kind of a scary thing but you know maybe they're doing
that sort of deduplication under the hood or you know or maybe they're yeah you know doing some
fancy stuff but i don't know we're just going to go now i'm going to go fork something and see if
i'm right about the uh about the the remote that the remote. That's funny. Hey, so while he's
doing that, here's another important piece of that. So we talked about the fact that a blob
is only content and the size is the hash of that. Um, a blob stores, no metadata about its content
whatsoever. So like I said, the file name's not there. There's no permissions. There's no,
who created it. None of that's there. It is just a content and the size, and that's super important. Now, the metadata is kept
somewhere that's kept in the tree that contains the blob. So that is kind of what knows what the
file name was that you gave it, right? So that hello world content that we talked about, you
could have named it hello.txt
or you could have named it greetings,
which I think is what they called it in the examples,
which I highly recommend going to the pages
that we have linked here
and just following along with what they do
and run these commands because it's eye-opening.
Yeah, it's cool.
So like one of the things we'll get to later,
it's like you actually create a file and you add it and you'll see your blob gets created then and then once you
commit it you'll see that another it's basically a blob too you know it's a it's serialized text
that will show up as well and that is actually the tree so you've got these uh these two objects
right there and then finally you'll commit and you'll end up with three total objects in your
repository for one file one is actual contents of the file one is the tree that has that additional metadata and the
final one is the commit that points to that tree yep and and here's the interesting thing that we
talked about earlier if you were to create um you know that one blob and then let's say you copied
and pasted that same thing all over the
place into multiple different directories, they would create a tree that would all point to the
same other thing with the contents, but they would have metadata about all the other file locations.
So it's, it's pretty interesting how they manage all that. And you can see it all with their low
level calls, um, that we'll talk about a little bit here coming up.
Yep, and I just thought it was kind of interesting.
They compared this early on to Unix file directories, and they kind of called out that Unix doesn't do the deduplication trick that we mentioned.
And that's because Unix is designed for those files to change. Like they anticipate that those changes are going to happen or potentially can
happen, which is definitely something they can't do because literally that hash, you know, comes
from the contents of those contents change. So does the hash. So the hashes are immutable.
Yep. So like I said, it's worth, we're going to have a link in the show notes here. It'll be down
in the resources. Introducing the blob, highly recommend clicking
that link and going up and trying this out. Like you don't have to do anything special. You can
just create a throwaway directory to do this stuff in and try it out. And it's pretty quick to go
through these things. But like we said, they create a file, they calculate the hash of the
file using this get hash dash object, and then whatever the file name is.
And if you were to follow their example verbatim with what they had, you'll get the same exact SHA-1 hash on your system because you're creating the same file, the same length.
So it's pretty crazy to see this.
And then what Jay-Z was talking about earlier, there's a couple of these are all super low level commands
right like this stuff that that we're talking about in the rest of this episode none of it
is things that you'll probably ever do day to day except to learn this is my definitely don't don't
do it yeah don't i wouldn't recommend it unless you're writing get tools or something right like
if you're writing the next get client, then maybe you do stuff like this,
but I can't think of any. It's pretty cool.
Like once you kind of know how it works,
like you could theoretically go do this stuff by hand.
Like aside from the SHA-1,
I wouldn't want to do a SHA-1 like with pen and paper,
but that you can actually go in,
create these files and do these things
and you'll have a valid, you know, valid Git.
So it's like you could rewrite Git
if you want to based on these instructions.
It's really cool.
Yep.
So like the one that we mentioned earlier, git cat-file-t and then a hash ID, that will tell you the type of the file.
So like when we were talking about earlier, if you created a file with some contents in it and then you did that git cat-file-t on that, it would tell you it was a blob. Um, and then there's other times that you can do
different types of, of hash IDs there. And it'll tell you if it's a tree or if it's a commit or
whatever, like this thing will tell you the low level types of the get system objects that it
sees. Um, and then the get cat dash file blob, and then you pass in the hash ID. We'll show you
the contents of it. So if you did put hello world in that thing that's what it would spit out on on your command line there um which
is really cool i mean it's just showing you the raw content of whatever you put into it
yeah so you know i mentioned those three files so i still had that set up so i went ahead and did the
git cat file dash t on each of those hashes and i got a blob a tree and let's do the last one live here
it should be a commit will it be i'm using my mac so while he's doing that what have you found
so i did try the fork in the background but uh it was commit yeah um and i should have i thought
about this like as i was doing it and then,
and sure enough,
like it doesn't automatically add a remote on your system when you do the
clone.
Uh,
so I was like,
you know,
it's like literally as I was typing the command,
I'm like,
wait a minute,
I'm not going to see these remotes there,
but a GitHub does say that like in their documentation for,
for example,
that they keep track of it.
So I'm guessing that maybe they're keeping that association as like a remote for it.
Maybe, you know, educated guess, but yeah.
Is it educated though?
I don't know.
It's just a guess.
Speculation.
It would make a lot of sense for them to kind of maintain that.
Or duplicating all that big, heavy data is a terrible idea.
For a free service.
Well, I mean...
A free account can go clone Kubernetes like 20 times.
Yeah.
I'm sure they're doing some special things behind the scenes right their own special
sauce okay okay wait a minute maybe maybe we're confusing things though because there's they could
create a clone of the repo right like a cop let me rephrase my wording there they could create a
copy of the repo there so that when you do your fork operation that I'm air quoting, and of course the listeners saw that I did that.
When you create that fork, right, it creates that copy for you.
And then that way you have your own repo to go and play in and mess around with, right?
Because that's supposed to be the point of the fork is that you can go experiment and then potentially make changes back to it.
Don't confuse that with the underlying infrastructure that that service
is sitting on top of, because like if it's a ZFS file system or even like there are other
NFS and SAN file systems that do deduplication at the file system level that, you know,
maybe that level is keeping your DDoSing from being that big of a problem.
Right.
Yeah, it's all implementation stuff
that we're going to have no idea what they're doing
unless we go work for them.
Yeah, it's kind of bugging my brain,
but maybe we'll be able to read up on how forks work.
Maybe it'll be later in the chapter.
I don't remember.
Yeah, possibly.
Hey, so while we're at it here, what we've talked about so far was just dealing with blobs. We haven't even talked about the chapter. I don't remember. Yeah, possibly. Hey, so, so while we're at it here, what we've
talked about so far was just dealing with blobs. We haven't even talked about the commits. We
haven't talked about the trees. We haven't talked about the repositories, nothing, right? We're just
talking about the fact that there is a file, it has its own hash and you know, you have this blob
and that is the base level unit for working with Git is the blob.
And then everything else sort of builds up from that.
So, hey, no one else is talking.
So I jumped in here to ask you about those reviews because, you know, we love those reviews.
And we love hearing the feedback, especially, especially when it's three plus stars.
We love those.
So if you have three plus stars in you,
we would love to hear it.
We tried to make it easy for you
by going to codingblocks.net
slash review.
So if you have a three plus star
in your heart
that you could bear to part with for us,
we would love it
if you went to codingblocks.net slash view and clicked maybe one of those links and left us a three plus review
it's such a low bar that you're setting there right like couldn't even go for four hey you know
i'm willing to go lower whoa you know don't push me because i'm close to the edge okay
nice all right okay well yeah sorry i was uh i was cleaning up some of my uh Because I'm close to the edge. Okay. Nice. All right.
Okay.
Well, yeah, sorry.
I was cleaning up some of my forking mess that I did there. Which, by the way, you went to Kubernetes, and I was like, no, let's just clone Scaffold.
Because that's more in our daily daily lives that's more in our control
like there's there's a better chance that we could get a commit into the scaffold pipeline then
but it's so much smaller we know something that has yeah oh yeah see there you go there you go
all right well uh then i will lead us into with. We head into my favorite portion of the show.
Surveys.
All right.
So this goes back to a few episodes back.
Kurt Frank gave us a survey idea about like, hey, which book should we finish?
Right.
And your choices were.
I'm going to try to read through these pretty quick
because there's a bunch of them.
Site reliability engineering,
designing data intensive applications,
domain driven design,
clean code, clean architecture,
the imposter's handbook,
the DevOps handbook,
any book, just finish one.
I actually like that you leave some of it for me to read on my own
or just move on to another book ain't nobody got time to go back to those old books
or maybe after last episode get from the bottom up all right
if we can't laugh at ourselves man who, who can we laugh at? Right. All right.
So, uh, this is one 81 according to Alan, uh,
Alan to tech has trademark rules of engagement. Alan, you are first.
And I'm, I'm hoping nobody says domain driven design. Um,
not that I didn't like it, but man, that one was hard.
I'm going to go with designing data-intensive applications,
and I will say we had a lot of choices here.
I'll go with 20%.
Okay.
Taking the safe road.
Yep.
Joe Zach, you kind of need to unmute for for people on the podcast to hear you he did that
on purpose yeah i had to i had to get some i had to vent a little bit because 20 is too low for
this wonderful book i think you could safely go with 36 so you're choosing the same one then huh
same one yeah can i change my vote? Yes.
You know what?
I will allow it.
All right, I appreciate that.
I'm going to go with the imposter's handbook then, and I'll go at 25%. I will jump up a good old 5% on it.
All right, I want to change mine.
What?
I will allow it.
Okay, let's go with DDIA with 40%.
Wait, isn't that the same book you already picked?
Same book.
He just upped it.
He upped it 4%.
Okay.
Final answers.
Final answers.
We're like mixing in the rules of a third game show here.
Here we go.
Does anyone want to phone a friend?
All right.
Can I get a 50-50?
Well, I got news for you.
Somebody almost won.
Oh, man.
Joe Zack.
Oh, man.
What was the percent?
Designing data-intensive applications was the fan favorite
or is the fan favorite.
You ready to kick yourself?
Yep. I want to kick yourself in the shins, you ready to kick yourself? Yep.
Because I want to kick yourself in the shins for you.
All right.
37% of the vote.
Oh, wow.
Nice.
When you said 36%, I was like, I'm sure he's cheated.
There's no way.
There's no way the Mathem of Chicken got that close.
So I am curious, though.
What was second and third on here?
Because maybe those are worth revisiting as well.
Alan?
Yeah?
Disappointment's about to be a big part of your life.
Are you ready?
Oh, man.
No, not domain-driven design.
Actually, I like that you leave some of it for me to read on my own was the number two okay that's
not bad but number three it was domain driven design wow i mean it was good but man it was
hard to read yeah i, I was really surprised.
Site reliability engineering, I was surprised that it was so low.
But also, Impostors Handbook and DevOps Handbook, I couldn't believe those were so low either.
Poor clean code.
Poor clean code.
Was it down in the dumps?
Oh, yeah.
Yeah, it was.
We won't talk about that.
Nobody wants to write clean code.
Yeah.
And obviously, nobody voted for Get From the Bottom Up because that wasn't one of the choices.
But clearly, it should have been.
Okay.
So, I got something new for us this time.
So, you ready for this?
Let's do it. so i got something new for us this time so you ready for this we've done this before but i'm
gonna like uh you know i think what did i call this last time i'm gonna i know i'm gonna call
it this is jeopardy for coding blocks so you ready so that here here's the new introduction
this is jeopardy i don't know that didn't sound anything like it that's not
in my head that's really good it sounded like it was going to be a good idea and then the execution
of it fell apart no no no it's pretty good man so here's the idea um we're we're talking about get
right and i'm going to give you a question, right? And you're going to see what Google,
you're going to try to see who can get closest to the top answer that Google
would come back with on your computer, on my computer.
But in my computer, I'm also like incognito to try it all.
Like, you know, you know, if you really want me to,
I'll spin up a VM and GCP and we'll do it there.
But we'll be back in just a moment, folks.
Yeah, yeah, yeah.
No, yeah, GCP is pretty fast.
Don't.
Okay, so here's the question.
Now, again, I'm going to give you a question,
and you're going to try to fill in the blank that Google Auto Suggest would do for that,
and whoever gets the closest is going to be the winner here.
Are you ready?
And this is going to be hard.
Do I have to buzz in? How do we buzz in who goes first uh i mean did you want to
have a first or go first or buzz in or just like okay we we can be gentlemen about this uh so we'll
we'll apply to tucko's rules of engagement here as well then so uh you know it's an odd number episode so alan will go first that's right
all right why is git
dot so hard okay so hard
jay uh well uh i have to choose something different. Uh, uh, so weird.
So weird versus so hard.
Yep.
Um,
I'm going to have to give Alan the win for this one. The second choice from Google was why is get so confusing?
Ah,
okay.
Yeah. Yeah. And so, uh, uh that's some i'm saying like you know
hard would be kind of like confusing more than weird but the number one the number one the
number one is why is git called git what does anybody know nobody asked that that was the
number one from google and it is actually in the Git readme.
And I will have a link to it as well as the, there's a link to, I'll have a link to the Wikipedia article for it as well.
Where Mr. Tavoles himself sarcastically, and I'm sure I bastardized that name as well.
That's trademark what I do.
Quipped about the name Git, which means unpleasant person in British English slang, apparently, according to Google.
And I won't say all of the wording here because I think like some of the wording, at least in the Wikipedia article, you know, some languages don't mind some choices of words, whereas in, you know, America, you know, we need that clean tag on that podcast title.
So at any rate, so I'm going to try to like do what I can here. But he said when he described the tool as the stupid content tracker and the name is one of four things depending on your mood.
Okay. The first one is, this is a random three letter combination that is pronounceable and is
not actually used by any common Unix command. And the fact that it is a mispronunciation of the G E T may or may not be relevant.
Okay.
That's number one.
Number two is stupid,
contemptible and despicable.
Simple.
Take your pick from the dictionary of slang.
Number three is it's an acronym for global information tracker because you're in a good mood and it actually works for you.
Angels sing and then light suddenly fills the room.
It's never that one for me.
Never.
Now I'm going to,
I'm going to like,
you know,
change some of the language on this one just because of,
uh,
I don't know,
Apple podcasting rules or whatever,
whatever.
Um,
huh?
So God darn idiotic truckload of crap when it breaks another acronym god darn idiotic
truckload only he wouldn't say it was like such a southern choice of vernacular and accent when he
says it i think i think I got the translation.
Yeah, okay.
Yeah, you could substitute some word.
You could figure out what he was really going after.
But that's from like, you know, the man himself
as he's describing it.
I just thought it was kind of funny.
And also that's the number one thing
that came up on Google.
All right.
That's crazy.
All right.
So let's get back into it.
All right. You want to take the lead on this one here, Outlaw?
You were busy looking up how GitHub worked in the last section.
Oh, yeah. Well, and now I'm trying to put these links in there before I forget them.
But yeah.
So blobs are stored in trees.
So remember that there's no metadata about the blobs.
It's just the data written.
So they kind of made the author, John Weigley.
Weigley.
Dang it.
He made a reference to it being like the file system, right?
And he had made a point about the inodes being that kind of metadata for it.
And you just had the blob, which was the file content itself and so here we're saying that like there's no metadata
about the blobs just the data within it uh is the is the content there git maintains the structure
of the files within the repository in a tree by attaching blobs as leaf nodes within a tree. And there was actually a quote, um,
in somewhere in the book too,
where he was,
where he said,
uh,
that,
how did he refer to it?
It was like the,
the,
um,
it represents your first,
it represents your files,
contents in blobs,
which are also leaf nodes in something awfully close to a dictionary called a
tree.
So going back to what Alan started with from the beginning,
just kind of tying those two things together.
Jay-Z actually said the hash, but that's fine.
You can implement a hash table as a tree.
It looks like a hash table if you ever have one described.
I was referring to, no, Alan, you definitely said it.
It was about that Git represents your file contents in blobs at the very start.
I was going back to that.
Gotcha.
So yeah, there were a bunch of cool commands in here that we get into that you never really needed to get into.
But one of them was git ls tree, and then you could give it a ref.
In this case, the command that they used in the book was they used the head.
I think I used the word variable last time, and we decided to call it an alias this time.
And I think even in the book, though, he had a different description for it, wasn't it?
I thought he called it alias. had a different description for it, wasn't it?
I thought you called it alias.
Maybe I'm thinking of the conversation that was in Slack where somebody referred to it as like a pointer or something.
I don't remember which.
Oh, yeah.
That was Slack.
Somebody said that it should be treated like C++.
Oh, right, right, right, right.
Yeah.
Yeah.
So get LSTreeHead will show you the tree of the latest commit in the current.
I don't like this choice of words, but directory.
Where you are on your file system, right?
So it's, it's actually on your file system.
If you do that, get LSTree.
Well, I'm not sure.
Like, so if you type in get LSTreehead though, I don't like referring to it as – I don't like the – so I don't know who put this note in there.
So I'm trying to be nice about this.
It was me, I think.
I don't like confusing terms like directory in when we talk about Git because I don't want to think of it necessarily as a file system, even though there is that that analogy at the beginning so i don't know maybe i'm wrong for not wanting to do that but at any rate
maybe maybe with the current um branch that you're in because you have to be in a branch in order for
you in order for head to point to something right well no uh yeah because
if you were in um if you checked out the commit then you're headless right now i'm forgetting
yeah i'm confusing myself
yeah that's all right um so just kind of catch up make sure i understand so we're talking about
basically how git maintains the structure of the files of the repository with the tree,
but attaching the blobs as the leaf nodes within the tree.
And so you can go in that folder
and actually see where those blobs live,
but conceptually these live in a tree.
And you can see this by doing a git ls tree head,
and assuming you've made at least one commit here,
you are going to get a result
that basically tells you what that blob so the
example here we've we've tried to uh kind of cut down on some of the examples like in the chapter
that has you like walk through some stuff when you don't want to read a bunch of commands but
the example that we're seeing here right out the gate is basically doing a get ls tree of head when
you've got one commit and what it's going to do is show you that you've got a blob and it's going
to show you the hash for the content of the blob as well as the file name so
it's basically showing it's kind of marrying that metadata that it knows about this content
and displaying it for you yeah i was i was wrong about my um comment about like if you were in the
headless state or the detached head state because it would still show you uh where you are because
head would still be pointing to where you're currently at but what if you don't have any commits
if you did if you have like i know the answer like you get a knitted a uh a
or what you want to be as a repository a repository so you don't have any commits in it
though yet like what if you had no two yep i would think you would get an error like a git log would give you an error right
because you don't have anything for it to point to yep so it tells you that the uh log doesn't
exist or sorry it says not a valid object uh name head when you do the git ls3 if you do get logs
as your current branch appears to be broken but both it's because the head hasn't been created.
It actually doesn't exist.
And you can actually see this.
Like when you walk through the examples, you're like, just open up this dot get folder and you'll see that there's literally, you know, there's a head file, but there's, it's not pointing to anything.
So it's cool.
Uh, yeah.
Okay.
So I'm now I'm trying to remember something because when you say like the point to
like it's just the contents of the file if i remember correctly well which thing you're talking
about i want to go back and double check and look at that and look at my git directory uh yeah so
if you go if you look in your git directory head is a file. And if you were to cap that file out,
it has just a commit ID in it.
Yeah.
So by,
I want,
I wanted to clarify the language of point two,
because it's not,
it's not like a symbolic link or anything like that.
It's just,
it's just a file that has the contents of what it's,
what it's representing.
So if you've got a repository with no commits into it you've got a
head file and it just says ref ref heads master but if i'm actually if i go and do this commit
then wait the font the head file actually had contents in it you're saying yeah it wasn't
zero size let me try i'm gonna do i expect it to be zero size. I'm making now
get test five
is the name of this folder. Don't we forget this?
Test five. We'll just make
sure. I think that was
the pilot that didn't make it back when they went
to get the Death Star,
right? Test five
was on the left. I think it was five.
Rogue five?
Red leader? I don't know.
So I'm doing a git knit.
And I'm looking in my folder
here. Yep.
You do have a head
file. Zero size.
No. It has ref
colon ref heads master
in it. Learn something new every day.
Yeah.
Interesting. But my objects directory only has two empty folders in it. Learn something new every day. Yeah, interesting. But my objects directory only has two empty
folders in it.
Okay. Now I'm creating
a file just to make sure.
And I'm narrating while I
do it.
So,
I just want to make sure.
Sorry, go ahead.
Well, I was going to go on to the get rev parse head
which decodes the head into the commit id it references so if you were to uh i mean you just
get back the the literally the command it's basically like the same as like cat in that file
if i remember correctly uh am i wrong okay i'm a dummy yeah okay so i i got tangled up on something yeah
it's the same thing as cat in the file yeah so check this out so if you do uh if you just switch
branches like get check out b and give it some other name guess what head now it has a ref to
the name of that branch so you know originally when i said master this because master is the
default name of uh my
branches so my when i did my get in it that's what i pointed to i check out another branch called
test now my head points to refs heads test
oh okay so
yeah and so check this out so now if you go into the get dot get folder, there is a folder under there called refs folder under there called heads.
And I have two, one for master, one for test.
Both of those point to and I hope I'm not leading us astray.
But I did do a commit here just because as I was kind of messing around
and both of these heads, master and test,
both have the file contents.
The only thing in this file right now
is a hash of that commit.
So if I do a git log, I see that same commit.
And real quick, going back to the thing
where it's saying git ls tree,
it'll show the tree of the latest commit in the current directory.
So that is accurate.
And I tested this out, too.
So if you're in a directory, and let's say you make two directories, and you do a get init in whatever directory you're in, then you make one directory called test1, you make another directory called test2.
And let's say in test1, you put file ABC and in test two, you put file DEF. If you do, after you commit that,
it's very important. After you commit those changes, if you did a get LSTree from your root level get, right? It'll show both those files in there and it'll give you the tree hashes of those. If you were to CD into
test one and then do a get LSTree from just test one, you'll only see the blob or the tree
that exists in that directory. So the get LSTree is actually, you know, it's contextual based off
where you are on your file system inside your Git repository.
So that's why it was worded that way, because it actually does list it out.
Like if you go up a directory, you'll see more than if you go down into a subdirectory.
Just to kind of close the loop, I did start a Git test six folder and i did again in it and it does create a head file on the head of the
contents of it say ref colon refs heads master and that's a file location so i go and drill into ref
refs heads uh there is no master because i don't have any commits yet and so that's why you know
we try doing like a git log you get an error um We do the Git LS tree, we get an error because we have no tree yet.
We have no commits.
So the head just points to a folder that doesn't exist yet.
But once you make that first commit,
then you get a folder under that heads for the branch name that has a list of
commits in it.
But I want to be careful here though,
because like one thing that's confusing with the example, though, Alan, the directory example that you gave, when you do that LSTree, it's not showing you the directory structure.
It's showing you the commit the commit history of that of that tree so you give it a a starting
point which in this case you know we were using head in the example but you could give it any
commit and i'm assuming that you could probably even point to it by like uh ref heads and branch
name so so so let's not even let's not even go that deep into it. Let's not confuse that. If you do a get ls
tree head in the root directory, it'll show you both of the other directory trees that are there.
If you go into one, like I said, I created a directory test one and test two. If you go into test one, you can run that same command, get LS dash tree head from there.
And it will only show you that portion of the tree.
So get LS tree is contextual based off where you run it.
So like, so here's the interesting thing, right?
So when I did that, like I said, I created a file in each one of the subdirectories.
When I do a get lstree from the root, and I'm not doing a dash R for recursion or anything,
I'm just doing a get lstree head from the root.
It shows me the two directories, and it gives me the hashes for those directories or those
trees that get as tracking, right? If I go into test one and I run that same command,
get LSTreeHead in that directory, it now shows me the text file I created in that directory
with its own blob hash. So the top level shows me the two tree hashes that were there.
And then when I went into the subdirectory, it showed me the hashes of the blob that I put there.
So it's actually showing different information at different levels of the tree, wherever you are on your file system. And that's why I want it. That's, that's, what's important. It's contextual
based off where you are in your get repository and the layout of that. Yeah, I see the same thing.
That is crazy. I never knew that. Yeah. I didn't expect that. And so here's same thing that is crazy i never knew that yeah i didn't expect that and and so
here's another thing that's really cool based off like the the kinds of things that we're talking
about here and what jay-z just mentioned the the dot get folder like when when he was talking about
head you can actually cat out dot get slash head and it will tell you what it's pointing at. It's
just, it's, it's exactly what we said earlier. It's the pointer to what branch or whatever you're
looking at. It's, it's basically just text, right? So a lot of the things or some of the things in
that get folder, it's literally just overriding. with we've talked about like when you add a new
commit that head will get updated to point to whatever you know that latest bit is so it's
just a text file and that is how git is keeping track of this stuff but it's not updating that
text file as you're changing directories though no no not as you're changing directories no i said
when you do commits i guess like that's. I never realized the contextual nature of it, but I also don't have to use, fortunately, the ls tree command often.
That's actually something worth calling out.
I don't remember if we said it earlier.
A lot of the commands we're talking about here, you should probably never, ever use as your regular day, right?
These are things that are useful in learning how to do this.
And maybe, like I said, if you're going to write a get tool, but I don't think you're ever going to be running a get LS tree unless you're doing some really special stuff, right?
Okay, I see it now.
Like, it says in the description for it, the behavior is list the contents of a given tree.
And they use the LS minus A as an example of the current working directory.
And it says the behavior is similar to that in that the path is taken as relative to the current working directory.
But you can use the dash dash full dash tree option to ignore that relativity.
It makes sense with being consistent with LS.
You run LS by default, it's going to use your current directory,
but you can do ls dot dot slash, do the directory up,
or pass an absolute path and it'll do it.
Yeah, I just never would have thought that it would
go and find all the blobs that are specific to that
because I just thought you're passing it
some kind of a ref, either a branch name or a commit ID, all the blobs that are specific to that because i just thought like you're passing it a uh some
kind of a ref you know either uh a branch name or a commit id and then it would just be like here
you go spitting out stuff for that but you know i guess that i guess if it did do that that would
be kind of dumb because then be like well we have other commands for that why do we need this one
so you know you know what's really interesting about this. Well, just to finish the loop, your, your analogy of it working like the LS that's in the name of it makes more sense.
Yeah.
So, so here's why people like, I think in the, the original article we talked about that I now kind of hate because of last episode, the Dominus one.
Um, but when he mentioned that the get CLI kind of is frustrating, like here's an example.
So like I mentioned, when you run that get LS tree from that root directory, you see
two trees, right?
Like it shows you a tree for test one and it's hash and then tree test two and it's
hash.
If you do a get LS tree dash R head for recursive, it just shows you the blob hashes from the subdirectories.
It doesn't show you the original tree stuff.
So it like modifies totally what you would sort of expect this thing to do.
Like I would expect it to almost, you know, give me the output of what it would have done at the root. And then in the sub directories instead, it just gave me the output as if I had gone down into each sub directory
and run the get LS tree. So it's, it's frustrating working with the get CLI because,
wait, I don't know. I'm missing, I'm missing that last point. If you do the dash R for the recursion
recursion or recursive, you're saying that you weren't seeing what's in the root? Because I am.
You do not.
No.
So I didn't create a file in the root.
So if I just do get ls-tree head in the root, then I see that I have tree one and tree two.
Or yeah, the trees are my directories, right?
It says tree.
Yeah, but then you do the dash R and you do see what the contents inside of there.
I see the contents, but I don't see that there's trees there yeah i see the blobs yeah but i mean it's
written out as the name though right as the name with the blob it just doesn't show the trees with
their hashes so again it's it's just oh i see let me make that let me make this distinction clear then you are seeing the the directory name or tree uh
but it was a directory that i put on my file system stored as a tree in git i do see that tree
no no that directory name as directory slash and then the file name but for the the objects that git is showing me it shows you
the uh uh what's that first bit where it has like the the read write group kind of stuff um no oh
man the attributes and then and then it shows you the type that it is which in this case is a blob
and then it shows you the hash of the blob the shaw one of the blob
but you can't see the shaw one of the directory or the the directory on my faucets and noise
which is a tree and get unless you didn't do the recursion right i mean it kind of makes sense it's
like it's like you're doing a an ls you know are you doing the LS minus A or are you doing it recursively?
So now this command is making so much more sense to me once you, like, tied in the LS to the regular file system.
I don't know why I never thought of it that way before.
Yeah.
That's cool.
So, yeah, again, this is stuff that it's worth doing this for the examples and learning how to get to doing things behind the scenes.
But I don't know that I can think of a time when I would ever actually go use
this.
Yeah.
I'm hoping that like one day I'll run into a get problem and like,
it'll make more sense because of this,
but I don't know if it will,
but it's still been really cool.
Yeah.
So I've been happy.
It's been like,
is this one of those books where like you really got to do the examples and
just kind of see it.
All right.
So we did the get rev parse head
i think you did that outlaw have we done the get cat file dash t head well we kind of talked about
this one already though because i mentioned like you had to specify the type right and wasn't this
where we were talking about that i think so with the head it's different it just tells you what's
at the head right um whereas if
you put in the hash you kind of know well maybe maybe you don't know what it is this wasn't the
one i was thinking of that yeah we i kind of jumped ahead a little bit yeah if you do a get
uh get cat file dash type on head then it tells you that the type is uh is a commit yes and it
like just like you know we said if you drill into this folder and
find this uh into the refs heads like and pick on your branch you're going to see assuming that
you've had at least one you're going to see a file named after your branch and it'll have
a single uh or sorry not a single it'll have yeah, it will be single. Commit hash in there.
And you know what's really interesting?
If you just throw the word commit in the middle of all that,
then it gives you the metadata.
So if you do get cat-file commit head,
then it'll give you all the metadata about that commit,
what tree it belongs to, who the author was, the committer,
all that kind of stuff.
So there's modifications to this get cat file that will give you different
information based off what you're trying to look for here.
Well, that's where you have to know the type first.
You do, right?
If you put, instead of commit, if you put, um, tree there instead of the other on head,
it would have failed.
Well, you just get weird stuff.
Yeah. You get get you get garbage if you do get cat file tree head you're right yeah you you get some really nasty looking stuff
i mean because you can break stuff uh yeah i'm assuming it's just like being kind of dumb about
it and assuming you already know what the type is and it's just going to be like,
okay,
this is the format that you want to see this.
And so I'm just going to print it out like that.
But you know,
again,
that's just an assumption.
Agreed there.
I wonder there's,
I'm,
it just seems so shocking though that it wouldn't have like a way to just
like you go figure out the type.
Why do I have to tell you?
Oh,
this last part, I forgot that I had put this in the notes,
or maybe this was already somewhere else.
But I think I went and looked this up because I was playing around with the git commands.
So if you want to see what git is maintaining and its own information about trees,
I put a set of commands here, and it's find space dot get slash objects and then space dash type and then
F. And it will actually list out everything that get is tracking. So it's it's kind of interesting
just to see what's going on behind the scenes. Again, I don't know that it serves any real
purpose. Well, if you're in bash. Oh, and if you're in bash,
yeah,
you're going to need the find.
Yeah.
I mean,
this is,
this goes back to where we started,
where we ended last episode.
And one of the comments made at the beginning about like how it's taking the
first two letters of whatever the Shaw is and creating a directory.
And then the rest of it is the file name.
And,
you know,
I was supposing,
I don't know,
maybe it's some kind of weird optimization thing,
but cause, cause what it spits back out to you is like literally in this find command is
going to spit back out the directory structure right because you're you're literally just saying
like hey find all of the things that are in this object's directory uh that are of type file
and and it spits it out but you don't know like what those types are. And then you'd have to do some like,
uh,
you know,
inline kind of awkward said,
or both type,
uh,
uh,
concatenation to get that directory back into the,
with the rest of the file name to get the actual complete shawl is one thing
so that you could then use that as like an input to,
uh,
Hey,
cat file minus T.
What is this thing? And, you know, well, you know, the interesting thing about this and the reason
why I thought this was kind of cool is it shows you that get is basically duplicating your
directory system and its own metadata, right. Um, to a certain degree, I mean, and even more so
because it's creating trees, it's creating,
um, objects it's or, or blobs and that kind of stuff. So like, as you add files to your system,
to your directory and that get repository, like this grows fast and it was odd to me. I'm not sure.
I'm sure they have a reason for it, but the hash, they always divided it up into the first two of the hash and then slash and then the rest of them.
I'm guessing that's for file system purposes, but I don't know why.
Yeah, that's what I was getting at is that like maybe that's some kind of weird optimization that they were deemed that like, you know, hey, this was this was good enough that if we did that,
we could break it up.
We don't run into file name problems.
We don't run into number of files kind of problems.
It'll make sure that you don't have more than 225 folders at that level.
Oh.
That's interesting. Oh, two is interesting.
I'm sorry.
15 squared.
Oh,
so I actually forgot.
So I put the note after this,
that find dot get objects,
that thing.
The whole reason I did that was because in the previous commands that they
were talking about in that,
in that page,
you know,
they were showing you the commit,
the tree,
the object,
all that kind of stuff.
After you go through that, if you do this find, you'll actually see that all of those
exist in the file system in that git folder.
And so it's kind of interesting that they all map out.
And like Outlaw said, you see them all there, but you don't have any metadata about them,
right?
Like you don't know if it's a tree or if it's a blob or whatever, but you can see that
everything that you've been looking at, all those hashes are in that Git metadata that it's
storing on the system.
The author actually walks through an example where
he does a cat file
on, a cat file
minus T on the different
commits to see like, okay, which one's a commit,
which one's a tree, which one's a blob,
and you know, let's go delete
stuff. Oh no, he didn't do that
part.
That's definitely going to ruin your repository. And, you know, let's go delete stuff. Oh, no, he didn't do that part. Yeah.
And that's definitely going to ruin your repository.
All right.
Maybe.
Maybe.
So the last bit that we're going to get into here is how trees are made.
Because this is sort of like the next step.
I know this one.
Yes.
You dig a hole.
Gotta dig the hole first, man. You do. or you just shove it down in the dirt right yeah i don't know maybe you don't have to dig a hole you
pollination bees birds do something i don't know something happens yeah so we've talked about this
a little bit that git contains its own metadata, right? So there's this notion of an index. And the way that they say this is it's what you use to initially create blobs out
of files. And that doesn't make a whole bunch of sense to me, at least not at this point,
but it does when you start looking at it on the file system. So what they say is if you were to
do a get ad without a commit, assuming that you're following along with the page that we'll have linked there, if you do a git log, so brand new repository, you get a netted it, you add a file, like you echo something to a file, and then you do a git add.
And then right after that, you do a git log, it'll blow up.
And it blows up because there is no log.
There's no
commit. So nothing has actually been committed to the repository at that point. Okay. Okay.
No, I'm trying to follow. I'm following along in my head. Okay. All right. So I'll continue.
All right. So here's, what's interesting. We've said it does still modify your repository
in a way, right? Because get has to still know about this. Well, there is another low level
command called get LS dash files, dash, dash stage. This will actually show you that you have
a file on your system and, and it's being referenced by the index, right? The
get index on, on what it knows about. So that's pretty good. Um, at this point though, still,
you've only done the get ad, you haven't done a kick get commit. The file is still not referenced
by a tree or a commit. It's only in that get index file. you had a question well i was just going to say that the
ls files by itself this goes back to um well no this is the same well command where we talked
about a minute ago it wasn't ls files ls tree yeah so this is similar to that though that it's
going to like just show you the files that are in your uh in your repository but now i'm curious that if like the ls files if i would go into a different
one and i say get ls files into a different directory and yep sure enough it shows only
the files that get knows about that are in whatever the current working directory is
yeah so that makes sense contextual yeah yeah and you know um i don't think they called it out
but i was just kind of watching as i was going through this. And I noticed that the actual blob got written into the objects folder when you did the add.
So you do the add, it creates the index, but it also kind of makes sense.
Like it shoves the file contents in the form of that blob into the objects as well.
Yep.
But it's not been committed yet, right?
So it's got all the metadata about it, but it hasn't done anything to put it committed into the repository yet.
Yeah, and if you do a reset, as you might expect,
it's going to both get rid of that index, it's going to clear that index file,
but it's also going to remove that object,
assuming it wasn't referenced by something else.
So it's going to kind of clean things up there.
Okay, so it did kill that blob then, that reference that it had there.
Yeah, because this shows like, hey,, that reference that it had there. Okay.
This shows like, hey, I don't need to do git reset anymore.
I can just delete this index file, but then it's going to leave stuff behind.
Yeah, it could get nasty at that point.
Okay.
So now the next thing that we were talking about, again, we're not doing a git commit yet.
That's too easy, right?
We want to take the hard road here based off how they're doing things. So what they do next is called get write dash tree. And this takes the content
of your index and it writes it to a tree, which is a new hash, right? That's another one of the
object types that Git knows about is this tree. So now you've got, you've got this object, like what Jay-Z was just talking about. It's
there. You've got, so the blob with the hash, now you have a tree with a hash. Um, and again,
what we said is if you're following along with what they've been doing on this page and you use
the same exact echo to a file, you're going to get the same exact hash that they have. Because remember the shot one is always the same for blobs. I have the same content,
same length, blah. All right. So, um, and then they say the next thing is pretty interesting
to a tree that has the same blobs in it and the same sub trees will also have the same hash
because they use the same hashing algorithm, right? So if you have, if, if I have the same file set up that Jay-Z has and the outlaw has,
we're all going to have the same hashes for our trees with this get right tree, um, command.
All right. Okay. So this low level right tree, what this does is it takes those contents of the index,
it writes them into a tree in preparation for a commit.
Now, this is what's interesting, right?
So behind the scenes, this is probably what the real tools out there are doing.
So now the next command that you would run is get commit tree.
You would pass in that tree's hash that you had. It then makes a commit
that holds that tree is what they say in the document, right? So now you've kind of gone
the full circle on these things, right? So now you have a commit that has a reference to that tree
that has a reference to that blob, and that is stored in your repository so now if you ran a
git log at this point i believe technically you should see some information in there right yep
yeah and i walked through this as well and so just to kind of sum it up again so what we did is we
created a file we did a git add and when you did that git add it created the blob for the file
contents if it didn't already exist and then it created that entry in the index we did this
right tree and what it is is it cleared that index file and it wrote a tree object into our objects
folder and then once we did the commit tree it created another object into this object folder
for the actual commit it took a hash that pointed to the tree the tree uh in this case, talk about a single file, pointed to our blob.
Yep.
And here's one other interesting thing about doing this low-level way
of working with these hashes in Git is typically if you're on a branch
and you do a commit and then you do another commit
and you do another commit, right?
That third commit is going to point to that second commit, right? We talked about Git log and you
have this sequential type history of things. Well, it's because the third commit had a parent of the
second commit and the second commit had a parent of the first commit, right? If you want to do that
with this Git commit tree, you actually have to do a dash P and pass in the hash of the previous commit that you want it to be its parent.
So there's a whole bunch of magic that happens behind the scene, or I guess not magic.
Now we're kind of demystifying a lot of it, but there's a whole lot of things.
Maybe, maybe, hopefully a little bit better than last time.
But when you do this, there's a whole lot of things.
When you just do your everyday regular git commit,
there's a lot of stuff that it's running behind the scenes for you
to link everything up and to make everything sort of easy, right?
I mean, there'll probably be people who'll be like, it's not easy.
There's a whole lot easier than this.
That's for sure.
Yeah, and so without that p argument,
what happens is your commit just points to the single tree, and the and time of single file points to a single blob. So I think if you did a git log here, you're just going to see your most recent commit. You basically lost your, you know, any others that you may have done.
I believe that's what it would be, right? Like you wouldn't have any history.
You're saying if you did, if you didn't include the parent.
The dash P, right?
Because there'd be no linkage, right?
I don't think.
So yeah, let me see here. I don't think I can reproduce this.
While he's doing that, my guess was going to be
that this would be the case of a shallow clone.
This would be the equivalent of doing that.
I only want from this point forward,
and I don't care about the past.
Yeah, that would make sense.
Now, also, while he's looking that up, I had another one for you, too.
As we were going through this whole index thing, I wanted to confirm this. the list of paths and whatnot,
that the SHAs of the blobs
that are part of the repo at that point in time, right?
But when you did that git add command,
well, no, I think in your example,
you didn't do the git add, right?
No, yeah, you did.
No, you do the git add.
You did do a git add in this example.
Yeah, you haven't committed it yet.
That git add command in the background creates the blob underneath the git objects for you.
That's what Jason was saying.
And then the index is pointing.
Oh, wow.
Yeah, that's what he was saying.
I missed that part.
Like when you did the git add, then it added that blob or that, yeah, the blob with the Shaw and you saw
that stuff. And then that's when he said, if you did a get reset at that point, it actually deletes
that blob and the Shaw from the index. So it all, yeah, I mean, it's sort of managing all that for
you when you do it. So here's a couple of extra things while Jay-Z is trying to finish up that one thing.
So we talked about in a lot of these things, when you create these SHAs of these objects, that they're the same, right?
The tree, if you have the same tree structure, it's the same SHA.
If you do the same blob, it's the same SHA.
However, your commits will always be different. And the reason they say is because it takes your author name and the date when
you did the commit and it's hashing those.
And so technically you should never have the same Shaw on anybody's.
It doesn't matter how similar the file is or how exact it is.
It shouldn't matter.
Now here's the next thing that it said that you have to do after this get
commit tree.
We're still not done.
You now have to overwrite the dotgit slash ref slash head slash master,
assuming you're on the master branch, to be the latest commit hash ID.
So you're basically overriding the contents of that file to point to the latest hash.
So that's the other thing that's happening behind the scenes for you
that you don't usually have to think about.
And that's telling you git that, hey, the named branch master should now reference that new commit
because that's what Git's going to read when it's looking at head.
And they said there was a safer way to do this instead of just overwriting that file
is you can use a git update-ref and then do refs heads master.
Again, like that's safer.
But, I mean, I don't know how many times you
use that one outlaw out of the three of us you're you're the git guy never like why why would i like
i would recommend everybody like understand it's good this is good to understand like i'm i'm
learning as we go through this like new things you know even as we go through this, like new things, you know, even as we go through this, but like I,
these commands are not for the faint of heart.
Like,
you know,
unless you gotta be in some pretty bad situations to where you're like,
okay,
I'm going to manually update the ref.
Right.
You're,
you're,
you were already in a really bad way.
If that's what you're doing.
Yeah.
And then the last thing that they said here,
that was pretty interesting,
at least with this tree section was was you can also change the symbolic ref by doing a get symbolic dash ref head refs heads master.
And this associates the working tree with the head of master.
So that was a whole bunch of commands to do what typically a git commit does for you right like i mean literally
that's that's basically what we just did was your typical git commit gained a lot of new respect for
it right right a little bit so uh jay-z are you still coming back with it or did you get it
uh what's that so something unexpected uh or that i didn't expect happened. So basically what I did is I did the last step.
So I created the file.
I added it the normal way with a git add.
And then I did the, what was it called?
The tree commit?
Commit tree.
Commit tree.
Yep.
Did you do the right tree first?
Sorry.
Yeah, I did the right tree.
Okay.
And then I did the commit tree and i did not pass
a parent and what i expected to happen is basically i expected to just kind of lose my history and
just see that one uh commit happen but instead uh what happened is that uh it did not get added to
my ref slash heads of master so when i do a git log i do not see my new commit right
and i do see the commit in my objects folder and if i do like a git cat file and that commit
i see that commit but that commit didn't end up in the chain so so well if you were to check out
no no i think the thing is is that like we're confusing like what does the branch point to versus what does that commit think so if you were to check out that commit and then do a get
log what do you see as its lineage like what does it show you yeah so it tells me i'm in a detached
head state when i do that yep which would make sense when you check out the commit yep and if i
do get log that's the only commit that it shows so yeah did not link it
up yeah it basically like it up start it's like as if it started everything over almost yep yep
so so uh oh well okay you you had this closing bit here i don't know if you want to do this
before i had something for you to think about like a brain teaser do you want to do that first jay-z oh i did isn't that oh hey yeah you did oh i see where
we are yeah so um sorry there's a anyway the notes but uh i was all absorbed in my example here so i
was just trying to kind of wrap up like what we've uh learned and uh i got a couple uh so what what
have you all learned tonight or uh you know? That I still know nothing about Git.
Oh, okay. I know a little bit more than I did before this,
I think. Yeah. So here's a couple.
After more than a decade, I'm still like, huh.
I can do that. Neat. There's still so much to learn.
So here's a couple notes um that i kind of took
is basically that blobs are unique i definitely never knew that you know i never really thought
about it um also uh what all those files mean so i of course have looked in uh the git folders
before and kind of wondered about the stuff you know i'd seen all the hashes and stuff and been
kind of confused and i just didn't really know what any of it meant and so it's kind of wondered about this stuff. You know, I'd seen all the hashes and stuff and been kind of confused. And I just didn't really know what any of it meant.
And so it's kind of cool to know that,
like when I look in the objects folder in particular,
there's blobs, trees, and commits all in there.
And now also, just because this most recent experiment
and seeing that my commit did not end up in this heads file,
it gives me a better understanding of that detached state message,
which I've seen before when checking out like a cherry pick or commit before i've got a better kind of sense
of what that means to be kind of uh outside of the branch structure outside of that uh that kind
of lineage uh which is really cool uh and also just the kind of how important that parentage is
um that was a big one for me oh i did have one more that i crossed off too soon which is just the
idea that um blobs are organized uh as part of trees and trees are kind of held by commits
the commit will point to a tree and that uh head is a pointer to a particular commit and remember
like we said that commit is able to look back at its parent, assuming that it's not in a headless state or isn't like the first commit, basically.
So I think the one that got me the most is learning that get behind the scenes is almost a duplicating, but it's it's sort of writing its own metadata about the file structure that you already have.
Right. Like I didn't know how deep it went with all that.
Like everything you're doing,
it's creating its own version of it behind the scenes.
Right.
And that's,
that's ultimately how it knows about what's on your system.
It's not,
it's not using your file system as is,
which is something I didn't know about like before this,
like I've been in the commit folder like you, and I looked around, whatever.
I just didn't realize what it was doing behind the scenes.
So it's pretty cool to know that it's writing its own metadata about everything.
Yeah, it's pretty cool.
And now I know, for example,
if I want to know where the metadata is stored for a commit,
who checked this in?
I know that that's in one of those folders in that objects file and it's the one that corresponds
to the commit i can get there by using the first two letters and then the rest of it and i can use
this get uh was it the catch cat file command assuming i know the type and i can actually read
what that is which is just kind of cool if i modify it then the contents inside that file
aren't going to match with the hash so i imagine things are just going to get weird and kind of cool if i modify it then the contents inside that file aren't going to match with the
hash so i imagine things are just going to get weird and kind of break and you should i mean
you should never never never muck with anything in that folder but just kind of interesting to
think about what would happen if you did okay eyebrows raised now we're getting into the fun
part so here so here's some brain teasers based on like how far we are now with with some of this
uh you know like as a thought exercise kind of thing you know to go through uh you know live
and on air um so earlier you had mentioned like if you were in that get objects directory and you
were to delete one of the files right or the directory that it would like wreck your repo. And I was like,
maybe, right now, you know, we'll, as we're going to continue going through this, this
get from the bottom up. And so maybe it'll like answer some questions, but I have my own theories
on stuff here. And so, you know, feel free to correct me in Slack or wherever. But why do you think that I said that maybe?
Well, the files might point to something that's like a detached, you know, a commit, something like a branch that you're not checked in.
For example, it could be some sort of object or tree or something that's not in something that you care about anymore um so you may not notice that it creates a problem uh it's
also you know we said that um objects get deleted when they're no longer used anymore so when i say
object i'm literally talking about the in the objects folder um but i don't have a good understanding
of how deletes work we haven't talked about that at all so how do i know that something isn't
referenced anymore and so i don't have a good sense of how deletes work we haven't talked about that at all so how do i know that something isn't referenced anymore and so i don't have a good sense of how it get
cleans up after itself so i guess it's possible that there are zombies but my guess would like
if someone told me that there was stuff in there that didn't need to be i would think that i had
either deleted a branch or had something that i checked out a commit for and kind of done some
weird stuff that just didn't have a way of referencing it more than git didn't know about anymore kind of lost track of it what what say you alan
i don't know okay here here's my thought process so in git there are a thing such thing as abandoned
objects objects that are not pointed to by anything. So, um,
what do I mean by that? So we talked about like the get, the get log, for example. So
you create your initial commit, then you create your second commit, your second commit points to
that first one, right? And now your, your head has been updated in your main branch to that second
commit. Then you create a third commit and the third main branch to that second commit, then you create a third
commit. And the third commit points to the second commit, second commit points to the first commit,
and head has been moved to that third commit in that new branch. Okay. So three commits in this
example, and all are being pointed to by something, right? But if you have a commit that isn't
pointed to anything, then it's just an abandoned object.
And I don't remember the exact term that Git has for it.
It might not be called abandoned.
Maybe it's orphaned object.
I think might be the correct term for it.
But so the example that Jay-Z did where he did his commit manually doing like the right tree commit tree and he never bothered to update the,
the head or the master ref.
In that example,
he made an orphan to commit that wasn't pointed to by anything.
And so there is a get GC command for the garbage collection and how it does
its magic of finding like all of the commits.
I'm not sure. I'm
hoping that we'll learn, but it will go through and prune all of those objects out. Now think
about this. We've also, have you ever wondered how it might be possible that a service like an Azure DevOps or a GitHub,
when you go in,
you know,
you make your branch,
you push up some stuff,
you PR it and,
or maybe you don't even PR it,
but one way or another,
you delete the branch.
And then it immediately is like,
gives you an undo option.
You're like,
I thought I deleted it.
Right.
But yet it still knows that it's there and so this goes in part with kind of my thinking of that that like when you when you
have the branch right you have this ref that that is the branch name right which is just a named
commit so that branch name is pointing to some particular commit. And now
you've deleted that branch that you may not have merged in anywhere, right? So let's, let's ignore
the PR thing that I said a moment ago, you haven't merged anywhere, but you delete the branch and it
gives you the undo option. So it still knows what the commit ID is because the commit itself hasn't
been deleted. That object hasn't been removed.
So it would be possible for the system behind the scenes to like recheck out that commit,
recreate a branch of whatever the previous name was.
And boom, now your branch exists again because now you've recreated a ref that points to
that particular thing.
So again, that's just my guess on like how things would work behind the scenes based on,
you know,
what we know so far.
Right.
And we'll find out,
maybe I'm wrong.
It's complicated.
Yeah,
it's good too.
Well,
I mean,
I was,
you make it sound like a breakup story.
Like,
like I just changed my Facebook status.
All right. it sound like a breakup story like like i just changed my facebook status that's awesome all right so uh we'll have we'll have links uh you know to this um to this to this book which is just like we're we're calling it a book but i want to be clear like this is free
you can it's on freely available on g. Um, the author thankfully made it,
uh,
free for the rest of us.
So,
um,
to share his wisdom with us.
So,
uh,
we'll have a link to that.
Um,
and as Alan said,
uh,
uh,
we hope that we,
we've explained it better this time.
Um,
but you know,
Hey,
let us know.
I mean,
you know,
we learned from our mistakes.
That's how we get,
uh,
stronger,
right?
Um, just like the Hulk.
Wait, that might be the wrong analogy there.
Whatever.
All right.
Well, with that, we head into Alan's favorite portion of the show.
It's the tip of the week.
So, you know, we've been talking a lot on this episode.
By the way, you know, we mentioned the book is on GitHub.
They take pull requests. It's actually been updated
four days ago, which is pretty cool.
Well, I was
just kind of messing around on Twitter the other
day, and I saw someone talking about forbidden
files in Windows, and I thought
that sounded kind of cool. And so I read the thread,
and I'll have a link to that in the show notes
here. There's a user called
Foon, F-O-O-N-E,
that posts a lot of really interesting stuff. There's a user called uh foone f-o-o-n-e that posts a lot of really interesting stuff there's a lot of uh interesting and strange kind of delvings into like how computers work
just kind of oddities and stuff and um i i found this account at some point and it was just kind of
um browsing through and reading up and uh this one kind of caught my attention for some reason but
um basically uh what this person was talking about is forbidden file names in windows turns out there are file names that you can't use uh
here's one of this example uh aux try creating if you're on windows try creating a file named aux
that doesn't work okay fine you get an error about AUX.txt or.h or
.anything,.info?
You just can't do it. Same with CON.
There's a
pretty good list of them.
I can link to the Windows
documentation, too, that has a full list.
Some of them obviously map to serial ports
and just older decisions from
back in the DOS days that have been carried forward.
But the author of the tweets went on to just do a bunch of experiments.
And they're like, well, what happens if I zip these up on Linux and then extract them in Windows?
Like, do I get an error message?
What does this look like?
And so I thought that was kind of funny.
And they went into great detail going through kind of what it means and how it works
and just kind of getting into weird situations with the computer.
But they also put up all the file names or examples of all the file names,
sometimes it's a pattern, on GitHub.
So on Windows, you can go and clone this repository.
It's called, it's under the username foon slash forbidden dash files.
You can clone this repository on windows
and uh i mean i'll go ahead and spell i guess you end up with a blank directory
which is funny and so this is kind of a weird situation and get where like you do a get clone
and then you're in this like weird state like what does you know get do like the files don't
exist so susan malls kind of it acts like you deleted them or something.
It's just this weird nonsense situation
that you shouldn't be able to get into, but it's pretty
funny.
Now I'm trying to get myself into a
similar weirdness, though. I'm trying to remember
where does Windows by default
put your WSL instance?
I don't remember where the files are.
Well, that's pretty cool. I just tried several of them and yeah it's an invalid device almost all of them but uh the user phone did say that they
created the file in wsl they created this repository and pushed it up in wsl so you know
it works there well yeah really not in dos yeah that's why that's why i was curious because i'm in wsl and i like you said
i have the the files and i'm like okay can i go view them in uh you know window windows can yeah
but i can't remember the path all right well i think that was one of the experiments they uh
and one of the things that was interesting is um that uh one of the experiments uh i don't remember which one
which one it was but uh see they tried to oh they tried to um they basically they uh just
threw in the files they got a bunch of error messages and it was interesting because it was
kind of um there's a lot of errors it was kind of confusing and it's just a wall of text and it makes you just kind of want to skip over it's weird it was just
kind of interesting to think that uh you could kind of slip in some malicious stuff in these
errors and i don't know it's they they um they slipped a nefarious message into a screenshot
here that's got all these other messages that you like it's kind of funny that your brain
once it starts noticing a pattern like this is a bunch of garbage you kind of skip over it until you really look closely and realize
that uh oh they're doing something very interesting with volume f in the screenshot so it's kind of
example of how you might be able to kind of hide what you're doing in errors which is totally
unrelated to the actual kind of issue here what they were discussing but i just thought it was
kind of funny i did try to uh use
the command prompt and like create aux.txt yeah and it doesn't throw an error it just doesn't do
it yeah kind of like the git checkout like it just doesn't do it yeah interesting cool well i've got
a couple of tips here um that are sort of follow-ups to previous tips. So I think last time I mentioned
the, the Maven dependency tree command. So MVN space dependency colon tree. So one, I don't
remember exactly what I mentioned in the previous one, but Derek Chase or Chas, I actually don't
even know how he says that. He mentioned that if you're doing a dependency tree call in Java, Maven specifically, don't use grep because it won't give you what you're actually looking for.
So, for example, let's say that you're looking like Google's Guava is one that comes up a lot because there's all kinds of version conflicts or
conflicting versions and whatnot that you can run into depending on what you're trying to do.
So if you were to say MVN space dependency colon tree, and then pipe that and grip,
um, Google Guava or just Guava, you'll see a line that comes out of that.
But the problem is you won't get the tree that got you to it, right?
So and then maybe you could do a grep dash C and say, hey, include so many lines before and after so you can see how things are happening.
But that's kind of hacky, like you'd have to do it multiple times to get what you want. The better answer is if you know the artifact that you're looking for,
you do an MVN space dependency colon tree space dash capital D and then lowercase includes equals.
And then you do the artifact that you're looking for. You can either do the group ID. So in a lot
of cases, it's something like com.google.guava or something right like I can't think of it off
top my head you could just do that and it'll show you anything that's using that particular group id
or you could put in the actual artifact id after the colon as well but if you do it that way with
the dash capital d includes that will actually show you the tree from that element that it found all the way up
to the root. So you can trace down exactly how you got to that artifact. Super nice. And it is
very helpful when you're doing things like that. So that is a great tip. So thank you, Derek, for
putting that up there. And for the Tukco's trademark rules of engagement. Wait, yes. Wait, this is
out of place. This is awkward. And I actually forgot about this. So I got to apologize here
because he actually wrote this to me a while back. So this is based off another tip that I'd given in
the past. So I had mentioned that Kafka cat for me, for some reason was not spitting out things
when I was doing a grip. Right. And I think we had talked about this
and at that point I was like, I don't even care. I'm not going to deal with this. Like I'll just
figure out how to get it. However else I did it. Right. Whatever that tip of the week was.
Well, he gave something that is, that is a really good tip that I've seen used in a lot of places.
And I honestly can't even say that I knew exactly what it meant. So what he's saying here is if you weren't seeing things in the grip,
it might be because things were going into standard error instead of standard out. So a way
to cheat it, to force it all into what you're trying to grip is you could do something like
the Kafka cat. Like I mentioned before, after that, you're going to do the number two, a greater than sign, the ampersand sign, and then the number one,
then you do the pipe and then you grep whatever your search term is. And what this is saying is
this is going to pipe the standard error to the standard out and then pipe that over to grep.
So that way, if for some reason, those, those records
were going into standard error, which were not being output to my grep command before those
would be combined with the standard outs and you'd see all of them. Um, I haven't tried it to see if
that may be what was, what was going on before, because I'd never had the problem in the past
where the Kafka cat wouldn't show it when I grept it. Um, so I'd never had the problem in the past where the Kafka cat
wouldn't show it when I grepped it. So I don't even know that I could recreate it now. But
knowing that two greater than ampersand one is a really nice tip for being able to get all the
output of something that's being written out to your terminals. It never dawned on me that it
might be going out to standard error when you were describing the previous problem and whatever that was.
Yeah, same.
It's been a few back, but yeah, that's a really good tip.
All right.
Well, yeah.
Hey, real quick.
Did you know yesterday I spotted an albino dalmatian?
Oh, really?
Tell me more.
I really did.
I don't know why you're saying it like that it was really
you spotted yeah it was the least i could do for him i got it okay
uh yeah so all right so uh for my tip this week um oh you know what i forgot to grab who shared this with me i will try to find that but um
so get is hard and you know messing it up is easy figuring out how to fix your
mistakes is impossible uh you know we're we're after all these years trying to learn it still
and uh so you know go to dang it get.com And I'll have a link to that. Uh,
so that you can see like common, uh, you know,
solutions to problems that you may or may not make. Um,
just think of the spelling of that as like Dan get, get.com.
Yeah. Um, so at any rate, uh know i'll have i'll have that one in there but yeah um
you liked that pun though that was a good one right did you know i submitted a whole bunch
of puns to a local pun competition and no i didn't know why do you say and why can't it just
be like i did it it needs to be Oh, I'm so excited for you.
I'm excited for you.
Sadly, no pun in 10 did.
Oh, Hey, hold on.
So I ran out of gas the other day and I called up the insurance company to,
to get roadside assurance and they just totaled my truck.
You don't get it. Come on, man. i did i will i ran out of gas the other day and i called my insurance company for roadside insurance
insurance assistance and they just totaled my truck yeah i mean so at first i assumed it was
like a joke about the gas prices being
totally yeah that's what it is but then i also realized that pretty much anytime you call an
insurance company now that somehow it's freaking totaled so then i got confused about this is just
a sad reality like of course the insurance comes you want to total it yeah it's like
bumper bumped totaled too soon totaled here's $500 for your new car.
Right.
Yeah, exactly.
Yeah, so that was from Tina.
And who has messed this one up?
Help me out here, Alan.
I'm going to say it as Gregory, but I'm sure that's probably wrong.
Was it?
Yeah, that's it.
Okay, it's just not like how we would spell it then.
Not how we would spell Gregory.
So it was a totally good guess on my part.
Oh,
you're going to say Gregori or something.
Well,
at first I was thinking like,
yeah,
maybe,
but then I'm like,
no,
I think if I like said it phonetically,
like,
have we talked about how I hate proper nouns?
Yeah.
This is why instead I like to talk to people
about dried grapes.
Hold, hold, hold. We're missing the punchline.
Why is there always
a punchline with me?
What's the dried grapes? I'm all about
raising awareness.
Thank you, Scott.
Okay, so I have one last
tip for you. I don't know if I've done it.
I thought I had already done this tip, but I couldn't find it.
But I just wanted to be definitely sure that this one is known.
So like how to vacay.
All right, so step one.
Disable your work email.
Preach.
And silence any Slack or Gchat or whatevs that you have.
Right.
So like slack in,
in G chat,
for example,
they make it kind of easy to where like you can go in there and say like,
Hey,
snooze notifications for this amount of time.
Although G chats annoying in that example,
or at least the hangouts was,
I haven't checked in the current G chat,
but,
um,
because it
would be like oh we want to do it for like a maximum amount of time of just eight hours you're
like no where's my seven days nah come back to me in eight hours right um but uh like slack you can
at least like customize it but you know what's super annoying is that like your mail options
don't do that you can't say like hey just i don't want that. You can't say like, Hey, just,
I don't want to, I don't want you to bother retrieving mail for this account because I'm
going to be tempted to read it. If I see that little red notification bubble pop up and
especially if it becomes an oval or elliptical or whatever, you know, like if it's round,
that's not so bad. But as soon as it gets out of that
shape, if it gets into pill shape, we're in trouble. So in iOS, go to your settings, mail
accounts and select your work account and then just turn off that mail slider. Leave it. It can
still continue to sync your content, your contacts and calendar, but just don't sync the mail.
Now, you Android users, I'm sorry.
You have to continue working during your vacation.
All right?
This tip isn't for you.
Part of the terms of service, when you set accept on that end user license agreement that we all, quote, read, and you just, like, clicked it, part of the terms there was that you would accept this, that you had to continue working on your vacation. So that's when you set up Android.
That's on you.
That's not on me.
It makes sense.
Yeah.
It checks out.
Um,
that's one thing.
Wait,
you have one other thing.
Yeah.
I,
I don't remember if I gave this tip or not.
So I'm just gonna say it again.
Uh,
Merle,
uh,
we talked about a bunch of times in the show,
uh,
especially,
uh,
during the SRE episodes, you know, you some types of spaces or again. Burley, we talked about him a bunch of times on the show, especially during the SRE episodes.
You know he's on Tabs and Spaces recently?
Oh, no, really?
Yeah, I don't think I mentioned him before.
And also, I think I did mention this one, but just in case, I didn't.
But Devin, Devin Goble, was on Tabs and Spaces too.
So, yeah, the show is doing good, getting some awesome guests.
Excellent.
Go check it out.
So I don't know if I thanked Scott for the raising awareness,
but yeah, so all three of them are in there.
So we hope you enjoyed it.
I mean, you know, we committed to another episode.
See what I did there?
You sure did.
So subscribe to us on iTunes, Spotify, Stitcher,
wherever you like to find your favorite podcast apps.
And like Joe awkwardly said before, if you haven't left us a review,
we would greatly appreciate it.
You know, it doesn't have to be a three-star.
It could be better.
He has a really low bar.
So, you know, we strive for excellence here.
And, well, Alan and I strive for excellence,
and Joe strives for whatever.
That's whatever gets you through the day.
That's right.
Hey,
so while you're up there at www.codingblocks.net,
make sure you check out our show notes,
examples,
discussions,
and more,
and send your feedback questions and rants to Slack or these episode as we did the last one.
And,
uh,
yeah.
Dang it.
Yeah.
And,
uh, if you're done second now, make sure to follow us on Twitter, at coding blocks, and we've got the website one. And yeah. Dang it. Yeah, and if you're done in Slack,
make sure to follow us on Twitter, at Coonblocks, and we've got
the website too. Don't forget. And I promised I would
give credit to the
for the Dang It
Git, and now I can't
find it, so why did I even
say that I would? Well, dang it.
Oh, geez.
Was it in Slack? No, we've got to know. Hold on.
Yeah, it was in Slack.
It was in Slack, but I...
Don't hang up.
Don't hang up.
Wait.
Well, no, I got to go.
Mom's on the line.
No, we got to wait.
No, I'm out.
I can't find it now, so we'll never know.
It's done.