If <upstream> is not specified, the upstream configured in branch.<name>.remote and branch.<name>.merge options will be used (see git-config(1) for details) and the --fork-point option is assumed. If you are currently not on any branch or if the current branch does not have a configured upstream, the rebase will abort.
One of the above extracts is a joke, one is real… So here’s five core git concepts explained. Hopefully after reading this the man pages will start to make more sense. If you’re confused by one I’ve missed, contact me to write it up for you (@ianmiell or LinkedIn). This post uses the ‘hard way‘ method to teach the concepts by having you type out the commands and think through what’s going on, without having to worry about breaking anything.
git-land-remotelands some applied remotes over the packed applied branches, and it is in various cases a possibility that a filter-branched error must prevent staged cleaning of some named stages.
I use the same method to teach git in my book Learn Git the Hard Way.
1) ReferenceMany will know this already, but I need to make sure you know it because it’s so fundamental. A ‘reference’ is a string that points to a commit. There are four main types of reference: HEAD, Tag, Branch, and Remote Reference
HEADHEAD is a special reference that always points to where the git repository is. If you checked out a branch, it’s pointed to the last commit in that branch. If you checked out a specific commit, it’s pointed to that commit. If you check out at a tag, it’s pointed to the commit of that tag. Every time you commit, the HEAD reference/pointer is moved from the old to the new commit. This happens automatically, but it’s all going on under the hood.
TagA tag is a reference that points to a specific commit. Whatever else happens (and unlike the HEAD), that tag will stay pointed at the commit it was originally pointed at. Branch A branch is like a tag, but will move when the HEAD moves. You can only be on one branch at a time. Type out these commands and explain what’s going on. Take your time:
$ mkdir lgthw_origin $ cd lgthw_origin $ git init $ echo 1 > afile $ git add afile $ git commit -m firstcommit $ git log --oneline --decorate --all --graph $ git branch otherbranch $ git tag firstcommittag $ git log --oneline --decorate --all --graph $ echo 2 >> afile $ git commit -am secondcommit $ git checkout otherbranch $ git log --oneline --decorate --all --graph $ echo 3 >> afile $ git commit -am thirdcommit $ git log --oneline --decorate --all --graphNow do it again and explain to someone else what’s going on.
Remote ReferenceA remote reference is a reference to code that’s from another repository. See below for more on that…
2) ‘Detached Head’Now that you know what HEAD is, then understanding what a ‘detached head’ is will be much easier. A ‘detached head’ is a git repository that’s checked out but has no branch associated with it. Continuing from the above listing, type this in:
$ git checkout firstcommittagYou get that scary message:
Note: checking out 'firstcommit'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name> HEAD is now at 1b1499c... firstcommitbut if you follow the instructions:
$ git log --oneline --decorate --all --graph $ git checkout -b firstcommitbranch $ git log --oneline --decorate --all --graphyou can figure out what’s going on. There was a tag, but no branch at that commit, so the
HEADwas detached from a branch.
3) Remote ReferenceA remote reference is a reference to a commit on another git repository.
$ cd .. $ git clone lgthw_origin lgthw_cloned $ cd lgthw_cloned $ git remote -v $ git log --oneline --decorate --all --graphThe log graph looks different doesn’t it? Compare that to the
git logoutput in the other folder and think about how they differ. What word do you see multiple times in the output that you didn’t see before? The cloned repo has its own copy of the branch (
firstcommitbranch) and tag (
firstcommit) because that’s where the repository’s
HEADwas when you cloned it.
$ git branch -ashows all the branches visible in this repository, both local and remote. Compare that to the output of the same command in the original folder. How does it differ? Now check out your local master:
$ git checkout masterand you get a message saying:
Branch master set up to track remote branch master from origin. Switched to a new branch 'master'So you’ve got a local reference
masterwhich ‘tracks’ the master in the remote repository. The local reference is
master, and the remote reference is
origin/master. Git assumed you meant your local master to track the remote master. The two branches look the same, but they are linked only by the configuration of this repository.
$ cd ../lgthw_origin $ git checkout master $ echo origin_change >> afile $ git commit -am 'Change on the origin'Then go back to the cloned repository and fetch the changes from the origin:
$ cd ../lgthw_cloned $ git fetch origin $ git log --oneline --decorate --all --graphCan you see what happened to your local master branch, and what happened to the origin’s? Why are they now separate? Note that you didn’t
git pullthe change.
git pulldoes a fetch and a merge, and we don’t want to confuse here by skipping steps and making it look like magic. In fact,
git pullis best avoided when you are learning git…
If you like this post, you’ll like my book Learn Git the Hard Way
It covers all this and much more in a similar style.
4) Fast ForwardYour git log graph should have looked like this:
* 90694b9 (origin/master) Change on the origin * d20fc9a (HEAD -> master) secondcommit | * 2e7ae21 (origin/otherbranch) thirdcommit |/ * 6c14f2f (tag: firstcommittag, origin/firstcommitbranch, origin/HEAD, firstcommitbranch) firstcommit
(Your ids may differ from the above – otherwise it should be the same.)Now, do you see how the
Change on the origincommit is not branched from your local
secondcommit– it’s in a ‘straight line’ from the
firstcommittag? That means that if you ‘merge’
origin/masterinto your local master, git can figure out that all it needs to do is move the
masterreference to where the
origin/masterbranch is and its ‘merge’ job is done.
$ git merge origin/master $ git log --oneline --decorate --all --graphThis is all a ‘fast forward’ is: git saw that there’s no need to do any merging, it can just ‘fast forward’ the references to the point you are merging to. Or if you prefer, it just moves the pointers along rather than create a new merge commit. We just did a
git pull, by the way. A
git pullconsists of a
git fetchand a
git merge. Breaking it down into these two steps helps reduce the mystery of why things can go wrong.
As an exercise, after finishing this article do the whole exercise again, but make a change to both origin/master and master and then do the fetch and merge to see what happens when a fast-forward is not possible.
origin/masterare now in sync, so now run these commands to see what a rebase is:
$ cd ../lgthw_origin $ git status $ echo origin_change_rebase >> afile $ git commit -am 'origin change rebase' $ git log --oneline --decorate --all --graphOK so far? You’ve made a change on master on the origin repo:
$ cd ../lgthw_cloned $ echo cloned_change_rebase >> anewfile $ git add anewfile $ git commit -m 'cloned change rebase in anewfile' $ git log --oneline --decorate --all --graph $ git fetch origin $ git log --oneline --decorate --all --graph $ git rebase origin/master $ git log --oneline --decorate --all --graphCan you see what’s happened? If not, have a close look at the last two
git logoutputs. That’s what a rebase is – it takes a set of commits and moves (or ‘re-bases’) them to another commit.
If you liked this post, you’ll like my book Learn Git the Hard Way It covers all this and much more in a similar style.
If you liked this post, you might also like these: Create your own Git diagrams A Git Serverless Pattern Power Git Log Graphing Interactive Git Rebase and Bisect Tutorials
If you enjoyed this, then please consider buying me a coffee to encourage me to do more.
14 thoughts on “Five Key Git Concepts Explained the Hard Way”
Very good stuff!
My only big nit so far is how the git docs and tutorials commonly mix terms : “git repository” is the database of commits, and actual directory with some revision of checked out files is usually a “workspace”. They do not necessarily map 1:1 (e.g. repos without a workspace, or many workspaces referring same index to download once and then check out several different branches). It really helps students when we name different concepts with different words.