From 4be11d253b3404841bed2f2bb384e0269ac5bb5e Mon Sep 17 00:00:00 2001 From: Lasse Schuirmann Date: Mon, 13 Apr 2015 23:54:16 +0200 Subject: [PATCH] doc: Add Hitchhikers Guide part 1 --- doc/General_Dev_Info/git_tutorial_1.md | 571 +++++++++++++++++++++++++ mkdocs.yml | 3 + 2 files changed, 574 insertions(+) create mode 100644 doc/General_Dev_Info/git_tutorial_1.md diff --git a/doc/General_Dev_Info/git_tutorial_1.md b/doc/General_Dev_Info/git_tutorial_1.md new file mode 100644 index 0000000000..190899df4c --- /dev/null +++ b/doc/General_Dev_Info/git_tutorial_1.md @@ -0,0 +1,571 @@ +# Introduction + +## What is This? + +This post tries to provide a **gentle introduction** to git. While it is aimed +at **newcomers** it is also meant to give a rather **good overview and +understanding** about what one can do with git and thus **is extensive**. It +follows the premise: + +> If you know how a thing works, you can make it do what you want it to. + +Please don't be afraid as I'm trying to use **light language** and **many +examples** so you can **read fast** through it and understand anyway (if I +succeed). I'm also trying to **highlight important things** at least for long +texts to ease reading a bit more. However, at some points this tutorial *may* +require you to **think for yourselves** a bit - it's a feature, not a bug. + +## For Whom is This? + +This tutorial is meant for everyone willing to learn git - it does not matter +if you are a **developer** who never really got the hang of it or a **student** +wanting to learn. Even if you are doing non coding tasks like **design** or +**documentation** git can be a gift from heaven. This tutorial is **for +everyone** - don't be scared by its length and believe me, **it pays off**! The +only **requirement** is that you have **git installed**, know `cd`, `ls` and +`mkdir` and **have something to commit** - and who doesn't have any digital +data!? + +## What's in There? + +This tutorial is the **first out of three** tutorials which are meant to **free +your mind** from a **traditional view on filesystems**. + +### Genesis + +This tutorial, **Genesis (i.e. "Creation" or "Beginning")**, will cover some +very basic things: + + * **Configuring** git so you can use it how you want. (Basic, aliases) + * **Creating** your git **repository** (play god once!) + * **Creating** your first git **commits**. + * **Learning** what the **repository** is and **where commits get stored**. + * **Browsing** through **history**. + * **Ignoring files**. + +### Exodus + +**Exodus (i.e. "going out")** will cover: + + * **Store** temporary changes **without committing**. + * **Navigating** commits in git. + * **Sharing** commits to a **remote place**. + * **Locally** (huh, that's sharing?) + * Via **email** + * To a **server** + * To a **client** + * Working **with others** (i.e. **non-linear**). + * **Join** things. + * **Linearize** things. + * **Writing good** commits. + * **Editing** commits. (Actually not editing but it feels like that.) + +### Apocalypse + +**Apocalypse (i.e. "uncovering")** will try to uncover some more advanced +features of git, finally freeing your mind from your non-versioned filesystem: + + * **Finding more information** about code. + * **Finding causes of bugs** in git. + * **Reverting** commits. + * **Reviewing** commits. + * **Travelling though time** and **changing history** (you want me to believe + you've never wanted to do that?) + * **Getting back** lost things. + * Let git **do things automatically**. + +## Some Warnings + +A short warning: If you ever really got the hang of git you will not be able to +**use something else** without symptoms of **frustration and +disappointment** - you'll end up writing every document versioned as an excuse +to use git. + +A warning for windows users: you may need to use equivalent commands to some +basic UNIX utilities or just install them with git. (Installer provides an +option for that.) In general it's a bit like travelling with Vogons - avoid +when possible. + +A warning for GUI users: **Don't use your GUI**. Be it the GitHub App or +SourceTree or something else - they usually try to make things more abstract +for us, thus they hinder us from understanding git and we can then not make git +do what we want. Being able to communicate **directly** with git is a great +thing and really bumps **productivity**! + +I wrote this tutorial to the best of my knowledge and experience, if you spot +an error or find something important is missing, be sure to drop me a message! + +## Preparation... + +So go now, grab a cup of coffee (or any other drink), a towel, take your best +keyboard and open a terminal beneath this window! + +# What's Git for Anyway? + +Before we really get started it is important to know what git roughly does: git +is a program that allows you to **manage files**. To be more specific git +allows you to **define changes on files**. In the end your repository is just a +**bunch of changes** that may be related to each other. + +# Setting Up Git + +Before we can continue we'll have to set up a few tiny things for git. For this +we will use the `git config --global` command which simply **stores** a **key +value pair** into your **user-global git configuration file** (usually stored +at `~/.gitconfig`). + +## WHOAMI + +Let's tell git who we are! This is pretty straightforward: + +``` +$ git config --global user.name "Ford Prefect" +$ git config --global user.email ford@prefect.bg +``` + +This makes git store values for "name" and "email" within the "user" section of +the gitconfig. + +## Editor + +For some operations git will give you an **editor** so you can enter needed +data. This editor is **vim by default**. Some people think vim is great (vim +*is* great!), some do not. If you belong to the latter group or don't know what +vim is and how to operate it, let's **change the editor**: + +``` +$ # Take an editor of your choice instead of nano +$ git config --global core.editor nano +``` + +Please make sure that the **command** you give to git always **starts as an own +process** and ends only when you finished editing the file. (Some editors might +detect running processes, pass the filename to them and exit immediately. Use +`-s` argument for gedit, `--wait` argument for sublime.) Please **don't use +notepad** on windows, this program is a perfect example of a text editor which +is too dumb to show text unless the text is written by itself. + +# Create a Repository + +So, lets get started - with nothing. Let's make an empty directory. You can do +that from your usual terminal: + +``` +$ mkdir git-tutorial +$ cd git-tutorial +$ ls -a +./ ../ +``` + +So, lets do the first git command here: + +``` +$ git init +Initialized empty Git repository in /home/lasse/prog/git-tutorial/.git/ +$ ls -a +./ ../ .git/ +``` + +So now we've got the `.git` folder. Since we just created a repository with +`git init`, so we can deduce, that this **.git directory must in fact be the +repository**! + +# Creating a God Commit + +So, let's create some content we can manage with git: + +``` +$ echo 'Hello World!' >> README +$ cat README +Hello World! +``` + +Since we know, that the .git directory is our repository, we also know that +**we did not add this file to our repository** yet. So how do we do that? + +As I've hinted before, our git repository **does not contain files** but only +**changes** - so how do we make a change out of our file? + +The answer lies in (1) `git add` and (2) `git commit` which allow us to (1) +specify what files/file changes we want to add to the change and (2) that we +want to pack those file changes into a so called **commit**. Git also offers a +helper command so we can see what will be added to our commit: `git status`. + +Let's try it out: + +``` +$ git status +On branch master + +Initial commit + +Untracked files: + (use "git add ..." to include in what will be committed) + + README + +nothing added to commit but untracked files present (use "git add" to track) +$ git add README +$ git status +On branch master + +Initial commit + +Changes to be committed: + (use "git rm --cached ..." to unstage) + + new file: README + +``` + +So obviously with `git add` we can **stage** files. What does that mean? + +As we know, when we're working in our directory **any actions on files won't +affect our repository**. So in order to **add a file** to the repository, we'll +have to **put it into a commit**. In order to do that, we need to **specify, +what files/changes should go into our commit**, i.e. stage them. When we did +`git add README`, we **staged** the file README, thus every change we did until +now to it will be **included in our next commit**. (You can also partially +stage files so if you edit README now the change won't be committed.) + +Now we'll do something very special in git - **creating the first commit**! +(We'll pass the `-v` argument to get a bit more info from git on what we're +doing.) + +``` +$ git commit -v +``` + +You should now get your editor with contents similar to this: + +``` + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# On branch master +# +# Initial commit +# +# Changes to be committed: +# new file: README +#ref: refs/heads/master + +# ------------------------ >8 ------------------------ +# Do not touch the line above. +# Everything below will be removed. +diff --git a/README b/README +new file mode 100644 +index 0000000..c57eff5 +--- /dev/null ++++ b/README +@@ -0,0 +1 @@ ++Hello World! +``` + +Since we're about to create a change, git asks us for a **description**. (Note: +Git actually allows to create commits without a description with a special +argument. This is not recommended for productive collaborative work!) + +Since we passed the `-v` parameter, git also shows us below what will be +included in our change. We'll look at this later. + +**Commit messages** are usually written in **imperative present tense** and +should follow certain guidelines. We'll come to this later. + +So, let's enter: `Add README` as our commit message, save and exit the editor. + +Now, let's take a look at what we've created, `git show` is the command that +shows us the **most recent commit**: + +``` +$ git show +commit ec6c903a0a18960cd73df18897e56738c4c6bb51 +Author: Lasse Schuirmann +Date: Fri Feb 27 14:12:01 2015 +0100 + + Add README + +diff --git a/README b/README +new file mode 100644 +index 0000000..980a0d5 +--- /dev/null ++++ b/README +@@ -0,0 +1 @@ ++Hello World! +``` + +So what do we see here: + + * It seems that commits have an **ID**, in this case + `ec6c903a0a18960cd73df18897e56738c4c6bb51`. + * Commits also have an **author** and a **creation date**. + * Of course they hold the **message** we wrote and **changes** to some files. + +What we see below the `diff ...` line is obviously the change. Let's take a +look at it: since **git can only describe changes**, it takes `/dev/null` +(which is a bit special, kind of an empty file, not important here), +**renames** it to `README` and **fills** it with our contents. + +So, this commit is pretty godish: It exists purely on it's own, has no +relations to any other commit (yet, it's based on an empty repository, right?) +and **creates a file out of nothing** (/dev/null is somehow all *and* nothing, +kind of a unix black hole). + +# Inspecting What Happened + +So, let's look in our repository! + +``` +$ ls -la .git +total 52 +drwxrwxr-x. 8 lasse lasse 4096 Feb 27 16:05 ./ +drwxrwxr-x. 3 lasse lasse 4096 Feb 27 14:11 ../ +drwxrwxr-x. 2 lasse lasse 4096 Feb 27 14:11 branches/ +-rw-rw-r--. 1 lasse lasse 486 Feb 27 14:12 COMMIT_EDITMSG +-rwxrw-r--. 1 lasse lasse 92 Feb 27 14:11 config* +-rw-rw-r--. 1 lasse lasse 73 Feb 27 14:11 description +-rw-rw-r--. 1 lasse lasse 23 Feb 27 14:11 HEAD +drwxrwxr-x. 2 lasse lasse 4096 Feb 27 14:11 hooks/ +-rw-rw-r--. 1 lasse lasse 104 Feb 27 14:11 index +drwxrwxr-x. 2 lasse lasse 4096 Feb 27 14:11 info/ +drwxrwxr-x. 3 lasse lasse 4096 Feb 27 14:12 logs/ +drwxrwxr-x. 7 lasse lasse 4096 Feb 27 14:12 objects/ +drwxrwxr-x. 4 lasse lasse 4096 Feb 27 14:11 refs/ +$ +``` + +Now let's look into it further to get to know what it is a bit more. I will try +to cover only important parts here, if you're interested even deeper, you can +try DuckDuckGo or take a look at this: +http://git-scm.com/docs/gitrepository-layout + +## The config file + +The **config file** is a similar file to the one where our **settings** in the +beginning got stored. (User and editor configuration, remember?) You can use it +to store settings **per repository**. + +## The objects directory + +The objects directory is an important one: It contains our commits. + +One could do a full tutorial on those things but that's not covered here. If +you want that, check out: +http://git-scm.com/book/en/v2/Git-Internals-Git-Objects + +We just saw the **ID** of the commit we made: +`ec6c903a0a18960cd73df18897e56738c4c6bb51` + +Now let's see if we find it in the objects directory: + +``` +$ ls .git/objects +98/ b4/ ec/ info/ pack/ +$ ls .git/objects/ec +6c903a0a18960cd73df18897e56738c4c6bb51 +``` + +So, when we create a commit, the contents (including metadata) are **hashed** +and git stores it finely into the objects directory. + +That isn't so complicated at all, is it? + +### Task: Objects + +`git show` accepts a commit ID as an argument. So you could e.g. do `git show +ec6c903a0a18960cd73df18897e56738c4c6bb51` instead of `git show` if this hash is +the current commit. + +Investigate what the other two objects are, which are stored in the objects +directory. (Ignore the info and pack subdirectory.) + +Do `git show` again and take a look at the line beginning with "index". I'm +sure you can make sense out of it! + +## The HEAD File + +The HEAD file is here so git knows what the current commit is, i.e. with which +objects it has to compare the files in the file system to e.g. generate a diff. +Let's look into it: + +``` +$ cat .git/HEAD +ref: refs/heads/master +``` + +So it actually only references to something else. + +So let's take a look into refs/heads/master - what ever this is: + +``` +$ cat .git/refs/heads/master +ec6c903a0a18960cd73df18897e56738c4c6bb51 +``` + +So this `HEAD` file refers to this `master` file which refers to our current +commit. We'll see how that makes sense later. + +# Creating a Child Commit + +Now, let's go on and create another commit. Let's add something to our README. +You can do that by yourself, I'm sure! + +Let's see what we've done: + +``` +$ git diff +diff --git a/README b/README +index 980a0d5..c9b319e 100644 +--- a/README ++++ b/README +@@ -1 +1,2 @@ + Hello World! ++Don't panic! +``` + +Let's commit it. However, since we're a bit lazy we **don't** want to **add** +the README **manually** again; the commit command has an argument that allows +you to **auto-stage all changes** to all files that are in our **repository**. +(So if you added **another file** which is **not in the repository** yet it +**won't be staged**!) + +``` +git commit -a -v +``` + +Well, you know the game. Can you come up with a **good message** on your own? + +``` +$ git show +commit 7b4977cdfb3f304feffa6fc22de1007dd2bebf26 +Author: Lasse Schuirmann +Date: Fri Feb 27 16:39:11 2015 +0100 + + README: Add usage instructions + +diff --git a/README b/README +index 980a0d5..c9b319e 100644 +--- a/README ++++ b/README +@@ -1 +1,2 @@ + Hello World! ++Don't panic! +``` + +So this **commit** obviously represents the **change** from a file named README +which **contents** are **stored in object** `980a0d5` to a file also named +README which **contents** are **stored in object** `c9b319e`. + +# A Glance At Our History + +Let's see a timeline of what we've done: + +``` +$ git log +commit 7b4977cdfb3f304feffa6fc22de1007dd2bebf26 +Author: Lasse Schuirmann +Date: Fri Feb 27 16:39:11 2015 +0100 + + README: Add usage instructions + +commit ec6c903a0a18960cd73df18897e56738c4c6bb51 +Author: Lasse Schuirmann +Date: Fri Feb 27 14:12:01 2015 +0100 + + Add README +``` + +That looks fairly easy. However I cannot withstand to point out that despite +commits look so fine, linearly **arranged** here, they are actually **nothing +more than commit objects, floating around** in the **.git/objects/ directory**. +So `git log` just **looks where HEAD points to** and recursively asks each +commit **what it's parent is** (if it has one). + +Since every good hitchhiker does know how to travel through time and change +events, we'll learn to do that in the next chapter ;) + +# Configuring Git Even Better + +## Better staging + +It is worth to mention that `git add` also **accepts directories** as an +argument. I.e. `git add .` **recursively adds all files** from the **current +directory**. + +In order to generally **ignore certain patterns** of files (e.g. it's **bad +practice** to **commit any generated stuff**), one can write a `.gitignore` +file. This file can look as follows: + +``` +README~ # Ignore gedit temporary files +*.o # Ignore compiled object files +``` + +The **exact pattern** is defined here: http://git-scm.com/docs/gitignore + +Files matching this pattern will: + + * Not be added with `git add` unless forced with `-f` + * Not be shown in `git status` as unstaged + +It is usually a good idea to **commit** the `.gitignore` **to the repository** +so all developers don't need to care about those files. + +## Aliases + +So, we've learned quite some stuff. However git command's aren't as +**intuitive** as they could be sometimes. They could be **shorter** too. So +let's define us some **aliases** of the commands we know. The ones given here +are **only suggestions**, you should **choose the aliases in a way that suits +best for you**! + +### Aliasing Git Itself + +If you're using git much, you might want to add `alias g=git` to your `.bashrc` +or `.zshrc` or whatever. (On windows you're a bit screwed. But what did you +expect? Really?) + +### Aliasing Git Commands + +Let's let git give us our editor since we don't want to edit just one value: + +``` +git config --global --edit +``` + +You can add aliases through the `[alias]` section, here are the aliases I +suggest: + +``` +[alias] +a = add +c = commit -v +ca = commit -v -a +d = diff +dif = diff # Thats a typo :) +i = init +l = log +st = status +stat = status +``` + +# Conclusion + +So what did we learn? + +We did some basic git commands: + + * `git config`: accessing git configuration + * `git init`: creating a repository + * `git status`: getting current status of files, staging and so on + * `git add`: staging files for the commit + * `git diff`: showing the difference between the current commit and what we + have on our file system + * `git commit`: writing staged changes to a commit + * `git log`: browsing history + +We also learned how git organizes commits, how it stores files and how we can +make git ignore files explicitly. + +I hope this helped you **understanding** a bit **what git does** and **what it +is**. The next tutorial will hopefully cover all the basics. (Some were already hinted here.) diff --git a/mkdocs.yml b/mkdocs.yml index 455d78348e..b472909b30 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -17,3 +17,6 @@ pages: 'Getting Involved', 'Writing Commit Messages'] - ['Getting_Involved/MAC_Hints.md', 'Getting Involved', 'MAC Hints'] +- ['General_Dev_Info/git_tutorial_1.md', + 'General Developer Information', + 'A Hitchhikers Guide To Git (1): Genesis']