diff --git a/book/01-introduction/1-introduction.asc b/book/01-introduction/1-introduction.asc index 966bf3711..96602d13f 100644 --- a/book/01-introduction/1-introduction.asc +++ b/book/01-introduction/1-introduction.asc @@ -1,3 +1,4 @@ +[[_getting_started]] == Getting Started This chapter will be about getting started with Git. @@ -34,7 +35,7 @@ RCS works by keeping patch sets (that is, the differences between files) in a sp 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))) +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))) For many years, this has been the standard for version control. .Centralized version control. @@ -211,11 +212,11 @@ You can either install it as a package or via another installer, or download the ==== 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, you can use yum: +If you’re on Fedora for example, you can use yum: $ yum install git -Or if you’re on a Debian-based distribution like Ubuntu, try apt-get: +If you’re on a Debian-based distribution like Ubuntu, try apt-get: $ apt-get install git @@ -245,32 +246,11 @@ The most official build is available for download on the Git website. Just go to http://git-scm.com/download/win[] and the download will start automatically. Note that this is a project called Git for Windows (also called msysGit), which is separate from Git itself; for more information on it, go to http://msysgit.github.io/[]. - 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. We'll learn more about those things a little later, but suffice it to say they're things you want. -=== First-Time Git Setup - -Now that you have Git on your system, you’ll want to do a few things to customize your Git environment. -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))) -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. - If you pass the option` --system` to `git config`, it reads and writes from this file specifically. -2. `~/.gitconfig` or `~/.config/git/config` file: Specific to your user. - You can make Git read and write to this file specifically by passing the `--global` option. -3. `config` file in the Git directory (that is, `.git/config`) of whatever repository you’re currently using: Specific to that single repository. - -Each level overrides values in the previous level, so values in `.git/config` trump those in `/etc/gitconfig`. - -On Windows systems, Git looks for the `.gitconfig` file in the `$HOME` directory (`C:\Users\$USER` for most people). -It also still looks for `/etc/gitconfig`, although it’s relative to the MSys root, which is wherever you decide to install Git on your Windows system when you run the installer. - ==== Installing from Source Some people may instead find it useful to install Git from source, because you’ll get the most recent version. @@ -302,10 +282,31 @@ After this is done, you can also get Git via Git itself for updates: $ git clone git://git.kernel.org/pub/scm/git/git.git + +=== First-Time Git Setup + +Now that you have Git on your system, you’ll want to do a few things to customize your Git environment. +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))) +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. + If you pass the option` --system` to `git config`, it reads and writes from this file specifically. +2. `~/.gitconfig` or `~/.config/git/config` file: Specific to your user. + You can make Git read and write to this file specifically by passing the `--global` option. +3. `config` file in the Git directory (that is, `.git/config`) of whatever repository you’re currently using: Specific to that single repository. + +Each level overrides values in the previous level, so values in `.git/config` trump those in `/etc/gitconfig`. + +On Windows systems, Git looks for the `.gitconfig` file in the `$HOME` directory (`C:\Users\$USER` for most people). +It also still looks for `/etc/gitconfig`, although it’s relative to the MSys root, which is wherever you decide to install Git on your Windows system when you run the installer. + ==== Your Identity The first thing you should do when you install Git is to set your user name and e-mail address. -This is important because every Git commit uses this information, and it’s immutably baked into the commits you pass around: +This is important because every Git commit uses this information, and it’s immutably baked into the commits you start creating: $ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com @@ -313,16 +314,21 @@ This is important because every Git commit uses this information, and it’s imm Again, you need to do this only once if you pass the `--global` option, because then Git will always use that information for anything you do on that system. If you want to override this with a different name or e-mail address for specific projects, you can run the command without the `--global` option when you’re in that project. -Many of the GUI tools will help you do this when you first run them as well. +Many of the GUI tools will help you do this when you first run them. ==== Your Editor Now that your identity is set up, you can configure the default text editor that will be used when Git needs you to type in a message. -By default, Git uses your system’s default editor, which is generally vi or Vim. +If not configured, Git uses your system’s default editor, which is generally Vim. If you want to use a different text editor, such as Emacs, you can do the following: $ git config --global core.editor emacs +[NOTE] +==== +Vim and Emacs are popular text editors often used by developers on Unix based systems like Linux and Mac. If you are not familiar with either of these editors or are on a Windows system, you may need to search for instructions for how to set up your favorite editor with Git. +==== + ==== Checking Your Settings If you want to check your settings, you can use the `git config --list` command to list all the settings Git can find at that point: @@ -362,6 +368,6 @@ These channels are regularly filled with hundreds of people who are all very kno === Summary -You should have a basic understanding of what Git is and how it’s different from the CVCS you may have been using. +You should have a basic understanding of what Git is and how it’s different from the centralized version control system you may have previously been using. You should also now have a working version of Git on your system that’s set up with your personal identity. It’s now time to learn some Git basics. diff --git a/book/02-git-basics/1-git-basics.asc b/book/02-git-basics/1-git-basics.asc index d8d9da928..850e36562 100644 --- a/book/02-git-basics/1-git-basics.asc +++ b/book/02-git-basics/1-git-basics.asc @@ -26,12 +26,12 @@ 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.) 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 commit: +You can accomplish that with a few `git add` commands that specify the files you want to track, followed by a `git commit`: [source,shell] ---- $ git add *.c -$ git add README +$ git add LICENSE $ git commit -m 'initial project version' ---- @@ -40,33 +40,33 @@ At this point, you have a Git repository with tracked files and an initial commi ==== Cloning an Existing Repository -If you want to get a copy of an existing Git repository – for example, a project you’d like to contribute to – the command you need is git clone. -If you’re familiar with other VCS systems such as Subversion, you’ll notice that the command is clone and not checkout. -This is an important distinction – Git receives a copy of nearly all data that the server has. -Every version of every file for the history of the project is pulled down when you run `git clone`. -In fact, if your server disk gets corrupted, you can use 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). +If you want to get a copy of an existing Git repository – for example, a project you’d like to contribute to – the command you need is `git clone`. +If you’re familiar with other VCS systems such as Subversion, you’ll notice that the command is "clone" and not "checkout". +This is an important distinction – instead of getting just a working copy, Git receives a full copy of nearly all data that the server has. +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]`. -For example, if you want to clone the Ruby Git library called Grit, you can do so like this: +For example, if you want to clone the Git linkable library called libgit2, you can do so like this: [source,shell] ---- -$ git clone https://github.com/schacon/grit.git +$ git clone https://github.com/libgit2/libgit2 ---- -That creates a directory named ``grit'', initializes a `.git` directory inside it, pulls down all the data for that repository, and checks out a working copy of the latest version. -If you go into the new `grit` directory, you’ll see the project files in there, ready to be worked on or used. -If you want to clone the repository into a directory named something other than grit, you can specify that as the next command-line option: +That creates a directory named ``libgit2'', initializes a `.git` directory inside it, pulls down all the data for that repository, and checks out a working copy of the latest version. +If you go into the new `libgit2` directory, you’ll see the project files in there, ready to be worked on or used. +If you want to clone the repository into a directory named something other than ``libgit2'', you can specify that as the next command-line option: [source,shell] ---- -$ git clone https://github.com/schacon/grit.git mygrit +$ git clone https://github.com/libgit2/libgit2 mylibgit ---- -That command does the same thing as the previous one, but the target directory is called `mygrit`. +That command does the same thing as the previous one, but the target directory is called `mylibgit`. Git has a number of different transfer protocols you can use. -The previous example uses the `git://` protocol, but you may also see `http(s)://` or `user@server:path/to/repo.git`, which uses the SSH transfer protocol. +The previous example uses the `https://` protocol, but you may also see `git://` or `user@server:path/to/repo.git`, which uses the SSH transfer protocol. <<_git_on_the_server>> will introduce all of the available options the server can set up to access your Git repository and the pros and cons of each. === Recording Changes to the Repository @@ -89,7 +89,7 @@ image::images/18333fig0201-tn.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. +The main tool you use to determine which files are in which state is the `git status` command.(((git, status))) If you run this command directly after a clone, you should see something like this: [source,shell] @@ -101,16 +101,16 @@ nothing to commit, working directory clean This means you have a clean working directory – in other words, there are no tracked and modified files. Git also doesn’t see any untracked files, or they would be listed here. -Finally, the command tells you which branch you’re on. -For now, that is always master, which is the default; you won’t worry about it here. -The next chapter will go over branches and references in detail. +Finally, the command tells you which branch you’re on and informs you that it has not diverged from the same branch on the server. +For now, that branch is always ``master'', which is the default; you won’t worry about it here. +<<_git_branching>> will go over branches and references in detail. Let’s say you add a new file to your project, a simple README file. If the file didn’t exist before, and you run `git status`, you see your untracked file like so: [source,shell] ---- -$ vim README +$ echo 'My Project' > README $ git status On branch master Untracked files: @@ -128,7 +128,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`. +In order to begin tracking a new file, you use the command `git add`.(((git, add))) To begin tracking the README file, you can run this: [source,shell] @@ -136,7 +136,7 @@ To begin tracking the README file, you can run this: $ git add README ---- -If you run your status command again, you can see that your README file is now tracked and staged: +If you run your status command again, you can see that your README file is now tracked and staged to be committed: [source,shell] ---- @@ -150,14 +150,14 @@ 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. -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. +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))) +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 Let’s change a file that was already tracked. -If you change a previously tracked file called `benchmarks.rb` and then run your `git status` command again, you get something that looks like this: +If you change a previously tracked file called ``benchmarks.rb'' and then run your `git status` command again, you get something that looks like this: [source,shell] ---- @@ -176,9 +176,9 @@ 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 (it’s 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). -Let’s run `git add` now to stage the benchmarks.rb file, and then run `git status` again: +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''. +Let’s run `git add` now to stage the ``benchmarks.rb'' file, and then run `git status` again: [source,shell] ---- @@ -214,6 +214,7 @@ Changes not staged for commit: (use "git checkout -- ..." to discard changes in working directory) modified: benchmarks.rb + ---- What the heck? @@ -235,6 +236,22 @@ Changes to be committed: modified: benchmarks.rb ---- +==== Short Status + +While the `git status` output is pretty comprehensive, it's also quite wordy. Git also has a short status flag so you can see your changes in a more compact way. If you run `git status -s` or `git status --short` you get a far more simplified output from the command. + +[source,shell] +---- +$ git status -s + M README +MM Rakefile +A lib/git.rb +M lib/simplegit.rb +?? LICENSE.txt +---- + +New files that aren't tracked have a `??` next to them, new files that have been added to the staging area have an `A`, modified files have an `M` and so on. There are two columns to the output - the left hand column indicates that the file is staged and the right hand column indicates that it's modified. So for example in that output, the `README` file is modified in the working directory but not yet staged, while the `lib/simplegit.rb` file is modified and staged. The `Rakefile` was modified, staged and then modified again, so there are changes to it that are both staged and unstaged. + ==== Ignoring Files Often, you’ll have a class of files that you don’t want Git to automatically add or even show you as being untracked. @@ -277,12 +294,17 @@ build/ # ignore all files in the build/ directory doc/*.txt # ignore doc/notes.txt, but not doc/server/arch.txt ---- +[TIP] +==== +GitHub maintains a fairly comprehensive list of good `.gitignore` file examples for dozens or projects and languages at https://github.com/github/gitignore[] if you want a starting point for your project. +==== + ==== 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. 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, `git diff` shows you the exact lines added and removed – the patch, as it were. +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. Let’s say you edit and stage the `README` file again and then edit the `benchmarks.rb` file without staging it. If you run your `git status` command, you once again see something like this: @@ -328,24 +350,22 @@ index 3cb747f..e445e28 100644 That command compares what is in your working directory with what is in your staging area. The result tells you the changes you’ve made that you haven’t yet staged. -If you want to see what you’ve staged that will go into your next commit, you can use `git diff --cached`. -(In Git versions 1.6.1 and later, you can also use `git diff --staged`, which may be easier to remember.) +If you want to see what you’ve staged that will go into your next commit, you can use `git diff --staged`. This command compares your staged changes to your last commit: [source,shell] ---- -$ git diff --cached +$ git diff --staged diff --git a/README b/README new file mode 100644 index 0000000..03902a1 --- /dev/null -+++ b/README2 -@@ -0,0 +1,5 @@ -+grit -+ by Tom Preston-Werner, Chris Wanstrath -+ https://github.com/mojombo/grit ++++ b/README +@@ -0,0 +1,4 @@ ++My Project ++ ++ This is my project and it is amazing. + -+Grit is a Ruby library for extracting information from a Git repository ---- It’s important to note that `git diff` by itself doesn’t show all changes made since your last commit – only changes that are still unstaged. @@ -414,8 +434,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. -The simplest way to commit is to type `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, status))) +The simplest way to commit is to type `git commit`:(((git, commit))) [source,shell] ---- @@ -488,7 +508,7 @@ $ git commit -a -m 'added new benchmarks' 1 file changed, 5 insertions(+), 0 deletions(-) ---- -Notice how you don’t have to run `git add` on the benchmarks.rb file in this case before you commit. +Notice how you don’t have to run `git add` on the ``benchmarks.rb'' file in this case before you commit. ==== Removing Files @@ -536,7 +556,7 @@ To do this, use the `--cached` option: [source,shell] ---- -$ git rm --cached readme.txt +$ git rm --cached README ---- You can pass files, directories, and file-glob patterns to the `git rm` command. @@ -610,7 +630,7 @@ To get the project, run [source,shell] ---- -git clone https://github.com/schacon/simplegit-progit.git +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: @@ -643,7 +663,7 @@ As you can see, this command lists each commit with its SHA-1 checksum, the auth A huge number and variety of options to the `git log` command are available to show you exactly what you’re looking for. Here, we’ll show you some of the most popular. -One of the more helpful options is `-p`, which shows the diff introduced in each commit. +One of the more helpful options is `-p`, which shows the difference introduced in each commit. You can also use `-2`, which limits the output to only the last two entries: [source,shell] @@ -731,6 +751,7 @@ Date: Sat Mar 15 10:31:28 2008 -0700 As you can see, the `--stat` option prints below each commit entry a list of modified files, how many files were changed, and how many lines in those files were added and removed. It also puts a summary of the information at the end. + Another really useful option is `--pretty`. This option changes the log output to formats other than the default. A few prebuilt options are available for you to use. @@ -751,9 +772,9 @@ This is especially useful when you’re generating output for machine parsing [source,shell] ---- $ git log --pretty=format:"%h - %an, %ar : %s" -ca82a6d - Scott Chacon, 11 months ago : changed the version number -085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code -a11bef0 - Scott Chacon, 11 months ago : first commit +ca82a6d - Scott Chacon, 6 years ago : changed the version number +085bb3b - Scott Chacon, 6 years ago : removed unnecessary test code +a11bef0 - Scott Chacon, 6 years ago : first commit ---- <> lists some of the more useful options that format takes. @@ -786,7 +807,7 @@ So, if you send in a patch to a project and one of the core members applies the We’ll cover this distinction a bit more in <<_distributed_git>>. The oneline and format options are particularly useful with another `log` option called `--graph`. -This option adds a nice little ASCII graph showing your branch and merge history, which we can see our copy of the Grit project repository: +This option adds a nice little ASCII graph showing your branch and merge history: [source,shell] ---- @@ -803,6 +824,8 @@ $ git log --pretty=format:"%h %s" --graph * 11d191e Merge branch 'defunkt' into local ---- +This type of output will become more interesting as we go through branching and merging in the next chapter. + Those are only some simple output-formatting options to `git log` – there are many more. <> lists the options we’ve covered so far, as well as some other common formatting options that may be useful, along with how they change the output of the log command. @@ -824,7 +847,7 @@ Those are only some simple output-formatting options to `git log` – there are ==== Limiting Log Output -In addition to output-formatting options, git log takes a number of useful limiting options – that is, options that let you show only a subset of commits. +In addition to output-formatting options, `git log` takes a number of useful limiting options – that is, options that let you show only a subset of commits. You’ve seen one such option already – the `-2` option, which show only the last two commits. In fact, you can do `-`, where `n` is any integer to show the last `n` commits. In reality, you’re unlikely to use that often, because Git by default pipes all output through a pager so you see only one page of log output at a time. @@ -843,6 +866,13 @@ You can also filter the list to commits that match some search criteria. The `--author` option allows you to filter on a specific author, and the `--grep` option lets you search for keywords in the commit messages. (Note that if you want to specify both author and grep options, you have to add `--all-match` or the command will match commits with either.) +Another really helpful filter is the `-S` option which takes a string and only shows the commits that introduced a change to the code that added or removed that string. For instance, if you wanted to find the last commit that added or removed a reference to a specific function, you could call: + +[source,shell] +---- +$ git log --Sfunction_name +---- + The last really useful option to pass to `git log` as a filter is a path. If you specify a directory or file name, you can limit the log output to commits that introduced a change to those files. This is always the last option and is generally preceded by double dashes (`--`) to separate the paths from the options. @@ -859,6 +889,8 @@ In <> we’ll list these and a few other common options for your | `--until`, `--before` | Limit the commits to those made before the specified date. | `--author` | Only show commits in which the author entry matches the specified string. | `--committer` | Only show commits in which the committer entry matches the specified string. +| `--grep` | Only show commits with a commit message containing the string +| `-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: @@ -885,27 +917,6 @@ Here, we’ll review a few basic tools for undoing changes that you’ve made. Be careful, because you can’t always undo some of these undos. This is one of the few areas in Git where you may lose some work if you do it wrong. -[[_reset]] -==== Reset Demystified - -**TODO** - -===== The Three Trees - -===== The Workflow - -===== The Role of Reset - -===== Reset With a Path - -===== A Fun Example - -===== Check It Out - -===== Summary - -==== Changing Your Last Commit - One of the common undos takes place when you commit too early and possibly forget to add some files, or you mess up your commit message. If you want to try that commit again, you can run commit with the `--amend` option: @@ -976,6 +987,13 @@ Changes not staged for commit: The command is a bit strange, but it works. The `benchmarks.rb` file is modified but once again unstaged. +[NOTE] +===== +While `git reset` _can_ be a dangerous command if you call it with `--hard`, in this instance the file in your working directory is not touched. Calling `git reset` without an option is not dangerous - it only touches your staging area. +===== + +For now this magic invocation is all you need to know about the `git reset` command. We'll go into much more detail about what `reset` does and how to master it to do really interesting things in <<_git_tools_reset>>. + ==== Unmodifying a Modified File What if you realize that you don’t want to keep your changes to the `benchmarks.rb` file? @@ -1008,18 +1026,19 @@ Changes to be committed: ---- You can see that the changes have been reverted. -You should also realize that this is a dangerous command: any changes you made to that file are gone – you just copied another file over it. + +[IMPORTANT] +===== +It's important to understand that `git checkout -- [file]` is a dangerous command. Any changes you made to that file are gone – you just copied another file over it. Don’t ever use this command unless you absolutely know that you don’t want the file. -If you just need to get it out of the way, we’ll go over stashing and branching in the next chapter; these are generally better ways to go. +===== + +If you would like to keep the changes you've made to that file but still need to get it out of the way for now, we’ll go over stashing and branching in the next chapter; these are generally better ways to go. -Remember, anything that is committed in Git can almost always be recovered. +Remember, anything that is __committed__ in Git can almost always be recovered. Even commits that were on branches that were deleted or commits that were overwritten with an `--amend` commit can be recovered (see <> for data recovery). However, anything you lose that was never committed is likely never to be seen again. -==== Undoing All Changes - -**TODO** - === Working with Remotes To be able to collaborate on any Git project, you need to know how to manage your remote repositories. @@ -1027,7 +1046,7 @@ Remote repositories are versions of your project that are hosted on the Internet You can have several of them, each of which generally is either read-only or read/write for you. Collaborating with others involves managing these remote repositories and pushing and pulling data to and from them when you need to share work. Managing remote repositories includes knowing how to add remote repositories, remove remotes that are no longer valid, manage various remote branches and define them as being tracked or not, and more. -In this section, we’ll cover these remote-management skills. +In this section, we’ll cover some of these remote-management skills. ==== Showing Your Remotes @@ -1037,7 +1056,7 @@ If you’ve cloned your repository, you should at least see origin – that is t [source,shell] ---- -$ git clone https://github.com/schacon/ticgit.git +$ git clone https://github.com/schacon/ticgit Cloning into 'ticgit'... remote: Reusing existing pack: 1857, done. remote: Total 1857 (delta 0), reused 0 (delta 0) @@ -1049,29 +1068,36 @@ $ git remote origin ---- -You can also specify `-v`, which shows you the URL that Git has stored for the shortname to be expanded to: +You can also specify `-v`, which shows you the URLs that Git has stored for the shortname to be used when reading and writing to that remote: [source,shell] ---- $ git remote -v -origin https://github.com/schacon/ticgit.git +origin https://github.com/schacon/ticgit (fetch) +origin https://github.com/schacon/ticgit (push) ---- If you have more than one remote, the command lists them all. -For example, my Grit repository looks something like this. +For example, a repository with multiple remotes for working with several collaborators might look something like this. [source,shell] ---- $ cd grit $ git remote -v -bakkdoor https://github.com/bakkdoor/grit.git -cho45 https://github.com/cho45/grit.git -defunkt https://github.com/defunkt/grit.git -koke git://github.com/koke/grit.git -origin git@github.com:mojombo/grit.git +bakkdoor https://github.com/bakkdoor/grit (fetch) +bakkdoor https://github.com/bakkdoor/grit (push) +cho45 https://github.com/cho45/grit (fetch) +cho45 https://github.com/cho45/grit (push) +defunkt https://github.com/defunkt/grit (fetch) +defunkt https://github.com/defunkt/grit (push) +koke git://github.com/koke/grit.git (fetch) +koke git://github.com/koke/grit.git (push) +origin git@github.com:mojombo/grit.git (fetch) +origin git@github.com:mojombo/grit.git (push) ---- -This means we can pull contributions from any of these users pretty easily. +This means we can pull contributions from any of these users pretty easily. We may additionally have permission to push to one or more of these, though we can't tell that here. + Notice that these remotes use a variety of protocols; we’ll cover why more about this in <<_git_on_the_server>>. ==== Adding Remote Repositories @@ -1083,12 +1109,12 @@ To add a new remote Git repository as a shortname you can reference easily, run ---- $ git remote origin -$ git remote add pb https://github.com/paulboone/ticgit.git +$ git remote add pb https://github.com/paulboone/ticgit $ git remote -v -origin https://github.com/schacon/ticgit.git (fetch) -origin https://github.com/schacon/ticgit.git (push) -pb https://github.com/paulboone/ticgit.git (fetch) -pb https://github.com/paulboone/ticgit.git (push) +origin https://github.com/schacon/ticgit (fetch) +origin https://github.com/schacon/ticgit (push) +pb https://github.com/paulboone/ticgit (fetch) +pb https://github.com/paulboone/ticgit (push) ---- Now you can use the string `pb` on the command line in lieu of the whole URL. @@ -1105,7 +1131,10 @@ From https://github.com/paulboone/ticgit * [new branch] master -> pb/master * [new branch] ticgit -> pb/ticgit ---- -Paul’s master branch is accessible locally as `pb/master` – you can merge it into one of your branches, or you can check out a local branch at that point if you want to inspect it. + +Paul’s master branch is now accessible locally as `pb/master` – you can merge it into one of your branches, or you can check out a local branch at that point if you want to inspect it. +(We’ll go over what branches are and how to use them in much more detail in <<_git_branching>>.) + ==== Fetching and Pulling from Your Remotes @@ -1118,11 +1147,10 @@ $ git fetch [remote-name] The command goes out to that remote project and pulls down all the data from that remote project that you don’t have yet. After you do this, you should have references to all the branches from that remote, which you can merge in or inspect at any time. -(We’ll go over what branches are and how to use them in much more detail in <<_git_branching>>.) If you clone a repository, the command automatically adds that remote repository under the name origin. So, `git fetch origin` fetches any new work that has been pushed to that server since you cloned (or last fetched from) it. -It’s important to note that the 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. +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. @@ -1133,7 +1161,7 @@ Running `git pull` generally fetches data from the server you originally cloned 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]`. -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 your work back up to the server: +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] ---- @@ -1154,12 +1182,12 @@ If you run this command with a particular shortname, such as `origin`, you get s ---- $ git remote show origin * remote origin - Fetch URL: https://github.com/schacon/ticgit.git - Push URL: https://github.com/schacon/ticgit.git + Fetch URL: https://github.com/schacon/ticgit + Push URL: https://github.com/schacon/ticgit HEAD branch: master Remote branches: - master tracked - ticgit tracked + master tracked + dev-branch tracked Local branch configured for 'git pull': master merges with remote master Local ref configured for 'git push': @@ -1177,33 +1205,32 @@ When you’re using Git more heavily, however, you may see much more information ---- $ git remote show origin * remote origin - URL: git@github.com:defunkt/github.git - Remote branch merged with 'git pull' while on branch issues - issues - Remote branch merged with 'git pull' while on branch master - master - New remote branches (next fetch will store in remotes/origin) - caching - Stale tracking branches (use 'git remote prune') - libwalker - walker2 - Tracked remote branches - acl - apiv2 - dashboard2 - issues - master - postgres - Local branch pushed with 'git push' - master:master ----- - -This command shows which branch is automatically pushed when you run `git push` on certain branches. + URL: https://github.com/my-org/complex-project + Fetch URL: https://github.com/my-org/complex-project + Push URL: https://github.com/my-org/complex-project + HEAD branch: master + Remote branches: + master tracked + dev-branch tracked + markdown-strip tracked + issue-43 new (next fetch will store in remotes/origin) + issue-45 new (next fetch will store in remotes/origin) + refs/remotes/origin/issue-11 stale (use 'git remote prune' to remove) + Local branches configured for 'git pull': + 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) + markdown-strip pushes to markdown-strip (up to date) + master pushes to master (up to date) +---- + +This command shows which branch is automatically pushed to when you run `git push` while on certain branches. It also shows you which remote branches on the server you don’t yet have, which remote branches you have that have been removed from the server, and multiple branches that are automatically merged when you run `git pull`. ==== Removing and Renaming Remotes -If you want to rename a reference, in newer versions of Git 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. For instance, if you want to rename `pb` to `paul`, you can do so with `git remote rename`: [source,shell] @@ -1268,7 +1295,9 @@ v1.8.5.5 ==== Creating Tags Git uses two main types of tags: lightweight and annotated. + A lightweight tag is very much like a branch that doesn’t change – it’s just a pointer to a specific commit. + Annotated tags, however, are stored as full objects in the Git database. They’re checksummed; contain the tagger name, e-mail, and date; have a tagging message; and can be signed and verified with GNU Privacy Guard (GPG). It’s generally recommended that you create annotated tags so you can have all this information; but if you want a temporary tag or for some reason don’t want to keep the other information, lightweight tags are available too. @@ -1310,52 +1339,6 @@ Date: Mon Mar 17 21:52:11 2008 -0700 That shows the tagger information, the date the commit was tagged, and the annotation message before showing the commit information. -==== Signed Tags - -You can also sign your tags with GPG, assuming you have a private key. -All you have to do is use `-s` instead of `-a`: - -[source,shell] ----- -$ git tag -s v1.5 -m 'my signed 1.5 tag' - -You need a passphrase to unlock the secret key for -user: "Ben Straub " -2048-bit RSA key, ID 800430EB, created 2014-05-04 - ----- - -If you run `git show` on that tag, you can see your GPG signature attached to it: - -[source,shell] --------- -$ git show v1.5 -tag v1.5 -Tagger: Ben Straub -Date: Sat May 3 20:29:41 2014 -0700 - -my signed 1.5 tag ------BEGIN PGP SIGNATURE----- -Version: GnuPG v1 - -iQEcBAABAgAGBQJTZbQlAAoJEF0+sviABDDrZbQH/09PfE51KPVPlanr6q1v4/Ut -LQxfojUWiLQdg2ESJItkcuweYg+kc3HCyFejeDIBw9dpXt00rY26p05qrpnG+85b -hM1/PswpPLuBSr+oCIDj5GMC2r2iEKsfv2fJbNW8iWAXVLoWZRF8B0MfqX/YTMbm -ecorc4iXzQu7tupRihslbNkfvfciMnSDeSvzCpWAHl7h8Wj6hhqePmLm9lAYqnKp -8S5B/1SSQuEAjRZgI4IexpZoeKGVDptPHxLLS38fozsyi0QyDyzEgJxcJQVMXxVi -RUysgqjcpT8+iQM1PblGfHR4XAhuOqN5Fx06PSaFZhqvWFezJ28/CLyX5q+oIVk= -=EFTF ------END PGP SIGNATURE----- - -commit ca82a6dff817ec66f44342007202690a93763949 -Author: Scott Chacon -Date: Mon Mar 17 21:52:11 2008 -0700 - - changed the verison number --------- - -A bit later, you’ll learn how to verify signed tags. - ==== Lightweight Tags Another way to tag commits is with a lightweight tag. @@ -1386,38 +1369,6 @@ Date: Mon Mar 17 21:52:11 2008 -0700 changed the verison number ---- -==== Verifying Tags - -To verify a signed tag, you use `git tag -v [tag-name]`. -This command uses GPG to verify the signature. -You need the signer’s public key in your keyring for this to work properly: - -[source,shell] ----- -$ git tag -v v1.4.2.1 -object 883653babd8ee7ea23e6a5c392bb739348b1eb61 -type commit -tag v1.4.2.1 -tagger Junio C Hamano 1158138501 -0700 - -GIT 1.4.2.1 - -Minor fixes since 1.4.2, including git-mv and git-http with alternates. -gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A -gpg: Good signature from "Junio C Hamano " -gpg: aka "[jpeg image of size 1513]" -Primary key fingerprint: 3565 2A26 2040 E066 C9A7 4A7D C0C6 D9A4 F311 9B9A ----- - -If you don’t have the signer’s public key, you get something like this instead: - -[source,shell] ----- -gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A -gpg: Can't check signature: public key not found -error: could not verify the tag 'v1.4.2.1' ----- - ==== Tagging Later You can also tag commits after you’ve moved past them. @@ -1507,12 +1458,13 @@ To git@github.com:schacon/simplegit.git Now, when someone else clones or pulls from your repository, they will get all your tags as well. + === Git 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 infer your command if you type it in partially. +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`. Here are a couple of examples you may want to set up: diff --git a/book/03-git-branching/1-git-branching.asc b/book/03-git-branching/1-git-branching.asc index f44c5f9e3..f884bdb27 100644 --- a/book/03-git-branching/1-git-branching.asc +++ b/book/03-git-branching/1-git-branching.asc @@ -1,3 +1,4 @@ +[[_git_branching]] == Git Branching Nearly every VCS has some form of branching support. diff --git a/book/07-git-tools/1-git-tools.asc b/book/07-git-tools/1-git-tools.asc index 725b3d31c..16f389785 100644 --- a/book/07-git-tools/1-git-tools.asc +++ b/book/07-git-tools/1-git-tools.asc @@ -605,6 +605,87 @@ This is a nice shortcut to recover stashed work easily and work on it in a new b ==== Cleaning your Working Directory + +=== Signing Your Work + +Git is cryptographically secure, but it's not foolproof. If you're taking work from others on the internet and want to verify that commits are actually from a trusted source, Git has a few ways to sign and verify work using GPG. + +==== Signed Tags + +You can also sign your tags with GPG, assuming you have a private key. +All you have to do is use `-s` instead of `-a`: + +[source,shell] +---- +$ git tag -s v1.5 -m 'my signed 1.5 tag' + +You need a passphrase to unlock the secret key for +user: "Ben Straub " +2048-bit RSA key, ID 800430EB, created 2014-05-04 + +---- + +If you run `git show` on that tag, you can see your GPG signature attached to it: + +[source,shell] +-------- +$ git show v1.5 +tag v1.5 +Tagger: Ben Straub +Date: Sat May 3 20:29:41 2014 -0700 + +my signed 1.5 tag +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1 + +iQEcBAABAgAGBQJTZbQlAAoJEF0+sviABDDrZbQH/09PfE51KPVPlanr6q1v4/Ut +LQxfojUWiLQdg2ESJItkcuweYg+kc3HCyFejeDIBw9dpXt00rY26p05qrpnG+85b +hM1/PswpPLuBSr+oCIDj5GMC2r2iEKsfv2fJbNW8iWAXVLoWZRF8B0MfqX/YTMbm +ecorc4iXzQu7tupRihslbNkfvfciMnSDeSvzCpWAHl7h8Wj6hhqePmLm9lAYqnKp +8S5B/1SSQuEAjRZgI4IexpZoeKGVDptPHxLLS38fozsyi0QyDyzEgJxcJQVMXxVi +RUysgqjcpT8+iQM1PblGfHR4XAhuOqN5Fx06PSaFZhqvWFezJ28/CLyX5q+oIVk= +=EFTF +-----END PGP SIGNATURE----- + +commit ca82a6dff817ec66f44342007202690a93763949 +Author: Scott Chacon +Date: Mon Mar 17 21:52:11 2008 -0700 + + changed the verison number +-------- + +==== Verifying Tags + +To verify a signed tag, you use `git tag -v [tag-name]`. +This command uses GPG to verify the signature. +You need the signer’s public key in your keyring for this to work properly: + +[source,shell] +---- +$ git tag -v v1.4.2.1 +object 883653babd8ee7ea23e6a5c392bb739348b1eb61 +type commit +tag v1.4.2.1 +tagger Junio C Hamano 1158138501 -0700 + +GIT 1.4.2.1 + +Minor fixes since 1.4.2, including git-mv and git-http with alternates. +gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A +gpg: Good signature from "Junio C Hamano " +gpg: aka "[jpeg image of size 1513]" +Primary key fingerprint: 3565 2A26 2040 E066 C9A7 4A7D C0C6 D9A4 F311 9B9A +---- + +If you don’t have the signer’s public key, you get something like this instead: + +[source,shell] +---- +gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A +gpg: Can't check signature: public key not found +error: could not verify the tag 'v1.4.2.1' +---- + === Searching === Interactive Staging