From 5c71b34ee03c93dad6ddf9e6b85ce98c7e4b97c3 Mon Sep 17 00:00:00 2001 From: James Musselman Date: Tue, 11 Mar 2025 15:31:18 -0500 Subject: [PATCH] add experiment --- rys-git-tutorial.md | 5874 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 5874 insertions(+) create mode 100644 rys-git-tutorial.md diff --git a/rys-git-tutorial.md b/rys-git-tutorial.md new file mode 100644 index 0000000..6c7ade1 --- /dev/null +++ b/rys-git-tutorial.md @@ -0,0 +1,5874 @@ +![](media/cover-art.png) + +[]{#navigation-document.xhtml} + +:::: {#navigation-document.xhtml_page} +::: {#navigation-document.xhtml_content} +```{=html} + +``` +::: +:::: + +[]{#introduction.xhtml} + +:::: {#introduction.xhtml_page} +::: {#introduction.xhtml_content} +# Introduction {#introduction.xhtml_introduction} + +Git is a version control system (VCS) created for a single task: +managing changes to your files. It lets you track every change a +software project goes through, as well as where those changes came from. +This makes Git an essential tool for managing large projects, but it can +also open up a vast array of possibilities for your personal workflow. + +## A Brief History of Revision Control {#introduction.xhtml_a-brief-history-of-revision-control} + +We'll talk more about the core philosophy behind Git in a moment, but +first, let's step through the evolution of version control systems in +general. + +### Files and Folders {#introduction.xhtml_files-and-folders} + +Before the advent of revision control software, there were only files +and folders. The only way to track revisions of a project was to copy +the entire project and give it a new name. Just think about how many +times you've saved a "backup" called `my-term-paper-2.doc`. This is the +simplest form of version control. + +![Revision control with files and folders](media/0-1.png) + +But, it's easy to see how copying files from folder to folder could +prove disastrous for software developers. What happens if you mis-label +a folder? Or if you overwrite the wrong file? How would you even know +that you lost an important piece of code? It didn't take long for +software developers to realize they needed something more reliable. + +### Local VCS {#introduction.xhtml_local-vcs} + +So, developers began writing utility programs dedicated to managing file +revisions. Instead of keeping old versions as independent files, these +new VCSs stored them in a database. When you needed to look at an old +version, you used the VCS instead of accessing the file directly. That +way, you would only have a single "checked out" copy of the project at +any given time, eliminating the possibility of mixing up or losing +revisions. + +![Local version control](media/0-2.png) + +At this point, versioning only took place on the developer's *local* +computer---there was no way to efficiently share code amongst several +programmers. + +### Centralized VCS {#introduction.xhtml_centralized-vcs} + +Enter the centralized version control system (CVCS). Instead of storing +project history on the developer's hard disk, these new CVCS programs +stored everything on a server. Developers checked out files and saved +them back into the project over a network. This setup let several +programmers collaborate on a project by giving them a single point of +entry. + +![Centralized version control](media/0-3.png) + +While a big improvement on local VCS, centralized systems presented a +new set of problems: how do multiple users work on the same files at the +same time? Just imagine a scenario where two people fix the same bug and +try to commit their updates to the central server. Whose changes should +be accepted? + +CVCSs addressed this issue by preventing users from overriding others' +work. If two changes conflicted, someone had to manually go in and merge +the differences. This solution worked for projects with relatively few +updates (which meant relatively few conflicts), but proved cumbersome +for projects with dozens of active contributors submitting several +updates everyday: development couldn't continue until all merge +conflicts were resolved and made available to the entire development +team. + +### Distributed VCS {#introduction.xhtml_distributed-vcs} + +The next generation of revision control programs shifted away from the +idea of a single centralized repository, opting instead to give every +developer their own *local* copy of the entire project. The resulting +*distributed* network of repositories let each developer work in +isolation, much like a local VCS---but now the conflict resolution +problem of CVCS had a much more elegant solution. + +![Distributed version control](media/0-4.png) + +Since there was no longer a central repository, everyone could develop +at their own pace, store the updates locally, and put off merging +conflicts until their convenience. In addition, distributed version +control systems (DVCS) focused on efficient management for separate +branches of development, which made it much easier to share code, merge +conflicts, and experiment with new ideas. + +The local nature of DVCSs also made development much faster, since you +no longer had to perform actions over a network. And, since each user +had a complete copy of the project, the risk of a server crash, a +corrupted repository, or any other type of data loss was much lower than +that of their CVCS predecessors. + +## The Birth of Git {#introduction.xhtml_the-birth-of-git} + +And so, we arrive at Git, a distributed version control system created +to manage the Linux kernel. In 2005, the Linux community lost their free +license to the BitKeeper software, a commercial DVCS that they had been +using since 2002. In response, Linus Torvalds advocated the development +of a new open-source DVCS as a replacement. This was the birth of Git. + +As a source code manager for the entire Linux kernel, Git had several +unique constraints, including: + +- Reliability +- Efficient management of large projects +- Support for distributed development +- Support for non-linear development + +While other DVCSs did exist at the time (e.g., GNU's Arch or David +Roundy's Darcs), none of them could satisfy this combination of +features. Driven by these goals, Git has been under active development +for several years and now enjoys a great deal of stability, popularity, +and community involvement. + +Git originated as a command-line program, but a variety of visual +interfaces have been released over the years. Graphical tools mask some +of the complexity behind Git and often make it easier to visualize the +state of a repository, but they still require a solid foundation in +distributed version control. With this in mind, we'll be sticking to the +command-line interface, which is still the most common way to interact +with Git. + +## Installation {#introduction.xhtml_installation} + +The upcoming modules will explore Git's features by applying commands to +real-world scenarios. But first, you'll need a working Git installation +to experiment with. Downloads for all supported platforms are available +via the [official Git website](http://git-scm.com). + +For Windows users, this will install a special command shell called *Git +Bash*. You should be using this shell instead of the native command +prompt to run Git commands. OS X and Linux users can access Git from a +normal shell. To test your installation, open a new command prompt and +run `git --version`. It should output something like +`git version 1.7.10.2 (Apple Git-33)`. + +## Get Ready! {#introduction.xhtml_get-ready} + +Remember that *Ry's Git Tutorial* is designed to *demonstrate* Git's +feature set, not just give you a superficial overview of the most common +commands. To get the most out of this tutorial, it's important to +actually execute the commands you're reading about. So, make sure you're +sitting in front of a computer, and let's get to it! +::: +:::: + +[]{#the-basics.xhtml} + +:::: {#the-basics.xhtml_page} +::: {#the-basics.xhtml_content} +# The Basics {#the-basics.xhtml_the-basics} + +Now that you have a basic understanding of version control systems in +general, we can start experimenting with Git. Using Git as a VCS is a +lot like working with a normal software project. You're still writing +code in files and storing those files in folders, only now you have +access to a plethora of Git commands to manipulate those files. + +For example, if you want to revert to a previous version of your +project, all you have to do is run a simple Git command. This command +will dive into Git's internal database, figure out what your project +looked like at the desired state, and update all the existing files in +your project folder (also known as the **working directory**). From an +external standpoint, it will look like your project magically went back +in time. + +This module explores the fundamental Git workflow: creating a +repository, staging and committing snapshots, configuring options, and +viewing the state of a repository. It also introduces the HTML website +that serves as the running example for this entire tutorial. A very +basic knowledge of HTML and CSS will give you a deeper understanding of +the purpose underlying various Git commands but is not strictly +required. + +## Create the Example Site {#the-basics.xhtml_create-the-example-site} + +Before we can execute any Git commands, we need to create the example +project. Create a new folder called `my-git-repo` to store the project, +then add a file called `index.html` to it. Open `index.html` in your +favorite text editor and add the following HTML. + +``` cp + + + + A Colorful Website + + + +

A Colorful Website

+

This is a website about color!

+ +

News

+ + + +``` + +Save the file when you're done. This serves as the foundation of our +example project. Feel free to open the `index.html` in a web browser to +see what kind of website it translates to. It's not exactly pretty, but +it serves our purposes. + +## Initialize the Git Repository {#the-basics.xhtml_initialize-the-git-repository} + +Now, we're ready to create our first Git repository. Open a command +prompt (or Git Bash for Windows users) and navigate to the project +directory by executing: + +``` k +cd /path/to/my-git-repo +``` + +where `/path/to/my-git-repo` is a path to the folder created in the +previous step. For example, if you created `my-git-repo` on your +desktop, you would execute: + +``` k +cd ~/Desktop/my-git-repo +``` + +Next, run the following command to turn the directory into a Git +repository. + +``` k +git init +``` + +This initializes the repository, which enables the rest of Git's +powerful features. Notice that there is now a `.git` directory in +`my-git-repo` that stores all the tracking data for our repository (you +may need to enable hidden files to view this folder). The `.git` folder +is the only difference between a Git repository and an ordinary folder, +so deleting it will turn your project back into an unversioned +collection of files. + +## View the Repository Status {#the-basics.xhtml_view-the-repository-status} + +Before we try to start creating revisions, it would be helpful to view +the status of our new repository. Execute the following in your command +prompt. + +``` k +git status +``` + +This should output something like: + +``` c +# On branch master +# +# Initial commit +# +# Untracked files: +# (use "git add ..." to include in what will be committed) +# +# index.html +nothing added to commit but untracked files present (use "git add" to track) +``` + +Ignoring the `On branch master` portion for the time being, this status +message tells us that we're on our initial commit and that we have +nothing to commit but "untracked files." + +An **untracked file** is one that is not under version control. Git +doesn't automatically track files because there are often project files +that we don't want to keep under revision control. These include +binaries created by a C program, compiled Python modules (`.pyc` files), +and any other content that would unnecessarily bloat the repository. To +keep a project small and efficient, you should only track *source* files +and omit anything that can be *generated* from those files. This latter +content is part of the build process---not revision control. + +## Stage a Snapshot {#the-basics.xhtml_stage-a-snapshot} + +So, we need to explicitly tell Git to add `index.html` to the +repository. The aptly named `git add` command tells Git to start +tracking `index.html`: + +``` k +git add index.html +git status +``` + +In place of the "Untracked files" list, you should see the following +status. + +``` c +# Changes to be committed: +# (use "git rm --cached ..." to unstage) +# +# new file: index.html +``` + +We've just added `index.html` to the **snapshot** for the next commit. A +snapshot represents the state of your project at a given point in time. +In this case, we created a snapshot with one file: `index.html`. If we +ever told Git to revert to this snapshot, it would replace the entire +project folder with this one file, containing the exact same HTML as it +does right now. + +Git's term for creating a snapshot is called **staging** because we can +add or remove multiple files before actually committing it to the +project history. Staging gives us the opportunity to group related +changes into distinct snapshots---a practice that makes it possible to +track the *meaningful* progression of a software project (instead of +just arbitrary lines of code). + +## Commit the Snapshot {#the-basics.xhtml_commit-the-snapshot} + +We have staged a snapshot, but we still need to **commit** it to the +project history. The next command will open a text editor and prompt you +to enter a message for the commit. + +``` k +git commit +``` + +Type `Create index page` for the message, leave the remaining text, save +the file, and exit the editor. You should see the message +`1 files changed` among a mess of rather ambiguous output. This changed +file is our `index.html`. + +As we just demonstrated, saving a version of your project is a two step +process: + +1. **Staging.** Telling Git what files to include in the next commit. +2. **Committing.** Recording the staged snapshot with a descriptive + message. + +Staging files with the `git add` command doesn't actually affect the +repository in any significant way---it just lets us get our files in +order for the next commit. Only after executing `git commit` will our +snapshot be recorded in the repository. Committed snapshots can be seen +as "safe" versions of the project. Git will never change them, which +means you can do almost anything you want to your project without losing +those "safe" revisions. This is the principal goal of any version +control system. + +![The stage/commit process](media/1-1.png) + +## View the Repository History {#the-basics.xhtml_view-the-repository-history} + +Note that `git status` now tells us that there is `nothing to commit`, +which means our current state matches what is stored in the repository. +The `git status` command will *only* show us uncommitted changes---to +view our project history, we need a new command: + +``` k +git log +``` + +When you execute this command, Git will output information about our one +and only commit, which should look something like this: + +``` k +commit b650e4bd831aba05fa62d6f6d064e7ca02b5ee1b +Author: unknown +Date: Wed Jan 11 00:45:10 2012 -0600 + + Create index page +``` + +Let's break this down. First, the commit is identified with a very +large, very random-looking string (`b650e4b...`). This is an SHA-1 +checksum of the commit's contents, which ensures that the commit will +never be corrupted without Git knowing about it. All of your SHA-1 +checksums will be different than those displayed in this tutorial due to +the different dates and authors in your commits. In the next module, +we'll see how a checksum also serves as a unique ID for a commit. + +Next, Git displays the author of the commit. But since we haven't told +Git our name yet, it just displays `unknown` with a generated username. +Git also outputs the date, time, and timezone (`-0600`) of when the +commit took place. Finally, we see the commit message that was entered +in the previous step. + +## Configure Git {#the-basics.xhtml_configure-git} + +Before committing any more snapshots, we should probably tell Git who we +are. We can do this with the `git config` command: + +``` k +git config --global user.name "Your Name" +git config --global user.email your.email@example.com +``` + +Be sure to replace `Your Name` and `your.email@example.com` with your +actual name and email. The `--global` flag tells Git to use this +configuration as a default for all of your repositories. Omitting it +lets you specify different user information for individual repositories, +which will come in handy later on. + +## Create New HTML Files {#the-basics.xhtml_create-new-html-files} + +Let's continue developing our website a bit. Start by creating a file +called `orange.html` with the following content. + +``` cp + + + + The Orange Page + + + +

The Orange Page

+

Orange is so great it has a + fruit named after it.

+ + +``` + +Then, add a `blue.html` page: + +``` cp + + + + The Blue Page + + + +

The Blue Page

+

Blue is the color of the sky.

+ + +``` + +## Stage the New Files {#the-basics.xhtml_stage-the-new-files} + +Next, we can stage the files the same way we created the first snapshot. + +``` k +git add orange.html blue.html +git status +``` + +Notice that we can pass more than one file to `git add`. After adding +the files, your status output should look like the following: + +``` c +# On branch master +# Changes to be committed: +# (use "git reset HEAD ..." to unstage) +# +# new file: blue.html +# new file: orange.html +``` + +Try running `git log`. It only outputs the first commit, which tells us +that `blue.html` and `orange.html` have not yet been added to the +repository's history. Remember, we can see *staged* changes with +`git status`, but not with `git log`. The latter is used only for +*committed* changes. + +![Status output vs. Log output](media/1-2.png) + +## Commit the New Files {#the-basics.xhtml_commit-the-new-files} + +Let's commit our staged snapshot: + +``` k +git commit +``` + +Use `Create blue and orange pages` as the commit message, then save and +close the file. Now, `git log` should output two commits, the second of +which reflects our name/email configuration. This project history can be +visualized as: + +![Current project history](media/1-3.png) + +Each circle represents a commit, the red circle designates the commit +we're currently viewing, and the arrow points to the preceding commit. +This last part may seem counterintuitive, but it reflects the underlying +relationship between commits (that is, a new commit refers to its parent +commit). You'll see this type of diagram many, many times throughout +this tutorial. + +## Modify the HTML Pages {#the-basics.xhtml_modify-the-html-pages} + +The `git add` command we've been using to stage *new* files can also be +used to stage *modified* files. Add the following to the bottom of +`index.html`, right before the closing `` tag: + +``` nt +

Navigation

+ +``` + +Next, add a home page link to the bottom of `orange.html` and +`blue.html` (again, before the `` line): + +``` nt +

Return to home page

+``` + +You can now navigate between pages when viewing them in a web browser. + +## Stage and Commit the Snapshot {#the-basics.xhtml_stage-and-commit-the-snapshot} + +Once again, we'll stage the modifications, then commit the snapshot. + +``` k +git status +git add index.html orange.html blue.html +git status +git commit -m "Add navigation links" +``` + +The `-m` option lets you specify a commit message on the command line +instead of opening a text editor. This is just a convenient shortcut (it +has the exact same effect as our previous commits). + +Our history can now be represented as the following. Note that the red +circle, which represents the current commit, automatically moves forward +every time we commit a new snapshot. + +![Current project history](media/1-4.png) + +## Explore the Repository[']{.apo}s History {#the-basics.xhtml_explore-the-repository} + +The `git log` command comes with a lot of formatting options, a few of +which will be introduced throughout this tutorial. For now, we'll just +use the convenient `--oneline` flag: + +``` k +git log --oneline +``` + +Condensing output to a single line is a great way to get a high-level +overview of a repository. Another useful configuration is to pass a +filename to `git log`: + +``` k +git log --oneline blue.html +``` + +This displays only the `blue.html` history. Notice that the initial +`Create index page` commit is missing, since `blue.html` didn't exist in +that snapshot. + +## Conclusion {#the-basics.xhtml_conclusion} + +In this module, we introduced the fundamental Git workflow: edit files, +stage a snapshot, and commit the snapshot. We also had some hands-on +experience with the components involved in this process: + +![The fundamental Git workflow](media/1-5.png) + +The distinction between the working directory, the staged snapshot, and +committed snapshots is at the very core of Git version control. Nearly +all other Git commands manipulate one of these components in some way, +so understanding the interplay between them is a fantastic foundation +for mastering Git. + +The next module puts our existing project history to work by reverting +to previous snapshots. This is all you need to start using Git as a +simple versioning tool for your own projects. + +## Quick Reference {#the-basics.xhtml_quick-reference} + +`git init` +: Create a Git repository in the current folder. + +`git status` +: View the status of each file in a repository. + +`git add ` +: Stage a file for the next commit. + +`git commit` +: Commit the staged files with a descriptive message. + +`git log` +: View a repository's commit history. + +`git config --global user.name ""` +: Define the author name to be used in all repositories. + +`git config --global user.email ` +: Define the author email to be used in all repositories. +::: +:::: + +[]{#undoing-changes.xhtml} + +:::::: {#undoing-changes.xhtml_page} +::::: {#undoing-changes.xhtml_content} +# Undoing Changes {#undoing-changes.xhtml_undoing-changes} + +In the last module, we learned how to record versions of a project into +a Git repository. The whole point of maintaining these "safe" copies is +peace of mind: should our project suddenly break, we'll know that we +have easy access to a functional version, and we'll be able to pinpoint +precisely where the problem was introduced. + +To this end, storing "safe" versions isn't much help without the ability +to restore them. Our next task is to learn how to view the previous +states of a project, revert back to them, and reset uncommitted changes. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repository for this +module](http://rypress.com/tutorials/git/media/repo-zips/undoing-changes.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git repository +from the above link, uncompress it, and you're good to go. + +## Display Commit Checksums {#undoing-changes.xhtml_display-commit-checksums} + +As a quick review, let's display our repository's history. Navigate a +command prompt (or Git Bash) to the `my-git-repo` folder and run the +following. + +``` k +git log --oneline +``` + +The output for this should look similar to the following, but contain +different commit checksums. + +``` s +1c310d2 Add navigation links +54650a3 Create blue and orange pages +b650e4b Create index page +``` + +Git only outputs the first 7 characters of the checksum (remember that +you can see the full version with the default formatting of `git log`). +These first few characters effectively serve as a unique ID for each +commit. + +## View an Old Revision {#undoing-changes.xhtml_view-an-old-revision} + +Using the new `git checkout` command, we can view the contents of a +previous snapshot. Make sure to change `54650a3` in the following +command to the ID of your *second* commit. + +``` k +git checkout 54650a3 +``` + +This will output a lot of information about a `detached HEAD` state. You +can ignore it for now. All you need to know is that the above command +turns your `my-git-repo` directory into an exact replica of the second +snapshot we committed in [The Basics](#the-basics.xhtml). + +Open the HTML files in a text editor or web browser to verify that the +navigation links we added in the third commit have disappeared. Running +`git log` will also tell us that the third commit is no longer part of +the project. After checking out the second commit, our repository +history looks like the following (the red circle represents the current +commit). + +![Checking out the 2nd commit](media/2-1.png) + +## View an Older Revision {#undoing-changes.xhtml_view-an-older-revision} + +Let's go even farther back in our history. Be sure to change `b650e4b` +to the ID of your *first* commit. + +``` k +git checkout b650e4b +``` + +Now, the `blue.html` and `orange.html` files are gone, as is the rest of +the `git log` history. + +![Checking out the 1st commit](media/2-2.png) + +In the last module, we said that Git was designed to never lose a +committed snapshot. So, where did our second and third snapshots go? A +simple `git status` will answer that question for us. It should return +the following message: + +``` c +# Not currently on any branch. +nothing to commit (working directory clean) +``` + +Compare this with the status output from the previous module: + +``` c +# On branch master +nothing to commit (working directory clean) +``` + +All of our actions in *The Basics* took place on the `master` branch, +which is where our second and third commits still reside. To retrieve +our complete history, we just have to check out this branch. This is a +very brief introduction to branches, but it's all we need to know to +navigate between commits. The next module will discuss branches in full +detail. + +## Return to Current Version {#undoing-changes.xhtml_return-to-current-version} + +We can use the same `git checkout` command to return to the `master` +branch. + +``` k +git checkout master +``` + +This makes Git update our working directory to reflect the state of the +`master` branch's snapshot. It re-creates the `blue.html` and +`orange.html` files for us, and the content of `index.html` is updated +as well. We're now back to the current state of the project, and our +history looks like: + +![Current project history](media/2-3.png) + +## Tag a Release {#undoing-changes.xhtml_tag-a-release} + +Let's call this a stable version of the example website. We can make it +official by **tagging** the most recent commit with a version number. + +``` k +git tag -a v1.0 -m "Stable version of the website" +``` + +Tags are convenient references to official releases and other +significant milestones in a software project. It lets developers easily +browse and check out important revisions. For example, we can now use +the `v1.0` tag to refer to the third commit instead of its random ID. To +view a list of existing tags, execute `git tag` without any arguments. + +In the above snippet, the `-a` flag tells Git to create an **annotated +tag**, which lets us record our name, the date, and a descriptive +message (specified via the `-m` flag). We'll use this tag to find the +stable version after we try some crazy experiments. + +## Try a Crazy Experiment {#undoing-changes.xhtml_try-a-crazy-experiment} + +We're now free to add experimental changes to the example site without +affecting any committed content. Create a new file called `crazy.html` +and add the following HTML. + +``` cp + + + + A Crazy Experiment + + + +

A Crazy Experiment

+

We're trying out a crazy + experiment! + +

Return to home page

+ + +``` + +## Stage and Commit the Snapshot {#undoing-changes.xhtml_stage-and-commit-the-snapshot} + +Stage and commit the new file as usual. + +``` k +git add crazy.html +git status +git commit -m "Add a crazzzy experiment" +git log +``` + +It's a good practice to run `git status` to see exactly what you're +committing before running `git commit -m`. This will keep you from +unintentionally committing a file that doesn't belong in the current +snapshot. + +As expected, the new snapshot shows up in the repository's history. If +your log history takes up more than one screen, you can scroll down by +pressing `Space` and return to the command line by pressing the letter +`q`. + +## View the Stable Commit {#undoing-changes.xhtml_view-the-stable-commit} + +Let's go back and take a look at our stable revision. Remember that the +`v1.0` tag now serves as a user-friendly shortcut to the third commit's +ID. + +``` k +git checkout v1.0 +``` + +After seeing the stable version of the site, we decide to scrap the +crazy experiment. But, before we undo the changes, we need to return to +the `master` branch. If we didn't, all of our updates would be on some +non-existent branch. As we'll discover next module, you should never +make changes directly to a previous revision. + +``` k +git checkout master +git log --oneline +``` + +At this point, our history should look like the following: + +``` s +514fbe7 Add a crazzzy experiment +1c310d2 Add navigation links +54650a3 Create blue and orange pages +b650e4b Create index page +``` + +## Undo Committed Changes {#undoing-changes.xhtml_undo-committed-changes} + +We're ready to restore our stable tag by removing the most recent +commit. Make sure to change `514fbe7` to the ID of the *crazy +experiment's commit* before running the next command. + +``` k +git revert 514fbe7 +``` + +This will prompt you for a commit message with a default of +`Revert "Add a crazzzy experiment"...`. You can leave the default +message and close the file. After verifying that `crazy.html` is gone, +take a look at your history with `git log --oneline`. + +``` s +506bb9b Revert "Add a crazzzy experiment" +514fbe7 Add a crazzzy experiment +1c310d2 Add navigation links +54650a3 Create blue and orange pages +b650e4b Create index page +``` + +Notice that instead of deleting the "crazzzy experiment" commit, Git +figures out how to undo the changes it contains, then tacks on another +commit with the resulting content. So, our fifth commit and our third +commit represent the exact same snapshot, as shown below. Again, Git is +designed to *never* lose history: the fourth snapshot is still +accessible, just in case we want to continue developing it. + +![Current project history](media/2-4.png) + +When using `git revert`, remember to specify the commit that you want to +undo---not the stable commit that you want to return to. It helps to +think of this command as saying "undo this commit" rather than "restore +this version." + +## Start a Smaller Experiment {#undoing-changes.xhtml_start-a-smaller-experiment} + +Let's try a smaller experiment this time. Create `dummy.html` and leave +it as a blank file. Then, add a link in the "Navigation" section of +`index.html` so that it resembles the following. + +``` nt +

Navigation

+ +``` + +In the next section, we're going to abandon this uncommitted experiment. +But since the `git revert` command requires a commit ID to undo, we +can't use the method discussed above. + +## Undo Uncommitted Changes {#undoing-changes.xhtml_undo-uncommitted-changes} + +Before we start undoing things, let's take a look at the status of our +repository. + +``` k +git status +``` + +We have a tracked file and an untracked file that need to be changed. +First, we'll take care of `index.html`: + +``` k +git reset --hard +``` + +This changes all *tracked* files to match the most recent commit. Note +that the `--hard` flag is what actually updates the file. Running +`git reset` without any flags will simply unstage `index.html`, leaving +its contents as is. In either case, `git reset` only operates on the +working directory and the staging area, so our `git log` history remains +unchanged. + +Next, let's remove the `dummy.html` file. Of course, we could manually +delete it, but using Git to reset changes eliminates human errors when +working with several files in large teams. Run the following command. + +``` k +git clean -f +``` + +This will remove all *untracked* files. With `dummy.html` gone, +`git status` should now tell us that we have a "clean" working +directory, meaning our project matches the most recent commit. + +***Be careful*** with `git reset` and `git clean`. Both operate on the +working directory, not on the committed snapshots. Unlike `git revert`, +they ***permanently*** undo changes, so make sure you really want to +trash what you're working on before you use them. + +## Conclusion {#undoing-changes.xhtml_conclusion} + +As noted in the previous module, most Git commands operate on one of the +three main components of a Git repository: the working directory, the +staged snapshot, or the committed snapshots. The `git reset` command +undoes changes to the working directory and the staged snapshot, while +`git revert` undoes changes contained in committed snapshots. Not +surprisingly, `git status` and `git log` directly parallel this +behavior. + +![Resetting vs. Reverting](media/2-5.png) + +I mentioned that instead of completely removing a commit, `git revert` +saves the commit in case you want to come back to it later. This is only +one reason for preserving committed snapshots. When we start working +with remote repositories, we'll see that altering the history by +removing a commit has dramatic consequences for collaborating with other +developers. + +This module also introduces the concept of switching between various +commits and branches with `git checkout`. Branches round out our +discussion of the core Git components, and they offer an elegant option +for optimizing your development workflow. In the next module, we'll +cover the basic Git branch commands. + +## Quick Reference {#undoing-changes.xhtml_quick-reference} + +`git checkout ` +: View a previous commit. + +`git tag -a -m ""` +: Create an annotated tag pointing to the most recent commit. + +`git revert ` +: Undo the specified commit by applying a new commit. + +`git reset --hard` +: Reset *tracked* files to match the most recent commit. + +`git clean -f` +: Remove *untracked* files. + +`git reset --hard` / ` git clean -f` +: Permanently undo uncommitted changes. +::::: +:::::: + +[]{#branches-1.xhtml} + +:::::: {#branches-1.xhtml_page} +::::: {#branches-1.xhtml_content} +# Branches, Part I {#branches-1.xhtml_branches-part-i} + +Branches are the final component of Git version control. This gives us +four core elements to work with throughout the rest of this tutorial: + +- The Working Directory +- The Staged Snapshot +- Committed Snapshots +- Development Branches + +In Git, a **branch** is an independent line of development. For example, +if you wanted to experiment with a new idea *without* using Git, you +might copy all of your project files into another directory and start +making your changes. If you liked the result, you could copy the +affected files back into the original project. Otherwise, you would +simply delete the entire experiment and forget about it. + +This is the exact functionality offered by Git branches---with some key +improvements. First, branches present an error-proof method for +incorporating changes from an experiment. Second, they let you store all +of your experiments in a single directory, which makes it much easier to +keep track of them and to share them with others. Branches also lend +themselves to several standardized workflows for both individual and +collaborative development, which will be explored in the latter half of +the tutorial. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repository for this +module](http://rypress.com/tutorials/git/media/repo-zips/branches-1.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git repository +from the above link, uncompress it, and you're good to go. + +## View Existing Branches {#branches-1.xhtml_view-existing-branches} + +Let's start our exploration by listing the existing branches for our +project. + +``` k +git branch +``` + +This will display our one and only branch: `* master`. The `master` +branch is Git's default branch, and the asterisk next to it tells us +that it's currently checked out. This means that the most recent +snapshot in the `master` branch resides in the working directory: + +![The `master` branch](media/3-1.png) + +Notice that since there's only one working directory for each project, +only one branch can be checked out at a time. + +## Checkout the Crazy Experiment {#branches-1.xhtml_checkout-the-crazy-experiment} + +The previous module left out some details about how checking out +previous commits actually works. We're now ready to tackle this topic in +depth. First, we need the checksums of our committed snapshots. + +``` k +git log --oneline +``` + +This outputs the following history. + +``` s +506bb9b Revert "Add a crazzzy experiment" +514fbe7 Add a crazzzy experiment +1c310d2 Add navigation links +54650a3 Create blue and orange pages +b650e4b Create index page +``` + +Check out the crazy experiment from the last module, remembering to +change `514fbe7` to the ID of your fourth commit. + +``` k +git checkout 514fbe7 +``` + +This command returns a message that says we're in a +`detached HEAD state` and that the `HEAD` is now at `514fbe7`. The +**HEAD** is Git's internal way of indicating the snapshot that is +currently checked out. This means the red circle in each of our history +diagrams actually represents Git's `HEAD`. The following figure shows +the state of our repository before and after we checked out an old +commit. + +![Checking out the 4th commit](media/3-2.png) + +As shown in the "before" diagram, the `HEAD` normally resides on the tip +of a development branch. But when we checked out the previous commit, +the `HEAD` moved to the middle of the branch. We can no longer say we're +on the `master` branch since it contains more recent snapshots than the +`HEAD`. This is reflected in the `git branch` output, which tells us +that we're currently on `(no branch)`. + +## Create a New Branch {#branches-1.xhtml_create-a-new-branch} + +We can't add new commits when we're not on a branch, so let's create one +now. This will take our current working directory and fork it into a new +branch. + +``` k +git branch crazy +``` + +Note that `git branch` is a versatile command that can be used to either +list branches or create them. However, the above command only *creates* +the `crazy` branch---it doesn't check it out. + +``` k +git checkout crazy +``` + +We're now free to experiment in the working directory without disturbing +anything in the `master` branch. The `crazy` branch is a *completely +isolated* development environment that can be visualized as the +following. + +![Creating a new branch](media/3-3.png) + +Right now, the `crazy` branch, `HEAD`, and working directory are the +exact same as the fourth commit. But as soon as we add another snapshot, +we'll see a fork in our project history. + +## Make a Rainbow {#branches-1.xhtml_make-a-rainbow} + +We'll continue developing our crazy experiment by changing `crazy.html` +to the following. + +``` cp + + + + A Crazy Experiment + + + +

A Crazy Experiment

+

Look! A Rainbow!

+ +
    +
  • Red
  • +
  • Orange
  • +
  • Yellow
  • +
  • Green
  • +
  • Blue
  • +
  • Indigo
  • +
  • Violet
  • +
+ +

Return to home page

+ + +``` + +## Stage and Commit the Rainbow {#branches-1.xhtml_stage-and-commit-the-rainbow} + +Hopefully, you're relatively familiar with staging and committing +snapshots by now: + +``` k +git add crazy.html +git status +git commit -m "Add a rainbow to crazy.html" +``` + +After committing on the `crazy` branch, we can see two independent lines +of development in our project: + +![Forked project history](media/3-4.png) + +Also notice that the `HEAD` (designated by the red circle) automatically +moved forward to the new commit, which is intuitively what we would +expect when developing a project. + +The above diagram represents the complete state of our repository, but +`git log` only displays the history of the current branch: + +``` s +677e0e0 Add a rainbow to crazy.html +514fbe7 Add a crazzzy experiment +*1c310d2 Add navigation links +*54650a3 Create blue and orange pages +*b650e4b Create index page +``` + +Note that the history *before* the fork is considered part of the new +branch (marked with asterisks above). That is to say, the `crazy` +history spans all the way back to the first commit: + +![History of the `crazy` branch](media/3-5.png) + +The project as a whole now has a complex history; however, each +individual branch still has a *linear* history (snapshots occur one +after another). This means that we can interact with branches in the +exact same way as we learned in the first two modules. + +## Rename the Rainbow {#branches-1.xhtml_rename-the-rainbow} + +Let's add one more snapshot to the `crazy` branch. Rename `crazy.html` +to `rainbow.html`, then use the following Git commands to update the +repository. + +``` k +git status +git rm crazy.html +git status +git add rainbow.html +git status +``` + +The `git rm` command tells Git to stop tracking `crazy.html` (and delete +it if necessary), and `git add` starts tracking `rainbow.html`. The +`renamed: crazy.html -> rainbow.html` message in the final status output +shows us that Git is smart enough to figure out when we're renaming a +file. + +Our snapshot is staged and ready to be committed: + +``` k +git commit -m "Rename crazy.html to rainbow.html" +git log --oneline +``` + +After this addition, our complete repository history looks like the +following. Remember that the `crazy` branch doesn't include any commits +in `master` after the fork. + +![Current project history](media/3-6.png) + +## Return to the Master Branch {#branches-1.xhtml_return-to-the-master-branch} + +Let's switch back to the `master` branch: + +``` k +git checkout master +git branch +git log --oneline +``` + +After the checkout, `crazy.html` doesn't exist in the working directory, +and the commits from the last few steps don't appear in the history. +These two branches became *completely independent* development +environments after they forked. You can think of them as separate +project folders that you switch between with `git checkout`. They do, +however, share their first four commits. + +![Shared branch history](media/3-7.png) + +## Create a CSS Branch {#branches-1.xhtml_create-a-css-branch} + +We're going to put our crazy experiment on the backburner for now and +turn our attention to formatting the HTML pages with a cascading +stylesheet (CSS). Again, if you're not all that comfortable with HTML +and CSS, the content of the upcoming files isn't nearly as important as +the Git commands used to manage them. + +Let's create and check out a new branch called `css`. + +``` k +git branch css +git checkout css +``` + +The new branch points to the currently checked out snapshot, which +happens to coincide with the `master` branch: + +![Creating the `css` branch](media/3-8.png) + +## Add a CSS Stylesheet {#branches-1.xhtml_add-a-css-stylesheet} + +Next, create a file called `style.css` with the following content. This +CSS is used to apply formatting to the HTML in our other files. + +``` nt +body { + padding: 20px; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 14px; + color: #111; +} + +p, ul { + margin-bottom: 10px; +} + +ul { + margin-left: 20px; +} +``` + +Commit the stylesheet in the usual fashion. + +``` k +git add style.css +git status +git commit -m "Add CSS stylesheet" +``` + +## Link the Stylesheet {#branches-1.xhtml_link-the-stylesheet} + +We still need to tell the HTML pages to use the formatting in +`style.css`. Add the following text on a separate line after the +`` element in `index.html`, `blue.html`, and `orange.html` +(remember that `rainbow.html` only exists in the `crazy` branch). You +should be able to see the CSS formatting by opening `index.html` in a +web browser. + +``` nt +<link rel="stylesheet" href="style.css" /> +``` + +Commit the changes. + +``` k +git add index.html blue.html orange.html +git status +git commit -m "Link HTML pages to stylesheet" +git log --oneline +``` + +This results in a repository history that looks like: + +![Current project history](media/3-9.png) + +## Return to the Master Branch (Again) {#branches-1.xhtml_return-to-the-master-branch-again} + +The `css` branch let us create and test our formatting without +threatening the stability of the `master` branch. But, now we need to +merge these changes into the main project. Before we attempt the merge, +we need to return to the `master` branch. + +``` k +git checkout master +``` + +Verify that `style.css` doesn't exist and that HTML pages aren't linked +to it. Our repository history remains unchanged, but the working +directory now matches the snapshot pointed to by the `master` branch. + +![Current project history](media/3-10.png) + +Take a look at the `git log --oneline` output as well. + +``` s +af23ff4 Revert "Add a crazzzy experiment" +a50819f Add a crazzzy experiment +4cd95d9 Add navigation links +dcb9e07 Create blue and orange pages +f757eb3 Create index page +``` + +As expected, there is no mention of the CSS additions in the history of +`master`, but we're about to change that. + +## Merge the CSS Branch {#branches-1.xhtml_merge-the-css-branch} + +Use the `git merge` command to take the snapshots from the `css` branch +and add them to the `master` branch. + +``` k +git merge css +``` + +Notice that this command always merges into the current branch: `css` +remains unchanged. Check the history to make sure that the `css` history +has been added to `master`. + +``` k +git log --oneline +``` + +The following diagram visualizes the merge. + +![Merging the `css` branch into `master`](media/3-11.png) + +Instead of re-creating the commits in `css` and adding them to the +history of `master`, Git reuses the existing snapshots and simply moves +the tip of `master` to match the tip of `css`. This kind of merge is +called a **fast-forward merge**, since Git is "fast-forwarding" through +the new commits in the `css` branch. + +After the merge, both branches have the exact same history, which makes +them redundant. Unless we wanted to keep developing on the `css` branch, +we're free to get rid of it. + +## Delete the CSS Branch {#branches-1.xhtml_delete-the-css-branch} + +We can safely delete a branch by passing the `-d` flag to `git branch`. + +``` k +git branch -d css +git branch +``` + +Since `css` and `master` represent the same branch, our history looks +the same, though the `css` branch has been removed. I've also put the +`master` branch's commits in a straight line in the following +visualization, making it easier to track during the upcoming modules. + +![Deleting the `css` branch](media/3-12.png) + +Deleting branches is a relatively "safe" operation in the sense that Git +will warn you if you're deleting an unmerged branch. This is just +another example of Git's commitment to never losing your work. + +## Conclusion {#branches-1.xhtml_conclusion} + +This module used two branches to experiment with new additions. In both +cases, branches gave us an environment that was completely isolated from +the "stable" version of our website (the `master` branch). One of our +experiments is waiting for us in the next module, while our CSS changes +have been merged into the stable project, and its branch is thus +obsolete. Using branches to develop small features like these is one of +the hallmarks of Git-based software management. + +While this module relied heavily on branch diagrams to show the complete +state of the repository, you don't need to keep this high-level overview +in mind during your everyday development. Creating a new branch is +really just a way to request an independent working directory, staging +snapshot, and history. You can think of branches as a way to multiply +the functionality presented in the first two module. + +Next, we'll practice our branch management skills by examining the +typical workflow of veteran Git users. We'll also discover more +complicated merges than the fast-forward merge introduced above. + +## Quick Reference {#branches-1.xhtml_quick-reference} + +`git branch` +: List all branches. + +`git branch <branch-name>` +: Create a new branch using the current working directory as its base. + +`git checkout <branch-name>` +: Make the working directory and the `HEAD` match the specified + branch. + +`git merge <branch-name>` +: Merge a branch into the checked-out branch. + +`git branch -d <branch-name>` +: Delete a branch. + +`git rm <file>` +: Remove a file from the working directory (if applicable) and stop + tracking the file. +::::: +:::::: + +[]{#branches-2.xhtml} + +:::::: {#branches-2.xhtml_page} +::::: {#branches-2.xhtml_content} +# Branches, Part II {#branches-2.xhtml_branches-part-ii} + +Now that we've covered the mechanics behind Git branches, we can discuss +the practical impact that they have on the software development process. +Instead of introducing new commands, this module covers how the typical +Git user applies this workflow to real projects, as well as some of the +problems that arise in a branched environment. + +To Git, a branch is a branch, but it's often useful to assign special +meaning to different branches. For example, we've been using `master` as +the stable branch for our example project, and we've also used a +temporary branch to add some CSS formatting. Temporary branches like the +latter are called **topic branches** because they exist to develop a +certain topic, then they are deleted. We'll work with two types of topic +branches later in this module. + +Amid our exploration of Git branches, we'll also discover that some +merges cannot be "fast-forwarded." When the history of two branches +diverges, a dedicated commit is required to combine the branches. This +situation may also give rise to a merge conflict, which must be manually +resolved before anything can be committed to the repository. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repository for this +module](http://rypress.com/tutorials/git/media/repo-zips/branches-2.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git repository +from the above link, uncompress it, and you're good to go. + +## Continue the Crazy Experiment {#branches-2.xhtml_continue-the-crazy-experiment} + +Let's start by checking out the `crazy` branch. + +``` k +git branch +git checkout crazy +git log --oneline +``` + +The `crazy` branch is a longer-running type of topic branch called a +**feature branch**. This is fitting, as it was created with the +intention of developing a specific *feature*. It's also a term that +makes Git's contribution to the development workflow readily apparent: +branches enable you to focus on developing one clearly defined feature +at a time. + +This brings us to my rule-of-thumb for using Git branches: + +- Create a new branch for each major addition to your project. +- *Don't* create a branch if you can't give it a specific name. + +Following these simple guidelines will have a dramatic impact on your +programming efficiency. + +## Merge the CSS Updates {#branches-2.xhtml_merge-the-css-updates} + +Note that the CSS formatting we merged into `master` is nowhere to be +found. This presents a bit of a problem if we want our experiment to +reflect these updates. Conveniently, Git lets us merge changes into +*any* branch (not just the `master` branch). So, we can pull the updates +in with the familiar `git merge` command. Remember that merging only +affects the checked-out branch. + +``` k +git merge master +git log --oneline +``` + +As of Git 1.7.10, this will open your editor and prompt you for a +message explaining why the commit was necessary. You can use the default +`Merge branch 'master' into crazy`. When you save and close the file, +you'll notice an extra commit in your project history. Recall that our +first merge didn't add any new commits; it just "fast-forwarded" the tip +of the `master` branch. This was not the case for our new merge, which +is shown below. + +![Merging `master` into the `crazy` branch](media/4-1.png) + +Take a moment to examine why the current merge couldn't be a +fast-forward one. How could Git have walked the `crazy` pointer over to +the tip of the `master` branch? It's not possible without backtracking, +which kind of defeats the idea of "fast-forwarding." We're left with a +new way to combine branches: the **3-way merge**. + +A 3-way merge occurs when you try to merge two branches whose history +has diverged. It creates an extra **merge commit** to function as a link +between the two branches. As a result, it has *two* parent commits. The +above figure visualizes this with two arrows originating from the tip of +`crazy`. It's like saying "this commit comes from both the `crazy` +branch *and* from `master`." After the merge, the `crazy` branch has +access to both its history and the `master` history. + +The name comes from the internal method used to create the merge commit. +Git looks at *three* commits (numbered in the above figure) to generate +the final state of the merge. + +This kind of branch interaction is a big part of what makes Git such a +powerful development tool. We can not only create independent lines of +development, but we can also share information between them by tying +together their histories with a 3-way merge. + +## Style the Rainbow Page {#branches-2.xhtml_style-the-rainbow-page} + +Now that we have access to the CSS updates from `master`, we can +continue developing our crazy experiment. Link the CSS stylesheet to +`rainbow.html` by adding the following HTML on the line after the +`<title>` element. + +``` nt +<link rel="stylesheet" href="style.css" /> +``` + +Stage and commit the update, then check that it's reflected in the +history. + +``` k +git status +git commit -a -m "Add CSS stylesheet to rainbow.html" +git log --oneline +``` + +Notice that we skipped the staging step this time around. Instead of +using `git add`, we passed the `-a` flag to `git commit`. This +convenient parameter tells Git to automatically include *all* tracked +files in the staged snapshot. Combined with the `-m` flag, we can stage +and commit snapshots with a single command. However, be careful not to +include unintended files when using the `-a` flag. + +## Link to the Rainbow Page {#branches-2.xhtml_link-to-the-rainbow-page} + +We still need to add a navigation link to the home page. Change the +"Navigation" section of `index.html` to the following. + +``` nt +<h2>Navigation</h2> +<ul> + <li style="color: #F90"> + <a href="orange.html">The Orange Page</a> + </li> + <li style="color: #00F"> + <a href="blue.html">The Blue Page</a> + </li> + <li> + <a href="rainbow.html">The Rainbow Page</a> + </li> +</ul> +``` + +As usual, stage and commit the snapshot. + +``` k +git commit -a -m "Link index.html to rainbow.html" +git log --oneline +``` + +## Fork an Alternative Rainbow {#branches-2.xhtml_fork-an-alternative-rainbow} + +Next, we're going to brainstorm an alternative to the current +`rainbow.html` page. This is a perfect time to create another topic +branch: + +``` k +git branch crazy-alt +git checkout crazy-alt +``` + +Remember, we can do whatever we want here without worrying about either +`crazy` or `master`. When `git branch` creates a branch, it uses the +current `HEAD` as the starting point for the new branch. This means that +we begin with the same files as `crazy` (if we called `git branch` from +`master`, we would have had to re-create `rainbow.html`). After creating +the new branch, our repository's history looks like: + +![Creating the `crazy-alt` branch](media/4-2.png) + +## Change the Rainbow {#branches-2.xhtml_change-the-rainbow} + +Change the colorful list in `rainbow.html` from: + +``` nt +<ul> + <li style="color: red">Red</li> + <li style="color: orange">Orange</li> + <li style="color: yellow">Yellow</li> + <li style="color: green">Green</li> + <li style="color: blue">Blue</li> + <li style="color: indigo">Indigo</li> + <li style="color: violet">Violet</li> +</ul> +``` + +to the following: + +``` nt +<div style="background-color: red"></div> +<div style="background-color: orange"></div> +<div style="background-color: yellow"></div> +<div style="background-color: green"></div> +<div style="background-color: blue"></div> +<div style="background-color: indigo"></div> +<div style="background-color: violet"></div> +``` + +Then, add some CSS formatting to `<head>` on the line after the `<meta>` +element: + +``` nt +<style> + div { + width: 300px; + height: 50px; + } +</style> +``` + +If you open `rainbow.html` in a browser, you should now see colorful +blocks in place of the colorful text. Don't forget to commit the +changes: + +``` k +git commit -a -m "Make a REAL rainbow" +``` + +The resulting project history is show below, with the first four commits +omitted for the sake of presentation. + +![Committing on the `crazy-alt` branch](media/4-3.png) + +## Emergency Update! {#branches-2.xhtml_emergency-update} + +*Our boss called in with some breaking news!* He needs us to update the +site immediately, but what do we do with our `rainbow.html` +developments? Well, the beauty of Git branches is that we can just leave +them where they are and add the breaking news to `master`. + +We'll use what's called a **hotfix branch** to create and test the news +updates. In contrast to our relatively long-running feature branch +(`crazy`), hotfix branches are used to quickly patch a production +release. For example, you'd use a hotfix branch to fix a time-sensitive +bug in a public software project. This distinction is useful for +demonstrating when it's appropriate to create a new branch, but it is +purely conceptual---a branch is a branch according to Git. + +``` k +git checkout master +git branch news-hotfix +git checkout news-hotfix +``` + +Change the "News" list in `index.html` to match the following. + +``` nt +<h2 style="color: #C00">News</h2> +<ul> + <li><a href="news-1.html">Blue Is The New Hue</a></li> +</ul> +``` + +And, create a new HTML page called `news-1.html` with the following +content. + +``` cp +<!DOCTYPE html> +<html lang="en"> +<head> + <title>Blue Is The New Hue + + + + +

Blue Is The New Hue

+

European designers have just announced that + Blue will be this year's + hot color.

+ +

Return to home page

+ + +``` + +We can't use `git commit -a` to automatically stage `news-1.html` +because it's an *untracked* file (as shown in `git status`). So, let's +use an explicit `git add`: + +``` k +git add index.html news-1.html +git status +git commit -m "Add 1st news item" +``` + +Test these additions in a browser to make sure that the links work, it's +typo free, etc. If everything looks good, we can "publish" the changes +by merging them into the stable `master` branch. Isolating this in a +separate branch isn't really necessary for our trivial example, but in +the real world, this would give you the opportunity to run build tests +without touching your stable project. + +## Publish the News Hotfix {#branches-2.xhtml_publish-the-news-hotfix} + +Remember that to merge into the `master` branch, we first need to check +it out. + +``` k +git checkout master +git merge news-hotfix +``` + +Since `master` now contains the news update, we can delete the hotfix +branch: + +``` k +git branch -d news-hotfix +git branch +``` + +The following diagram reflects our repository's history before and after +the merge. Can you figure out why was this a fast-forward merge instead +of a 3-way merge? + +![Fast-forwarding `master` to the `news-hotfix` branch](media/4-4.png) + +Also notice that we have another fork in our history (the commit before +`master` branches in two directions), which means we should expect to +see another merge commit in the near future. + +## Complete the Crazy Experiment {#branches-2.xhtml_complete-the-crazy-experiment} + +Ok, let's finish up our crazy experiment with one more commit. + +``` k +git checkout crazy +``` + +Note that the news article is nowhere to be found, as should be expected +(this branch is a completely isolated development environment). + +We'll finish up our crazy experiment by adding a news item for it on the +home page. Change the news list in `index.html` to the following: + +``` nt +

News

+ +``` + +Astute readers have probably observed that this directly conflicts with +what we changed in the `news-hotfix` branch. We should *not* manually +add in the other news item because it has no relationship with the +current branch. In addition, there would be no way to make sure the link +works because `news-1.html` doesn't exist in this branch. This may seem +trivial, but imagine the errors that could be introduced had +`news-hotfix` made dozens of different changes. + +We'll simply stage and commit the snapshot as if there were no +conflicts: + +``` k +git commit -a -m "Add news item for rainbow" +git log --oneline +``` + +Look at all those experimental commits (marked with asterisks below)! + +``` s +*42fa173 Add news item for rainbow +*7147cc5 Link index.html to rainbow.html +*6aa4b3b Add CSS stylesheet to rainbow.html +b9ae1bc Merge branch 'master' into crazy +ae4e756 Link HTML pages to stylesheet +98cd46d Add CSS stylesheet +*33e25c9 Rename crazy.html to rainbow.html +*677e0e0 Add a rainbow to crazy.html +506bb9b Revert "Add a crazzzy experiment" +*514fbe7 Add a crazzzy experiment +1c310d2 Add navigation links +54650a3 Create blue and orange pages +b650e4b Create index page +``` + +## Publish the Crazy Experiment {#branches-2.xhtml_publish-the-crazy-experiment} + +We're finally ready to merge our `crazy` branch back into `master`. + +``` k +git checkout master +git merge crazy +``` + +You should get a message that reads: + + Auto-merging index.html + CONFLICT (content): Merge conflict in index.html + Automatic merge failed; fix conflicts and then commit the result. + +This is our first **merge conflict**. Conflicts occur when we try to +merge branches that have edited the same content. Git doesn't know how +to combine the two changes, so it stops to ask us what to do. We can see +exactly what went wrong with the familiar `git status` command: + +``` c +# On branch master +# Changes to be committed: +# +# new file: rainbow.html +# +# Unmerged paths: +# (use "git add/rm ..." as appropriate to mark resolution) +# +# both modified: index.html +# +``` + +We're looking at the staged snapshot of a merge commit. We never saw +this with the first 3-way merge because we didn't have any conflicts to +resolve. But now, Git stopped to let us modify files and resolve the +conflict before committing the snapshot. The "Unmerged paths" section +contains files that have a conflict. + +Open up `index.html` and find the section that looks like: + + <<<<<<< HEAD +
  • Blue Is The New Hue
  • + ======= +
  • Our New Rainbow
  • + >>>>>>> crazy + +Git went ahead and modified the conflicted file to show us exactly which +lines are afflicted. The format of the above text shows us the +difference between the two versions of the file. The section labeled +`<<<<<<< HEAD` shows us the version in the current branch, while the +part after the `=======` shows the version in the `crazy` branch. + +## Resolve the Merge Conflicts {#branches-2.xhtml_resolve-the-merge-conflicts} + +We can change the affected lines to whatever we want in order to resolve +the conflict. Edit the news section of `index.html` to keep changes from +both versions: + +``` nt +

    News

    + +``` + +The `<<<<<<<`, `=======`, and `>>>>>>>` markers are only used to show us +the conflict and should be deleted. Next, we need to tell Git that we're +done resolving the conflict: + +``` k +git add index.html +git status +``` + +That's right, all you have to do is add `index.html` to the staged +snapshot to mark it as resolved. Finally, complete the 3-way merge: + +``` k +git commit +``` + +We didn't use the `-m` flag to specify a message because Git already +gives us a default message for merge commits. It also gives us a +"Conflicts" list, which can be particularly handy when trying to figure +out where something went wrong in a project. Save and close the file to +create the merge commit. + +The final state of our project looks like the following. + +![Merging the `crazy` branch into `master`](media/4-5.png) + +## Cleanup the Feature Branches {#branches-2.xhtml_cleanup-the-feature-branches} + +Since our crazy experiment has been successfully merged, we can get rid +of our feature branches. + +``` k +git branch -d crazy +git branch -d crazy-alt +``` + +As noted in the last module, the `git branch -d` command won't let you +delete a branch that contains unmerged changes. But, we really do want +to scrap the alternative experiment, so we'll follow the error message's +instructions for overriding this behavior: + +``` k +git branch -D crazy-alt +``` + +Because we never merged `crazy-alt` into `master`, it is lost forever. +However, the `crazy` branch is still accessible through its commits, +which are now reachable via the `master` branch. That is to say, it is +still part of the structure of the repository's history, even though we +deleted our reference to it. + +![Deleting the feature branches](media/4-6.png) + +Fast-forward merges are *not* reflected in the project history. This is +the tangible distinction between fast-forward merges and 3-way merges. +The next module will discuss the appropriate usage of both and the +potential complications of a non-linear history. + +## Conclusion {#branches-2.xhtml_conclusion} + +This module demonstrated the three most common uses of Git branches: + +- To develop long-running features (`crazy`) +- To apply quick updates (`news-hotfix`) +- To record the evolution of a project (`master`) + +In the first two cases, we needed an *isolated* environment to test some +changes before integrating them with our stable code. As you get more +comfortable with Git, you should find yourself doing virtually +everything in an isolated topic branch, then merging it into a stable +branch once you're done. Practically, this means you'll never have a +broken version of your project. + +We used the permanent `master` branch as the foundation for all of these +temporary branches, effectively making it the historian for our entire +project. In addition to `master`, many programmers often add a second +permanent branch called `develop`. This lets them use `master` to record +*really* stable snapshots (e.g., public releases) and use `develop` as +more of a preparation area for `master`. + +This module also introduced the 3-way merge, which combines two branches +using a dedicated commit. The 3-way merge and the fast-forward merge are +actually what makes branching so powerful: they let developers share and +integrate independent updates with reliable results. + +Next, we'll learn how to clean up our repository's history. Using a new +Git command, we'll be able to better manage merge commits and make sure +our history is easy to navigate. + +## Quick Reference {#branches-2.xhtml_quick-reference} + +`git commit -a -m ""` +: Stage all tracked files and commit the snapshot using the specified + message. + +`git branch -D ` +: Force the removal of an unmerged branch (*be careful*: it will be + lost forever). +::::: +:::::: + +[]{#rebasing.xhtml} + +:::::: {#rebasing.xhtml_page} +::::: {#rebasing.xhtml_content} +# Rebasing {#rebasing.xhtml_rebasing} + +Let's start this module by taking an in-depth look at our history. The +six commits asterisked below are part of the same train of thought. We +even developed them in their own feature branch. However, they show up +interspersed with commits from other branches, along with a superfluous +merge commit (`b9ae1bc`). In other words, our repository's history is +kind of messy: + +``` s +ec1b8cb Merge branch 'crazy' +*42fa173 Add news item for rainbow +3db88e1 Add 1st news item +*7147cc5 Link index.html to rainbow.html +*6aa4b3b Add CSS stylesheet to rainbow.html +b9ae1bc Merge branch 'master' into crazy +ae4e756 Link HTML pages to stylesheet +98cd46d Add CSS stylesheet +*33e25c9 Rename crazy.html to rainbow.html +*677e0e0 Add a rainbow to crazy.html +506bb9b Revert "Add a crazzzy experiment" +*514fbe7 Add a crazzzy experiment +1c310d2 Add navigation links +54650a3 Create blue and orange pages +b650e4b Create index page +``` + +Fortunately, Git includes a tool to help us clean up our commits: +`git rebase`. Rebasing lets us move branches around by changing the +commit that they are *based* on. Conceptually, this is what it allows us +to do: + +![Rebasing a feature branch onto `master`](media/5-1.png) + +After rebasing, the `feature` branch has a new parent commit, which is +the same commit pointed to by `master`. Instead of joining the branches +with a merge commit, rebasing integrates the `feature` branch by +building *on top of* `master`. The result is a perfectly linear history +that reads more like a story than the hodgepodge of unrelated edits +shown above. + +To explore Git's rebasing capabilities, we'll need to build up our +example project so that we have something to work with. Then, we'll go +back and rewrite history using `git rebase`. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repository for this +module](http://rypress.com/tutorials/git/media/repo-zips/rebasing.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git repository +from the above link, uncompress it, and you're good to go. + +## Create an About Section {#rebasing.xhtml_create-an-about-section} + +We'll begin by creating an about page for the website. Remember, we +should be doing all of our work in isolated branches so that we don't +cause any unintended changes to the stable version of the project. + +``` k +git branch about +git checkout about +``` + +The next few steps break this feature into several unnecessarily small +commits so that we can see the effects of a rebase. First, make a new +directory in `my-git-repo` called `about`. Then, create the empty file +`about/index.html`. Stage and commit a snapshot. + +``` k +git add about +git status +git commit -m "Add empty page in about section" +``` + +Note that `git add` can also add entire directories to the staging area. + +## Add an About Page {#rebasing.xhtml_add-an-about-page} + +Next, we'll add some HTML to `about/index.html`: + +``` cp + + + + About Us + + + + +

    About Us

    +

    We're a small, colorful website with just two employees:

    + + + +

    Return to home page

    + + +``` + +Stage and commit the snapshot. + +``` k +git status +git commit -a -m "Add contents to about page" +``` + +After a few commits on this branch, our history looks like the +following. + +![Adding the `about` branch](media/5-2.png) + +## Another Emergency Update! {#rebasing.xhtml_another-emergency-update} + +*Our boss just gave us some more breaking news!* Again, we'll use a +hotfix branch to update the site without affecting our about page +developments. Make sure to base the updates on `master`, not the `about` +branch: + +``` k +git checkout master +git branch news-hotfix +git checkout news-hotfix +git branch +``` + +Change the "News" section in `index.html` to: + +``` nt +

    News

    + +``` + +Commit a snapshot: + +``` k +git status +git commit -a -m "Add 2nd news item to index page" +``` + +Then, create a new page called `news-2.html`: + +``` cp + + + + A Red Rebellion + + + + +

    A Red Rebellion

    + +

    Earlier today, several American design firms + announced that they have completely rejected the use + of blue in any commercial ventures. They have + opted instead for Red.

    + +

    Return to home page

    + + +``` + +Stage and commit another snapshot: + +``` k +git add news-2.html +git status +git commit -m "Add article for 2nd news item" +``` + +## Publish News Hotfix {#rebasing.xhtml_publish-news-hotfix} + +We're ready to merge the news update back into `master`. + +``` k +git checkout master +git merge news-hotfix +git branch -d news-hotfix +``` + +The `master` branch hasn't been altered since we created `news-hotfix`, +so Git can perform a fast-forward merge. Our repository now looks like +the following. + +![Fast-forwarding `master` to the `news-hotfix`](media/5-3.png) + +## Rebase the About Branch {#rebasing.xhtml_rebase-the-about-branch} + +This puts us in the exact same position as we were in before our first +3-way merge. We want to pull changes from `master` into a feature +branch, only this time we'll do it with a rebase instead of a merge. + +``` k +git checkout about +git rebase master +git log --oneline +``` + +Originally, the `about` branch was based on the +`Merge branch 'crazy-experiment'` commit. The rebase took the entire +`about` branch and plopped it onto the *tip* of the `master` branch, +which is visualized in the following diagram. Also notice that, like the +`git merge` command, `git rebase` requires you to be on the branch that +you want to move. + +![Rebasing the `about` branch onto `master`](media/5-4.png) + +After the rebase, `about` is a linear extension of the `master` branch, +enabling us to do a fast-forward merge later on. Rebasing also allowed +us to integrate the most up-to-date version of `master` *without a merge +commit*. + +## Add a Personal Bio {#rebasing.xhtml_add-a-personal-bio} + +With our news hotfix out of the way, we can now continue work on our +about section. Create the file `about/me.html` with the following +contents: + +``` cp + + + + About Me + + + + +

    About Me

    +

    I'm a big nerd.

    + +

    Interests

    +
      +
    • Computers
    • +
    • Mathematics
    • +
    • Typography
    • +
    + +

    Return to about page

    + + +``` + +Then, commit the changes to the repository. + +``` k +git add about/me.html +git commit -m "Add HTML page for personal bio" +git log --oneline +``` + +Remember that thanks to the rebase, `about` rests on top of `master`. +So, all of our about section commits are grouped together, which would +not be the case had we merged instead of rebased. This also eliminates +an unnecessary fork in our project history. + +## Add Dummy Page for Mary {#rebasing.xhtml_add-dummy-page-for-mary} + +Once again, the next two snapshots are unnecessarily trivial. However, +we'll use an *interactive* rebase to combine them into a single commit +later on. That's right, `git rebase` not only lets you move branches +around, it enables you to manipulate individual commits as you do so. + +Create a new empty file in the about section: `about/mary.html`. + +``` k +git add about +git status +git commit -m "Add empty HTML page for Mary's bio" +``` + +## Link to the About Section {#rebasing.xhtml_link-to-the-about-section} + +Then, add a link to the about page in `index.html` so that its +"Navigation" section looks like the following. + +``` nt +

    Navigation

    + +``` + +Don't forget to commit the change: + +``` k +git commit -a -m "Add link to about section in home page" +``` + +## Clean Up the Commit History {#rebasing.xhtml_clean-up-the-commit-history} + +Before we merge into the `master` branch, we should make sure we have a +clean, meaningful history in our feature branch. By rebasing +interactively, we can choose *how* each commit is transferred to the new +base. Specify an interactive rebase by passing the `-i` flag to the +rebase command: + +``` k +git rebase -i master +``` + +This should open up a text editor populated with all of the commits +introduced in the `about` branch, listed from oldest to newest. The +listing defines exactly how Git will transfer the commits to the new +base. Leaving it as is will do a normal `git rebase`, but if we move the +lines around, we can change the order in which commits are applied. + +In addition, we can replace the `pick` command before each line to edit +it or combine it with other commits. All of the available commands are +shown in the comment section of the rebase listing, but right now, we +only need the `squash` command. This will condense our unnecessarily +small commits into a single, meaningful snapshot. Change your listing to +match the following: + +``` k +pick 5cf316e Add empty page in about section +squash 964e013 Add contents to about page +pick 89db9ab Add HTML page for personal bio +squash 2bda8e5 Add empty HTML page for Mary's bio +pick 915466f Add link to about section in home page +``` + +Then, begin the rebase by saving and closing the editor. The following +list describes the rebasing process in-depth and tells you what you need +to change along the way. + +1. Git moves the `5cf316e` commit to the tip of `master`. +2. Git combines the snapshots of `964e013` and `5cf316e`. +3. Git stops to ask you what commit message to use for the combined + snapshot. It automatically includes the messages of both commits, + but you can delete that and simplify it to just + `Create the about page`. Save and exit the text editor to continue. +4. Git repeats this process for commits `89db9ab` and `2bda8e5`. Use + `Begin creating bio pages` for the message. +5. Git adds the final commit (`915466f`) on top of the commits created + in the previous steps. + +You can see the result of all this activity with `git log --oneline`, as +well as in the diagram below. The five commits originally in `about` +have been condensed to three, and two of them have new messages. Also +notice that they all have different commit ID's. These new ID's tell us +that we didn't just *move* a couple of commits---we've literally +rewritten our repository history with brand new commits. + +![Results of the interactive rebase](media/5-5.png) + +Interactive rebasing gives you complete control over your project +history, but this can also be very dangerous. For example, if you were +to delete a line from the rebase listing, the associated commit wouldn't +be transferred to the new base, and its content would be lost forever. +In a future module, we'll also see how rewriting history can get you in +trouble with public Git repositories. + +## Stop to Amend a Commit {#rebasing.xhtml_stop-to-amend-a-commit} + +The previous rebase only stopped us to edit the *messages* of each +commit. We can take this one step further and alter a *snapshot* during +the rebase. Start by running another interactive rebasing session. Note +that we've still been using `master` as the new base because it selects +the desired commits from the `about` branch. + +``` k +git rebase -i master +``` + +Specify the `edit` command for the second commit, as shown below. + +``` k +pick 58dec2a Create the about page +edit 6ac8a9f Begin creating bio pages +pick 51c958c Add link to about section in home page +``` + +When Git starts to move the second commit to the new base, it will stop +to do some "amending." This gives you the opportunity to alter the +staged snapshot before committing it. + +![Stopping to amend a commit](media/5-6.png) + +We'll leave a helpful note for Mary, whom we'll meet in the +[Remotes](#remotes.xhtml) module. Open up `about/mary.html` and add the +following. + + [Mary, please update your bio!] + +We're currently between commits in a rebase, but we can alter the staged +snapshot in the exact same way as we have been throughout this entire +tutorial: + +``` k +git add about/mary.html +git status +git commit --amend +``` + +You can use the default message created by `git commit`. The new +`‑‑amend` flag tells Git to *replace* the existing commit with the +staged snapshot instead of creating a new one. This is also very useful +for fixing premature commits that often occur during normal development. + +## Continue the Interactive Rebase {#rebasing.xhtml_continue-the-interactive-rebase} + +Remember that we're in the middle of a rebase, and Git still has one +more commit that it needs to re-apply. Tell Git that we're ready to move +on with the `--continue` flag: + +``` k +git rebase --continue +git log --oneline +``` + +Note that our history still appears to be the same (because we used the +default commit message above), but the `Begin creating bio pages` commit +contains different content than it did before the rebase, along with a +new ID. + +If you ever find yourself lost in the middle of a rebase and you're +afraid to continue, you can use the `‑‑abort` flag to abandon it and +start over from scratch. + +## Publish the About Section {#rebasing.xhtml_publish-the-about-section} + +The point of all this interactive rebasing is to generate a *meaningful* +history that we can merge back into `master`. And, since we've rebased +`about` onto the tip of `master`, Git will be able to perform a +fast-forward merge instead of using a merge commit to join the two +branches. + +``` k +git checkout master +git log --oneline +git merge about +git log --oneline +``` + +Don't forget to delete the obsolete `about` branch. + +``` k +git branch -d about +``` + +Our final history is shown in the figure below. As you can see, a linear +history is much easier to comprehend than the back-and-forth merging of +the previous module. But on the other hand, we don't have the slightest +notion of *how* we got to our current state. + +![Merging and deleting the `about` branch](media/5-7.png) + +## Conclusion {#rebasing.xhtml_conclusion} + +Rebasing enables fast-forward merges by moving a branch to the tip of +another branch. It effectively eliminates the need for merge commits, +resulting in a completely linear history. To an outside observer, it +will seem as though you created every part of your project in a neatly +planned sequence, even though you may have explored various alternatives +or developed unrelated features in parallel. Rebasing gives you the +power to choose exactly what gets stored in your repositories. + +This can actually be a bit of a controversial topic within the Git +community. Some believe that the benefits discussed in this module +aren't worth the hassle of rewriting history. They take a more "pure" +approach to Git by saying that your history should reflect *exactly* +what you've done, ensuring that no information is ever lost. +Furthermore, an advanced configuration of `git log` can display a linear +history from a highly-branched repository. + +But, others contend that merge commits should be *meaningful*. Instead +of merging at arbitrary points just to access updates, they claim that +merge commits should represent a symbolic joining of two branches. In +particular, large software projects (such as the Linux kernel) typically +advocate interactive rebasing to keep the repository as clean and +straightforward as possible. + +The use of `git rebase` is entirely up to you. Customizing the evolution +of your project can be very beneficial, but it might not be worth the +trouble when you can accomplish close to the same functionality using +merges exclusively. As a related note, you can use the following command +to force a merge commit when Git would normally do a fast-forward merge. + +``` k +git merge --no-ff +``` + +The next module will get a little bit more involved in our project +history. We'll try fixing mistakes via complex rebases and even learn +how to recover deleted commits. + +## Quick Reference {#rebasing.xhtml_quick-reference} + +`git rebase ` +: Move the current branch's commits to the tip of ``, which + can be either a branch name or a commit ID. + +`git rebase -i ` +: Perform an interactive rebase and select actions for each commit. + +`git commit --amend` +: Add staged changes to the most recent commit instead of creating a + new one. + +`git rebase --continue` +: Continue a rebase after amending a commit. + +`git rebase --abort` +: Abandon the current interactive rebase and return the repository to + its former state. + +`git merge --no-ff ` +: Force a merge commit even if Git could do a fast-forward merge. +::::: +:::::: + +[]{#rewriting-history.xhtml} + +:::::: {#rewriting-history.xhtml_page} +::::: {#rewriting-history.xhtml_content} +# Rewriting History {#rewriting-history.xhtml_rewriting-history} + +The previous module on rebasing taught us how to move commits around and +perform some basic edits while doing so, but now we're going to really +get our hands dirty. We'll learn how to split up commits, revive lost +snapshots, and completely rewrite a repository's history to our exact +specifications. + +Hopefully, this module will get you much more comfortable with the core +Git components, as we'll be inspecting and editing the internal makeup +of our project. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repository for this +module](http://rypress.com/tutorials/git/media/repo-zips/rewriting-history.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git repository +from the above link, uncompress it, and you're good to go. + +## Create the Red Page {#rewriting-history.xhtml_create-the-red-page} + +First, let's create a new branch and add a few more HTML pages. + +``` k +git checkout -b new-pages +git branch +``` + +Notice that we created a new branch and checked it out in a single step +by passing the `-b` flag to the `git checkout` command. + +Next, create the file `red.html` and add the following content: + +``` cp + + + + The Red Page + + + + +

    The Red Page

    +

    Red is the color of passion!

    + +

    Return to home page

    + + +``` + +We'll hold off on committing this page for the moment. + +## Create the Yellow Page {#rewriting-history.xhtml_create-the-yellow-page} + +Create a file called `yellow.html`, which should look like the +following. + +``` cp + + + + The Yellow Page + + + + +

    The Yellow Page

    +

    Yellow is the color of the sun!

    + +

    Return to home page

    + + +``` + +## Link and Commit the New Pages {#rewriting-history.xhtml_link-and-commit-the-new-pages} + +Next, we'll link both new pages to the home page. Add the following +items to the "Navigation" section in `index.html`: + +``` nt +
  • + The Red Page +
  • +
  • + The Yellow Page +
  • +``` + +Then, commit all of these changes in a single snapshot. + +``` k +git add red.html yellow.html index.html +git status +git commit -m "Add new HTML pages" +``` + +This is an example of a *bad* commit. It performed multiple, unrelated +tasks, and it has a relatively generic commit message. Thus far, we +haven't really specified when it's appropriate to commit changes, but +the general rules are essentially the same as for branch creation: + +- Commit a snapshot for each significant addition to your project. +- *Don't* commit a snapshot if you can't come up with a single, + specific message for it. + +This will ensure that your project has a meaningful commit history, +which gives you the ability to see exactly when and where a feature was +added or a piece of functionality was broken. However, in practice, +you'll often wind up committing several changes in a single snapshot, +since you won't always know what constitutes a "well-defined" addition +as you're developing a project. Fortunately, Git lets us go back and fix +up these problem commits after the fact. + +## Create and Commit the Green Page {#rewriting-history.xhtml_create-and-commit-the-green-page} + +Let's create one more page before splitting that "bad" commit: Add the +following HTML to a file called `green.html`. + +``` cp + + + + The Green Page + + + + +

    The Green Page

    +

    Green is the color of earth.

    + +

    Return to home page

    + + +``` + +Add a link to `index.html` in the "Navigation" section: + +``` nt +
  • + The Green Page +
  • +``` + +And finally, stage the green page and commit the snapshot. + +``` k +git add green.html index.html +git status +git commit -m "Add green page" +``` + +## Begin an Interactive Rebase {#rewriting-history.xhtml_begin-an-interactive-rebase} + +The commits introduced in our `new-pages` branch are: + +``` s +4c3027c Add green page +db96c72 Add new HTML pages +``` + +But, we want these commits to look more like: + +``` s +4c3027c Add green page +9b1a64f Add yellow page +77a1cf1 Add red page +``` + +To achieve this, we can use the same interactive rebasing method covered +in the previous module, only this time we'll actually *create* commits +in the middle of the rebasing procedure. + +``` k +git rebase -i master +``` + +Change the rebase listing to the following, then save the file and exit +the editor to begin the rebase. + +``` k +edit db96c72 Add new HTML pages +pick 4c3027c Add green page +``` + +## Undo the Generic Commit {#rewriting-history.xhtml_undo-the-generic-commit} + +First, let's take a look at where we are with `git log --oneline`: + +``` s +db96c72 Add new HTML pages +7070b0e Add link to about section in home page +... +``` + +When Git encountered the `edit` command in the rebase configuration, it +stopped to let us edit the commit. As a result, the green page commit +doesn't appear in our history yet. This should be familiar from the +previous module. But instead of *amending* the current commit, we're +going to completely remove it: + +``` k +git reset --mixed HEAD~1 +git log --oneline +git status +``` + +The `git reset` command moves the checked out snapshot to a new commit, +and the `HEAD~1` parameter tells it to reset to the commit that occurs +immediately before the current `HEAD` (likewise, `HEAD~2` would refer to +second commit before `HEAD`). In this particular case, `HEAD~1` happens +to coincide with `master`. The effect on our repository can be +visualized as: + +![Resetting to `HEAD~1`](media/6-1.png) + +You may recall from [Undoing Changes](#undoing-changes.xhtml) that we +used `git reset --hard` to undo uncommitted changes to our project. The +`--hard` flag told Git to make the working directory look exactly like +the most recent commit, giving us the intended effect of removing +uncommitted changes. + +But, this time we used the `--mixed` flag to preserve the working +directory, which contains the changes we want to separate. That is to +say, the `HEAD` moved, but the working directory remained unchanged. Of +course, this results in a repository with uncommitted modifications. We +now have the opportunity to add the `red.html` and `yellow.html` files +to distinct commits. + +## Split the Generic Commit {#rewriting-history.xhtml_split-the-generic-commit} + +Let's start with the red page. Since we only want to commit content that +involves the red page, we'll have to manually go in and remove the +yellow page's link from the "Navigation" section. In `index.html`, +change this section to match the following: + +``` nt +

    Navigation

    + +``` + +Now, we can group the red page's updates into an independent commit. + +``` k +git add red.html index.html +git status +git commit -m "Add red page" +``` + +Next up is the yellow page. Go ahead and add it back to the "Navigation" +section in `index.html`: + +``` nt +
  • + The Yellow Page +
  • +``` + +And again, stage and commit the snapshot. + +``` k +git add yellow.html index.html +git status +git commit -m "Add yellow page" +``` + +We've successfully split up the contents of a single commit into two new +snapshots, as shown below. + +![Creating two new commits while rebasing](media/6-2.png) + +But, don't forget that the rebase still needs to transfer the green +page: + +``` k +git rebase --continue +``` + +To summarize, we removed the "bad" commit from the current branch with +`git reset`, keeping the contained HTML files intact with the `‑‑mixed` +flag. Then, we committed them in separate snapshots with the usual +`git add` and `git commit` commands. The point to remember is that +during a rebase you can add, delete, and edit commits to your heart's +content, and the entire result will be moved to the new base. + +## Remove the Last Commit {#rewriting-history.xhtml_remove-the-last-commit} + +Next, we're going to "accidentally" remove the green page commit so we +can learn how to retrieve it via Git's internal repository data. + +``` k +git reset --hard HEAD~1 +git status +git log --oneline +``` + +This moves the checked-out commit backward by one snapshot, along with +the `new-pages` pointer. Note that `git status` tells us that we have +nothing to commit, since the `--hard` flag obliterated any changes in +the working directory. And of course, the `git log` output shows that +the `new-pages` branch no longer contains the green commit. + +This behavior is slightly different from the reset we used in the +interactive rebase: this time the *branch* moved with the new `HEAD`. +Since we were on `(no branch)` during the rebase, there was no branch +tip to move. However, in general, `git reset` is used to move branch +tips around and optionally alter the working directory via one of its +many flags (e.g., `--mixed` or `--hard`). + +![Removing the most recent commit](media/6-3.png) + +The commit that we removed from the branch is now a **dangling commit**. +Dangling commits are those that cannot be reached from any branch and +are thus in danger of being lost forever. + +## Open the Reflog {#rewriting-history.xhtml_open-the-reflog} + +Git uses something called the **reflog** to record every change you make +to your repository. Let's take a look at what it contains: + +``` k +git reflog +``` + +The resulting output should look something like the following. Depending +on your version of Git, the messages might be slightly different. You +can press `Space` to scroll through the content or `q` to exit. + +``` s +9b1a64f HEAD@{0}: reset: moving to HEAD~1 +002185c HEAD@{1}: rebase -i (finish): returning to refs/heads/new-pages +002185c HEAD@{2}: rebase -i (pick): Add green page +9b1a64f HEAD@{3}: commit: Add yellow page +77a1cf1 HEAD@{4}: commit: Add red page +7070b0e HEAD@{5}: reset: moving to HEAD~1 +... +``` + +The above listing reflects our last few actions. For example, the +current `HEAD`, denoted by `HEAD@{0}`, resulted from reseting `HEAD` to +`HEAD~1`. Four actions ago, the yellow page was applied during our +rebase, as shown in `HEAD@{3}`. + +The reflog is a *chronological* listing of our history, without regard +for the repository's branch structure. This lets us find dangling +commits that would otherwise be lost from the project history. + +## Revive the Lost Commit {#rewriting-history.xhtml_revive-the-lost-commit} + +At the beginning of each reflog entry, you'll find a commit ID +representing the `HEAD` after that action. Check out the commit at +`HEAD@{2}`, which should be where the rebase added the green page +(change the ID below to the ID from *your* reflog). + +``` k +git checkout 002185c +``` + +This puts us in a `detached HEAD` state, which means our `HEAD` is no +longer on the tip of a branch. We're actually in the opposite situation +as we were in [Undoing Changes](#undoing-changes.xhtml) when we checked +out a commit *before* the branch tip. Now, we're looking at a commit +*after* the tip of the branch, but we still have a `detached HEAD`: + +![Checking out a dangling commit](media/6-4.png) + +To turn our dangling commit into a full-fledged branch, all we have to +do is create one: + +``` k +git checkout -b green-page +``` + +We now have a branch that can be merged back into the project: + +![Creating a branch from the dangling commit](media/6-5.png) + +The above diagram makes it easy to see that the `green-page` branch is +an extension of `new-pages`, but how would we figure this out if we +weren't drawing out the state of our repository every step of the way? + +## Filter the Log History {#rewriting-history.xhtml_filter-the-log-history} + +To view the differences between branches, we can use Git's log-filtering +syntax. + +``` k +git log new-pages..green-page +``` + +This will display all commits contained in `green-page` that aren't in +the `new-pages` branch. The above command tells us that `green-page` +contains one more snapshot than `new-pages`: our dangling commit +(although, it's not really dangling anymore since we created a branch +for it). + +You can also use this syntax to limit the output of `git log`. For +example, to display the last 4 commits on the current branch, you could +use: + +``` k +git log HEAD~4..HEAD +``` + +However, this is a bit verbose for such a common task, so Git developers +added the `-n` flag as an easier way to limit output. + +``` k +git log -n 4 +``` + +The `-n 4` parameter tells Git to show only the last four commits from +the current `HEAD`, making it the equivalent of the `HEAD~4..HEAD` +syntax shown above. Similarly, `-n 3`, `-n 2`, and `-n 1` would display +three, two, and one commit, respectively. This feature becomes very +useful once a repository grows beyond one screenful of history. + +## Merge in the Revived Branch {#rewriting-history.xhtml_merge-in-the-revived-branch} + +We've revived our lost commit, and now we're ready to merge everything +back into the `master` branch. Before we do the merge, let's see exactly +what we're merging: + +``` k +git checkout master +git log HEAD..green-page --stat +``` + +The `git log HEAD..green-page` command shows us only those commits in +`green-page` that aren't in `master` (since `master` is the current +branch, we can refer to it as `HEAD`). The new `--stat` flag includes +information about which files have been changed in each commit. For +example, the most recent commit tells us that 14 lines were added to the +`green.html` file and 3 lines were added to `index.html`: + +``` k +commit 002185c71e6674915eb75be2afb4ca52c2c7fd1b +Author: Ryan +Date: Wed Jan 11 06:49:50 2012 -0600 + + Add green page + + green.html | 14 ++++++++++++++ + index.html | 3 +++ + 2 files changed, 17 insertions(+), 0 deletions(-) +``` + +If we didn't already know what was in this new commit, the log output +would tell us which files we needed to look at. But, we authored all of +these changes, so we can skip right to the merge. + +``` k +git merge green-page +``` + +The following diagram shows the state of our repository after the merge. + +![Fast-forwarding `master` to the `green-page` branch](media/6-6.png) + +Note that the `green-page` branch already contains all the history of +`new-pages`, which is why we merged the former instead of the latter. If +this wasn't the case, Git would complain when we try to run the +following command. + +``` k +git branch -d new-pages +``` + +We can go ahead and delete the green page branch, too. + +``` k +git branch -d green-page +``` + +## Conclusion {#rewriting-history.xhtml_conclusion} + +This module took an in-depth look at rebasing, resetting, and the +reflog. We learned how to split old commits into one or more new +commits, and how to revive "lost" commits. Hopefully, this has given you +a better understanding of the interaction between the working directory, +the stage, branches, and committed snapshots. We also explored some new +options for displaying our commit history, which will become an +important skill as our project grows. + +We did a lot of work with branch tips this module. It's important to +realize that Git uses the *tip* of a branch to represent the *entire +branch*. That is to say, a branch is actually a pointer to a single +commit---not a container for a series of commits. This idea has been +implicitly reflected in our diagrams: + +![Branch tips, not containers](media/6-7.png) + +The history is represented by the parent of each commit (designated by +arrows), not the branch itself. So, to request a new branch, all Git has +to do is create a reference to the current commit. And, to add a +snapshot to a branch, it just has to move the branch reference to the +new commit. An understanding of Git's branch representation should make +it easier to wrap your head around merging, rebasing, and other kinds of +branch manipulation. + +We'll revisit Git's internal representation of a repository in the +[final module](#plumbing.xhtml) of this tutorial. But now, we're finally +ready to discuss multi-user development, which happens to rely entirely +on Git branches. + +## Quick Reference {#rewriting-history.xhtml_quick-reference} + +`git reflog` +: Display the local, chronological history of a repository. + +`git reset --mixed HEAD~` +: Move the `HEAD` backward `` commits, but don't change the working + directory. + +`git reset --hard HEAD~` +: Move the `HEAD` backward `` commits, and change the working + directory to match. + +`git log ..` +: Display the commits reachable from `` but not from ``. + These parameters can be either commit ID's or branch names. + +`git log --stat` +: Include extra information about altered files in the log output. +::::: +:::::: + +[]{#remotes.xhtml} + +:::::: {#remotes.xhtml_page} +::::: {#remotes.xhtml_content} +# Remotes {#remotes.xhtml_remotes} + +Simply put, a **remote repository** is one that is not your own. It can +be another Git repository that's on your company's network, the +internet, or even your local filesystem, but the point is that it's a +repository distinct from your `my-git-repo` project. + +We've already seen how branches can streamline a workflow within a +single repository, but they also happen to be Git's mechanism for +sharing commits between repositories. **Remote branches** act just like +the local branches that we've been using, only they represent a branch +in someone else's repository. + +![Accessing a feature branch from a remote repository](media/7-1.png) + +This means that we can adapt our merging and rebasing skills to make Git +a fantastic collaboration tool. Over the next few modules, we'll be +exploring various multi-user workflows by pretending to be different +developers working on our example website. + +For several parts of this module, we're going to pretend to be Mary, the +graphic designer for our website. Mary's actions are clearly denoted by +including her name in the heading of each step. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repository for this +module](http://rypress.com/tutorials/git/media/repo-zips/remotes.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git repository +from the above link, uncompress it, and you're good to go. + +## Clone the Repository (Mary) {#remotes.xhtml_clone-the-repository-mary} + +First, Mary needs her own copy of the repository to work with. The +[Distributed Workflows](#distributed-workflows.xhtml) module will +discuss network-based remotes, but right now we're just going to store +them on the local filesystem. + +``` k +cd /path/to/my-git-repo +cd .. +git clone my-git-repo marys-repo +cd marys-repo +``` + +The first two lines navigate the command shell to the directory *above* +`my-git-repo`. Make sure to change `/path/to/my-git-repo` to the actual +path to your repository. The `git clone` command copies our repository +into `marys-repo`, which will reside in the same directory as +`my-git-repo`. Then, we navigate to Mary's repository so we can start +pretending to be Mary. + +Run `git log` to verify that Mary's repository is in fact a copy of our +original repository. + +## Configure The Repository (Mary) {#remotes.xhtml_configure-the-repository-mary} + +First off, Mary needs to configure her repository so that we know who +contributed what to the project. + +``` k +git config user.name "Mary" +git config user.email mary.example@rypress.com +``` + +You may recall from the first module that we used a `--global` flag to +set the configuration for the entire Git installation. But since Mary's +repository is on the local filesystem, she needs a *local* +configuration. + +Use a text editor to open up the file called `config` in the `.git` +folder of Mary's project (you may need to enable hidden files to see +`.git`). This is where local configurations are stored, and we see +Mary's information at the bottom of the file. Note that this overrides +the global configuration that we set in [The Basics](#the-basics.xhtml). + +## Start Mary's Day (Mary) {#remotes.xhtml_start-marys-day-mary} + +Today, Mary is going to be working on her bio page, which she should +develop in a separate branch: + +``` k +git checkout -b bio-page +``` + +Mary can create and check out branches just like we did in our copy of +the project. Her repository is a completely isolated development +environment, and she can do whatever she wants in here without worrying +about what's going on in `my-git-repo`. Just as branches are an +abstraction for the working directory, the staged snapshot, and a commit +history, a repository is an abstraction for branches. + +## Create Mary's Bio Page (Mary) {#remotes.xhtml_create-marys-bio-page-mary} + +Let's complete Mary's biography page. In `marys-repo`, change +`about/mary.html` to: + +``` cp + + + + About Mary + + + + +

    About Mary

    +

    I'm a graphic designer.

    + +

    Interests

    +
      +
    • Oil Painting
    • +
    • Web Design
    • +
    + +

    Return to about page

    + + +``` + +Again, we're developing this in a branch as a best-practice step: our +`master` branch is only for stable, tested code. Stage and commit the +snapshot, then take a look at the result. + +``` k +git commit -a -m "Add bio page for Mary" +git log -n 1 +``` + +The `Author` field in the log output should reflect the local +configurations we made for Mary's name and email. Remember that the +`-n 1` flag limits history output to a single commit. + +## Publish the Bio Page (Mary) {#remotes.xhtml_publish-the-bio-page-mary} + +Now, we can publish the bio page by merging into the `master` branch. + +``` k +git checkout master +git merge bio-page +``` + +Of course, this results in a fast-forward merge. We'll eventually pull +this update into `my-git-repo` once we stop pretending to be Mary. +Here's what Mary's repository looks like compared to ours: + +![Merging Mary's `bio-page` branch with her `master`](media/7-2.png) + +Notice that both repositories have normal, local branches---we haven't +had any interaction between the two repositories, so we don't see any +remote branches yet. Before we switch back to `my-git-repo`, let's +examine Mary's remote connections. + +## View Remote Repositories (Mary) {#remotes.xhtml_view-remote-repositories-mary} + +Mary can list the connections she has to other repositories using the +following command. + +``` k +git remote +``` + +Apparently, she has a remote called `origin`. When you clone a +repository, Git automatically adds an `origin` remote pointing to the +original repository, under the assumption that you'll probably want to +interact with it down the road. We can request a little bit more +information with the `-v` (verbose) flag: + +``` k +git remote -v +``` + +This shows the full path to our original repository, verifying that +`origin` is a remote connection to `my-git-repo`. The same path is +designated as a "fetch" and a "push" location. We'll see what these mean +in a moment. + +## Return to Your Repository (You) {#remotes.xhtml_return-to-your-repository-you} + +Ok, we're done being Mary, and we can return to our own repository. + +``` k +cd ../my-git-repo +``` + +Notice that Mary's bio page is still empty. It's very important to +understand that this repository and Mary's repository are completely +separate. While she was altering her bio page, we could have been doing +all sorts of other things in `my-git-repo`. We could have even changed +her bio page, which would result in a merge conflict when we try to pull +her changes in. + +## Add Mary as a Remote (You) {#remotes.xhtml_add-mary-as-a-remote-you} + +Before we can get ahold of Mary's bio page, we need access to her +repository. Let's look at our current list of remotes: + +``` k +git remote +``` + +We don't have any (`origin` was never created because we didn't clone +from anywhere). So, let's add Mary as a remote repository. + +``` k +git remote add mary ../marys-repo +git remote -v +``` + +We can now use `mary` to refer to Mary's repository, which is located at +`../marys-repo`. The `git remote add` command is used to bookmark +another Git repository for easy access, and our connections can be seen +in the figure below. + +![Connections to remote repositories](media/7-3.png) + +Now that our remote *repositories* are setup, we'll spend the rest of +the module discussing remote *branches*. + +## Fetch Mary's Branches (You) {#remotes.xhtml_fetch-marys-branches-you} + +As noted earlier, we can use remote branches to access snapshots from +another repository. Let's take a look at our current remote branches +with the `-r` flag: + +``` k +git branch -r +``` + +Again, we don't have any. To populate our remote branch listing, we need +to **fetch** the branches from Mary's repository: + +``` k +git fetch mary +git branch -r +``` + +This will go to the "fetch" location shown in `git remote -v` and +download all of the branches it finds there into our repository. The +resulting branches are shown below. + + mary/bio-page + mary/master + +Remote branches are always listed in the form +`/` so that they will never be mistaken for +local branches. The above listing reflects the state of Mary's +repository at the time of the fetch, but they will not be automatically +updated if Mary continues developing any of her branches. + +That is to say, our remote branches are not *direct* links into Mary's +repository---they are read-only copies of her branches, stored in our +own repository. This means that we would have to do another fetch to +access new updates. + +![Mary's remote branches in our repository](media/7-4.png) + +The above figure shows the state of *our* repository. We have access to +Mary's snapshots (represented as squares) and her branches, even though +we don't have a real-time connection to Mary's repository. + +## Check Out a Remote Branch {#remotes.xhtml_check-out-a-remote-branch} + +Let's check out a remote branch to review Mary's changes. + +``` k +git checkout mary/master +``` + +This puts us in a `detached HEAD` state, just like we were in when we +checked out a dangling commit. This shouldn't be that surprising, +considering that our remote branches are *copies* of Mary's branches. +Checking out a remote branch takes our `HEAD` off the tip of a local +branch, illustrated by the following diagram. + +![Checking out Mary's `master` branch](media/7-5.png) + +We can't continue developing if we're not on a local branch. To build on +`mary/master` we either need to merge it into our own local `master` or +create another branch. We did the latter in [Branches, Part +I](#branches-1.xhtml) to build on an old commit and in [the previous +module](#rewriting-history.xhtml) to revive a "lost" commit, but right +now we're just looking at what Mary did, so the `detached HEAD` state +doesn't really affect us. + +## Find Mary's Changes {#remotes.xhtml_find-marys-changes} + +We can use the same log-filtering syntax from the previous module to +view Mary's changes. + +``` k +git log master..mary/master --stat +``` + +This shows us what Mary has added to her master branch, but it's also a +good idea to see if we've added any new changes that aren't in Mary's +repository: + +``` k +git log mary/master..master --stat +``` + +This won't output anything, since we haven't altered our database since +Mary cloned it. In other words, our history hasn't *diverged*---we're +just *behind* by a commit. + +## Merge Mary's Changes {#remotes.xhtml_merge-marys-changes} + +Let's approve Mary's changes and integrate them into our own `master` +branch. + +``` k +git checkout master +git merge mary/master +``` + +Even though `mary/master` is a remote branch, this still results in a +fast-forward merge because there is a linear path from our `master` to +the tip of `mary/master`: + +![Before merging Mary's `master` branch into our own](media/7-6.png) + +After the merge, the snapshots from Mary's remote branch become a part +of our local `master` branch. As a result, our `master` is now +synchronized with Mary's: + +![After merging Mary's master `branch` into our own](media/7-7.png) + +Notice that we only interacted with Mary's `master` branch, even though +we had access to her `bio-page`. If we hadn't been pretending to be +Mary, we wouldn't have known what this feature branch was for or if it +was ready to be merged. But, since we've designated `master` as a stable +branch for the project, it was safe to integrate those updates (assuming +Mary was also aware of this convention). + +## Push a Dummy Branch {#remotes.xhtml_push-a-dummy-branch} + +To complement our `git fetch` command, we'll take a brief look at +**pushing**. Fetching and pushing are *almost* opposites, in that +fetching imports branches, while pushing exports branches to another +repository. Let's take a look: + +``` k +git branch dummy +git push mary dummy +``` + +This creates a new branch called `dummy` and sends it to Mary. Switch +into Mary's repository to see what we did: + +``` k +cd ../marys-repo +git branch +``` + +You should find a new `dummy` branch in her *local* branch listing. I +said that `git fetch` and `git push` are *almost* opposites because +pushing creates a new *local* branch, while fetching imports commits +into *remote* branches. + +Now, put yourself in Mary's shoes. She was developing in her own +repository when, all of a sudden, a new `dummy` branch appeared out of +nowhere. Obviously, pushing branches into other people's repositories +can make for a chaotic workflow. So, as a general rule, **you should +never push into another developer's repository**. But then, why does +`git push` even exist? + +Over the next few modules, we'll see that pushing is a necessary tool +for maintaining public repositories. Until then, just remember to never, +ever push into one of your friend's repositories. Let's get rid of these +dummy branches and return to our repository. + +``` k +git branch -d dummy +cd ../my-git-repo +git branch -d dummy +``` + +## Push a New Tag {#remotes.xhtml_push-a-new-tag} + +An important property of `git push` is that it does not automatically +push tags associated with a particular branch. Let's examine this by +creating a new tag. + +``` k +git tag -a v2.0 -m "An even stabler version of the website" +``` + +We now have a `v2.0` tag in `my-git-repo`, which we can see by running +the `git tag` command. Now, let's try pushing the branch to Mary's +repository. + +``` k +git push mary master +``` + +Git will say her `master` branch is already up-to-date, and her +repository will remain unchanged. Instead of pushing the branch that +contains the tag, Git requires us to manually push the tag itself: + +``` k +git push mary v2.0 +``` + +You should now be able to see the `v2.0` tag in Mary's repository with a +quick `git tag`. It's very easy to forget to push new tags, so if it +seems like your project has lost a tag or two, it's most likely because +you didn't to push them to the remote repository. + +## Conclusion {#remotes.xhtml_conclusion} + +In this module, we learned how remote branches can be used to access +content in someone else's repository. The remotes listed in `git remote` +are merely bookmarks for a full path to another repository. We used a +local path, but as we'll soon see, Git can use the SSH protocol to +access repositories on another computer. + +The convention of `master` as a stable branch allowed us to pull changes +without consulting Mary, but this doesn't necessarily have to be the +case. When implementing your own workflow, Git offers you a lot of +flexibility about when and where you should pull from your team members. +As long as you clearly define your project conventions, you can +designate special uses or privileges to *any* branch. + +That said, it's important to note that remotes are for *people*, whereas +branches are for *topics*. Do *not* create separate branches for each of +your developers---give them separate repositories and bookmark them with +`git remote add`. Branches should always be for project development, not +user management. + +Now that we know how Git shares information between repositories, we can +add some more structure to our multi-user development environment. The +next module will show you how to set up and access a shared central +repository. + +## Quick Reference {#remotes.xhtml_quick-reference} + +`git clone ` +: Create a copy of a remote Git repository. + +`git remote` +: List remote repositories. + +`git remote add ` +: Add a remote repository. + +`git fetch ` +: Download remote branch information, but do not merge anything. + +`git merge /` +: Merge a remote branch into the checked-out branch. + +`git branch -r` +: List remote branches. + +`git push ` +: Push a local branch to another repository. + +`git push ` +: Push a tag to another repository. +::::: +:::::: + +[]{#centralized-workflows.xhtml} + +:::::: {#centralized-workflows.xhtml_page} +::::: {#centralized-workflows.xhtml_content} +# Centralized Workflows {#centralized-workflows.xhtml_centralized-workflows} + +In the previous module, we shared information directly between two +developers' repositories: `my-git-repo` and `marys-repo`. This works for +very small teams developing simple programs, but larger projects call +for a more structured environment. This module introduces one such +environment: the **centralized workflow**. + +We'll use a third Git repository to act as a central communication hub +between us and Mary. Instead of pulling changes into `my-git-repo` from +`marys-repo` and vice versa, we'll push to and fetch from a dedicated +storage repository. After this module, our workflow will look like the +following. + +![The centralized workflow](media/8-1.png) + +Typically, you would store the central repository on a server to allow +internet-based collaboration. Unfortunately, server configuration can +vary among hosting providers, making it hard to write universal +step-by-step instructions. So, we'll continue exploring remote +repositories using our local filesystem, just like in the previous +module. + +If you have access to a server, feel free to use it to host the central +repository that we're about to create. You'll have to provide SSH paths +to your server-based repository in place of the paths provided below, +but other than that, you can follow this module's instructions as you +find them. For everyone else, our network-based Git experience will +begin in the next module. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repositories for this +module](http://rypress.com/tutorials/git/media/repo-zips/centralized-workflows.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git +repositories from the above link, uncompress them, and you're good to +go. + +## Create a Bare Repository (Central) {#centralized-workflows.xhtml_create-a-bare-repository-central} + +First, let's create our central "communication hub." Again, make sure to +change `/path/to/my-git-repo` to the actual path to your repository. If +you've decided to host the central repository on your server, you should +SSH into it and run the `git init` command wherever you'd like to store +the repository. + +``` k +cd /path/to/my-git-repo +cd .. +git init --bare central-repo.git +``` + +As in the very first module, `git init` creates a new repository. But +this time, we used the `--bare` flag to tell Git that we don't want a +working directory. This will prevent us from developing in the central +repository, which eliminates the possibility of messing up another +user's environment with `git push`. A central repository is only +supposed to act as a *storage facility*---not a development environment. + +If you examine the contents of the resulting `central-repo.git` folder, +you'll notice that it contains the exact same files as the `.git` folder +in our `my-git-repo` project. Git has *literally* gotten rid of our +working directory. The conventional `.git` extension in the directory +name is a way to convey this property. + +## Update Remotes (Mary and You) {#centralized-workflows.xhtml_update-remotes-mary-and-you} + +We've successfully set up a central repository that can be used to share +updates between us, Mary, and any other developers. Next, we should add +it as a remote to both `marys-repo` and `my-git-repo`. + +``` k +cd marys-repo +git remote rm origin +git remote add origin ../central-repo.git +``` + +Now for our repository: + +``` k +cd ../my-git-repo +git remote add origin ../central-repo.git +git remote rm mary +``` + +Note that we deleted the remote connections between Mary and our +`my-git-repo` folder with `git remote rm`. For the rest of this module, +we'll only use the central repository to share updates. + +If you decided to host the central repository on a server, you'll need +to change the `../central-repo.git` path to: +`ssh://user@example.com/path/to/central-repo.git`, substituting your SSH +username and server location for `user@example.com` and the central +repository's location for `path/to/central-repo.git`. + +## Push the Master Branch (You) {#centralized-workflows.xhtml_push-the-master-branch-you} + +We didn't *clone* the central repository---we just initialized it as a +bare repository. This means it doesn't have any of our project history +yet. We can fix that using the `git push` command introduced in the last +module. + +``` k +git push origin master +``` + +Our central repository now contains our entire `master` branch, which we +can double-check with the following. + +``` k +cd ../central-repo.git +git log +``` + +This should output the familiar history listing of the `master` branch. + +Recall that `git push` creates *local* branches in the destination +repository. We said it was dangerous to push to a friend's repository, +as they probably wouldn't appreciate new branches appearing at random. +However, it's safe to create local branches in `central-repo.git` +because it has no working directory, which means it's impossible to +disturb anyone's development. + +## Add News Update (You) {#centralized-workflows.xhtml_add-news-update-you} + +Let's see our new centralized collaboration workflow in action by +committing a few more snapshots. + +``` k +cd ../my-git-repo +git checkout -b news-item +``` + +Create a file called `news-3.html` in `my-git-repo` and add the +following HTML. + +``` cp + + + + Middle East's Silent Beast + + + + +

    Middle East's Silent Beast

    +

    Late yesterday evening, the Middle East's largest + design house—until now, silent on the West's colorful + disagreement—announced the adoption of + Yellow as this year's + color of choice.

    + +

    Return to home page

    + + +``` + +Next, add a link to the "News" section of `index.html` so that it looks +like: + +``` nt +

    News

    + +``` + +Stage and commit a snapshot. + +``` k +git add news-3.html index.html +git status +git commit -m "Add 3rd news item" +``` + +## Publish the News Item (You) {#centralized-workflows.xhtml_publish-the-news-item-you} + +Previously, "publishing" meant merging with the local `master` branch. +But since we're *only* interacting with the central repository, our +`master` branch is private again. There's no chance of Mary pulling +content directly from our repository. + +Instead, everyone accesses updates through the *public* `master` branch, +so "publishing" means pushing to the central repository. + +``` k +git checkout master +git merge news-item +git branch -d news-item +git push origin master +``` + +After merging into `master` as we normally would, `git push` updates the +central repository's `master` branch to reflect our local `master`. From +our perspective, the push can be visualized as the following: + +![Pushing `master` to the central repository](media/8-2.png) + +Note that this accomplishes the exact same thing as going into the +central repository and doing a fetch/fast-forward merge, except +`git push` allows us to do everything from inside `my-git-repo`. We'll +see some other convenient features of this command later in the module. + +## Update CSS Styles (Mary) {#centralized-workflows.xhtml_update-css-styles-mary} + +Next, let's pretend to be Mary again and add some CSS formatting (she is +our graphic designer, after all). + +``` k +cd ../marys-repo +git checkout -b css-edits +``` + +Add the following to the end of `style.css`: + +``` nt +h1 { + font-size: 32px; +} + +h2 { + font-size: 24px; +} + +a:link, a:visited { + color: #03C; +} +``` + +And, stage and commit a snapshot. + +``` k +git commit -a -m "Add CSS styles for headings and links" +``` + +## Update Another CSS Style (Mary) {#centralized-workflows.xhtml_update-another-css-style-mary} + +Oops, Mary forgot to add some formatting. Append the `h3` styling to +`style.css`: + +``` nt +h3 { + font-size: 18px; + margin-left: 20px; +} +``` + +And of course, stage and commit the updates. + +``` k +git commit -a -m "Add CSS styles for 3rd level headings" +``` + +## Clean Up Before Publishing (Mary) {#centralized-workflows.xhtml_clean-up-before-publishing-mary} + +Before Mary considers pushing her updates to the central repository, she +needs to make sure she has a clean history. This *must* be done by Mary, +because it's near-impossible to change history after it has been made +public. + +``` k +git rebase -i master +``` + +This highlights another benefit of using isolated branches to develop +independent features. Mary doesn't need to go back and figure out what +changes need to be rebased, since they all reside in her current branch. +Change the rebase configuration to: + +``` k +pick 681bd1c Add CSS styles for headings and links +squash eabac68 Add CSS styles for 3rd level headings +``` + +When Git stops to ask for the combined commit message, just use the +first commit's message: + + Add CSS styles for headings and links + +Consider what would have happened had Mary rebased *after* pushing to +the central repository. She would be re-writing commits that other +developers may have already pulled into their project. To Git, Mary's +re-written commits look like entirely new commits (since they have +different ID's). This situation is shown below. + +![Squashing a public commit](media/8-3.png) + +The commits labeled *1* and *2* are the public commits that Mary would +be rebasing. Afterwards, the public history is still the exact same as +Mary's original history, but now her local `master` branch has diverged +from `origin/master`---even though they represent the same snapshot. + +So, to publish her rebased `master` branch to the central repository, +Mary would have to merge with `origin/master`. This cannot be a +fast-forward merge, and the resulting merge commit is likely to confuse +her collaborators and disrupt their workflow. + +This brings us to the most important rule to remember while rebasing: +**Never, ever rebase commits that have been pushed to a shared +repository**. + +If you need to change a public commit, use the `git revert` command that +we discussed in [Undoing Changes](#undoing-changes.xhtml). This creates +a new commit with the required modifications instead of re-writing old +snapshots. + +## Publish CSS Changes (Mary) {#centralized-workflows.xhtml_publish-css-changes-mary} + +Now that her history is cleaned up, Mary can publish the changes. + +``` k +git checkout master +git merge css-edits +git branch -d css-edits +``` + +She shouldn't push the `css-edits` branch to the server, since it's no +longer under development, and other collaborators wouldn't know what it +contains. However, if we had all decided to develop the CSS edits +together and wanted an isolated environment to do so, it would make +sense to publish it as an independent branch. + +Mary still needs to push the changes to the central repository. But +first, let's take a look at the state of everyone's project. + +![Before publishing Mary's CSS changes](media/8-4.png) + +You might be wondering how Mary can push her local `master` up to the +central repository, since it has progressed since Mary last fetched from +it. This is a common situation when many developers are working on a +project simultaneously. Let's see how Git handles it: + +``` k +git push origin master +``` + +This will output a verbose rejection message. It seems that Git won't +let anyone push to a remote server if it doesn't result in a +fast-forward merge. This prevents us from losing the `Add 3rd news item` +commit that would need to be overwritten for `origin/master` to match +`mary/master`. + +## Pull in Changes (Mary) {#centralized-workflows.xhtml_pull-in-changes-mary} + +Mary can solve this problem by pulling in the central changes before +trying to push her CSS changes. First, she needs the most up-to-date +version of the `origin/master` branch. + +``` k +git fetch origin +``` + +Remember that Mary can see what's in `origin/master` and not in the +local `master` using the `..` syntax: + +``` k +git log master..origin/master +``` + +And she can also see what's in her `master` that's not in +`origin/master`: + +``` k +git log origin/master..master +``` + +Since both of these output a commit, we can tell that Mary's history +diverged. This should also be clear from the diagram below, which shows +the updated `origin/master` branch. + +![Fetching the central repository's `master` branch](media/8-5.png) + +Mary is now in the familiar position of having to pull in changes from +another branch. She can either merge, which *cannot* be fast-forwarded, +or she can rebase for a linear history. + +Typically, you'll want to rebase your changes on top of those found in +your central repository. This is the equivalent of saying, "I want to +add my changes to what everyone else has already done." As previously +discussed, rebasing also eliminates superfluous merge commits. For these +reasons, Mary will opt for a rebase. + +``` k +git rebase origin/master +git push origin master +``` + +After the rebase, Mary's `master` branch contains everything from the +central repository, so she can do a fast-forward push to publish her +changes. + +![Updating the central repository's `master`](media/8-6.png) + +## Pull in Changes (You) {#centralized-workflows.xhtml_pull-in-changes-you} + +Finally, we'll switch back to our repository and pull in Mary's CSS +formatting. + +``` k +cd ../my-git-repo +git fetch origin +git log master..origin/master --stat +git log origin/master..master --stat +``` + +Of course, the second log command won't output anything, since we +haven't added any new commits while Mary was adding her CSS edits. It's +usually a good idea to check this before trying to merge in a remote +branch. Otherwise, you might end up with some extra merge commits when +you thought you were fast-forwarding your branch. + +``` k +git merge origin/master +``` + +Our repository is now synchronized with the central repository. Note +that Mary may have moved on and added some new content that we don't +know about, but it doesn't matter. The only changes we need to know +about are those in `central-repo.git`. While this doesn't make a huge +difference when we're working with just one other developer, imagine +having to keep track of a dozen different developers' repositories in +real-time. This kind of chaos is precisely the problem a centralized +collaboration workflow is designed to solve: + +![The centralized workflow with many developers](media/8-7.png) + +The presence of a central communication hub condenses all this +development into a single repository and ensures that no one overwrites +another's content, as we discovered while trying to push Mary's CSS +updates. + +## Conclusion {#centralized-workflows.xhtml_conclusion} + +In this module, we introduced another remote repository to serve as the +central storage facility for our project. We also discovered bare +repositories, which are just like ordinary repositories---minus the +working directory. Bare repositories provide a "safe" location to push +branches to, as long as you remember not to rebase the commits that it +already contains. + +We hosted the central repository on our local filesystem, right next to +both ours and Mary's projects. However, most real-world central +repositories reside on a remote server with internet access. This lets +any developer fetch from or push to the repository over the internet, +making Git a very powerful multi-user development platform. Having the +central repository on a remote server is also an affordable, convenient +way to back up a project. + +Next up, we'll configure a network-based repository using a service +called GitHub. In addition to introducing network access for Git +repositories, this will open the door for another collaboration +standard: the integrator workflow. + +## Quick Reference {#centralized-workflows.xhtml_quick-reference} + +`git init --bare ` +: Create a Git repository, but omit the working directory. + +`git remote rm ` +: Remove the specified remote from your bookmarked connections. +::::: +:::::: + +[]{#distributed-workflows.xhtml} + +:::::: {#distributed-workflows.xhtml_page} +::::: {#distributed-workflows.xhtml_content} +# Distributed Workflows {#distributed-workflows.xhtml_distributed-workflows} + +Now that we know how to share information via a centralized workflow, we +can appreciate some of the drawbacks of this collaboration model. While +it may be convenient, allowing everyone to push to an "official" +repository raises some legitimate security concerns. It means that for +anyone to contribute content, they need access to the *entire project.* + +This is fine if you're only interacting with a small team, but imagine a +scenario where you're working on an open-source software project and a +stranger found a bug, fixed it, and wants to incorporate the update into +the main project. You probably don't want to give them push-access to +your central repository, since they could start pushing all sorts of +random snapshots, and you would effectively lose control of the project. + +But, what you can do is tell the contributor to push the changes to +*their own* public repository. Then, you can pull their bug fix into +your private repository to ensure it doesn't contain any undeclared +code. If you approve their contributions, all you have to do is merge +them into a local branch and push it to the main repository, just like +we did in the previous module. You've become an *integrator*, in +addition to an ordinary developer: + +![The integrator workflow](media/9-1.png) + +In this module, we'll experience all of this first-hand by creating a +free public repository on [Bitbucket.org](http://bitbucket.org) and +incorporating a contribution from an anonymous developer named John. +Bitbucket is a DVCS hosting provider that makes it very easy to set up a +Git repository and start collaborating with a team of developers. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repositories for this +module](http://rypress.com/tutorials/git/media/repo-zips/distributed-workflows.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git +repositories from the above link, uncompress them, and you're good to +go. + +## Create a Bitbucket Account {#distributed-workflows.xhtml_create-a-bitbucket-account} + +The first part of this module will walk you through setting up a +Bitbucket account. Navigate your web browser to +[Bitbucket.org](http://bitbucket.org) and sign up for a free account. + +![The Bitbucket logo](media/bitbucket-logo.png) + +You can choose any username for your account, but the email address +should match the one you assigned to your Git installation with +`git config` in [The Basics](#the-basics.xhtml). If you need to change +your email, you can run another +`git config --global user.email you@example.com` command. + +## Create a Public Repository (You) {#distributed-workflows.xhtml_create-a-public-repository-you} + +To create our first networked Git repository, log into your Bitbucket +account, and navigate to *Repositories \> Create repository*. Use +`my-git-repo` as the *Repository Name*, and anything you like for the +*Description* field. Since this is just an example project, go ahead and +uncheck the *This is a private repository* field. Select *HTML/CSS* for +the *Language* field, then go ahead and click *Create repository*. + +![Bitbucket's new repository form](media/9-4.png) + +Essentially, we just ran `git init --bare` on a Bitbucket server. We can +now push to and fetch from this repository as we did with +`central-repo.git` in the previous module. + +After initialization, Bitbucket offers some helpful instructions, but +don't follow them just yet---we'll walk through importing an existing +repository in the next section. + +![Bitbucket's setup instructions](media/9-5.png) + +## Push to the Public Repository (You) {#distributed-workflows.xhtml_push-to-the-public-repository-you} + +Before populating this new repository with our existing `my-git-repo` +project, we first need to point our `origin` remote to the Bitbucket +repository. Be sure to change the `` portion to your actual +Bitbucket username. + +``` k +cd /path/to/my-git-repo +git remote rm origin +git remote add origin https://@bitbucket.org//my-git-repo.git +``` + +The utility of remotes should be more apparent than in previous modules, +as typing the full path to this repository every time we needed to +interact with it would be rather tedious. + +To populate the remote repository with our existing code, we can use the +same push mechanism as with a centralized workflow. When prompted for a +password, use the one that you signed up with. + +``` k +git push origin master +``` + +## Browse the Public Repository (You) {#distributed-workflows.xhtml_browse-the-public-repository-you} + +We should now be able to see our project on the Bitbucket site. The +*Source* tab displays all of the files in the project, and the *Commits* +tab contains the entire commit history. Note that the branch structure +of the repository is also visualized to the left of each commit. + +![Our history in Bitbucket's Commit tab](media/9-6.png) + +This repository now serves as the "official" copy of our example +website. We'll tell everyone else to download from this repository, and +we'll push all the changes from our local `my-git-repo` to it. However, +it's important to note that this "official" status is merely a +convention. As the `master` branch is just another branch, our Bitbucket +repository is just another repository according to Git. + +Having both a public and a private repository for each developer makes +it easy to incorporate contributions from third-parties, even if you've +never met them before. + +## Clone the Repository (John) {#distributed-workflows.xhtml_clone-the-repository-john} + +Next, we're going to pretend to be John, a third-party contributor to +our website. John noticed that we didn't have a pink page and, being the +friendly developer that he is, wants to create one for us. We'd like to +let him contribute, but we don't want to give him push-access to our +entire repository---this would allow him to re-write or even delete all +of our hard work. + +Fortunately, John knows how to exploit Bitbucket's collaboration +potential. He'll start by cloning a copy of our public repository: + +``` k +cd /path/to/my-git-repo +cd .. +git clone http://bitbucket.org//my-git-repo.git johns-repo +cd johns-repo +``` + +You should now have another copy of our repository called `johns-repo` +in the same folder as `my-git-repo`. This is John's *private* +repository---a completely isolated environment where he can safely +develop the pink page. Let's quickly configure his name and email: + +``` k +git config user.name "John" +git config user.email john.example@rypress.com +``` + +## Add the Pink Page (John) {#distributed-workflows.xhtml_add-the-pink-page-john} + +Of course, John should be developing his contributions in a dedicated +feature branch. + +``` k +git checkout -b pink-page +``` + +In addition to being a best practice, this makes it easy for the +integrator to see what commits to include. When John's done, he'll tell +us where to find his repository and what branch the new feature resides +in. Then, we'll be able merge his content with minimal effort. + +Create the file `pink.html` and add the following code: + +``` cp + + + + The Pink Page + + + + +

    The Pink Page

    +

    Pink is girly, + flirty and fun!

    + +

    Return to home page

    + + +``` + +Add the pink page to the "Navigation" section in `index.html`: + +``` nt +
  • + The Pink Page +
  • +``` + +Then, stage and commit the snapshot as normal. + +``` k +git add pink.html index.html +git status +git commit -m "Add pink page" +``` + +## Publish the Pink Page (John) {#distributed-workflows.xhtml_publish-the-pink-page-john} + +Now, John needs to publish his contributions to a public repository. +Remember that we don't want him to push to *our* public repository, +which is stored in his `origin` remote. In fact, he *can't* push to +`origin` for reasons we'll discuss in a moment. + +Instead, he'll create his own Bitbucket repository that we can pull +contributions from. In the real world, John would have his own Bitbucket +account, but for convenience, we'll just store his public repository +under our existing account. Once again, navigate to your Bitbucket home +page and click *Repositories \> Create repository* to create John's +public repository. For the *Name* field, use `johns-repo`. + +![John's new repository form](media/9-7.png) + +Back in John's private repository, we'll need to add this as a remote: + +``` k +git remote add john-public https://@bitbucket.org//johns-repo.git +``` + +This is where John will publish the pink page for us to access. Since +he's pushing with HTTPS, he'll need to enter the password for his +Bitbucket account (which is actually the password for *your* account). + +``` k +git push john-public pink-page +``` + +All John needs to do now is tell us the name of the feature branch and +send us a link to his repository, which will be: + + http://bitbucket.org//johns-repo.git + +Note that John used a different path for pushing to his public +repository than the one he gave us for fetching from it. The most +important distinction is the transport protocol: the former used +`https://` while the latter used `http://`. Accessing a repository over +HTTPS (or SSH) lets you fetch or push, but as we saw, requires a +password. This prevents unknown developers from overwriting commits. + +On the other hand, fetching over HTTP requires no username or password, +but pushing is not possible. This lets anyone fetch from a repository +without compromising its security. In the integrator workflow, other +developers access your repository via HTTP, while you publish changes +via HTTPS. This is also the reason why John can't push to his `origin` +remote. + +Of course, if you're working on a private project, anonymous HTTP access +would be disabled for that repository. + +## View John's Contributions (You) {#distributed-workflows.xhtml_view-johns-contributions-you} + +Ok, we're done being John and we're ready to integrate his code into the +official project. Let's start by switching back into our repository and +adding John's public repository as a remote. + +``` k +cd ../my-git-repo +git remote add john http://bitbucket.org//johns-repo.git +``` + +Note that we don't care about anything in John's private +repository---the only thing that matters are his published changes. +Let's download his branches and take a look at what he's been working +on: + +``` k +git fetch john +git branch -r +git log master..john/pink-page --stat +``` + +We can visualize this history information as the following. + +![Before merging John's `pink-page` branch](media/9-8.png) + +Let's take a look at his actual changes: + +``` k +git checkout john/pink-page +``` + +Open up the `pink.html` file to see if it's ok. Remember that John isn't +a trusted collaborator, and we would normally have no idea what this +file might contain. With that in mind, it's incredibly important to +verify its contents. **Never blindly merge content from a third-party +contributor.** + +## Integrate John's Contributions (You) {#distributed-workflows.xhtml_integrate-johns-contributions-you} + +Assuming we approve John's updates, we're now ready to merge it into the +project. + +``` k +git checkout master +git merge john/pink-page +``` + +Notice that is the exact same way we incorporated Mary's changes in the +centralized workflow, except now we're pulling from and pushing to +different locations: + +![The integrator workflow with John](media/9-9.png) + +Furthermore, John's workflow is just like ours: develop in a local, +private repository, then push changes to the public one. The integrator +workflow is merely a standardized way of organizing the collaboration +effort---nothing has changed about how we develop locally, and we're +using the same Git commands as we have been for the last few modules. + +## Publish John's Contributions (You) {#distributed-workflows.xhtml_publish-johns-contributions-you} + +We've integrated John's contribution into our local `my-git-repo` +repository, but no one else knows what we've done. It's time to publish +our `master` branch again. + +``` k +git push origin master +``` + +Since we designated our public Bitbucket repository as the "official" +source for our project, everyone (i.e., Mary and John) will now be able +to synchronize with it. + +## Update Mary's Repository (Mary) {#distributed-workflows.xhtml_update-marys-repository-mary} + +Mary should now be pulling changes from our Bitbucket repository instead +of the central one from the previous module. This should be fairly easy +for her to configure. + +``` k +cd ../marys-repo +git remote rm origin +git remote add origin http://bitbucket.org//my-git-repo.git +``` + +Again, remember to change `` to your Bitbucket account's +username. For the sake of brevity, we'll do a blind merge to add John's +updates to Mary's repository (normally, Mary should check what she's +integrating before doing so). + +``` k +git checkout master +git fetch origin +git rebase origin/master +``` + +For Mary, it doesn't really matter that the updates came from John. All +she has to know is that the "official" `master` branch moved forward, +prompting her to synchronize her private repository. + +## Update John's Repository (John) {#distributed-workflows.xhtml_update-johns-repository-john} + +John still needs to incorporate the pink page into his `master` branch. +He should *not* merge directly from his `pink-page` topic branch because +we could have edited his contribution before publishing it or included +other contributions along with it. Instead, he'll pull from the +"official" `master`: + +``` k +cd ../johns-repo +git checkout master +git fetch origin +git rebase origin/master +``` + +If John had updated `master` directly from his local `pink-page`, it +could have wound up out-of-sync from the main project. For this reason, +the integrator workflow requires that everyone *pull* from a single, +official repository, while they all *push* to their own public +repositories: + +![The integrator workflow with many developers](media/9-10.png) + +In this way, additions from one contributor can be approved, integrated, +and made available to everyone without interrupting anyone's independent +developments. + +## Conclusion {#distributed-workflows.xhtml_conclusion} + +Using the integrator workflow, our private development process largely +remains the same (develop a feature branch, merge it into `master`, and +publish it). But, we've added an additional task: incorporating changes +from third-party contributors. Luckily, this doesn't require any new +skills---just access to a few more remote repositories. + +While this setup forces us to keep track of more remotes, it also makes +it much, much easier to work with a large number of developers. You'll +never have to worry about security using an integrator workflow because +you'll still be the only one with access to the "official" repository. + +There's also an interesting side-effect to this kind of security. By +giving each developer their own public repository, the integrator +workflow creates a more stable development environment for open-source +software projects. Should the lead developer stop maintaining the +"official" repository, any of the other participants could take over by +simply designating their public repository as the new "official" +project. This is part of what makes Git a *distributed* version control +system: there is no single central repository that Git forces everyone +to rely upon. + +![John/Mary taking over project maintenance](media/9-11.png) + +In the next module, we'll take a look at an even more flexible way to +share commits. This low-level approach will also give us a better +understanding of how Git internally manages our content. +::::: +:::::: + +[]{#patch-workflows.xhtml} + +:::::: {#patch-workflows.xhtml_page} +::::: {#patch-workflows.xhtml_content} +# Patch Workflows {#patch-workflows.xhtml_patch-workflows} + +Thus far, all of the collaboration workflows we've seen rely heavily on +branches. For example, in the last module, a contributor had to publish +an entire *branch* for us to merge into our project. However, it's also +possible to communicate directly on the *commit* level using a +***patch***. + +A patch file represents a single set of changes (i.e., a commit) that +can be applied to any branch, in any order. In this sense, the patch +workflow is akin to interactive rebasing, except you can easily share +patches with other developers. This kind of communication lessens the +importance of a project's branch structure and gives complete control to +the project maintainer (at least with regards to incorporating +contributions). + +Integrating on the commit level will also give us a deeper understanding +of how a Git repository records project history. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repositories for this +module](http://rypress.com/tutorials/git/media/repo-zips/patch-workflows.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git +repositories from the above link, uncompress them, and you're good to +go. If you've set up a Bitbucket account, you should also run the +following commands to configure the downloaded repositories: + +``` k +cd /path/to/my-git-repo +git remote add origin https://@bitbucket.org//my-git-repo.git +cd ../marys-repo +git remote add origin http://bitbucket.org//my-git-repo.git +``` + +## Change the Pink Page (Mary) {#patch-workflows.xhtml_change-the-pink-page-mary} + +We'll begin by pretending to be Mary again. Mary didn't like the pink +page that John contributed and wants to change it. + +``` k +cd /path/to/marys-repo +git checkout -b pink-page +``` + +Developing in a new branch not only gives Mary an isolated environment, +it also makes it easier to create a series of patches once she's done +editing the pink page. Find these lines in `pink.html`: + +``` nt +

    Pink is girly, +flirty and fun!

    +``` + +and change them to the following. + +``` nt +

    Only real men wear pink!

    +``` + +Stage and commit the update as normal. + +``` k +git commit -a -m "Change pink to a manly color" +``` + +Note that Mary's local development process doesn't change at all. +Patches---like the centralized and integrator workflows---are merely a +way to share changes amongst developers. It has little effect on the +core Git concepts introduced in the first portion of this tutorial. + +## Create a Patch (Mary) {#patch-workflows.xhtml_create-a-patch-mary} + +Mary can create a patch from the new commit using the `git format‑patch` +command. + +``` k +git format-patch master +``` + +This creates a file called `0001-Change-pink-to-a-manly-color.patch` +that contains enough information to re-create the commit from the last +step. The `master` parameter tells Git to generate patches for every +commit in the current branch that's missing from `master`. + +Open up the patch file in a text editor. As shown by the addresses in +the top of the file, it's actually a complete email. This makes it +incredibly easy to send patches to other developer. Further down, you +should see the following. + +``` gh +index 98e10a1..828dd1a 100644 +--- a/pink.html ++++ b/pink.html +@@ -7,8 +7,7 @@ + + +

    The Pink Page

    +-

    Pink is girly, +- flirty and fun!

    ++

    Only real men wear pink!

    + +

    Return to home page

    + +``` + +This unique formatting is called a ***diff***, because it shows the +*diff*erence between two versions of a file. In our case, it tells us +what happened to the `pink.html` file between the `98e10a1` and +`828dd1a` commits (your patch will contain different commit ID's). The +`-7,8 +7,7` portion describes the lines affected in the respective +versions of the file, and the rest of the text shows us the content that +has been changed. The lines beginning with `-` have been deleted in the +new version, and the line starting with `+` has been added. + +While you don't have to know the ins-and-outs of diffs to make use of +patches, you do need to understand that a single patch file represents a +complete commit. And, since it's a normal file (and also an email), it's +much easier to pass around than a Git branch. + +Delete the patch file for now (we'll re-create it later). + +## Add a Pink Block (Mary) {#patch-workflows.xhtml_add-a-pink-block-mary} + +Before learning how to turn patches back into commits, Mary will add one +more snapshot. + +In `pink.html`, add the following on the line after the `` tag. + +``` nt + +``` + +And, add the next line of HTML after `Only real men wear pink!`: + +``` nt +
    +``` + +Stage and commit the snapshot. + +``` k +git commit -a -m "Add a pink block of color" +``` + +Mary's repository now contains two commits after the tip of `master`: + +![Adding two commits on the `pink-page` branch](media/10-1.png) + +## Create Patch of Entire Branch (Mary) {#patch-workflows.xhtml_create-patch-of-entire-branch-mary} + +Mary can use the same command as before to generate patches for all the +commits in her `pink-page` branch. + +``` k +git format-patch master +``` + +The first patch is the exact same as we previously examined, but we also +have a new one called `0002-Add-a-pink-block-of-color.patch`. Note that +the first line of the commit message will always be used to make a +descriptive filename for the patch. You should find the following diff +in the second patch. + +``` gh +index 828dd1a..2713b10 100644 +--- a/pink.html ++++ b/pink.html +@@ -4,10 +4,17 @@ + The Pink Page + + ++ + + +

    The Pink Page

    +

    Only real men wear pink!

    ++
    + +

    Return to home page

    + +``` + +This is the same formatting as the first patch, except its lack of `-` +lines indicate that we only added HTML during the second commit. As you +can see, this patch is really just a machine-readable summary of our +actions from the previous section. + +## Mail the Patches (Mary) {#patch-workflows.xhtml_mail-the-patches-mary} + +Now that Mary has prepared a series of patches, she can send them to the +project maintainer (us). In the typical patch workflow, she would send +them via email using one of the following methods: + +- Copying and pasting the contents of the patch files into an email + client. If she uses this method, Mary would have to make sure that + her email application doesn't change the whitespace in the patch + upon sending it. +- Sending the patch file as an attachment to a normal email. +- Using the convenient `git send-email` command and specifying a file + or a directory of files to send. For example, `git send-email .` + will send all the patches in the current directory. Git also + requires some special configurations for this command. Please + consult the [official Git + documentation](http://www.kernel.org/pub/software/scm/git/docs/git-send-email.html) + for details. + +The point is, the `.patch` files need to find their way into the Git +repository of whoever wants to add it to their project. For our example, +all we need to do is copy the patches into the `my-git-repo` directory +that represents our local version of the project. + +## Apply the Patches (You) {#patch-workflows.xhtml_apply-the-patches-you} + +Copy the two patch files from `marys-repo` into `my-git-repo`. Using the +new `git am` command, we can use these patches to add Mary's commits to +our repository. + +``` k +cd ../my-git-repo +git checkout -b patch-integration +git am < 0001-Change-pink-to-a-manly-color.patch +git log master..HEAD --stat +``` + +First, notice that we're doing our integrating in a new topic branch. +Again, this ensures that we won't destroy our existing functionality and +gives us a chance to approve changes. Second, the `git am` command takes +a patch file and creates a new commit from it. The log output shows us +that our integration branch contains Mary's update, along with her +author information. + +Let's repeat the process for the second commit. + +``` k +git am < 0002-Add-a-pink-block-of-color.patch +git log master..HEAD --stat +``` + +The `git am` command is configured to read from something called +"standard input," and the `<` character is how we can turn a file's +contents into standard input. As it's really more of an operating system +topic, you can just think of this syntax as a quirk of the `git am` +command. + +After applying this patch, our integration branch now looks exactly like +Mary's `pink-page` branch. We applied Mary's patches in the same order +she did, but that didn't necessarily have to be the case. The whole idea +behind patches is that they let you isolate a commit and move it around +as you please. + +## Integrate the Patches (You) {#patch-workflows.xhtml_integrate-the-patches-you} + +Once again, we're in the familiar situation of integrating a topic +branch into the stable `master` branch. + +``` k +git checkout master +git merge patch-integration +git branch -d patch-integration +git clean -f +git push origin master +``` + +Mary's updates are now completely integrated into our local repository, +so we can get rid of the patch files with `git clean`. This was also an +appropriate time to push changes to the public repository so other +developers can access the most up-to-date version of the project. + +## Update Mary's Repository (Mary) {#patch-workflows.xhtml_update-marys-repository-mary} + +Mary might be tempted to merge her `pink-page` branch directly into her +`master` branch, but this would be a mistake. Her `master` branch *must* +track the "official" repository's `master`, as discussed in the previous +module. + +``` k +cd ../marys-repo +git checkout master +git fetch origin +git rebase origin/master +git branch -D pink-page +git clean -f +``` + +Patches are a convenient way to share commits amongst developers, but +the patch workflow still requires an "official" repository that contains +*everybody's* changes. What would have happened if Mary wasn't the only +one sending patches to us? We may very well have applied several +different patches or applied Mary's contributions in a different order. +Using Mary's `pink-page` to update her `master` branch would completely +ignore all these updates. + +Taking this into consideration, our final patch workflow resembles the +following. + +![The patch workflow](media/10-2.png) + +## Conclusion {#patch-workflows.xhtml_conclusion} + +Whereas remote repositories are a way to share entire *branches*, +patches are a way to send individual *commits* to another developer. +Keep in mind that patches are usually only sent to a project maintainer, +who then integrates them into the "official" project for all to see. It +would be impossible for everyone to communicate using only patches, as +no one would be applying them in the same order. Eventually, everyone's +project history would look entirely different. + +In many ways, patches are a simpler way to accept contributions than the +integrator workflow from the previous module. Only the project +maintainer needs a public repository, and he'll never have to peek at +anyone else's repository. From the maintainer's perspective, patches +also provide the same security as the integrator workflow: he still +won't have to give anyone access to his "official" repository. But, now +he won't have to keep track of everybody's remote repositories, either. + +As a programmer, you're most likely to use patches when you want to fix +a bug in someone else's project. After fixing it, you can send them a +patch of the resulting commit. For this kind of one-time-fix, it's much +more convenient for you to generate a patch than to set up a public Git +repository. + +This module concludes our discussion of the standard Git workflows. +Hopefully, you now have a good idea of how Git can better manage your +personal and professional software projects using a centralized, +integrator, or patch workflow. In the next module, we'll switch gears +and introduce a variety of practical Git commands. + +## Quick Reference {#patch-workflows.xhtml_quick-reference} + +`git format-patch ` +: Create a patch for each commit contained in the current branch but + not in ``. You can also specify a commit ID instead of + ``. + +`git am < ` +: Apply a patch to the current branch. +::::: +:::::: + +[]{#tips-and-tricks.xhtml} + +:::::: {#tips-and-tricks.xhtml_page} +::::: {#tips-and-tricks.xhtml_content} +# Tips & Tricks {#tips-and-tricks.xhtml_tips-tricks} + +This module presents a broad survey of useful Git utilities. We'll take +a step back from the theoretical aspects of Git and focus on common +tasks like preparing a project for release and backing up a repository. +While working through this module, your goal shouldn't be to master all +of these miscellaneous tools, but rather to understand why they were +created and when they might come in handy. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repositories for this +module](http://rypress.com/tutorials/git/media/repo-zips/tips-and-tricks.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git +repositories from the above link, uncompress them, and you're good to +go. + +## Archive The Repository {#tips-and-tricks.xhtml_archive-the-repository} + +First, let's export our repository into a ZIP archive. Run the following +command in your local copy of `my-git-repo`. + +``` k +git archive master --format=zip --output=../website-12-10-2012.zip +``` + +Or, for Unix users that would prefer a tarball: + +``` k +git archive master --format=tar --output=../website-12-10-2012.tar +``` + +This takes the current `master` branch and places all of its files into +a ZIP archive (or a tarball), omitting the `.git` directory. Removing +the `.git` directory removes all version control information, and you're +left with a single snapshot of your project. + +You can send the resulting archive to a client for review, even if they +don't have Git installed on their machine. This is also an easy way to +create Git-independent backups of important revisions, which is always a +good idea. + +## Bundle the Repository {#tips-and-tricks.xhtml_bundle-the-repository} + +Similar to the `git archive` command, `git bundle` turns a repository +into a single file. However, in this case, the file retains the +versioning information of the entire project. Try running the following +command. + +``` k +git bundle create ../repo.bundle master +``` + +It's like we just pushed our `master` branch to a remote, except it's +contained in a file instead of a remote repository. We can even clone it +using the same `git clone` command: + +``` k +cd .. +git clone repo.bundle repo-copy -b master +cd repo-copy +git log +cd ../my-git-repo +``` + +The log output should show you the entire history of our `master` +branch, and `repo.bundle` is also the `origin` remote for the new +repository. This is the exact behavior we encountered when cloning a +"normal" Git repository. + +Bundles are a great way to backup entire Git repositories (not just an +isolated snapshot like `git archive`). They also let you share changes +without a network connection. For example, if you didn't want to +configure the SSH accounts for a private Git server, you could bundle up +the repository, put it on a jump drive, and walk it over to your +co-worker's computer. Of course, this could become a bit tiresome for +active projects. + +We won't be needing the `repo.bundle` file and `repo-copy` folder, so go +ahead and delete them now. + +## Ignore a File {#tips-and-tricks.xhtml_ignore-a-file} + +Remember that Git doesn't automatically track files because we don't +want to record generated files like C binaries or compiled Python +modules. But, seeing these files under the "Untracked files" list in +`git status` can get confusing for large projects, so Git lets us ignore +content using a special text file called `.gitignore`. Each file or +directory stored in `.gitignore` will be invisible to Git. + +Let's see how this works by creating a file called `notes.txt` to store +some personal (private) comments about the project. Add some text to it +and save it, then run the following. + +``` k +git status +``` + +As expected, this will show `notes.txt` in the "Untracked files" +section. Next, create a file called `.gitignore` in the `my-git-repo` +folder and add the following text to it. Windows users can create a file +that starts with a period by executing the `touch .gitignore` command in +Git Bash (you should also make sure hidden files are visible in your +file browser). + +``` k +notes.txt +``` + +Run another `git status` and you'll see that the notes file no longer +appears under "Untracked files", but `.gitignore` does. This is a common +file for Git-based projects, so let's add it to the repository. + +``` k +git add .gitignore +git commit -m "Add .gitignore file" +git status +``` + +You can also specify entire directories in `.gitignore` or use the `*` +wildcard to ignore files with a particular extension. For example, the +following is a typical `.gitignore` file for a simple C project. It +tells Git to overlook all `.o`, `.out`, and `.exe` files in the +repository. + + *.o + *.out + *.exe + +## Stash Uncommitted Changes {#tips-and-tricks.xhtml_stash-uncommitted-changes} + +Next, we'll take a brief look at **stashing**, which conveniently +"stashes" away uncommitted changes. Open up `style.css` and change the +`h1` element to: + +``` nt +h1 { + font-size: 32px; + font-family: "Times New Roman", serif; +} +``` + +Now let's say we had to make an emergency fix to our project. We don't +want to commit an unfinished feature, and we also don't want to lose our +current CSS addition. The solution is to temporarily remove these +changes with the `git stash` command: + +``` k +git status +git stash +git status +``` + +Before the stash, `style.css` was listed as "Changed by not updated." +The `git stash` command hid these changes, giving us a clean working +directory. We're now able to switch to a new hotfix branch to make our +important updates---without having to commit a meaningless snapshot just +to save our current state. + +Let's pretend we've completed our emergency update and we're ready to +continue working on our CSS changes. We can retrieve our stashed content +with the following command. + +``` k +git stash apply +``` + +The `style.css` file now looks the same as it did before the stash, and +we can continue development as if we were never interrupted. Whereas +patches represent a committed snapshot, a stash represents a set of +*un*committed changes. It takes the uncommitted modifications, stores +them internally, then does a `git reset --hard` to give us a clean +working directory. This also means that stashes can be applied to *any* +branch, not just the one from which it was created. + +In addition to temporarily storing uncommitted changes, this makes +stashing a simple way to transfer modifications between branches. So, +for example, if you ever found yourself developing on the wrong branch, +you could stash all your changes, checkout the correct branch, then run +a `git stash apply`. + +Let's undo these CSS updates before moving on. + +``` k +git reset --hard +``` + +## Hook into Git's Internals {#tips-and-tricks.xhtml_hook-into-gits-internals} + +Arguably, Git's most useful configuration options are its **hooks**. A +hook is a script that Git executes every time a particular event occurs +in a repository. In this section, we'll take a hands-on look at Git +hooks by automatically publishing our website every time someone pushes +to the `central-repo.git` repository. + +In the `central-repo.git` directory, open the `hooks` directory and +rename the file `post-update.sample` to `post-update`. After removing +the `.sample` extension, this script will be executed whenever *any* +branch gets pushed to `central-repo.git`. Replace the default contents +of `post-update` with the following. + +``` c +#!/bin/sh + +# Output a friendly message +echo "Publishing master branch!" >&2 + +# Remove the old `my-website` directory (if necessary) +rm -rf ../my-website + +# Create a new `my-website` directory +mkdir ../my-website + +# Archive the `master` branch +git archive master --format=tar --output=../my-website.tar + +# Uncompress the archive into the `my-website` directory +tar -xf ../my-website.tar -C ../my-website + +exit 0 +``` + +While shell scripts are outside the scope of this tutorial, the majority +of commands in the above code listing should be familiar to you. In +short, this new `post-update` script creates an archive of the `master` +branch, then exports it into a directory called `my-website`. This is +our "live" website. + +We can see the script in action by pushing a branch to the +`central-repo.git` repository. + +``` k +git push ../central-repo.git master +``` + +After the central repository receives the new `master` branch, our +`post-update` script is executed. You should see the +`Publishing master branch!` message echoed from the script, along with a +new `my-website` folder in the same directory as `my-git-repo`. You can +open `index.html` in a web browser to verify that it contains all the +files from our `master` branch, and you can also see the intermediate +`.tar` archive produced by the hook. + +This is a simple, unoptimized example, but Git hooks are infinitely +versatile. Each of the `.sample` scripts in the `hooks` directory +represents a different event that you can listen for, and each of them +can do anything from automatically creating and publishing releases to +enforcing a commit policy, making sure a project compiles, and of +course, publishing websites (that means no more clunky FTP uploads). +Hooks are even configured on a per-repository basis, which means you can +run different scripts in your local repository than your central +repository. + +For a detailed description of the available hooks, please consult the +[official Git +documentation](http://www.kernel.org/pub/software/scm/git/docs/githooks.html). + +## View Diffs Between Commits {#tips-and-tricks.xhtml_view-diffs-between-commits} + +Up until now, we've been using `git log --stat` to view the changes +introduced by new commits. However, this doesn't show us which lines +have been changed in any given file. For this level of detail, we need +the `git diff` command. Let's take a look at the updates from the +`Add a pink block of color` commit: + +``` k +git diff HEAD~2..HEAD~1 +``` + +This will output the diff between the `Add a pink block of color` commit +(`HEAD~1`) and the one before it (`HEAD~2`): + +``` gh +index 828dd1a..2713b10 100644 +--- a/pink.html ++++ b/pink.html +@@ -4,10 +4,17 @@ + The Pink Page + + ++ + + +

    The Pink Page

    +

    Only real men wear pink!

    ++
    + +

    Return to home page

    + +``` + +This diff looks nearly identical to the patches we created in the +previous module, and it shows exactly what was added to get from +`HEAD~2` to `HEAD~1`. The `git diff` command is incredibly useful for +pinpointing contributions from other developers. For example, we could +have used the following to view the differences between John's +`pink-page` branch and our `master` before merging it into the project +in [Distributed Workflows](#distributed-workflows.xhtml). + +``` k +git diff master..john/pink-page +``` + +This flexible command can also generate a detailed view of our +uncommitted changes. Open up `blue.html`, make any kind of change, and +save the file. Then, run `git diff` without any arguments: + +``` k +git diff +``` + +And, just in case we forgot what was added to the staging area, we can +use the `--cached` flag to generate a diff between the staged snapshot +and the most recent commit: + +``` k +git add blue.html +git diff --cached +``` + +A plain old `git diff` won't output anything after `blue.html` is added +to the staging area, but the changes are now visible through the +`‑‑cached` flag. These are the three main configurations of the +`git diff` command. + +## Reset and Checkout Files {#tips-and-tricks.xhtml_reset-and-checkout-files} + +We've used `git reset` and `git checkout` many times throughout this +tutorial; however, we've only seen them work with branches/commits. You +can also reset and check out individual files, which slightly alters the +behavior of both commands. + +The `git reset` we're accustomed to moves the current branch to a new +commit and optionally updates the working directory to match. But when +we pass a file path, `git reset` updates the *staging area* to match the +given commit instead of the working directory, and it doesn't move the +current branch pointer. This means we can remove `blue.html` from the +staged snapshot with the following command. + +``` k +git reset HEAD blue.html +git status +``` + +This makes the `blue.html` in the staging area match the version stored +in `HEAD`, but it leaves the working directory and current branch alone. +The result is a staging area that matches the most recent commit and a +working directory that contains the modified `blue.html` file. In other +words, this type of `git reset` can be used to unstage a file: + +![Using `git reset` with a file path](media/11-1.png) + +Let's take this one step further with `git checkout`. The `git checkout` +we've been using updates the working directory *and* switches branches. +If we add a file path to `git checkout`, it narrows its focus to only +the specified file and does *not* update the branch pointer. This means +that we can "check out" the most recent version of `blue.html` with the +following command. + +``` k +git checkout HEAD blue.html +git status +``` + +Our `blue.html` file now looks exactly like the version stored in +`HEAD`, and we thus have a clean working directory. Passing a file path +to `git checkout` reverts that file to the specified commit. + +![Using `git checkout` with a file path](media/11-2.png) + +To summarize the file-path behavior of `git reset` and `git checkout`, +both take a committed snapshot as an reference point and make a file in +the staging area or the working directory match that reference, +respectively. + +## Aliases and Other Configurations {#tips-and-tricks.xhtml_aliases-and-other-configurations} + +Typing `git checkout` every time you wanted to see a new branch over the +last ten modules has been a bit verbose. Fortunately, Git lets you +create **aliases**, which are shortcuts to other commands. Let's create +a few aliases for our most common commands: + +``` k +git config --global alias.co checkout +git config --global alias.ci commit +git config --global alias.br branch +``` + +Now, we can use `git co` instead of `git checkout`, `git ci` for +committing, and `git br` for listing branches. We can even use +`git br ` for creating a new branch. + +Git stores these aliases in a global config file, similar to the local +config file we looked at in Mary's repository +(`marys-repo/.git/config`). By default, global configurations reside in +`~/.gitconfig`, where the `~` character represents your home directory. +This file should resemble the following. + + [user] + name = Ryan + email = ryan.example@rypress.com + [alias] + co = checkout + ci = commit + br = branch + +Of course, your settings should reflect the name and email you entered +in [The Basics](#the-basics.xhtml). As you can see, all of our new +aliases are also stored in `.gitconfig`. Let's add a few more useful +configurations by modifying this file directly. Append the following to +`.gitconfig`. + + [color] + status = always + [core] + editor = gvim + +This makes sure Git colorizes the output of `git status` and that it +uses the gVim text editor for creating commit messages. To use a +different editor, simply change `gvim` to the command that opens your +editor. For example, Emacs users would use `emacs`, and Notepad users +would use `notepad.exe`. + +Git includes a long list of configuration options, all of which can be +found in the [official +manual](http://www.kernel.org/pub/software/scm/git/docs/git-config.html). +Note that storing your global configurations in a plaintext file makes +it incredibly easy to transfer your settings to a new Git installation: +just copy `~/.gitconfig` onto your new machine. + +## Conclusion {#tips-and-tricks.xhtml_conclusion} + +In this module, we learned how to export snapshots, backup repositories, +ignore files, stash temporary changes, hook into Git's internals, +generate diffs, reset individual files, and create shorter aliases for +common commands. While it's impossible to cover all of Git's supporting +features in a hands-on guide such as this, I hope that you now have a +clearer picture of Git's numerous capabilities. + +With all of these convenient features, it's easy to get so caught up in +designing the perfect workflow that you lose sight of Git's underlying +purpose. As you add new commands to your repertoire, remember that Git +should always make it *easier* to develop a software project---never +harder. If you ever find that Git is causing more harm than good, don't +be scared to drop some of the advanced features and go back to the +basics. + +The final module will go a long way towards helping you realize the full +potential of Git's version control model. We'll explore Git's internal +database by manually inspecting and creating snapshots. Equipped with +this low-level knowledge, you'll be more than ready to venture out into +the reality of Git-based project management. + +## Quick Reference {#tips-and-tricks.xhtml_quick-reference} + +`git archive --format=zip --output=` +: Export a single snapshot to a ZIP archive called ``. + +`git bundle create ` +: Export an entire branch, complete with history, to the specified + file. + +`git clone repo.bundle -b ` +: Re-create a project from a bundled repository and checkout + ``. + +`git stash` +: Temporarily stash changes to create a clean working directory. + +`git stash apply` +: Re-apply stashed changes to the working directory. + +`git diff ..` +: View the difference between two commits. + +`git diff` +: View the difference between the working directory and the staging + area. + +`git diff --cached` +: View the difference between the staging area and the most recent + commit. + +`git reset HEAD ` +: Unstage a file, but don't alter the working directory or move the + current branch. + +`git checkout ` +: Revert an individual file to match the specified commit without + switching branches. + +`git config --global alias. ` +: Create a shortcut for a command and store it in the global + configuration file. +::::: +:::::: + +[]{#plumbing.xhtml} + +:::::: {#plumbing.xhtml_page} +::::: {#plumbing.xhtml_content} +# Plumbing {#plumbing.xhtml_plumbing} + +In [Rewriting History](#rewriting-history.xhtml), I talked about the +internal representation of a Git repository. I may have mislead you a +bit. While the reflog, interactive rebasing, and resetting may be more +complex features of Git, they are still considered part of the +**porcelain**, as is every other command we've covered. In this module, +we'll take a look at Git's **plumbing**---the low-level commands that +give us access to Git's *true* internal representation of a project. + +Unless you start hacking on Git's source code, you'll probably never +need to use the plumbing commands presented below. But, manually +manipulating a repository will fill in the conceptual details of how Git +actually stores your data, and you should walk away with a much better +understanding of the techniques that we've been using throughout this +tutorial. In turn, this knowledge will make the familiar porcelain +commands even more powerful. + +We'll start by inspecting Git's object database, then we'll manually +create and commit a snapshot using only Git's low-level interface. + +::: {.icon-text .download-icon-text} +![](media/icons/download.png){style="max-width: 45px"} + +[Download the repository for this +module](http://rypress.com/tutorials/git/media/repo-zips/plumbing.zip) +::: + +::: {style="clear: both"} +::: + +If you've been following along from the previous module, you already +have everything you need. Otherwise, download the zipped Git repository +from the above link, uncompress it, and you're good to go. + +## Examine Commit Details {#plumbing.xhtml_examine-commit-details} + +First, let's take a closer look at our latest commit with the +`git cat-file` plumbing command. + +``` k +git cat-file commit HEAD +``` + +The `commit` parameter tells Git that we want to see a commit object, +and as we already know, `HEAD` refers to the most recent commit. This +will output the following, although your IDs and user information will +be different. + + tree 552acd444696ccb1c3afe68a55ae8b20ece2b0e6 + parent 6a1d380780a83ef5f49523777c5e8d801b7b9ba2 + author Ryan 1326496982 -0600 + committer Ryan 1326496982 -0600 + + Add .gitignore file + +This is the complete representation of a commit: a tree, a parent, user +data, and a commit message. The user information and commit message are +relatively straightforward, but we've never seen the *tree* or *parent* +values before. + +A **tree object** is Git's representation of the "snapshots" we've been +talking about since the beginning of this tutorial. They record the +state of a directory at a given point, without any notion of time or +author. To tie trees together into a coherent project history, Git wraps +each one in a **commit object** and specifies a **parent**, which is +just another commit. By following the parent of each commit, you can +walk through the entire history of a project. + +![Commit and tree objects](media/12-1.png) + +Notice that each commit refers to one and only one tree object. From the +`git cat-file` output, we can also infer that trees use SHA-1 checksums +for their ID's. This will be the case for all of Git's internal objects. + +## Examine a Tree {#plumbing.xhtml_examine-a-tree} + +Next, let's try to inspect a tree using the same `git cat-file` command. +Make sure to change `552acd4` to the ID of your tree from the previous +step. + +``` k +git cat-file tree 552acd4 +``` + +Unfortunately, trees contain binary data, which is quite ugly when +displayed in its raw form. So, Git offers another useful plumbing +command: + +``` k +git ls-tree 552acd4 +``` + +This will output the contents of the tree, which looks an awful lot like +a directory listing: + + 100644 blob 99ed0d431c5a19f147da3c4cb8421b5566600449 .gitignore + 040000 tree ab4947cb27ef8731f7a54660655afaedaf45444d about + 100644 blob cefb5a651557e135666af4c07c7f2ab4b8124bd7 blue.html + 100644 blob cb01ae23932fd9704fdc5e077bc3c1184e1af6b9 green.html + 100644 blob e993e5fa85a436b2bb05b6a8018e81f8e8864a24 index.html + 100644 blob 2a6deedee35cc59a83b1d978b0b8b7963e8298e9 news-1.html + 100644 blob 0171687fc1b23aa56c24c54168cdebaefecf7d71 news-2.html + ... + +By examining the above output, we can presume that "blobs" represent +files in our repository, whereas trees represent folders. Go ahead and +examine the `about` tree with another `git ls-tree` to see if this +really is the case. You should see the contents of our `about` folder. + +So, **blob objects** are how Git stores our file data, tree objects +combine blobs and other trees into a directory listing, then commit +objects tie trees into a project history. These are the only types of +objects that Git needs to implement nearly all of the porcelain commands +we've been using, and their relationship is summed up as follows: + +![Commit, tree, and blob objects](media/12-2.png) + +## Examine a Blob {#plumbing.xhtml_examine-a-blob} + +Let's take a look at the blob associated with `blue.html` (be sure to +change the following to the ID next to `blue.html` in *your* tree +output). + +``` k +git cat-file blob cefb5a6 +``` + +This should display the entire contents of `blue.html`, confirming that +blobs really are plain data files. Note that blobs are pure content: +there is no mention of a filename in the above output. That is to say, +the name `blue.html` is stored in the *tree that contains the blob*, not +the blob itself. + +You may recall from [The Basics](#the-basics.xhtml) that an SHA-1 +checksum ensures an object's contents is never corrupted without Git +knowing about it. Checksums work by using the object's contents to +generate a unique character sequence. This not only functions as an +identifier, it also guarantees that an object won't be silently +corrupted (the altered content would generate a different ID). + +When it comes to blob objects, this has an additional benefit. Since two +blobs with the same data will have the same ID, Git *must* share blobs +across multiple trees. For example, our `blue.html` file hasn't been +changed since it was created, so our repository will only have a single +associated blob, and all subsequent trees will refer to it. By not +creating duplicate blobs for each tree object, Git vastly reduces the +size of a repository. With this in mind, we can revise our Git object +diagram to the following. + +![Commit, tree, and shared blob objects](media/12-3.png) + +However, as soon as you change a single line in a file, Git must create +a new blob object because its contents will have changed, resulting in a +new SHA-1 checksum. + +## Examine a Tag {#plumbing.xhtml_examine-a-tag} + +The fourth and final type of Git object is the **tag object** We can use +the same `git cat-file` command to show the details of a tag. + +``` k +git cat-file tag v2.0 +``` + +This will output the commit ID associated with `v2.0`, along with the +tag's name, author, creation date, and message. The straightforward +relationship between tags and commits gives us our finalized Git object +diagram: + +![Commit, tree, blob, and tag objects](media/12-4.png) + +## Inspect Git's Branch Representation {#plumbing.xhtml_inspect-gits-branch-representation} + +We now have the tools to fully explore Git's branch representation. +Using the `-t` flag, we can determine what kind of object Git uses for +branches. + +``` k +git cat-file -t master +``` + +That's right, a branch is just a reference to a commit object, which +means we can view it with a normal `git cat-file`. + +``` k +git cat-file commit master +``` + +This will output the exact same information as our original +`git cat-file commit HEAD`. It seems that both the `master` branch and +`HEAD` are simply references to a commit object. + +Using a text editor, open up the `.git/refs/heads/master` file. You +should find the commit checksum of the most recent commit, which you can +view with `git log -n 1`. This single file is all Git needs to maintain +the `master` branch---all other information is extrapolated through the +commit object relationships discussed above. + +The `HEAD` reference, on the other hand, is recorded in `.git/HEAD`. +Unlike the branch tips, `HEAD` is not a direct link to a commit. +Instead, it refers to a branch, which Git uses to figure out which +commit is currently checked out. Remember that a `detached HEAD` state +occurred when `HEAD` did not coincide with the tip of any branch. +Internally, all this means to Git is that `.git/HEAD` doesn't contain a +local branch. Try checking out an old commit: + +``` k +git checkout HEAD~1 +``` + +Now, `.git/HEAD` should contain a commit ID instead of a branch. This +tells Git that we're in a `detached HEAD` state. Regardless of what +state you're in, the `git checkout` command will always record the +checked-out reference in `.git/HEAD`. + +Let's get back to our `master` branch before moving on: + +``` k +git checkout master +``` + +## Explore the Object Database {#plumbing.xhtml_explore-the-object-database} + +While we have a basic understanding of Git's object interaction, we have +yet to explore where Git keeps all of these objects. In your +`my-git-repo` repository, open the folder `.git/objects`. This is Git's +object database. + +Each object, regardless of type, is stored as a file, using its SHA-1 +checksum as the filename (sort of). But, instead of storing all objects +in a single folder, they are split up using the first two characters of +their ID as a directory name, resulting in an object database that looks +something like the following. + + 00 10 28 33 3e 51 5c 6e 77 85 95 f7 + 01 11 29 34 3f 52 5e 6f 79 86 96 f8 + 02 16 2a 35 41 53 63 70 7a 87 98 f9 + 03 1c 2b 36 42 54 64 71 7c 88 99 fa + 0c 26 30 3c 4e 5a 6a 75 83 91 a0 info + 0e 27 31 3d 50 5b 6b 76 84 93 a2 pack + +For example, an object with the following ID: + + 7a52bb857229f89bffa74134ee3de48e5e146105 + +is stored in a folder called `7a`, using the remaining characters +(`52bb8...`) as a filename. This gives us an object ID, but before we +can inspect items in the object database, we need to know what type of +object it is. Again, we can use the `-t` flag: + +``` k +git cat-file -t 7a52bb8 +``` + +Of course, change the object ID to an object from *your* database (don't +forget to combine the folder name with the filename to get the full ID). +This will output the type of commit, which we can then pass to a normal +call to `git cat-file`. + +``` k +git cat-file blob 7a52bb8 +``` + +My object was a blob, but yours may be different. If it's a tree, +remember to use `git ls-tree` to turn that ugly binary data into a +pretty directory listing. + +## Collect the Garbage {#plumbing.xhtml_collect-the-garbage} + +As your repository grows, Git may automatically transfer your object +files into a more compact form know as a "pack" file. You can force this +compression with the garbage collection command, but beware: this +command is undo-able. If you want to continue exploring the contents of +the `.git/objects` folder, you should do so before running the following +command. Normal Git functionality will not be affected. + +``` k +git gc +``` + +This compresses individual object files into a faster, smaller pack file +and removes dangling commits (e.g., from a deleted, unmerged branch). + +Of course, all of the same object ID's will still work with +`git cat-file`, and all of the porcelain commands will remain +unaffected. The `git gc` command only changes Git's storage +mechanism---not the contents of a repository. Running `git gc` every now +and then is usually a good idea, as it keeps your repository optimized. + +## Add Files to the Index {#plumbing.xhtml_add-files-to-the-index} + +Thus far, we've been discussing Git's low-level representation of +committed snapshots. The rest of this module will shift gears and use +more "plumbing" commands to manually prepare and commit a new snapshot. +This will give us an idea of how Git manages the working directory and +the staging area. + +Create a new file called `news-4.html` in `my-git-repo` and add the +following HTML. + +``` cp + + + + Indigo Invasion + + + + +

    Indigo Invasion

    +

    Last week, a coalition of Asian designers, artists, + and advertisers announced the official color of Asia: + Indigo.

    + +

    Return to home page

    + + +``` + +Then, update the `index.html` "News" section to match the following. + +``` nt +

    News

    + +``` + +Instead of `git add`, we'll use the low-level `git update-index` command +to add files to the staging area. The **index** is Git's term for the +staged snapshot. + +``` k +git status +git update-index index.html +git update-index news-4.html +``` + +The last command will throw an error---Git won't let you add a new file +to the index without explicitly stating that it's a new file: + +``` k +git update-index --add news-4.html +git status +``` + +We've just moved the working directory into the index, which means we +have a snapshot prepared for committal. However, the process won't be +quite as simple as a mere `git commit`. + +## Store the Index in the Database {#plumbing.xhtml_store-the-index-in-the-database} + +Remember that all commits refer to a tree object, which represents the +snapshot for that commit. So, before creating a commit object, we need +to add our index (the staged tree) to Git's object database. We can do +this with the following command. + +``` k +git write-tree +``` + +This command creates a tree object from the index and stores it in +`.git/objects`. It will output the ID of the resulting tree (yours may +be different): + + 5f44809ed995e5b861acf309022ab814ceaaafd6 + +You can examine your new snapshot with `git ls-tree`. Keep in mind that +the only new blobs created for this commit were `index.html` and +`news-4.html`. The rest of the tree contains references to existing +blobs. + +``` k +git ls-tree 5f44809 +``` + +So, we have our tree object, but we have yet to add it to the project +history. + +## Create a Commit Object {#plumbing.xhtml_create-a-commit-object} + +To commit the new tree object, we need to manually figure out the ID of +the parent commit. + +``` k +git log --oneline -n 1 +``` + +This will output the following line, though your commit ID will be +different. We'll use this ID to specify the parent of our new commit +object. + +``` s +3329762 Add .gitignore file +``` + +The `git commit-tree` command creates a commit object from a tree and a +parent ID, while the author information is taken from an environment +variable set by Git. Make sure to change `5f44809` to your tree ID, and +`3329762` to your most recent commit ID. + +``` k +git commit-tree 5f44809 -p 3329762 +``` + +This command will wait for more input: the commit message. Type +`Add 4th news item` and press `Enter` to create the commit message, then +`Ctrl-Z` and `Enter` for Windows or `Ctrl-D` for Unix to specify an +"End-of-file" character to end the input. Like the `git write-tree` +command, this will output the ID of the resulting commit object. + + c51dc1b3515f9f8e80536aa7acb3d17d0400b0b5 + +You'll now be able to find this commit in `.git/objects`, but neither +`HEAD` nor the branches have been updated to include this commit. It's a +*dangling commit* at this point. Fortunately for us, we know where Git +stores its branch information. + +![Creating a dangling commit](media/12-5.png) + +## Update HEAD {#plumbing.xhtml_update-head} + +Since we're not in a `detached HEAD` state, `HEAD` is a reference to a +branch. So, all we need to do to update `HEAD` is move the `master` +branch forward to our new commit object. Using a text editor, replace +the contents of `.git/refs/heads/master` with the output from +`git commit-tree` in the previous step. + +If this file seems to have disappeared, don't fret! This just means that +the `git gc` command packed up all of our branch references into single +file. Instead of `.git/refs/heads/master`, open up `.git/packed-refs`, +find the line with `refs/heads/master`, and change the ID to the left of +it. + +Now that our `master` branch points to the new commit, we should be able +to see the `news-4.html` file in the project history. + +``` k +git log -n 2 +``` + +The last four sections explain everything that happens behind the scenes +when we execute `git commit -a -m "Some Message"`. Aren't you glad you +won't have to use Git's plumbing ever again? + +![Manually updating the `master` branch](media/12-6.png) + +## Conclusion {#plumbing.xhtml_conclusion} + +After this module, you hopefully have a solid grasp of the object +database that underlies almost every Git command. We examined commits, +trees, blobs, tags, and branches, and we even created a commit object +from scratch. All of this was meant to give you a deeper understanding +of Git's porcelain commands, and you should now feel ready to adapt Git +to virtually any task you could possibly demand from a version control +system. + +As you migrate these skills to real-world projects, remember that Git is +merely a tool for tracking your files, not a cure-all for managing +software projects. No amount of intimate Git knowledge can make up for a +haphazard set of conventions within a development team. + +Thus concludes our journey through Git-based revision control. This +tutorial was meant to prepare you for the realities of distributed +software development---not to transform you into a Git expert overnight. +You should be able to manage your own projects, collaborate with other +Git users, and, perhaps most importantly, understand exactly what any +other piece of Git documentation is trying to convey. + +Your job now is to take these skills and apply them to new projects, +sift through complex histories that you've never seen before, talk to +other developers about their Git workflows, and take the time to +actually try all of those "I wonder what would have happened if..." +scenarios. Good luck! + +For questions, comments, or suggestions, please [contact +us](http://rypress.com/about). + +## Quick Reference {#plumbing.xhtml_quick-reference} + +`git cat-file ` +: Display the specified object, where `` is one of `commit`, + `tree`, `blob`, or `tag`. + +`git cat-file -t ` +: Output the type of the specified object. + +`git ls-tree ` +: Display a pretty version of the specified tree object. + +`git gc` +: Perform a garbage collection on the object database. + +`git update-index [--add] ` +: Stage the specified file, using the optional `--add` flag to denote + a new untracked file. + +`git write-tree` +: Generate a tree from the index and store it in the object database. + Returns the ID of the new tree object. + +`git commit-tree -p ` +: Create a new commit object from the given tree object and parent + commit. Returns the ID of the new commit object. +::::: +::::::