diff --git a/book/01-introduction/1-introduction.asc b/book/01-introduction/1-introduction.asc index e2d38460d..a808aa90b 100644 --- a/book/01-introduction/1-introduction.asc +++ b/book/01-introduction/1-introduction.asc @@ -5,8 +5,9 @@ This chapter will be about getting started with Git. We will begin at the beginning by explaining some background on version control tools, then move on to how to get Git running on your system and finally how to get it setup to start working with. At the end of this chapter you should understand why Git is around, why you should use it and you should be all setup to do so. -=== About Version Control (((version control))) +=== About Version Control +(((version control))) What is "version control", and why should you care? Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. For the examples in this book you will use software source code as the files being version controlled, though in reality you can do this with nearly any type of file on a computer. @@ -16,8 +17,9 @@ It allows you to revert files back to a previous state, revert the entire projec Using a VCS also generally means that if you screw things up or lose files, you can easily recover. In addition, you get all this for very little overhead. -==== Local Version Control Systems (((version control,local version control))) +==== Local Version Control Systems +(((version control,local))) Many people’s version-control method of choice is to copy files into another directory (perhaps a time-stamped directory, if they’re clever). This approach is very common because it is so simple, but it is also incredibly error prone. It is easy to forget which directory you’re in and accidentally write to the wrong file or copy over files you don’t mean to. @@ -31,8 +33,9 @@ One of the more popular VCS tools was a system called RCS, which is still distri Even the popular Mac OS X operating system includes the `rcs` command when you install the Developer Tools. RCS works by keeping patch sets (that is, the differences between files) in a special format on disk; it can then re-create what any file looked like at any point in time by adding up all the patches. -==== Centralized Version Control Systems (((version control,centralized version control))) +==== Centralized Version Control Systems +(((version control,centralized))) The next major issue that people encounter is that they need to collaborate with developers on other systems. To deal with this problem, Centralized Version Control Systems (CVCSs) were developed. These systems, such as CVS, Subversion, and Perforce, have a single server that contains all the versioned files, and a number of clients that check out files from that central place. (((CVS)))(((Subversion)))(((Perforce))) @@ -51,8 +54,9 @@ If that server goes down for an hour, then during that hour nobody can collabora If the hard disk the central database is on becomes corrupted, and proper backups haven’t been kept, you lose absolutely everything – the entire history of the project except whatever single snapshots people happen to have on their local machines. Local VCS systems suffer from this same problem – whenever you have the entire history of the project in a single place, you risk losing everything. -==== Distributed Version Control Systems (((version control,distributed version control))) +==== Distributed Version Control Systems +(((version control,distributed))) This is where Distributed Version Control Systems (DVCSs) step in. In a DVCS (such as Git, Mercurial, Bazaar or Darcs), clients don’t just check out the latest snapshot of the files: they fully mirror the repository. Thus if any server dies, and these systems were collaborating via it, any of the client repositories can be copied back up to the server to restore it. @@ -80,7 +84,7 @@ Some of the goals of the new system were as follows: * Simple design * Strong support for non-linear development (thousands of parallel branches) * Fully distributed -* Able to handle large projects like the Linux kernel efficiently (speed and data size)(((Linux))) +* Able to handle large projects like the Linux kernel efficiently (speed and data size) Since its birth in 2005, Git has evolved and matured to be easy to use and yet retain these initial qualities. It’s incredibly fast, it’s very efficient with large projects, and it has an incredible branching system for non-linear development (See <<_git_branching>>). @@ -209,8 +213,9 @@ Before you start using Git, you have to make it available on your computer. Even if it's already installed, it's probably a good idea to update to the latest version. You can either install it as a package or via another installer, or download the source code and compile it yourself. -==== Installing on Linux(((Linux, installing))) +==== Installing on Linux +(((Linux, installing))) If you want to install Git on Linux via a binary installer, you can generally do so through the basic package-management tool that comes with your distribution. If you’re on Fedora for example, you can use yum: @@ -222,8 +227,9 @@ If you’re on a Debian-based distribution like Ubuntu, try apt-get: For more options, there are instructions for installing on several different Unix flavors on the Git website, at http://git-scm.com/download/linux[]. -==== Installing on Mac(((Mac, installing))) +==== Installing on Mac +(((Mac, installing))) There are several ways to install Git on a Mac. The easiest is probably to install the Xcode Command Line Tools.(((Xcode))) On Mavericks (10.9) or above you can do this simply by trying to run 'git' from the Terminal the very first time. @@ -248,7 +254,7 @@ Note that this is a project called Git for Windows (also called msysGit), which Another easy way to get Git installed is by installing GitHub for Windows. The installer includes a command line version of Git as well as the GUI. -It also works well with Powershell, and sets up solid credential caching and sane CRLF settings. +It also works well with Powershell, and sets up solid credential caching and sane CRLF settings.((Powershell))((CRLF))((credential caching)) We'll learn more about those things a little later, but suffice it to say they're things you want. ==== Installing from Source @@ -289,7 +295,7 @@ Now that you have Git on your system, you’ll want to do a few things to custom You should have to do these things only once on any given computer; they’ll stick around between upgrades. You can also change them at any time by running through the commands again. -Git comes with a tool called `git config` that lets you get and set configuration variables that control all aspects of how Git looks and operates.(((git, config))) +Git comes with a tool called `git config` that lets you get and set configuration variables that control all aspects of how Git looks and operates.(((git commands, config))) These variables can be stored in three different places: 1. `/etc/gitconfig` file: Contains values for every user on the system and all their repositories. @@ -345,7 +351,7 @@ If you want to check your settings, you can use the `git config --list` command You may see keys more than once, because Git reads the same key from different files (`/etc/gitconfig` and `~/.gitconfig`, for example). In this case, Git uses the last value for each unique key it sees. -You can also check what Git thinks a specific key’s value is by typing `git config `:(((git, config))) +You can also check what Git thinks a specific key’s value is by typing `git config `:(((git commands, config))) $ git config user.name John Doe @@ -358,7 +364,7 @@ If you ever need help while using Git, there are three ways to get the manual pa $ git --help $ man git- -For example, you can get the manpage help for the config command by running(((git, help))) +For example, you can get the manpage help for the config command by running(((git commands, help))) $ git help config diff --git a/book/02-git-basics/1-git-basics.asc b/book/02-git-basics/1-git-basics.asc index 35ceda89d..395bdf682 100644 --- a/book/02-git-basics/1-git-basics.asc +++ b/book/02-git-basics/1-git-basics.asc @@ -23,7 +23,7 @@ $ git init This creates a new subdirectory named `.git` that contains all of your necessary repository files – a Git repository skeleton. At this point, nothing in your project is tracked yet. -(See <<_git_internals>> for more information about exactly what files are contained in the `.git` directory you just created.) +(See <<_git_internals>> for more information about exactly what files are contained in the `.git` directory you just created.)(((git commands, init))) If you want to start version-controlling existing files (as opposed to an empty directory), you should probably begin tracking those files and do an initial commit. You can accomplish that with a few `git add` commands that specify the files you want to track, followed by a `git commit`: @@ -46,7 +46,7 @@ This is an important distinction – instead of getting just a working copy, Git Every version of every file for the history of the project is pulled down by default when you run `git clone`. In fact, if your server disk gets corrupted, you can often use nearly any of the clones on any client to set the server back to the state it was in when it was cloned (you may lose some server-side hooks and such, but all the versioned data would be there – see <<_git_on_the_server>> for more details). -You clone a repository with `git clone [url]`. +You clone a repository with `git clone [url]`.(((git commands, clone))) For example, if you want to clone the Git linkable library called libgit2, you can do so like this: [source,shell] @@ -87,7 +87,7 @@ image::images/lifecycle.png[The lifecycle of the status of your files.] ==== Checking the Status of Your Files -The main tool you use to determine which files are in which state is the `git status` command.(((git, status))) +The main tool you use to determine which files are in which state is the `git status` command.(((git commands, status))) If you run this command directly after a clone, you should see something like this: [source,shell] @@ -126,7 +126,7 @@ You do want to start including README, so let’s start tracking the file. ==== Tracking New Files -In order to begin tracking a new file, you use the command `git add`.(((git, add))) +In order to begin tracking a new file, you use the command `git add`.(((git commands, add))) To begin tracking the README file, you can run this: [source,shell] @@ -149,7 +149,7 @@ Changes to be committed: You can tell that it’s staged because it’s under the ``Changes to be committed'' heading. If you commit at this point, the version of the file at the time you ran `git add` is what will be in the historical snapshot. -You may recall that when you ran `git init` earlier, you then ran `git add (files)` – that was to begin tracking files in your directory.(((git, init)))(((git, add))) +You may recall that when you ran `git init` earlier, you then ran `git add (files)` – that was to begin tracking files in your directory.(((git commands, init)))(((git commands, add))) The `git add` command takes a path name for either a file or a directory; if it’s a directory, the command adds all the files in that directory recursively. ==== Staging Modified Files @@ -175,7 +175,7 @@ Changes not staged for commit: ---- The ``benchmarks.rb'' file appears under a section named ``Changed but not staged for commit'' – which means that a file that is tracked has been modified in the working directory but not yet staged. -To stage it, you run the `git add` command. `git add` is a multipurpose command – you use it to begin tracking new files, to stage files, and to do other things like marking merge-conflicted files as resolved. It may be helpful to think of it more as ``add this content to the next commit'' rather than ``add this file to the project''. +To stage it, you run the `git add` command. `git add` is a multipurpose command – you use it to begin tracking new files, to stage files, and to do other things like marking merge-conflicted files as resolved. It may be helpful to think of it more as ``add this content to the next commit'' rather than ``add this file to the project''.(((git commands, add))) Let’s run `git add` now to stage the ``benchmarks.rb'' file, and then run `git status` again: [source,shell] @@ -254,7 +254,7 @@ New files that aren't tracked have a `??` next to them, new files that have been Often, you’ll have a class of files that you don’t want Git to automatically add or even show you as being untracked. These are generally automatically generated files such as log files or files produced by your build system. -In such cases, you can create a file listing patterns to match them named `.gitignore`. +In such cases, you can create a file listing patterns to match them named `.gitignore`.(((ignoring files))) Here is an example `.gitignore` file: [source,shell] @@ -299,7 +299,7 @@ GitHub maintains a fairly comprehensive list of good `.gitignore` file examples ==== Viewing Your Staged and Unstaged Changes -If the `git status` command is too vague for you – you want to know exactly what you changed, not just which files were changed – you can use the `git diff` command. +If the `git status` command is too vague for you – you want to know exactly what you changed, not just which files were changed – you can use the `git diff` command.(((git commands, diff))) We’ll cover `git diff` in more detail later, but you’ll probably use it most often to answer these two questions: What have you changed but not yet staged? And what have you staged that you are about to commit? Although `git status` answers those questions very generally by listing the file names, `git diff` shows you the exact lines added and removed – the patch, as it were. @@ -432,8 +432,8 @@ index 3cb747f..e445e28 100644 Now that your staging area is set up the way you want it, you can commit your changes. Remember that anything that is still unstaged – any files you have created or modified that you haven’t run `git add` on since you edited them – won’t go into this commit. They will stay as modified files on your disk. -In this case, the last time you ran `git status`, you saw that everything was staged, so you’re ready to commit your changes.(((git, status))) -The simplest way to commit is to type `git commit`:(((git, commit))) +In this case, the last time you ran `git status`, you saw that everything was staged, so you’re ready to commit your changes.(((git commands, status))) +The simplest way to commit is to type `git commit`:(((git commands, commit))) [source,shell] ---- @@ -441,7 +441,7 @@ $ git commit ---- Doing so launches your editor of choice. -(This is set by your shell’s `$EDITOR` environment variable – usually vim or emacs, although you can configure it with whatever you want using the `git config --global core.editor` command as you saw in <<_getting_started>>). +(This is set by your shell’s `$EDITOR` environment variable – usually vim or emacs, although you can configure it with whatever you want using the `git config --global core.editor` command as you saw in <<_getting_started>>).(((editor, changing default)))(((git commands, config))) The editor displays the following text (this example is a Vim screen): @@ -486,6 +486,7 @@ Every time you perform a commit, you’re recording a snapshot of your project t ==== Skipping the Staging Area +(((staging area, skipping))) Although it can be amazingly useful for crafting commits exactly how you want them, the staging area is sometimes a bit more complex than you need in your workflow. If you want to skip the staging area, Git provides a simple shortcut. Adding the `-a` option to the `git commit` command makes Git automatically stage every file that is already tracked before doing the commit, letting you skip the `git add` part: @@ -510,6 +511,7 @@ Notice how you don’t have to run `git add` on the ``benchmarks.rb'' file in th ==== Removing Files +(((files, removing))) To remove a file from Git, you have to remove it from your tracked files (more accurately, remove it from your staging area) and then commit. The `git rm` command does that, and also removes the file from your working directory so you don’t see it as an untracked file the next time around. @@ -579,6 +581,7 @@ This command removes all files that end with `~`. ==== Moving Files +(((files, moving))) Unlike many other VCS systems, Git doesn’t explicitly track file movement. If you rename a file in Git, no metadata is stored in Git that tells it you renamed the file. However, Git is pretty smart about figuring that out after the fact – we’ll deal with detecting file movement a bit later. @@ -631,7 +634,7 @@ To get the project, run git clone https://github.com/schacon/simplegit-progit ---- -When you run `git log` in this project, you should get output that looks something like this: +When you run `git log` in this project, you should get output that looks something like this:(((git commands, log))) [source,shell] ---- @@ -765,7 +768,7 @@ a11bef06a3f659402fe7563abf99ad00de2209e6 first commit ---- The most interesting option is `format`, which allows you to specify your own log output format. -This is especially useful when you’re generating output for machine parsing – because you specify the format explicitly, you know it won’t change with updates to Git: +This is especially useful when you’re generating output for machine parsing – because you specify the format explicitly, you know it won’t change with updates to Git:(((log formatting))) [source,shell] ---- @@ -891,7 +894,7 @@ In <> we’ll list these and a few other common options for your | `-S` | Only show commits adding or removing code matching the string |================================ -For example, if you want to see which commits modifying test files in the Git source code history were committed by Junio Hamano and were not merges in the month of October 2008, you can run something like this: +For example, if you want to see which commits modifying test files in the Git source code history were committed by Junio Hamano and were not merges in the month of October 2008, you can run something like this:(((log filtering))) [source,shell] ---- @@ -1049,7 +1052,7 @@ In this section, we’ll cover some of these remote-management skills. ==== Showing Your Remotes -To see which remote servers you have configured, you can run the `git remote` command. +To see which remote servers you have configured, you can run the `git remote` command.(((git commands, remote))) It lists the shortnames of each remote handle you’ve specified. If you’ve cloned your repository, you should at least see origin – that is the default name Git gives to the server you cloned from: @@ -1101,7 +1104,7 @@ Notice that these remotes use a variety of protocols; we’ll cover why more abo ==== Adding Remote Repositories -I’ve mentioned and given some demonstrations of adding remote repositories in previous sections, but here is how to do it explicitly. +I’ve mentioned and given some demonstrations of adding remote repositories in previous sections, but here is how to do it explicitly.(((git commands, remote))) To add a new remote Git repository as a shortname you can reference easily, run `git remote add [shortname] [url]`: [source,shell] @@ -1137,7 +1140,7 @@ Paul’s master branch is now accessible locally as `pb/master` – you can merg ==== Fetching and Pulling from Your Remotes -As you just saw, to get data from your remote projects, you can run: +As you just saw, to get data from your remote projects, you can run:(((git commands, fetch))) [source,shell] ---- @@ -1152,14 +1155,14 @@ So, `git fetch origin` fetches any new work that has been pushed to that server It’s important to note that the `git fetch` command pulls the data to your local repository – it doesn’t automatically merge it with any of your work or modify what you’re currently working on. You have to merge it manually into your work when you’re ready. -If you have a branch set up to track a remote branch (see the next section and <<_git_branching>> for more information), you can use the `git pull` command to automatically fetch and then merge a remote branch into your current branch. +If you have a branch set up to track a remote branch (see the next section and <<_git_branching>> for more information), you can use the `git pull` command to automatically fetch and then merge a remote branch into your current branch.(((git commands, pull))) This may be an easier or more comfortable workflow for you; and by default, the `git clone` command automatically sets up your local master branch to track the remote master branch (or whatever the default branch is called) on the server you cloned from. Running `git pull` generally fetches data from the server you originally cloned from and automatically tries to merge it into the code you’re currently working on. ==== Pushing to Your Remotes When you have your project at a point that you want to share, you have to push it upstream. -The command for this is simple: `git push [remote-name] [branch-name]`. +The command for this is simple: `git push [remote-name] [branch-name]`.(((git commands, push))) If you want to push your master branch to your `origin` server (again, cloning generally sets up both of those names for you automatically), then you can run this to push any commits you've done back up to the server: [source,shell] @@ -1174,7 +1177,7 @@ See <<_git_branching>> for more detailed information on how to push to remote se ==== Inspecting a Remote -If you want to see more information about a particular remote, you can use the `git remote show [remote-name]` command. +If you want to see more information about a particular remote, you can use the `git remote show [remote-name]` command.(((git commands, remote))) If you run this command with a particular shortname, such as `origin`, you get something like this: [source,shell] @@ -1219,7 +1222,7 @@ $ git remote show origin dev-branch merges with remote dev-branch master merges with remote master Local refs configured for 'git push': - dev-branch pushes to dev-branch (up to date) + dev-branch pushes to dev-branch (up to date) markdown-strip pushes to markdown-strip (up to date) master pushes to master (up to date) ---- @@ -1229,7 +1232,7 @@ It also shows you which remote branches on the server you don’t yet have, whic ==== Removing and Renaming Remotes -If you want to rename a reference you can run `git remote rename` to change a remote’s shortname. +If you want to rename a reference you can run `git remote rename` to change a remote’s shortname.(((git commands, remote))) For instance, if you want to rename `pb` to `paul`, you can do so with `git remote rename`: [source,shell] @@ -1254,6 +1257,7 @@ origin === Tagging +(((tags))) Like most VCSs, Git has the ability to tag specific points in history as being important. Typically people use this functionality to mark release points (v1.0, and so on). In this section, you’ll learn how to list the available tags, how to create new tags, and what the different types of tags are. @@ -1261,7 +1265,7 @@ In this section, you’ll learn how to list the available tags, how to create ne ==== Listing Your Tags Listing the available tags in Git is straightforward. -Just type `git tag`: +Just type `git tag`:(((git commands, tag))) [source,shell] ---- @@ -1303,8 +1307,9 @@ It’s generally recommended that you create annotated tags so you can have all ==== Annotated Tags +(((tags, annotated))) Creating an annotated tag in Git is simple. -The easiest way is to specify `-a` when you run the `tag` command: +The easiest way is to specify `-a` when you run the `tag` command:(((git commands, tag))) [source,shell] ---- @@ -1340,6 +1345,7 @@ That shows the tagger information, the date the commit was tagged, and the annot ==== Lightweight Tags +(((tags, lightweight))) Another way to tag commits is with a lightweight tag. This is basically the commit checksum stored in a file – no other information is kept. To create a lightweight tag, don’t supply the `-a`, `-s`, or `-m` option: @@ -1355,7 +1361,7 @@ v1.4-lw v1.5 ---- -This time, if you run `git show` on the tag, you don’t see the extra tag information. +This time, if you run `git show` on the tag, you don’t see the extra tag information.(((git commands, show))) The command just shows the commit: [source,shell] @@ -1397,7 +1403,7 @@ To tag that commit, you specify the commit checksum (or part of it) at the end o $ git tag -a v1.2 9fceb02 ---- -You can see that you’ve tagged the commit: +You can see that you’ve tagged the commit:(((git commands, tag))) [source,shell] ---- @@ -1425,7 +1431,7 @@ Date: Sun Apr 27 20:43:35 2008 -0700 ==== Sharing Tags -By default, the `git push` command doesn’t transfer tags to remote servers. +By default, the `git push` command doesn’t transfer tags to remote servers.(((git commands, push))) You will have to explicitly push tags to a shared server after you have created them. This process is just like sharing remote branches – you can run `git push origin [tagname]`. @@ -1460,11 +1466,12 @@ Now, when someone else clones or pulls from your repository, they will get all y === Git Aliases +(((aliases))) Before we finish this chapter on basic Git, there's just one little tip that can make your Git experience simpler, easier, and more familiar: aliases. We won’t refer to them or assume you’ve used them later in the book, but you should probably know how to use them. Git doesn’t automatically infer your command if you type it in partially. -If you don’t want to type the entire text of each of the Git commands, you can easily set up an alias for each command using `git config`. +If you don’t want to type the entire text of each of the Git commands, you can easily set up an alias for each command using `git config`.(((git commands, config))) Here are a couple of examples you may want to set up: [source,shell] diff --git a/book/03-git-branching/1-git-branching.asc b/book/03-git-branching/1-git-branching.asc index 931fa3851..9737bdcc8 100644 --- a/book/03-git-branching/1-git-branching.asc +++ b/book/03-git-branching/1-git-branching.asc @@ -1,6 +1,7 @@ [[_git_branching]] -== Git Branching(((git, branching))) +== Git Branching +(((branches))) Nearly every VCS has some form of branching support. Branching means you diverge from the main line of development and continue to do work without messing with that main line. In many VCS tools, this is a somewhat expensive process, often requiring you to create a new copy of your source code directory, which can take a long time for large projects. @@ -30,7 +31,7 @@ $ git commit -m 'initial commit of my project' ---- When you create the commit by running `git commit`, Git checksums each subdirectory (in this case, just the root project directory) and stores those tree objects in the Git repository. -Git then creates a commit object that has the metadata and a pointer to the root project tree so it can re-create that snapshot when needed. +Git then creates a commit object that has the metadata and a pointer to the root project tree so it can re-create that snapshot when needed.(((git commands, commit))) Your Git repository now contains five objects: one blob for the contents of each of your three files, one tree that lists the contents of the directory and specifies which file names are stored as which blobs, and one commit with the pointer to that root tree and all the commit metadata. @@ -49,7 +50,9 @@ Every time you commit, it moves forward automatically. [NOTE] ==== -The ``master'' branch in Git is not a special branch. It is exactly like any other branch. The only reason nearly every repository has one is that the `git init` command creates it by default and most people don't bother to change it. +The ``master'' branch in Git is not a special branch.(((master))) +It is exactly like any other branch. +The only reason nearly every repository has one is that the `git init` command creates it by default and most people don't bother to change it. ==== .A branch and its commit history @@ -57,10 +60,11 @@ image::images/branch-and-history.png[A branch and its commit history.] ==== Creating a new branch +(((branches, creating))) What happens if you create a new branch? Well, doing so creates a new pointer for you to move around. Let's say you create a new branch called testing. -You do this with the `git branch` command: +You do this with the `git branch` command:(((git commands, branch))) [source,shell] ---- @@ -96,7 +100,8 @@ You can see the ``master'' and ``testing'' branches that are right there next to ==== Switching branches -To switch to an existing branch, you run the `git checkout` command. +(((branches, switching))) +To switch to an existing branch, you run the `git checkout` command.(((git commands, checkout))) Let's switch to the new testing branch: [source,shell] @@ -140,7 +145,9 @@ It essentially rewinds the work you've done in your testing branch so you can go [NOTE] .Switching branches changes files in your working directory ==== -It's important to note that when you switch branches in Git, files in your working directory will change. If you switch to an older branch, your working directory will be reverted to look like it did the last time you committed on that branch. If Git cannot do it cleanly, it will not let you switch at all. +It's important to note that when you switch branches in Git, files in your working directory will change. +If you switch to an older branch, your working directory will be reverted to look like it did the last time you committed on that branch. +If Git cannot do it cleanly, it will not let you switch at all. ==== Let's make a few changes and commit again: @@ -151,15 +158,17 @@ $ vim test.rb $ git commit -a -m 'made other changes' ---- -Now your project history has diverged (see Figure 3-9). +Now your project history has diverged (see <>). You created and switched to a branch, did some work on it, and then switched back to your main branch and did other work. Both of those changes are isolated in separate branches: you can switch back and forth between the branches and merge them together when you're ready. And you did all that with simple `branch`, `checkout`, and `commit` commands. +[[divergent_history]] .Divergent history image::images/advance-master.png[Divergent history.] -You can also see this easily with the `git log` command. If you run `git log --oneline --decorate --graph --all` it will print out the history of your commits, showing where your branch pointers are and how your history has diverged. +You can also see this easily with the `git log` command. +If you run `git log --oneline --decorate --graph --all` it will print out the history of your commits, showing where your branch pointers are and how your history has diverged. [source,shell] ---- @@ -201,6 +210,7 @@ You'll do the following: ==== Basic Branching +(((branches, basic workflow))) First, let's say you're working on your project and have a couple of commits already. .A simple commit history @@ -274,7 +284,7 @@ $ git commit -a -m 'fixed the broken email address' image::images/basic-branching-4.png[Hotfix branch based on `master`.] You can run your tests, make sure the hotfix is what you want, and merge it back into your master branch to deploy to production. -You do this with the `git merge` command: +You do this with the `git merge` command:(((git commands, merge))) [source,shell] ---- @@ -325,6 +335,7 @@ If you need to pull it in, you can merge your `master` branch into your `iss53` ==== Basic Merging +(((branches, merging)))(((merging))) Suppose you've decided that your issue #53 work is complete and ready to be merged into your `master` branch. In order to do that, you'll merge in your `iss53` branch, much like you merged in your `hotfix` branch earlier. All you have to do is check out the branch you wish to merge into and then run the `git merge` command: @@ -366,6 +377,7 @@ $ git branch -d iss53 ==== Basic Merge Conflicts +(((merging, conflicts))) Occasionally, this process doesn't go smoothly. If you changed the same part of the same file differently in the two branches you're merging together, Git won't be able to merge them cleanly. If your fix for issue #53 modified the same part of a file as the `hotfix`, you'll get a merge conflict that looks something like this: @@ -426,7 +438,7 @@ please contact us at email.support@github.com This resolution has a little of each section, and the `<<<<<<<`, `=======`, and `>>>>>>>` lines have been completely removed. After you've resolved each of these sections in each conflicted file, run `git add` on each file to mark it as resolved. Staging the file marks it as resolved in Git. -If you want to use a graphical tool to resolve these issues, you can run `git mergetool`, which fires up an appropriate visual merge tool and walks you through the conflicts: +If you want to use a graphical tool to resolve these issues, you can run `git mergetool`, which fires up an appropriate visual merge tool and walks you through the conflicts:(((git commands, mergetool))) [source,shell] ---- @@ -495,9 +507,10 @@ You can modify that message with details about how you resolved the merge if you === Branch Management +(((branches, managing))) Now that you've created, merged, and deleted some branches, let's look at some branch-management tools that will come in handy when you begin using branches all the time. -The `git branch` command does more than just create and delete branches. +The `git branch` command does more than just create and delete branches.(((git commands, branch))) If you run it with no arguments, you get a simple listing of your current branches: [source,shell] @@ -560,6 +573,7 @@ In this section, we'll cover some common workflows that this lightweight branchi ==== Long-Running Branches +(((branches, long-running))) Because Git uses a simple three-way merge, merging from one branch into another multiple times over a long period is generally easy to do. This means you can have several branches that are always open and that you use for different stages of your development cycle; you can merge regularly from some of them into others. @@ -587,6 +601,7 @@ Again, having multiple long-running branches isn't necessary, but it's often hel [[_topic_branches]] ==== Topic Branches +(((branches, topic))) Topic branches, however, are useful in projects of any size. A topic branch is a short-lived branch that you create and use for a single particular feature or related work. This is something you've likely never done with a VCS before because it's generally too expensive to create and merge branches. @@ -617,6 +632,7 @@ When you're branching and merging, everything is being done only in your Git rep === Remote Branches +(((branches, remote)))(((references, remote))) Remote branches are references (pointers) to the state of branches in your remote repositories. They're local branches that you can't move; they're moved automatically for you whenever you do any network communication. Remote branches act as bookmarks to remind you where the branches on your remote repositories were the last time you connected to them. @@ -633,7 +649,7 @@ Git also gives you your own local `master` branch starting at the same place as [NOTE] .``origin'' is not special ==== -Just like the branch name ``master'' does not have any special meaning in Git, neither does ``origin''. While ``master'' is the default name for a starting branch when you run `git init` which is the only reason it's widely used, ``origin'' is the default name for a remote when you run `git clone`. If you run `git clone -o booyah` instead, then you will have `booyah/master` as your default remote branch. +Just like the branch name ``master'' does not have any special meaning in Git, neither does ``origin''. While ``master'' is the default name for a starting branch when you run `git init` which is the only reason it's widely used, ``origin'' is the default name for a remote when you run `git clone`. If you run `git clone -o booyah` instead, then you will have `booyah/master` as your default remote branch.(((origin))) ==== .Server and local repositories after cloning @@ -667,12 +683,13 @@ image::images/remote-branches-5.png[Remote tracking branch for `teamone/master`. ==== Pushing +(((pushing))) When you want to share a branch with the world, you need to push it up to a remote that you have write access to. Your local branches aren't automatically synchronized to the remotes you write to – you have to explicitly push the branches you want to share. That way, you can use private branches for work you don't want to share, and push up only the topic branches you want to collaborate on. If you have a branch named `serverfix` that you want to work on with others, you can push it up the same way you pushed your first branch. -Run `git push (remote) (branch)`: +Run `git push (remote) (branch)`:(((git commands, push))) [source,shell] ---- @@ -723,6 +740,7 @@ This gives you a local branch that you can work on that starts where `origin/ser ==== Tracking Branches +(((branches, tracking)))(((branches, upstream))) Checking out a local branch from a remote branch automatically creates what is called a ``tracking branch'' (or sometimes an ``upstream branch''). Tracking branches are local branches that have a direct relationship to a remote branch. If you're on a tracking branch and type `git push`, Git automatically knows which server and branch to push to. @@ -763,7 +781,7 @@ Branch serverfix set up to track remote branch serverfix from origin. [NOTE] .Upstream shorthand ==== -When you have an tracking branch set up, you can reference it with the `@{upstream}` or `@{u}` shorthand. So if you're on the `master` branch and it's tracking `origin/master`, you can say something like `git merge @{u}` instead of `git merge origin/master` if you wish. +When you have an tracking branch set up, you can reference it with the `@{upstream}` or `@{u}` shorthand. So if you're on the `master` branch and it's tracking `origin/master`, you can say something like `git merge @{u}` instead of `git merge origin/master` if you wish.(((+++@{u}+++)))(((+++@{upstream}+++))) ==== If you want to see what tracking branches you have set up, you can use the `-vv` option to `git branch`. This will list out your local branches with more information including what each branch is tracking and if your local branch is ahead, behind or both. @@ -783,6 +801,7 @@ It's important to note that these numbers are only since the last time you fetch ==== Pulling +(((pulling))) While the `git fetch` command will fetch down all the changes on the server that you don't have yet, it will not modify your working directory at all. It will simply get the data for you and let you merge it yourself. However, there is a command called `git pull` which is essentially a `git fetch` immediately followed by a `git merge` in most cases. @@ -792,6 +811,7 @@ There are other uses of the `pull` command that we'll address in [[_git_tools]], ==== Deleting Remote Branches +(((branches, deleting remote))) Suppose you're done with a remote branch – say you and your collaborators are finished with a feature and have merged it into your remote's `master` branch (or whatever branch your stable codeline is in). You can delete a remote branch using the `--delete` option to `git push`. If you want to delete your `serverfix` branch from the server, you run the following: @@ -808,6 +828,7 @@ Basically all this does is remove the pointer from the server. The Git server wi [[_rebasing]] === Rebasing +(((rebasing))) In Git, there are two main ways to integrate changes from one branch into another: the `merge` and the `rebase`. In this section you'll learn what rebasing is, how to do it, why it's a pretty amazing tool, and in what cases you won't want to use it. @@ -826,7 +847,7 @@ image::images/basic-rebase-2.png[Merging to integrate diverged work history.] However, there is another way: you can take the patch of the change that was introduced in `C3` and reapply it on top of `C4`. In Git, this is called _rebasing_. -With the `rebase` command, you can take all the changes that were committed on one branch and replay them on another one. +With the `rebase` command, you can take all the changes that were committed on one branch and replay them on another one.(((git commands, rebase))) In this example, you'd run the following: @@ -934,6 +955,7 @@ image::images/interesting-rebase-5.png[Final commit history.] [[_rebase_peril]] ==== The Perils of Rebasing +(((rebasing, perils of))) Ahh, but the bliss of rebasing isn't without its drawbacks, which can be summed up in a single line: **Do not rebase commits that exist outside your repository.** @@ -989,6 +1011,7 @@ But if you do, tell everyone who's working on that branch to `git pull --rebase` ==== Rebase vs. Merge +(((rebasing, vs. merging)))(((merging, vs. rebasing))) Now that you've seen rebasing and merging in action, you may be wondering which one is better. Before we can answer this, let's step back a bit and talk about what history means. diff --git a/book/04-git-server/1-git-server.asc b/book/04-git-server/1-git-server.asc index cbc6c27c9..73ce60355 100644 --- a/book/04-git-server/1-git-server.asc +++ b/book/04-git-server/1-git-server.asc @@ -1,5 +1,6 @@ == Git on the Server +(((serving repositories))) At this point, you should be able to do most of the day-to-day tasks for which you’ll be using Git. However, in order to do any collaboration in Git, you’ll need to have a remote Git repository. Although you can technically push changes to and pull changes from individuals’ repositories, doing so is discouraged because you can fairly easily confuse what they’re working on if you’re not careful. @@ -25,6 +26,7 @@ Here we’ll discuss what they are and in what basic circumstances you would wan ==== Local Protocol +(((protocols, local))) The most basic is the _Local protocol_, in which the remote repository is in another directory on disk. This is often used if everyone on your team has access to a shared filesystem such as an NFS mount, or in the less likely case that everyone logs in to the same computer. The latter wouldn’t be ideal, because all your code repository instances would reside on the same computer, making a catastrophic loss much more likely. @@ -90,6 +92,7 @@ We'll cover the newer ``smart'' HTTP protocol first. ===== Smart HTTP +(((protocols, smart HTTP))) The ``smart'' HTTP protocol operates very similarly to the SSH or Git protocols but runs over standard HTTP/S ports and can use various HTTP authentication mechanisms, meaning it's often easier on the user than something like SSH, since you can use things like username/password basic authentication rather than having to set up SSH keys. It has probably become the most popular way to use Git now, since it can be set up to both serve anonymously like the `git://` protocol, and can also be pushed over with authentication like the SSH protocol. Instead of having to set up different URLs for these things, you can now use a single URL for both. If you try to push and the repository requires authentication (which it normally should), the server can prompt for a username and password. The same goes for read access. @@ -98,6 +101,7 @@ In fact, for services like GitHub, the URL you use to view the repository online ===== Dumb HTTP +(((protocols, dumb HTTP))) If the server does not respond with a Git HTTP smart service, the Git client will try to fall back to the simpler ``dumb'' HTTP protocol. The Dumb protocol expects the bare Git repository to be served like normal files from the web server. The beauty of the Dumb HTTP protocol is the simplicity of setting it up. @@ -114,7 +118,7 @@ $ mv hooks/post-update.sample hooks/post-update $ chmod a+x hooks/post-update ---- -That’s all. +That’s all.(((hooks, post-update))) The `post-update` hook that comes with Git by default runs the appropriate command (`git update-server-info`) to make HTTP fetching and cloning work properly. This command is run when you push to this repository (over SSH perhaps); then, other people can clone via something like @@ -150,6 +154,7 @@ If you're using HTTP for authenticated pushing, providing your credentials is so ==== The SSH Protocol +(((protocols, SSH))) A common transport protocol for Git when self-hosting is over SSH. This is because SSH access to servers is already set up in most places – and if it isn’t, it’s easy to do. SSH is also an authenticated network protocol; and because it’s ubiquitous, it’s generally easy to set up and use. @@ -186,6 +191,7 @@ If you want to allow anonymous read-only access to your projects and also want t ==== The Git Protocol +(((protocols, git))) Next is the Git protocol. This is a special daemon that comes packaged with Git; it listens on a dedicated port (9418) that provides a service similar to the SSH protocol, but with absolutely no authentication. In order for a repository to be served over the Git protocol, you must create the `git-export-daemon-ok` file – the daemon won’t serve a repository without that file in it – but other than that there is no security. @@ -222,7 +228,7 @@ Actually setting up a production server within your infrastructure will certainl In order to initially set up any Git server, you have to export an existing repository into a new bare repository – a repository that doesn’t contain a working directory. This is generally straightforward to do. -In order to clone your repository to create a new bare repository, you run the clone command with the `--bare` option. +In order to clone your repository to create a new bare repository, you run the clone command with the `--bare` option.(((git commands, clone, bare))) By convention, bare repository directories end in `.git`, like so: [source,shell] @@ -264,7 +270,7 @@ $ git clone user@git.example.com:/opt/git/my_project.git If a user SSHs into a server and has write access to the `/opt/git/my_project.git` directory, they will also automatically have push access. -Git will automatically add group write permissions to a repository properly if you run the `git init` command with the `--shared` option. +Git will automatically add group write permissions to a repository properly if you run the `git init` command with the `--shared` option.(((git commands, init, bare))) [source,shell] ---- @@ -291,6 +297,7 @@ If you want some repositories to be read-only to certain users and read/write to ===== SSH Access +(((serving repositories, SSH))) If you have a server to which all your developers already have SSH access, it’s generally easiest to set up your first repository there, because you have to do almost no work (as we covered in the last section). If you want more complex access control type permissions on your repositories, you can handle them with the normal filesystem permissions of the operating system your server runs. @@ -311,6 +318,7 @@ As long as each user can get shell access on the machine, any SSH authentication [[_generate_ssh_key]] === Generating Your SSH Public Key +(((SSH keys))) That being said, many Git servers authenticate using SSH public keys. In order to provide a public key, each user in your system must generate one if they don’t already have one. This process is similar across all operating systems. @@ -402,7 +410,7 @@ $ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys $ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys ---- -Now, you can set up an empty repository for them by running `git init` with the `--bare` option, which initializes the repository without a working directory: +Now, you can set up an empty repository for them by running `git init` with the `--bare` option, which initializes the repository without a working directory:(((git commands, init, bare))) [source,shell] ---- @@ -460,7 +468,7 @@ At the bottom, you should find a line that looks something like this: git:x:1000:1000::/home/git:/bin/sh ---- -Change `/bin/sh` to `/usr/bin/git-shell` (or run `which git-shell` to see where it’s installed). +Change `/bin/sh` to `/usr/bin/git-shell` (or run `which git-shell` to see where it’s installed).(((git-shell))) The line should look something like this: [source,shell] @@ -482,17 +490,18 @@ Connection to gitserver closed. Now Git network commands will still work just fine but the users won't be able to get a shell. As the output states, you can also set up a directory in the ``git'' user's home directory that customizes the `git-shell` command a bit. For instance, you can restrict the Git commands that the server will accept or you can customize the message that users see if they try to SSH in like that. -Run `git help shell` for more information on customizing the shell. +Run `git help shell` for more information on customizing the shell.(((git commands, help))) === Git Daemon +(((serving repositories, git protocol))) Next we'll set up a daemon serving repositories over the ``Git'' protocol. This is common choice for fast, unauthenticated access to your Git data. Remember that since it's not an authenticated service, anything you serve over this protocol is public within it's network. If you’re running this on a server outside your firewall, it should only be used for projects that are publicly visible to the world. If the server you’re running it on is inside your firewall, you might use it for projects that a large number of people or computers (continuous integration or build servers) have read-only access to, when you don’t want to have to add an SSH key for each. In any case, the Git protocol is relatively easy to set up. -Basically, you need to run this command in a daemonized manner: +Basically, you need to run this command in a daemonized manner:(((git commands, daemon))) [source,shell] ---- @@ -550,12 +559,13 @@ The presence of that file tells Git that it’s OK to serve this project without === Smart HTTP +(((serving repositories, HTTP))) We now have authenticated access though SSH and unauthenticated access through `git://`, but there is also a protocol that can do both at the same time. -Setting up Smart HTTP is basically just enabling a CGI script that is provided with Git called `git-http-backend` on the server.((git, http-backend)) +Setting up Smart HTTP is basically just enabling a CGI script that is provided with Git called `git-http-backend` on the server.((git commands, "http-backend")) This CGI will read the path and headers sent by a `git fetch` or `git push` to an HTTP URL and determine if the client can communicate over HTTP (which is true for any client since version 1.6.6). If the CGI sees that the client is smart, it will communicate smartly with it, otherwise it will fall back to the dumb behavior (so it is backward compatible for reads with older clients). -Let's walk though a very basic setup. We'll set this up with Apache as the CGI server. If you don't have Apache setup, you can do so on a Linux box with something like this: +Let's walk though a very basic setup. We'll set this up with Apache as the CGI server. If you don't have Apache setup, you can do so on a Linux box with something like this:(((Apache))) [source,shell] ---- @@ -619,6 +629,7 @@ For more information on configuring authentication in Apache, check out the Apac === GitWeb +(((serving repositories, GitWeb)))(((GitWeb))) Now that you have basic read/write and read-only access to your project, you may want to set up a simple web-based visualizer. Git comes with a CGI script called GitWeb that is sometimes used for this. @@ -629,7 +640,7 @@ image::images/git-instaweb.png[The GitWeb web-based user interface.] If you want to check out what GitWeb would look like for your project, Git comes with a command to fire up a temporary instance if you have a lightweight server on your system like `lighttpd` or `webrick`. On Linux machines, `lighttpd` is often installed, so you may be able to get it to run by typing `git instaweb` in your project directory. If you’re running a Mac, Leopard comes preinstalled with Ruby, so `webrick` may be your best bet. -To start `instaweb` with a non-lighttpd handler, you can run it with the `--httpd` option. +To start `instaweb` with a non-lighttpd handler, you can run it with the `--httpd` option.(((git commands, instaweb))) [source,shell] ---- @@ -690,6 +701,7 @@ At this point, you should be able to visit `http://gitserver/` to view your repo === GitLab +(((serving repositories, GitLab)))(((GitLab))) GitWeb is pretty simplistic though. If you're looking for a more modern, fully featured Git server, there are some several open source solutions out there that you can install instead. As GitLab is one of the more popular ones, we'll cover installing and using it as an example. @@ -701,7 +713,7 @@ GitLab is a database-backed web application, so its installation is a bit more i Fortunately, this process is very well-documented and supported. There are a few methods you can pursue to install GitLab. -To get something up and running quickly, you can download a virtual machine image or a one-click installer from https://bitnami.com/stack/gitlab[], and tweak the configuration to match your particular environment. +To get something up and running quickly, you can download a virtual machine image or a one-click installer from https://bitnami.com/stack/gitlab[], and tweak the configuration to match your particular environment.(((bitnami))) One nice touch Bitnami has included is the login screen (accessed by typing alt-→); it tells you the IP address and default username and password for the installed GitLab. [[bitnami]]