Skip to content

Instantly share code, notes, and snippets.

@james-dowling
Created April 27, 2012 07:52
Show Gist options
  • Save james-dowling/2507154 to your computer and use it in GitHub Desktop.
Save james-dowling/2507154 to your computer and use it in GitHub Desktop.
Unformatted notes from my quick-fire rundown on what I learned from Ben H's Workshow
These are my notes from my hands-on talk entitled "I went to Ben H's Git Workshop and all I got was this stupid Knowledge"
Lots of people asked me to tweet them, even thought they are just a mix of notes-to-self, things to say, and things to type.
Enjoy FWIF
BEFORE ANYTHING, CLONE RAILS AND CREATE A COMMIT
So, all git info is kept in the .git folder in the root folder of the repo
let's look in there…..
cd .git
ls -la
The first file we'll look at is HEAD
if we cat that, we get a link to a ref file
that file will be in .git/refs
refs has a file for every branch
If we cat the file referenced in HEAD, we get a pointer to the commit we've got checkout out right now
That commit will be in objects.
cd to .git/objects
ls
Now, we can't see any pointers to tell us where to go next… so what we'll do is look at the first two digits of the SHA in master
and we cd there!
and our filename is not the whole name of the sha (that would be redundant), but instead, the rest of the sha
CAT THE COMMIT
So, that's no good to us. The reason it's all garbled is that it's a zip file.
TRY TO UNZIP THE FILE (Doesn't work) cat filename | gunzip
So, to save space, git removes the headers on the zip file and this breaks gunzip.
I've thrown together a command line alias called "gitgrow"
DEMO
alias gitgrow='ruby -rzlib -e '\''print Zlib::Inflate.new.inflate(STDIN.read)'\'' < '
basically, the tool has no real-world use :P
Now, what's very interesting here is that the sha representing the commit is not random, but in fact a sha1 digest of the contents:
gitgrow *commit_file_name* | openssl dgst -sha1
So, once the commit is created, git creates a folder named after the first two letters of that sha1, and then leaves the commit itself zipped up, with no headers in there with the name of the remainder of that sha1
MAGIC!
Ok, so we see in the commit that its parents are listed in the commit (only one here)
So, if you follow me, the name of a commit is dependent on the name of it's parent, because its parent's name helped build the sha that it is named after. And so on….. all the way down the git tree.
CREATE A NEW BRANCH - SHOW IT'S REFERENCE IN HEADS
SWITCH BACK TO MASTER
CREATE A NEW COMMIT
SHOW MASTER POINTING TO A NEW COMMIT, and the new branch's head pointing to the old commit
'NOW LET's TALK ABOUT MERGE OPTIONS"
AND ON THE WAY THERE<,I'LL SHOW HOW MAN PAGES WORK FOR GIT COMMANDS
man git-merge
FIND --no-ff (using `/`)
NOW LETS TALK ABOUT fast forwarding
go:
git checkout -b new_branch
touch hello
git add hello
git commit -m "a commit on the new branch"
git checkout master
git merge new_branch
git status
`say omfg` - no merge commit because it "fast forwarded"
this is only good if you're the only person working on the project, and you never have more than one feature branch going at one time.
So, use --no-ff pretty-much always
Still, if you ever start a branch, throw in a few commits, then realise you didn't need a feature branch, you can explicitly specify a --ff-only merge. So that'll only work if nobody has merged in anything since you created the branch.
MORE ON MERGES:
octopus merges allow merges of multiples heads in the some commit.
when this happens, it starts to become more obvious what the point of ^ and ~ is
^ goes to the first parent
~ goes to the next parent at the same level
so you can checkout any one of those with the refspec HEAD^2~3
Does anybody actually do this? Yes. Linus Torvalds. The end. I don't even know why he does it.
I guess to amalgamate a release …. or something
If you go through the repo for git, you'll see plenty of these.
GIT LOG
git log SHOWS A LIST OF COMMITS
git log -p ALSO SHOWS THE CONTENTS OF EACH COMMIT
git log --graph
git smart-log SHOWS A GRAPH OF COMMITS JUST LIKE GLEN MADDERN LIKES IT
IT DOES THIS BY USING THE --pretty FLAG AND SPECIFYING A FORMAT
SHOW THEM THE COMMAND AT THE TOP
git-smart always shows you which git command it used.
REFLOG
git reflog shows everything you've done ever
It's a really useful tool if you want to know what the hell you just did, other than what commits you've made
another way to do that is to use 'git log -g'
IS THE REFLOG JUST A SIMPLIFIED REPOSITORY??
Best thing about the reflog is that you can `reset --hard` to wherever head was at before a history changing commit like a reflog
Do a
git reset --hard HEAD@{5}
ORIG_HEAD
special file in .git/
Any history "changing" action will keep a record of where HEAD was pointing at before it created a whole new treelet
So instead of going
git reset --hard HEAD@{0}
you can go
git reset --hard ORIG_HEAD
Admittedly, this is a less relevant tool, given the advent of the reflog
REBASING
Ben hates to rebase. It's basically not good.
….because it duplicates commits. (more on that later)
If you say, branched off a feature branch, and then merge it all together, all the duplicates end up on the master branch at the end usually causing conflicts.
So, only use it for pull-type scenarios!
COMPARING TWO BRANCHES
***********************************
git diff master..production
SHOWS THE DIFFERENCES BETWEEN MASTER AND PRODUCTION
=========================
git log master..production
SHOWS WHAT COMMITS ARE ON PRODUCTION BUT NOT ON MASTER
***********************************
GIT HAS GARBAGE COLLECTION
this is the only way in which commits can get deleted!
It happens when dangling commits get dropped off the end of the reflog
git gc --auto HAPPENS WHENEVER YOU DO A COMMIT
checks whether git thinks any garbage collection is necessary.
git gc HAPPENS RIGHT AWAY
What does it do?
it does a pack on the objects in the objects folder
This deletes duplicates, and mostly just clears out the objects folder
if you want to learn about git pack files, check out these two sites:
gitref.org
progit.org
There is a bad thing about pack files
Pushes are sometimes bigger than they have to be, as they may contain redundant code
Whenever you do a pull from github, you usually just download a single pack file.
Neat trick…… branch from a commit
git checkout -b branchname SHA
can use ~ and ^ with this
INTERACTIVE REBASES
git rebase -i SHA
opens editors for each of these commits
These gives us a whole bunch of optional keywords to use.
eg
pick: use this commit as is
reword: change message, but use commit
edit: we'll ammend the commit before commiting
lots more
You can even reorder the commit's order in the tree!
Don't tell anybody, but you can actually alter your history this way!
A good way to make Glen Maddern cry
If you want to rebase your entire current branch this way….
just choose the commit **before** the earliest commit you want to rebase
SO, DO REBASES REWRITE HISTORY?
Complicated question actually.
In fact, you'll find that the reflog will keep the original history, for a time :)
You'll remember that all commits' shas are products of their parents shas?
That's why a rebase is the only way to seriously fuck with your history more than one commit ago. New shas, influencing their childrens' shas need to be created for all descendants of the interactively changed commit.
As a side note, git doesn't delete the old commits, just creates the new ones, and points your branch's ref file to the latest of the new commits. So, again, history is immutable. if you ever want to go back how it was before, you can just check your reflog for the sha of the commit before the rebase happened.
If you're going to do interactive rebases to rewrite history, make sure the commits you're rewriting aren't referenced from other branches. As you can imagine, this creates scary duplication in the repo, and thus causes incredibly stressful merges.
GIT STATUS
this is actually verbose by default
use -s to make it short.
GIT ADD
git add -u
same as git add --update
like an add for a whole directory, but never adds new files
also, does a `git rm` on any files which have been removed
git add -A
So, does the same thing as --update
Obviously, will add new files too
git log SHA
SHOWS THE GIT LOG *AT THE TIME THAT COMMIT WAS MADE*
TRACKING REMOTE BRANCHES
A remote tracking branch is one which you will pull or fetch from automatically, without having to specify the branch in the command line. Just go `git pull` or `git fetch`
THE GRAPH
Just the overall git tree.
A TREELET
Stupid name imo
The tree which lead to a single refspec
A refspec can be a SHA, The first 8 digits of a SHA, or HEAD~ etc
GIT SMART-PULL
will do a merge on occasion!
If there are no local commits, then it'll merge, otherwise it'll do a rebase -p
GIT PULL --REBASE
Never ever do this
For one thing, it's actually broken - it can delete your work from the graph occasionally!
Also, it doesn't do a -p with the rebase, so merges get squashed!!!
The bad thing about merges getting squashed, is when there are multiple commits which have been merged in, you can just revert the merge. But when they're all in the same thread of commits, you have to revert them all individually. Pretty crap to have to do on a saturday morning on-call
GIT RESET
--soft : RESETS THE HEAD TO THE COMMIT SPECIFIED. ALL LATER CHANGES ARE "staged"
--hard : SAME AS --soft, BUT DISCARDS CHANGES LATER THAN THE SPECIFIED COMMIT
GIT CLEAN
does nothing by default
only works if you specify `-f`
it deletes untracked files
if you'd like to do a dry-run, you can use `-n` instead of `-f`
be very careful to specify the correct paths!!!!
if you use -x instead of -f, it will even delete file which match lines in your .gitignore!
Ben says that it's basically used by psychopaths on their prod machines
ooorrrr…….. for getting rid of bullshit logs, test generated attachments etc
basically nuts. never do this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment