├── .gitignore ├── manuscript ├── acknowledgements.md ├── basic-rebasing.md ├── reordering-commits.md ├── autosquashing-commits.md ├── foreword.md ├── interactive-rebasing.md ├── squashing-commits-together.md ├── generating-changelogs-with-clog.md ├── splitting-up-existing-commits.md ├── the-problem-with-basic-merging.md ├── three-way-and-fast-forward-merges.md ├── execute-programs-during-interactive-rebases.md ├── images │ ├── git_tree.png │ ├── title_page.png │ ├── author_pascal.jpg │ ├── author_christoph.jpg │ ├── git-repo-folder-structure.png │ ├── git-branching-commits-abstract-2.svg │ ├── git-branching-new-branch.svg │ ├── git-detached-head-2.svg │ ├── git-branching-head-pointer-2.svg │ ├── git-branching-head-pointer.svg │ └── git-detached-head-3.svg ├── Book.txt ├── about-the-authors.md ├── introduction.md ├── branching-in-git.md └── understanding-commits-in-git.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /manuscript/acknowledgements.md: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | -------------------------------------------------------------------------------- /manuscript/basic-rebasing.md: -------------------------------------------------------------------------------- 1 | # Basic rebasing 2 | -------------------------------------------------------------------------------- /manuscript/reordering-commits.md: -------------------------------------------------------------------------------- 1 | # Reordering commits 2 | -------------------------------------------------------------------------------- /manuscript/autosquashing-commits.md: -------------------------------------------------------------------------------- 1 | # Autosquashing commits 2 | -------------------------------------------------------------------------------- /manuscript/foreword.md: -------------------------------------------------------------------------------- 1 | {frontmatter} 2 | 3 | # Foreword 4 | -------------------------------------------------------------------------------- /manuscript/interactive-rebasing.md: -------------------------------------------------------------------------------- 1 | # Interactive rebasing 2 | -------------------------------------------------------------------------------- /manuscript/squashing-commits-together.md: -------------------------------------------------------------------------------- 1 | # Squashing commits together 2 | -------------------------------------------------------------------------------- /manuscript/generating-changelogs-with-clog.md: -------------------------------------------------------------------------------- 1 | # Generating changelogs with clog 2 | -------------------------------------------------------------------------------- /manuscript/splitting-up-existing-commits.md: -------------------------------------------------------------------------------- 1 | # Splitting up existing commits 2 | -------------------------------------------------------------------------------- /manuscript/the-problem-with-basic-merging.md: -------------------------------------------------------------------------------- 1 | # The problem with basic merging 2 | -------------------------------------------------------------------------------- /manuscript/three-way-and-fast-forward-merges.md: -------------------------------------------------------------------------------- 1 | # Three-way and fast-forward merges 2 | -------------------------------------------------------------------------------- /manuscript/execute-programs-during-interactive-rebases.md: -------------------------------------------------------------------------------- 1 | # Execute projects during interactive rebases 2 | -------------------------------------------------------------------------------- /manuscript/images/git_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtram/rebase-book/HEAD/manuscript/images/git_tree.png -------------------------------------------------------------------------------- /manuscript/images/title_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtram/rebase-book/HEAD/manuscript/images/title_page.png -------------------------------------------------------------------------------- /manuscript/images/author_pascal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtram/rebase-book/HEAD/manuscript/images/author_pascal.jpg -------------------------------------------------------------------------------- /manuscript/images/author_christoph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtram/rebase-book/HEAD/manuscript/images/author_christoph.jpg -------------------------------------------------------------------------------- /manuscript/images/git-repo-folder-structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thoughtram/rebase-book/HEAD/manuscript/images/git-repo-folder-structure.png -------------------------------------------------------------------------------- /manuscript/Book.txt: -------------------------------------------------------------------------------- 1 | foreword.md 2 | about-the-authors.md 3 | acknowledgements.md 4 | introduction.md 5 | understanding-commits-in-git.md 6 | three-way-and-fast-forward-merges.md 7 | the-problem-with-basic-merging.md 8 | basic-rebasing.md 9 | interactive-rebasing.md 10 | reordering-commits.md 11 | squashing-commits-together.md 12 | autosquashing-commits.md 13 | splitting-up-existing-commits.md 14 | executing-programs-during-interactive-rebases.md 15 | generating-changelogs-with-clog.md 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rebase 2 | > The complete guide on rebasing in git 3 | 4 | **Status of this book:** This book is a work in progress. Please subscribe at [leanpub](https://leanpub.com/rebase-the-complete-guide-on-rebasing-in-git) to follow the progress and get notified once we publish a first version of this book. 5 | 6 | ## Anything you want to get covered in this book? 7 | 8 | If there's something on rebasing you really want to get covered because there aren't enough (or good enough) resources out there, please open an issue on this repo and let us know! 9 | -------------------------------------------------------------------------------- /manuscript/about-the-authors.md: -------------------------------------------------------------------------------- 1 | # About the authors 2 | 3 | 4 | ## Christoph Burgdorf 5 | 6 | Christoph is a software engineer and began with programming at the age of 10 with BASIC but has since moved on to become proficient in various different programming languages and technologies. 7 | 8 | He has contributed to many projects, including [AngularJS](http://angularjs.org), jquery-ui, [TodoMVC](http://todomvc.com) and the banshee media player and is also the creator of the [nickel.rs](http://nickel.rs) framework. When he's not evangelizing git, he likes to travel the world with his bicycle. 9 | 10 | You can also find and follow him on [GitHub](http://github.com/cburgdorf) and [Twitter](http://twitter.com/cburgdorf). 11 | 12 | ## Pascal Precht 13 | 14 | Pascal is a front-end engineer with a love for semantic markup and evolving technologies in the open web. He loves contributing to open source and is the creator of the popular [angular-translate](http://angular-translate.github.io) module. 15 | 16 | Pascal loves to travel the world and [speaks](http://pascalprecht.github.io/talks/) at conferences and meetups. When he's not busy preparing the next workshop or conference talk, you might find him outside with his skateboard. 17 | 18 | You can also find and follow him on [GitHub](http://github.com/PascalPrecht) and [Twitter](http://twitter.com/PascalPrecht). 19 | -------------------------------------------------------------------------------- /manuscript/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | The invention of Git was by all means one of the best things that happened to the software industry in the past ten years. It's not that we haven't had version control before. In fact, most of us were happily using SVN or other version control systems before we made the switch. We didn't know how much better things could get. 4 | 5 | On the other hand, I've never met anyone who wanted to go back to SVN after he grokked the full power of Git. Git has features that you'll learn to love after you employed them in your daily workflow but didn't even know they existed before. 6 | 7 | This book is about Git's most powerful feature: Rebasing. If you now think: *"I know what rebasing is. Why write an entire book on it?"*, read on. You'll be surprised how much there is about rebasing that you probably don't know. 8 | 9 | ## Who is this Book is For? 10 | 11 | This book is intended as a guide for people who are already familiar with Git. While a deep understanding of Git isn't necessary to use this book, you would miss many basic features of Git, if this is your first Git book. If you don't feel familiar with the basics of Git we recommend reading the free [Pro Git Book](http://git-scm.com/book) before you read on. 12 | 13 | ## Overview 14 | 15 | **Chapter 1: Understanding Commits in Git** gives you a quick introduction on what commits in Git actually are and what their anatomy looks like. This knowledge is fundamental to understanding merging and rebasing in future chapters. 16 | 17 | **Chapter 2: Branching in Git** makes you understand how branching works in Git and how they are handled under the hood. This knowledge is critical in order to understand merging and rebasing in future chapters. 18 | 19 | **Chapter 3: Three-way and Fast-Forward Merges** details what merges are and what types of merges exist. It also discusses when a certain type of merge happens when doing a merge. 20 | 21 | **Chapter 4: The Problem with Basic Merging** discusses arguments that generally speak against basic merging and why it makes sense to avoid them in certain environments. 22 | 23 | **Chapter 5: Basic Rebasing** introduces the basic rebasing feature of Git. It details what a rebase is and why it is so powerful. 24 | 25 | **Chapter 6: Interactive Rebasing** introduces interactive rebasing as the next level of rebasing in Git. Interactive rebasing lets you reorder, squash and split commits and turns out to be one of the most powerful features. 26 | 27 | **Chapter 7: Reordering Commits** details how to reorder commits of an existing Git commit history. 28 | 29 | **Chapter 8: Squashing Commits** discusses how to squash existing work-in-progress in order to generate a clean Git commit history. 30 | 31 | **Chapter 9: Auto-Squashing Commits** gives you details on how to automate the squashing process when rebaseing in Git. 32 | 33 | **Chapter 10: Splitting Up Existing Commits** details how to go back in time and split up existing commits of an existing commit history. 34 | 35 | **Chapter 11: Executing Programs during Interactive Rebases** discusses how to execute programs when rebasing interactively. This is a feature that is not very well known but quite powerful when it comes to automating tasks during rebases. 36 | 37 | **Chapter 12: Generating Changelogs with Clog** introduces `clog` as a platform independent command line tool to generate nicely readable changelogs based on a Git repositorys commit history. 38 | 39 | ## Help and Support 40 | 41 | You can file issues, suggest changes, and open pull requests for this book by visiting: [http://github.com/thoughtram/rebase-book/](http://github.com/thoughtram/rebase-book) 42 | -------------------------------------------------------------------------------- /manuscript/branching-in-git.md: -------------------------------------------------------------------------------- 1 | # Branching in Git 2 | 3 | In the last chapter we learned the anatomy of a commit in Git. In order to understand what a rebase is, we first need to learn about the concepts of branches in Git. This chapter discusses how branches in Git are technically represented and how simple and yet powerful they are. 4 | 5 | ## Understanding Branches 6 | 7 | When we create commit objects, each commit usually points to one or more parent commits. With each commit pointing to it's parent commit, Git is not only able to track the entire project history, it can also reconstruct any state of the project that happened during the development with the help of branches. A branch basically tells us, in which development branch we're currently working in, since there can be many, but technically, it's just a pointer at a commit. 8 | 9 | To get a better picture of this, let's take a look at the following simple commit history. 10 | 11 | ![A simple commit history](/images/git-branching-commits-abstract-2.svg) 12 | 13 | The figure shows a very abstract representation of a commit history that has just three commits with, of course, each commit having it's own SHA-1 hash. Let's assume our entire repository history is made up only from those three commits. There's a pointer called `master` pointing at commit `a5c3eb`. Guess what, this pointer is a branch. The `master` branch is the default branch that Git already created for us when we initialized our repository. 14 | 15 | As mentioned earlier, a branch is really just a pointer pointing at a specific commit. In fact, we can inspect the file system and verify exactly that. Simply open the file `.git/refs/heads/master` and take a look at it's contents. Don't worry about the file structure for now. We'll talk about this part of the `.git` folder later. We can see that the file really just contains a SHA that points at a commit object in our repository. Another interesting fact: A branch is a movable pointer. Whenever we make a new commit, the branch points at that particular commit. Let's learn how we can create new branches. 16 | 17 | I> A branch is a movable pointer that points at a specific commit. 18 | 19 | ## Creating Branches 20 | 21 | Creating a branch in Git is pretty straight forward and very easy at the same time. All we need to do is to execute `git branch `. Let's create a branch called `feature` and see what actually happens. After running `git branch feature`, this is what our commit graph then looks like: 22 | 23 | ![Creating another branch](/images/git-branching-new-branch.svg) 24 | 25 | Seen that? We just created another pointer called `feature` pointing at the exact same commit. Basically, all Git does, it creates a file called `feature` in `.git/refs/heads` with the contents of the SHA-1 hash of the commit. Now that we have two different branches pointing at the same commit, how does Git know which branch is currently checked out? This is where the `HEAD` pointer comes into play. 26 | 27 | ## Understanding HEAD 28 | 29 | If you're familiar with other version control systems, you probably have a different understand of what the `HEAD` is. In Git, `HEAD` is a special pointer that simply points to at the currently checked out branch or commit. Coming back to our example, we're currently working in the `master` branch, which is why `HEAD` points at `master`. 30 | 31 | ![Understanding HEAD](/images/git-branching-head-pointer.svg) 32 | 33 | And again, it's just a simple file inside the `.git` folder. The file called `HEAD` contains a string of the branch name that is currently checked out. We can verify it by simply switching to our `feature` branch that we've just created by running the following command. 34 | 35 | {title="Switching to another branch",linenos=off,lang="sh"} 36 | git checkout feature 37 | 38 | Opening `.git/HEAD` shows us that `HEAD` now points at `feature`, which points at our latest commit. Here's a graphical representation of what happened. 39 | 40 | ![HEAD pointing at feature branch](/images/git-branching-head-pointer-2.svg) 41 | 42 | This is why branches in Git are so super cheap. It doesn't copy the whole working directory in a new branch folder. Git really just creates a file with the branch name containing the commit SHA to point at and a `HEAD` file that points at the currently checked out branch. If we switch to another branch, what happens is that Git changes the content of `HEAD`. No more black magic involved. 43 | 44 | We mentioned earlier, that a branch is in fact a movable pointer. By "movable" we mean that it automatically updates itself and points at the next commit, in case we're making one. To make this a bit more clear, let's assume we made yet another commit in our `feature` branch. Here's what our graph will them look like: 45 | 46 | ![Adding a new commit to feature](/images/git-branching-head-pointer-3.svg) 47 | 48 | We created a new commit `c57e22` and the `feature` pointer moved on to it. `master` is still pointing at the other commit, simply because `feature` is the currently checked out branch. Let's switch back to `master` by running `git checkout master`. 49 | 50 | ![Switching back to master](/images/git-branching-head-pointer-4.svg) 51 | 52 | `HEAD` now points to `master` again and the state of the entire working directory has been changed to what it was at `a5c3eb`. The next interesting thing to take a look at is how branches behave when they diverge. We jumped back to the state of where `master` is, but what happens when we make a new commit from here? Let's just modify some files and find it out. Our commit graph now looks something like this. 53 | 54 | ![Diverged branches](/images/git-branching-head-pointer-5.svg) 55 | 56 | A new commit `3aa2ff` appeared and `master` moved on to it. At this point our history has diverged. We now have a parallel evolutions of our code base and can simply jump back and forth between them with the power of branches. 57 | 58 | ## Summary 59 | 60 | In this chapter we learned that branches are just simple pointers that point at a specific commit SHA. We also learned about what the `HEAD` in Git is and that it simply points to the branch that is currently checked out. We created new branches and made them even diverged. At this point you may be wondering how to *merge* both ends back together. This is exactly what we will detail in our next chapter on three-way and fast-forward merges. 61 | -------------------------------------------------------------------------------- /manuscript/understanding-commits-in-git.md: -------------------------------------------------------------------------------- 1 | {mainmatter} 2 | 3 | # Understanding commits in Git 4 | 5 | The book's goal is to give you a deep understanding of what rebasing in Git is, how it works and what it does. In order to understand all that, it is essential to get a picture of what a commit looks like and how Git deals with its data on a file system level. 6 | 7 | The first thing we are going to do is to take a closer look at the anatomy of a commit in Git and learn the low level building blocks that assemble it. Then, we are also going to look into what those weird hashes consisting of numbers and characters, that Git apparently produces quite often, are all about. Once we learned that, we are going to learn that all the operations Git does are actually super trivial and it's also going to be a lot easier to follow things that happen during our daily usage of it. But first, let's start with the long revision names we were talking about. 8 | 9 | ## What's up with those long revision names? 10 | 11 | One of the first things people notice when they switch from other version control systems to Git, is that revisions use hard to remember 40 characters long hashes. They are pretty much impossible to read and also look quite cryptic, especially when they appear the very first time on the screen. Let's generate one of those hashes real quick, just to make sure we're all on the same page. 12 | 13 | {title="Creating a first commit",linenos=off,lang="sh"} 14 | $ mkdir app && cd app && git init 15 | $ echo "foo" >> foo 16 | $ git add foo 17 | $ git commit -m "adds foo" 18 | 19 | Running the commands above in a dedicated terminal creates a new folder `app`, initializes an empty Git repository in it, and finally adds and commits a file `foo` to it. If we now run `git log` to see the history of our commits that are reachable from the currently checked out branch, we see something like this: 20 | 21 | {title="Logging commit data",linenos=off,lang="sh"} 22 | commit f4f78b319c308600eab015a5d6529add21660dc1 23 | Author: Pascal Precht 24 | Date: Sat Nov 29 00:06:08 2014 +0100 25 | 26 | adds foo 27 | 28 | There it is. We have a commit hash that says `f4f78b319c308600eab015a5d6529add21660dc1`. So what is it that causes these long hashes that don't seem to mean anything for us humans? And why do we need them at all and not just use revision names such as `r4711` or `r4712`? 29 | 30 | It turns out that using 40 bytes long hashes is actually pretty clever. Of course, they are hard to read and even harder to remember, but they were also not necessarily made for humans in the first place. These hashes are used by Git to make the data we are working with **addressable** on a file system level. Not only that, but they also ensure our data is cryptographically secure. Git comes with integrity by default. 31 | 32 | If you and me both look at revision `f4f78b319c308600eab015a5d6529add21660dc1` on our machines and Git tells us that we have a clean working directory, we can be 100% sure that we are looking at exactly the same files. There is no way someone could manipulate a single bit without Git knowing about it. 33 | 34 | This is especially important in a distributed version control system, because in that way, there's no chance that bits could go lost in transit without Git noticing it. 35 | 36 | Okay, we now know that these hashes somehow ensure that our data isn't broken, corrupted or manipulated, and that Git is able to use them to address data in our file system (however that even works). However, Git surely doesn't randomly choose a couple of numbers and characters and put them together as a hash to work and rely on that right? So where do these hashes come from and what meaning do they have? 37 | 38 | ## Introducing SHA-1 39 | 40 | Those 40 character revision identifiers are actually so called SHA-1 hashes. SHA-1 is an algorithm that takes some data as input and generates a unique 40 character string from it. But what does *unique* mean in that context? Unique means that **no other** input data should ever produce the same hash. However, **the same** input data should always produce exactly the same hash. So if we generate a SHA-1 hash from a string `thoughtram` and do it again another time, the resulting hash looks exactly the same as in the first run. 41 | 42 | I> SHA-1 is an algorithm that generates unique 40 character strings. 43 | 44 | On a UNIX system, we can simply try that out by running the following command in a terminal: 45 | 46 | {title="Generating a SHA-1 hash from a string",linenos=off,lang="sh"} 47 | echo -n "thoughtram" | openssl sha1 48 | 49 | This should print out the hash `a9eb85ea214a6cfa6882f4be041d5cce7bee3e45` no matter if we run it on your machine or on mine. It's the SHA-1 representation of the string `thoughtram`. Okay, this made things a bit more clear, but when looking at the hash we're getting, it's not quite the same when we write the string to a file and commit it to a Git repository, right? That's because there's more happening behind the scene and we'll shed some light into that particular darkness now. 50 | 51 | ## Hashes over hashes 52 | 53 | Just hashing a string is, of course, not enough. As we know, the same string always returns the exact same hash. So assuming Git would just use a hash of a simple string for its commits, that would conflict in no-time since there'll be cases (especially when working with code), where the same string appears more than once. 54 | 55 | Git needs more data to make each commit actually unique. Let's take a look at a very abstract presentation of what the implementation of a `git commit` command looks like and iterate on it until we have a strong understanding of the internal representation. In principle it looks like this in pseudo code: 56 | 57 | {title="Pseudo code representation of Git's commit command",linenos=off,lang="sh"} 58 | sha1( 59 | metaData 60 | commitMessage, 61 | committer, 62 | commitDate, 63 | author, 64 | authoringDate 65 | , 66 | hashOfWorkingDirectory 67 | ) 68 | 69 | 70 | What this pseudo code shows, is that a commit is a SHA-1 hash consisting of two things: 71 | 72 | - **The commit meta data** - Which is the commit message, the committer, a commit date, the author and an authoring date of the commit. 73 | - **Another hash** - That represents a snapshot of our entire working directory, which means all of its folders and files recursively. 74 | 75 | It may not become clear up front, but let that sink in for a second. A commit is a hash over some meta data and another hash based on the current working directory. 76 | 77 | Now we know what a commit object is made of, but it's still not clear where the hash for the current working directory comes from. In order to get a picture of that, we have to take a look at the different object types that Git deals with. 78 | 79 | ## Meet the tree object 80 | 81 | Git knows about four different types of objects: 82 | 83 | - Blobs 84 | - Trees 85 | - Commits 86 | - Annotated Tags 87 | 88 | 89 | Only three of them are essential to create actual commits and commit histories, these are the blobs, the trees and the commit objects. We take a deeper look at them one by one and start with the tree object. 90 | 91 | When I said `hashOfWorkingDirectory` I made a bit of an oversimplification. Yes it's true, it's a hash over the entire working directory with all its files and folders excluding ignored files. But at the same time it's not quite *that* simple. Let's assume the following project structure and then examine how it is represented with the corresponding tree object. 92 | 93 | ![Sample repository folder structure](images/git-repo-folder-structure.png) 94 | 95 | This project structure is a Git repository, which is why we can see a `.git` folder. Beside that it has an `assets` folder where we can find media files and stylesheets. And last but not least, we have a `app.js` file next to the `assets` folder, that probably has our actual application logic. 96 | 97 | Now let's take a look at what Git's representation of this working directory looks like: 98 | 99 | ![Git's representation of sample working directory](images/git_tree.png) 100 | 101 | Okay, so that looks quite cryptic at a first glance. What we see here is Git's representation of our sample folder in a kind of abstracted way to make it easier to visualize how it stores its data. Let's take a deeper look, beginning with the blobs. "Blob" is an acronym for **Binary Large Object**. A blob represents raw data without any association to anything. That means, a blob doesn't even have a file name - it's really just the pure data. 102 | 103 | Taking a look at the figure we can see that each file is stored as a blob. But what exactly does that mean? Let's keep things simple and just assume that Git generates the SHA-1 hash of the contents of `logo.png` and puts it somewhere addressable as `aa1b2fb696a831c89c53f787e03d863691d2b671`. It also generates the SHA-1 hash of the contents of `app.css` and puts it somewhere addressable as `4c511f16ef2644854d04cabebfcecc82be0eb04f`. Same goes for the `app.js` file. Now there's a hash for all files that we have. However, notice that at this point there's no connection between the file name `logo.png` and the hash `aa1b2fb696a831c89c53f787e03d863691d2b671`. This is done on a higher level for good reasons. 104 | 105 | Both `logo.png` and `app.css` are in the same directory `assets`. This directory is represented as a **tree object** (represented as rectangles in the figure). You can think of The tree object as a dictionary that maps (file) names to SHA-1 hashes. And behind those hashes, there may be simple files (represented as blobs) or even other tree objects. 106 | 107 | So we can see that in our example it maps the name `logo.png` to the hash `aa1b2f...` and the name `app.css` to the hash `4c511f...`. Eventually the tree object itself is also hashed and represented by the SHA-1 hash `7cf2a1...`. 108 | 109 | But we aren't done yet. Both, the `assets` folder and the `app.js` file, are in the same directory. It's the top level directory and again it works like a dictionary. It maps the name `assets` to the hash `7cf2a1...` (the child tree object!) and the name `app.js` to the hash `29bfcf...`. And then again the dictionary itself is also hashed and becomes the root tree object with hash `9c435a...`. 110 | 111 | Wow, that was complicated, wasn't it? Don't be scared by all these hashes, what counts is the principle. Let that sink in again, `9c435a...` is the hash of the root tree object which essentially translates into a dictionary that maps names to hashes and those hashes can refer to blobs (for files) or other tree objects which in turn are dictionaries themselves that map names to hashes which can refer to...ah well, you get the idea. 112 | 113 | ## The commit object 114 | 115 | Now that we have a basic idea of how Git represents its data in blobs and trees, we can go back to our commit object from above and fill it with life. Let's assume we freshly started the repository and this is our initial commit. What follows is again pseudo code to demonstrate what exactly is used to get to the commit hash. 116 | 117 | {title="Pseudo commit command",linenos=off,lang="sh"} 118 | sha1( 119 | metaData 120 | commitMessage => "initial commit", 121 | committer => Christoph Burgdorf , 122 | commitDate => Sat Nov 8 10:56:57 2014 +0100, 123 | author => Christoph Burgdorf , 124 | authorDate => Sat Nov 8 10:56:57 2014 +0100 125 | , 126 | hashOfWorkingDirectory => 9c435a86e664be00db0d973e981425e4a3ef3f8d 127 | ) 128 | 129 | It's all the meta data plus the hash of the root tree object. And of course Git creates a SHA-1 hash from those contents. The commit hash. 130 | 131 | Remember we mentioned Git has integrity? You can't change a single thing about this commit without getting a different SHA-1 commit hash. Want to change the commit message? The commit message is part of the content that is used to produce the SHA-1 hash, changing it will change the commit hash. What if we just add a whitespace somewhere in `app.css`? Doesn't matter. The SHA-1 hash of `app.css` won't be `4c511f...` anymore and that in turn will cause the `assets` tree object to not be `7cf2a1...` anymore and that in turn will cause the root tree object to not be `9c435a...` anymore. That's integrity. 132 | 133 | ## Summary 134 | 135 | Congratulations! We now know how Git handles the data that we commit to our repositories. We've learned that these cryptic hashes are SHA-1 hashes, to make data addressable. We've also learned that Git creates a hash over all contents as blobs and folders as trees recursively to finally create another hash of that data, along with some meta data to create actual commit objects. And because everything is hashed from the ground up, we know that we can't change anything without Git knowing it. 136 | 137 | Please note that we simplified some parts intentionally in order to reduce the noise and make the essence easier to grasp. If you like to dig deeper, we highly recommend to read up on the Git's internals in the [Git book](http://git-scm.com/book/en/v2/Git-Internals-Git-Objects). 138 | 139 | In the next chapter we take a look at branches and how we can use them to increase productivity, as well as flexibility. 140 | -------------------------------------------------------------------------------- /manuscript/images/git-branching-commits-abstract-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /manuscript/images/git-branching-new-branch.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /manuscript/images/git-detached-head-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /manuscript/images/git-branching-head-pointer-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /manuscript/images/git-branching-head-pointer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /manuscript/images/git-detached-head-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | --------------------------------------------------------------------------------