From d44c85e3381a2fd3df94d5555b9a634b2f79da05 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Wed, 8 Oct 2014 15:35:47 +0200 Subject: [PATCH 01/26] add small section on git difftool --- book/02-git-basics/sections/recording-changes.asc | 7 +++++++ book/C-git-commands/1-git-commands.asc | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/book/02-git-basics/sections/recording-changes.asc b/book/02-git-basics/sections/recording-changes.asc index 750b89c8b..21e0999ba 100644 --- a/book/02-git-basics/sections/recording-changes.asc +++ b/book/02-git-basics/sections/recording-changes.asc @@ -360,6 +360,13 @@ index 3cb747f..e445e28 100644 log.size ---- +[[_git_difftool]] +[NOTE] +.Git Diff in an External Tool +==== +We will continue to use the `git diff` command in various ways throughout the rest of the book. There is another way to look at these diffs if you prefer a graphical or external diff viewing program instead. If you run `git difftool` instead of `git diff`, you can view any of these diffs in software like Araxis, emerge, vimdiff and more. Run `git difftool --tool-help` to see what is available on your system. +==== + [[_committing_changes]] ==== Committing Your Changes diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index b27f12110..46e4aa629 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -107,8 +107,7 @@ Finally, we use it to effectively compare submodule changes with `--submodule` i The `git difftool` command simply launches an external tool to show you the difference between two trees in case you want to use something other than the built in `git diff` command. -TODO: We don't ever cover this, lol. - +We only briefly mention this in <<_git_difftool>>. ==== git commit From e8224cb43b249f5b7a8d26e699b01884f01f90e2 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Thu, 9 Oct 2014 13:44:59 +0200 Subject: [PATCH 02/26] log, stash and tag --- book/02-git-basics/sections/tagging.asc | 1 + .../sections/viewing-history.asc | 1 + .../sections/contributing.asc | 1 + .../sections/maintaining.asc | 1 + .../sections/advanced-merging.asc | 1 + book/07-git-tools/sections/notes.asc | 1 + .../sections/revision-selection.asc | 1 + book/C-git-commands/1-git-commands.asc | 27 +++++++++++++++++++ 8 files changed, 34 insertions(+) diff --git a/book/02-git-basics/sections/tagging.asc b/book/02-git-basics/sections/tagging.asc index 8320272db..13666c50d 100644 --- a/book/02-git-basics/sections/tagging.asc +++ b/book/02-git-basics/sections/tagging.asc @@ -1,3 +1,4 @@ +[[_git_tagging]] === Tagging (((tags))) diff --git a/book/02-git-basics/sections/viewing-history.asc b/book/02-git-basics/sections/viewing-history.asc index 5dc3c49e6..44470282c 100644 --- a/book/02-git-basics/sections/viewing-history.asc +++ b/book/02-git-basics/sections/viewing-history.asc @@ -1,3 +1,4 @@ +[[_viewing_history]] === Viewing the Commit History After you have created several commits, or if you have cloned a repository with an existing commit history, you'll probably want to look back to see what has happened. diff --git a/book/05-distributed-git/sections/contributing.asc b/book/05-distributed-git/sections/contributing.asc index e42bccfa2..a0d50426c 100644 --- a/book/05-distributed-git/sections/contributing.asc +++ b/book/05-distributed-git/sections/contributing.asc @@ -89,6 +89,7 @@ The Git project has well-formatted commit messages – try running `git log --no In the following examples, and throughout most of this book, for the sake of brevity this book doesn't have nicely-formatted messages like this; instead, we use the `-m` option to `git commit`. Do as we say, not as we do. +[[_private_team]] ==== Private Small Team (((contributing, private small team))) diff --git a/book/05-distributed-git/sections/maintaining.asc b/book/05-distributed-git/sections/maintaining.asc index a6da6f6f4..88b1c3526 100644 --- a/book/05-distributed-git/sections/maintaining.asc +++ b/book/05-distributed-git/sections/maintaining.asc @@ -410,6 +410,7 @@ If you need to, you can interact with the rerere cache using the `git rerere` co When it's invoked alone, Git checks its database of resolutions and tries to find a match with any current merge conflicts and resolve them (although this is done automatically if `rerere.enabled` is set to `true`). There are also subcommands to see what will be recorded, to erase specific resolution from the cache, and to clear the entire cache. We will cover rerere in more detail in <<_rerere>>. +[[_tagging_releases]] ==== Tagging Your Releases (((tags)))(((tags, signing))) diff --git a/book/07-git-tools/sections/advanced-merging.asc b/book/07-git-tools/sections/advanced-merging.asc index e8140649f..e520feb0d 100644 --- a/book/07-git-tools/sections/advanced-merging.asc +++ b/book/07-git-tools/sections/advanced-merging.asc @@ -362,6 +362,7 @@ The `git checkout` command can also take `--ours` and `--theirs` options, which This can be particularly useful for conflicts of binary files where you can simply choose one side, or where you only want to merge certain files in from another branch - you can do the merge and then checkout certain files from one side or the other before committing. +[[_merge_log]] ===== Merge Log Another useful tool when resolving merge conflicts is `git log`. This can help you get context on what may have contributed to the conflicts. Reviewing a little bit of history to remember why two lines of development were touching the same area of code can be really helpful sometimes. diff --git a/book/07-git-tools/sections/notes.asc b/book/07-git-tools/sections/notes.asc index e3a5d4c8b..a100b4d01 100644 --- a/book/07-git-tools/sections/notes.asc +++ b/book/07-git-tools/sections/notes.asc @@ -1,3 +1,4 @@ +[[_git_notes]] === Notes One of the cool things about Git is that it has strong cryptographic integrity. If you change any bit in the commit data or any of the files it keeps, all the checksums change, including the commit SHA and every commit SHA since that one. However, that means that in order to amend the commit in any way, for instance to add some comments on something or even sign off on a commit, you have to change the SHA of the commit itself. diff --git a/book/07-git-tools/sections/revision-selection.asc b/book/07-git-tools/sections/revision-selection.asc index ce3b622f5..76e97c14c 100644 --- a/book/07-git-tools/sections/revision-selection.asc +++ b/book/07-git-tools/sections/revision-selection.asc @@ -104,6 +104,7 @@ $ git rev-parse topic1 ca82a6dff817ec66f44342007202690a93763949 ---- +[[_git_reflog]] ==== RefLog Shortnames One of the things Git does in the background while you’re working away is keep a ``reflog'' – a log of where your HEAD and branch references have been for the last few months. diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index 46e4aa629..95f0835cc 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -197,10 +197,37 @@ We mention it quickly in <<_basic_merge_conflicts>> and go into detail on how to ==== git log +The `git log` command is used to show the reachable recorded history of a project from the most recent commit snapshot backwards. By default it will only show the history of the branch you're currently on, but can be given different or even multiple heads or branches from which to traverse. It is also often used to show differences between two or more branches at the commit level. + +This command is used in nearly every chapter of the book to demonstrate the history of a project. + +We introduce the command and cover it in some depth in <<_viewing_history>>. There we look at the `-p` and `--stat` option to get an idea of what was introduced in each commit and the `--pretty` and `--oneline` options to view the history more concisely, along with some simple date and author filtering options. + +In <<_create_new_branch>> we use it with the `--decorate` option to easily visualize where our branch pointers are located and we also use the `--graph` option to see what divergent histories look like. + +In <<_private_team>> and <<_commit_ranges>> we cover the `branchA..branchB` syntax to use the `git log` command to see what commits are unique to a branch relative to another branch. In <<_commit_ranges>> we go through this fairly extensively. + +In <<_merge_log>> and <<_triple_dot>> we cover using the `branchA...branchB` format and the `--left-right` syntax to see what is in one branch or the other but not in both. In <<_merge_log>> we also look at how to use the `--merge` option to help with merge conflict debugging as well as using the `--cc` option to look at merge commit conflicts in your history. + +In <<_git_notes>> we use the `--notes=` option to display notes inline in the log output, and in <<_git_reflog>> we use the `-g` option to view the Git reflog through this tool instead of doing branch traversal. + +In <<_searching>> we look at using the `-S` and `-L` options to do fairly sophisticated searches for something that happened historically in the code such as seeing the history of a function. + +In <<_signing_commits>> we see how to use `--show-signature` to add a validation string to each commit in the `git log` output based on if it was validly signed or not. + ==== git stash +The `git stash` command is used to temporarily store uncomitted work in order to clean out your working directory without having to commit unfinished work on a branch. + +This is basically entirely covered in <<_git_stashing>>. + ==== git tag +The `git tag` command is used to give a permanant bookmark to a specific point in the code history. Generally this is used for things like releases. + +This command is introduced and covered in detail in <<_git_tagging>> and we use it in practice in <<_tagging_releases>>. + +We also cover how to create a GPG signed tag with the `-s` flag and verify one with the `-v` flag in <<_signing>>. === Sharing and Updating Projects From 4a33d46c4b1557214bd33715059594ee99f1962d Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Thu, 9 Oct 2014 13:59:44 +0200 Subject: [PATCH 03/26] plumbing section and flesh out the rest of the commands --- book/06-github/sections/3-maintaining.asc | 1 + book/07-git-tools/sections/reset.asc | 1 + .../sections/revision-selection.asc | 1 + book/C-git-commands/1-git-commands.asc | 127 +++++++++++------- 4 files changed, 79 insertions(+), 51 deletions(-) diff --git a/book/06-github/sections/3-maintaining.asc b/book/06-github/sections/3-maintaining.asc index 0233d0a69..b6bc447cf 100644 --- a/book/06-github/sections/3-maintaining.asc +++ b/book/06-github/sections/3-maintaining.asc @@ -100,6 +100,7 @@ image::images/maint-02-merge.png[Merge button] If you decide you don't want to merge it, you can also just close the Pull Request and the person who opened it will be notified. +[[_pr_refs]] ===== Pull Request Refs If you're dealing with a *lot* of Pull Requests and don't want to add a bunch of remotes or do one time pulls every time, there is a neat trick that GitHub allows you to do. This is a bit of an advanced trick and we'll go over the details of this a bit more in <<_refspec>>, but it can be pretty useful. diff --git a/book/07-git-tools/sections/reset.asc b/book/07-git-tools/sections/reset.asc index 5a840e8d3..4a3a4e97e 100644 --- a/book/07-git-tools/sections/reset.asc +++ b/book/07-git-tools/sections/reset.asc @@ -48,6 +48,7 @@ $ git ls-tree -r HEAD The `cat-file` and `ls-tree` commands are ``plumbing'' commands that are used for lower level things and not really used in day-to-day work, but they help us see what's going on here. +[[_the_index]] ===== The Index The Index is your *proposed next commit*. We've also been referring to this concept as Git's ``Staging Area'' as this is what Git looks at when you run `git commit`. diff --git a/book/07-git-tools/sections/revision-selection.asc b/book/07-git-tools/sections/revision-selection.asc index 76e97c14c..cc9675f57 100644 --- a/book/07-git-tools/sections/revision-selection.asc +++ b/book/07-git-tools/sections/revision-selection.asc @@ -81,6 +81,7 @@ If all 6.5 billion humans on Earth were programming, and every second, each one A higher probability exists that every member of your programming team will be attacked and killed by wolves in unrelated incidents on the same night. ==== +[[_branch_references]] ==== Branch References The most straightforward way to specify a commit requires that it have a branch reference pointed at it. diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index 95f0835cc..a005daf40 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -5,6 +5,7 @@ Throughout the book we have introduced dozens of Git commands and have tried har In this appendix, we'll go through all the Git commands we addressed throughout the book, grouped roughly by what they're used for. We'll talk about what each command very generally does and then point out where in the book you can find us having used it. + === Setup and Config There are two commands that are used quite a lot, from the first invocations of Git to common every day tweaking and referencing, the `config` and `help` commands. @@ -33,6 +34,7 @@ The `git help` command is used to show you all the documentation shipped with Gi We introduced the `git help` command in <<_git_help>> and showed you how to use it to find more information about the `git shell` in <<_setting_up_server>>. + === Getting and Creating Projects There are two ways to get a Git repository. One is to copy it from an existing repository on the network or elsewhere and the other is to create a new one in an existing directory. @@ -65,6 +67,7 @@ Finally, in <<_cloning_submodules>> we learn the `--recursive` option to make cl Though it's used in many other places through the book, these are the ones that are somewhat unique or where it is used in ways that are a little different. + === Basic Snapshotting For the basic workflow of staging content and committing it to your history, there are only a few basic commands. @@ -147,6 +150,7 @@ The `git mv` command is a thin convience command to move a file and then run `gi We only briefly mention this command in <<_git_mv>>. + === Branching and Merging There are just a handful of commands that implement most of the branching and merging functionality in Git. @@ -229,80 +233,101 @@ This command is introduced and covered in detail in <<_git_tagging>> and we use We also cover how to create a GPG signed tag with the `-s` flag and verify one with the `-v` flag in <<_signing>>. + === Sharing and Updating Projects -fetch -pull -push -remote -submodule +==== fetch + +==== pull + +==== push + +==== remote + +==== submodule + === Inspection and Comparison -show -log -diff -shortlog -describe +==== show + +==== shortlog + +==== describe + === Patching -apply -cherry-pick -diff -rebase -revert +==== apply + +==== cherry-pick + +==== rebase + +==== revert + === Debugging -bisect -blame -grep +==== bisect + +==== blame + +==== grep + === Email -am -apply -format-patch -send-email -request-pull +==== am + +==== apply + +==== format-patch + +==== send-email + +==== request-pull + === External Systems -svn -fast-import +==== svn + +==== fast-import + === Administration -clean -gc -fsck -reflog -filter-branch -instaweb -archive +==== clean + +==== gc + +==== fsck + +==== reflog + +==== filter-branch + +==== instaweb + +==== archive + === Server Admin -daemon -update-server-info +==== daemon + +==== update-server-info + === Plumbing Commands -cat-file -commit-tree -count-objects -diff-index -for-each-ref -hash-object -ls-files -merge-base -read-tree -rev-list -rev-parse -show-ref -symbolic-ref -update-index -update-ref -verify-pack -write-tree +There were also quite a number of lower level plumbing commands that we encountered in the book. + +The first one we encounter is `ls-remote` in <<_pr_refs>> which we use to look at the raw references on the server. + +We use `ls-files` in <<_manual_remerge>>, <<_rerere>> and <<_the_index>> to take a more raw look at what your staging area looks like. + +We also mention `rev-parse` in <<_branch_references>> to take just about any string and turn it into an object SHA. + +However, most of the low level plumbing commands we cover are in <<_git_internals>>, which is more or less what the chapter is focused on. We tried to avoid use of them throughout most of the rest of the book. From 0c0da3efe42b613c9ef6730841644cff92457631 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Thu, 9 Oct 2014 14:00:08 +0200 Subject: [PATCH 04/26] manual remerge link --- book/07-git-tools/sections/advanced-merging.asc | 1 + 1 file changed, 1 insertion(+) diff --git a/book/07-git-tools/sections/advanced-merging.asc b/book/07-git-tools/sections/advanced-merging.asc index e520feb0d..a9ad50d69 100644 --- a/book/07-git-tools/sections/advanced-merging.asc +++ b/book/07-git-tools/sections/advanced-merging.asc @@ -136,6 +136,7 @@ Since in this case, the actual file changes were not conflicting, once we ignore This is a lifesaver if you have someone on your team who likes to occasionally reformat everything from spaces to tabs or vice-versa. +[[_manual_remerge]] ===== Manual File Re-merging Though Git handles whitespace pre-processing pretty well, there are other types of changes that perhaps Git can't handle automatically, but are scriptable fixes. As an example, let's pretend that Git could not handle the whitespace change and we needed to do it by hand. From 2671a49431e0b2f656507757d1630ffe62acb88e Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Thu, 9 Oct 2014 14:42:43 +0200 Subject: [PATCH 05/26] fetch and pull --- book/02-git-basics/sections/remotes.asc | 3 ++- book/03-git-branching/sections/rebasing.asc | 1 + book/07-git-tools/sections/notes.asc | 1 + book/C-git-commands/1-git-commands.asc | 22 +++++++++++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/book/02-git-basics/sections/remotes.asc b/book/02-git-basics/sections/remotes.asc index 2363167d2..cff522c68 100644 --- a/book/02-git-basics/sections/remotes.asc +++ b/book/02-git-basics/sections/remotes.asc @@ -1,3 +1,4 @@ +[[_remote_repos]] === Working with Remotes To be able to collaborate on any Git project, you need to know how to manage your remote repositories. @@ -94,7 +95,7 @@ From https://github.com/paulboone/ticgit 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]] ==== Fetching and Pulling from Your Remotes As you just saw, to get data from your remote projects, you can run:(((git commands, fetch))) diff --git a/book/03-git-branching/sections/rebasing.asc b/book/03-git-branching/sections/rebasing.asc index 227cdbdd2..774e01ea6 100644 --- a/book/03-git-branching/sections/rebasing.asc +++ b/book/03-git-branching/sections/rebasing.asc @@ -170,6 +170,7 @@ If you run a `git log` when your history looks like this, you'll see two commits Furthermore, if you push this history back up to the server, you'll reintroduce all those rebased commits to the central server, which can further confuse people. It's pretty safe to assume that the other developer doesn't want `C4` and `C6` to be in the history; that's why she rebased in the first place. +[[_rebase_rebase]] ==== Rebase when you Rebase If you *do* find yourself in a situation like this, Git has some further magic that might help you out. If someone on your team force pushes changes that overwrite work that you've based work on, your challenge is to figure out what is yours and what they've rewritten. diff --git a/book/07-git-tools/sections/notes.asc b/book/07-git-tools/sections/notes.asc index a100b4d01..517ab9b90 100644 --- a/book/07-git-tools/sections/notes.asc +++ b/book/07-git-tools/sections/notes.asc @@ -161,6 +161,7 @@ To https://github.com/schacon/kidgloves In fact, you may want to just make that `git push origin refs/notes/*` which will push all your notes. This is what Git does normally for something like tags. When you run `git push origin --tags` it basically expands to `git push origin refs/tags/*`. +[[_getting_notes]] ==== Getting Notes Unfortunately, getting notes is even more difficult. Notes do not come down with a clone and there nothing like `git fetch --notes`. In order to fetch notes, you have to specify both sides of the refspec. diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index a005daf40..bcfc26f11 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -236,10 +236,32 @@ We also cover how to create a GPG signed tag with the `-s` flag and verify one w === Sharing and Updating Projects +There are not very many commands in Git that access the network, nearly all of the commands operate on the local database. When you are ready to share your work or pull changes from elsewhere, there are a handful of commands that deal with remote repositories. + ==== fetch +The `git fetch` command communicates with a remote repository and fetches down all the information that is in that repository that is not in your current one and stores it in your local database. + +We first look at this command in <<_fetching_and_pulling>> and we continue to see examples of it use in <<_remote_branches>>. + +We also use it in several of the examples in <<_contributing_project>>. + +We use it to fetch a single specific reference that is outside of the default space in <<_pr_refs>> and we see how to fetch from a bundle in <<_bundling>>. + +We set up highly custom refspecs in order to make `git fetch` do something a little different than the default in <<_getting_notes>> and <<_refspec>>. + ==== pull +The `git pull` command is basically a combination of the `git fetch` and `git merge` commands, where Git will fetch from the remote you specify and then immediately try to merge it into the branch you're on. + +We introduce it quicking in <<_fetching_and_pulling>> and show how to see what it will merge if you run it in <<_inspecting_remote>>. + +We also see how to use it to help with rebasing difficulties in <<_rebase_rebase>>. + +We use it with a URL to pull in changes in a one-off fashion in <<_checking_out_remotes>. + +Finally, we very quickly mention that you can use the `--verify-signatures` option to it in order to verify that commits you are pulling have been GPG signed. + ==== push ==== remote From e86fc25dd20559e3619f57d09be4a0ce26fe7a70 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Sun, 12 Oct 2014 20:20:18 -0700 Subject: [PATCH 06/26] Embedding: intro edits --- book/B-embedding-git/1-embedding-git.asc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/book/B-embedding-git/1-embedding-git.asc b/book/B-embedding-git/1-embedding-git.asc index 6f9b5c2fb..d1845f15e 100644 --- a/book/B-embedding-git/1-embedding-git.asc +++ b/book/B-embedding-git/1-embedding-git.asc @@ -2,9 +2,9 @@ == Embedding Git in your Applications If your application is for developers, chances are good that it could benefit from integration with source control. -Even other applications, such as document editors, could potentially benefit from version-control features, and Git's model works very well for many different scenarios. +Even non-developer applications, such as document editors, could potentially benefit from version-control features, and Git's model works very well for many different scenarios. -Beyond the most trivial use-cases, if you want to make your app work with Git repositories, you have essentially two choices. +If you need to integrate Git with your application, you have essentially three choices: spawning a shell and using the Git command-line tool; Libgit2; and JGit. include::sections/command-line.asc[] From beccdc4c71ae29c4ef2b68a042663c8e3dfb3d47 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Sun, 12 Oct 2014 20:20:39 -0700 Subject: [PATCH 07/26] JGit: setup and plumbing --- book/B-embedding-git/sections/jgit.asc | 115 ++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/book/B-embedding-git/sections/jgit.asc b/book/B-embedding-git/sections/jgit.asc index 9d078e89a..c2cef6734 100644 --- a/book/B-embedding-git/sections/jgit.asc +++ b/book/B-embedding-git/sections/jgit.asc @@ -1,4 +1,117 @@ === JGit (((jgit)))(((java))) -If you want to use Git from within a Java program, there is another fully features Git library called JGit. +If you want to use Git from within a Java program, there is a fully featured Git library called JGit. +JGit is a relatively full-featured implementation of Git written natively in Java, and is widely used in the Java community. +The JGit project is under the Eclipse umbrella, and its home can be found at http://www.eclipse.org/jgit[]. + +==== Getting Set Up + +There are a number of ways to connect your project with JGit and start writing code against it. +Probably the easiest is to use Maven – the integration is accomplished by adding the following snipped to the `` tag in your pom.xml file: + +[source,xml] +---- + + org.eclipse.jgit + org.eclipse.jgit + 3.5.0.201409260305-r + +---- + +The `version` will most likely have advanced by the time you read this; check http://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit[] for updated repository information. +Once this step is done, Maven will automatically acquire and use the JGit libraries that you'll need. + +If you would rather manage the binary dependencies yourself, pre-built JGit binaries are available from http://www.eclipse.org/jgit/download[]. +You can build them into your project by running a command like this: + +[source,shell] +---- +javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java +java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App +---- + +==== Plumbing + +JGit has two basic levels of API: plumbing and porcelain. +The terminology for these comes from Git itself, and JGit is divided into roughly the same kinds of areas. +Porcelain APIs are a friendly front-end for common user-level actions (the sorts of things a normal user would use the Git command-line tool for), while the plumbing APIs are for interacting with low-level repository objects directly. + +The starting point for most JGit sessions is the `Repository` class, and the first thing you'll want to do is create an instance of it. +For a filesystem-based repository (yes, JGit allows for other storage models), this is accomplished using `FileRepositoryBuilder`: + +[source,java] +---- +// Create a new repository; the path must exist +Repository newlyCreatedRepo = FileRepositoryBuilder.create( + new File("/tmp/new_repo/.git")); + +// Open an existing repository +Repository existingRepo = new FileRepositoryBuilder() + .setGitDir(new File("my_repo/.git")) + .build(); +---- + +The builder has a fluent API for providing all the things it needs to find a Git repository, whether or not your program knows exactly where it's located. +It can use environment variables (`.readEnvironment()`), start from a place in the working directory and search (`.setWorkTree(…).findGitDir()`), or just open a known `.git` directory as above. + +Once you have a `Repository` instance, you can do all sorts of things with it. +Here's a quick sampling: + +[source,java] +---- +// Get a reference +Ref master = repo.getRef("master"); + +// Get the object the reference points to +ObjectId masterTip = master.getObjectId(); + +// Rev-parse +ObjectId obj = repo.resolve("HEAD~~"); + +// Load raw object contents +ObjectLoader loader = r.open(masterTip); +loader.copyTo(System.out); + +// Create a branch +RefUpdate createBranch1 = r.updateRef("refs/heads/branch1"); +createBranch1.setNewObjectId(masterTip); +createBranch1.update(); + +// Delete a branch +RefUpdate deleteBranch1 = r.updateRef("refs/heads/branch1"); +deleteBranch1.setForceUpdate(true); +deleteBranch1.delete(); + +// Config +Config cfg = r.getConfig(); +String name = cfg.getString("user", null, "name"); +---- + +There's quite a bit going on here, so let's go through it one section at a time. + +The first line gets a pointer to the `master` reference. +JGit automatically grabs the _actual_ master ref, which lives at `refs/heads/master`, and returns an object that lets you get information about the reference (Ref instances are read-only). +You can get the name (`.getName()`), and either the target object of a direct reference (`.getObjectId()`) or the reference pointed to by a symbolic ref (`.getTarget()`). +Ref objects are also used to represent tag refs and objects, so you can ask if the tag is ``peeled,'' meaning that it points to the final target of a (potentially long) string of tag objects. + +The second line gets the target of the `master` reference, which is returned as an ObjectId instance. +ObjectId represents the SHA-1 hash of an object, which might or might not exist in Git's object database. +The third line is similar, but shows how JGit handles the rev-parse syntax (for more on this, see <<_branch_references>>); you can pass any single-point branch specifier that Git understands, and JGit will return either a valid ObjectId for that object, or `null`. + +The next two lines show how to load the raw contents of an object. +In this example, we call `ObjectLoader.copyTo()` to stream the contents of the object directly to stdout, but ObjectLoader also has methods to read the type and size of an object, as well as return it as an array of bytes. +For large objects (where `.isLarge()` returns `true`), you can call `.openStream()` to get an InputStream-like object that can read the raw object data. + +The next few lines show what it takes to create a new branch. +We create a RefUpdate instance, configure some parameters, and call `.update()` to trigger the change. +Directly following this is how to delete that same branch. +Note that `.setForceUpdate(true)` is required for this to complete. + +The last example shows how to fetch the `user.name` value from the Git configuration files. +This Config instance uses the repository we opened earlier for local configuration, but will automatically detect the global and system configuration files and read values from them as well. + + +==== Porcelain + +==== Further Reading From 652bccb03bed35d5e44b077077fdb20edec4491b Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 13 Oct 2014 10:50:33 +0200 Subject: [PATCH 08/26] forgot to add these xlinks --- book/02-git-basics/sections/remotes.asc | 1 + book/05-distributed-git/sections/contributing.asc | 1 + 2 files changed, 2 insertions(+) diff --git a/book/02-git-basics/sections/remotes.asc b/book/02-git-basics/sections/remotes.asc index cff522c68..1aee826d9 100644 --- a/book/02-git-basics/sections/remotes.asc +++ b/book/02-git-basics/sections/remotes.asc @@ -133,6 +133,7 @@ If you and someone else clone at the same time and they push upstream and then y You'll have to pull down their work first and incorporate it into yours before you'll be allowed to push. See <<_git_branching>> for more detailed information on how to push to remote servers. +[[_inspecting_remote]] ==== Inspecting a Remote If you want to see more information about a particular remote, you can use the `git remote show [remote-name]` command.(((git commands, remote))) diff --git a/book/05-distributed-git/sections/contributing.asc b/book/05-distributed-git/sections/contributing.asc index a0d50426c..21cc9212a 100644 --- a/book/05-distributed-git/sections/contributing.asc +++ b/book/05-distributed-git/sections/contributing.asc @@ -1,3 +1,4 @@ +[[_contributing_project]] === Contributing to a Project (((contributing))) From 2fb691db06d94c6e1d419c0482bd9a2f7a7ee283 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 13 Oct 2014 12:40:39 +0200 Subject: [PATCH 09/26] push, remote and submodule --- book/02-git-basics/sections/remotes.asc | 1 + book/02-git-basics/sections/tagging.asc | 1 + .../sections/remote-branches.asc | 2 ++ book/07-git-tools/sections/notes.asc | 1 + book/07-git-tools/sections/submodules.asc | 1 + book/08-customizing-git/sections/hooks.asc | 1 + book/10-git-internals/sections/refspec.asc | 1 + book/C-git-commands/1-git-commands.asc | 29 +++++++++++++++++-- 8 files changed, 35 insertions(+), 2 deletions(-) diff --git a/book/02-git-basics/sections/remotes.asc b/book/02-git-basics/sections/remotes.asc index 1aee826d9..67632709d 100644 --- a/book/02-git-basics/sections/remotes.asc +++ b/book/02-git-basics/sections/remotes.asc @@ -117,6 +117,7 @@ If you have a branch set up to track a remote branch (see the next section and < 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_remotes]] ==== Pushing to Your Remotes When you have your project at a point that you want to share, you have to push it upstream. diff --git a/book/02-git-basics/sections/tagging.asc b/book/02-git-basics/sections/tagging.asc index 13666c50d..ee79a2390 100644 --- a/book/02-git-basics/sections/tagging.asc +++ b/book/02-git-basics/sections/tagging.asc @@ -173,6 +173,7 @@ Date: Sun Apr 27 20:43:35 2008 -0700 ... ---- +[[_sharing_tags]] ==== Sharing Tags By default, the `git push` command doesn't transfer tags to remote servers.(((git commands, push))) diff --git a/book/03-git-branching/sections/remote-branches.asc b/book/03-git-branching/sections/remote-branches.asc index 11b2a4736..d63809261 100644 --- a/book/03-git-branching/sections/remote-branches.asc +++ b/book/03-git-branching/sections/remote-branches.asc @@ -50,6 +50,7 @@ Because that server is a subset of the data your `origin` server has right now, .Remote tracking branch for `teamone/master` image::images/remote-branches-5.png[Remote tracking branch for `teamone/master`.] +[[_pushing_branches]] ==== Pushing (((pushing))) @@ -189,6 +190,7 @@ If you have a tracking branch set up as demonstrated in the last section, either Generally it's better to simply use the `fetch` and `merge` commands explicitly as the magic of `git pull` can often be confusing. +[[_delete_branches]] ==== Deleting Remote Branches (((branches, deleting remote))) diff --git a/book/07-git-tools/sections/notes.asc b/book/07-git-tools/sections/notes.asc index 517ab9b90..a3d5514ce 100644 --- a/book/07-git-tools/sections/notes.asc +++ b/book/07-git-tools/sections/notes.asc @@ -133,6 +133,7 @@ You can also switch the current namespace you're using so that the default for w $ git config core.notesRef refs/notes/bugzilla ---- +[[_sharing_notes]] === Sharing Notes The notes (as you may have noticed in the previous section) are stored as references, just like branches and tags. This means you can push them to a server. However, Git has a bit of magic built in to expand a branch name like `master` to it's full name, which is `refs/heads/master`. Unfortunately, Git has no such magic built in for notes. So to push your notes to a server you cannot simply run something like `git push origin bugzilla`. Git will do diff --git a/book/07-git-tools/sections/submodules.asc b/book/07-git-tools/sections/submodules.asc index d2d8d21c9..203f4f8c8 100644 --- a/book/07-git-tools/sections/submodules.asc +++ b/book/07-git-tools/sections/submodules.asc @@ -451,6 +451,7 @@ Unable to merge 'c75e92a2b3855c9e5b66f915308390d9db204aca' in submodule path 'Db You can go into the submodule directory and fix the conflict just as you normally would. +[[_publishing_submodules]] ===== Publishing Submodule Changes Now we have some changes in our submodule directory. Some of these were brought in from upstream by our updates and others were made locally and aren't available to anyone else yet as we haven't pushed them yet. diff --git a/book/08-customizing-git/sections/hooks.asc b/book/08-customizing-git/sections/hooks.asc index 60ed58328..d24af1671 100644 --- a/book/08-customizing-git/sections/hooks.asc +++ b/book/08-customizing-git/sections/hooks.asc @@ -73,6 +73,7 @@ The last hook to run during a `git am` operation is `post-applypatch`, which run You can use it to notify a group or the author of the patch you pulled in that you've done so. You can't stop the patching process with this script. +[[_other_client_hooks]] ===== Other Client Hooks The `pre-rebase` hook runs before you rebase anything and can halt the process by exiting non-zero. diff --git a/book/10-git-internals/sections/refspec.asc b/book/10-git-internals/sections/refspec.asc index caab9fb0a..1abf5379c 100644 --- a/book/10-git-internals/sections/refspec.asc +++ b/book/10-git-internals/sections/refspec.asc @@ -95,6 +95,7 @@ If you have a QA team that pushes a series of branches, and you want to get the If you have a complex workflow process that has a QA team pushing branches, developers pushing branches, and integration teams pushing and collaborating on remote branches, you can namespace them easily this way. +[[_pushing_refspecs]] ==== Pushing Refspecs It's nice that you can fetch namespaced references that way, but how does the QA team get their branches into a `qa/` namespace in the first place? diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index bcfc26f11..530a2fb1e 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -258,16 +258,41 @@ We introduce it quicking in <<_fetching_and_pulling>> and show how to see what i We also see how to use it to help with rebasing difficulties in <<_rebase_rebase>>. -We use it with a URL to pull in changes in a one-off fashion in <<_checking_out_remotes>. +We show how to use it with a URL to pull in changes in a one-off fashion in <<_checking_out_remotes>>. -Finally, we very quickly mention that you can use the `--verify-signatures` option to it in order to verify that commits you are pulling have been GPG signed. +Finally, we very quickly mention that you can use the `--verify-signatures` option to it in order to verify that commits you are pulling have been GPG signed in <<_signing_commits>>. ==== push +The `git push` command is used to communicate with another repository, calculate what your local database has that the remote one does not, and then pushes the difference into the other repository. It requires write access to the other repository and so normally is authenticated somehow. + +We first look at the `git push` command in <<_pushing_remotes>>. Here we cover the basics of pushing a branch to a remote repository. In <<_pushing_branches>> we go a little deeper into pushing specific branches and in <<_tracking_branches>> we see how to set up tracking branches to automatically push to. In <<_delete_branches>> we use the `--delete` flag to delete a branch on the server with `git push`. + +Throughout <<_contributing_project>> we see several examples of using `git push` to share work on branches through multiple remotes. + +We see how to use it to share tags that you have made with the `--tags` option in <<_sharing_tags>>. + +In <<_sharing_notes>> we use it in a slightly less common way to share references for commit notes -- references that sit outside of the normal refs namespace. + +In <<_publishing_submodules>> we use the `--recurse-submodules` option to check that all of our submodules work has been published before pushing the superproject, which can be really helpful when using submodules. + +In <<_other_client_hooks>> we talk briefly about the `pre-push` hook, which is a script we can setup to run before a push completes to verify that it should be allowed to push. + +Finally, in <<_pushing_refspecs>> we look at pushing with a full refspec instead of the general shortcuts that are normally used. This can help you be very specific about what work you wish to share. + ==== remote +The `git remote` command is a management tool for your record of remote repositories. It allows you to save long URLs as short handles, such as ``origin'' so you don't have to type them out all the time. You can have several of these and the `git remote` command is used to add, change and delete them. + +This command is covered in detail in <<_remote_repos>>, including listing, adding, removing and renaming them. + +It is used in nearly every subsequent chapter in the book too, but always in the standard `git remote add ` format. + ==== submodule +The `git submodule` command is used to manage external repositories within a normal repositories. This could be for libraries or other types of shared resources. The `submodule` command has several sub-commands (`add`, `update`, `sync`, etc) for managing these resources. + +This command is only mentioned and entirely covered in <<_git_submodules>>. === Inspection and Comparison From 0cce6a40cbb1987869e0a26ee5b9eea435477312 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 13 Oct 2014 15:24:16 +0200 Subject: [PATCH 10/26] inspection and comparison --- book/02-git-basics/sections/tagging.asc | 1 + book/05-distributed-git/sections/maintaining.asc | 3 +++ book/07-git-tools/sections/revision-selection.asc | 1 + book/C-git-commands/1-git-commands.asc | 15 +++++++++++++++ 4 files changed, 20 insertions(+) diff --git a/book/02-git-basics/sections/tagging.asc b/book/02-git-basics/sections/tagging.asc index ee79a2390..19b10e380 100644 --- a/book/02-git-basics/sections/tagging.asc +++ b/book/02-git-basics/sections/tagging.asc @@ -49,6 +49,7 @@ 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. +[[_annotated_tags]] ==== Annotated Tags (((tags, annotated))) diff --git a/book/05-distributed-git/sections/maintaining.asc b/book/05-distributed-git/sections/maintaining.asc index 88b1c3526..d46360caf 100644 --- a/book/05-distributed-git/sections/maintaining.asc +++ b/book/05-distributed-git/sections/maintaining.asc @@ -466,6 +466,7 @@ $ git show maintainer-pgp-pub | gpg --import They can use that key to verify all your signed tags. Also, if you include instructions in the tag message, running `git show ` will let you give the end user more specific instructions about tag verification. +[[_build_number]] ==== Generating a Build Number (((build numbers)))(((git commands, describe))) @@ -486,6 +487,7 @@ The `git describe` command favors annotated tags (tags created with the `-a` or You can also use this string as the target of a checkout or show command, although it relies on the abbreviated SHA-1 value at the end, so it may not be valid forever. For instance, the Linux kernel recently jumped from 8 to 10 characters to ensure SHA-1 object uniqueness, so older `git describe` output names were invalidated. +[[_preparing_release]] ==== Preparing a Release (((releasing)))(((git commands, archive))) @@ -510,6 +512,7 @@ $ git archive master --prefix='project/' --format=zip > `git describe master`.zi You now have a nice tarball and a zip archive of your project release that you can upload to your website or e-mail to people. +[[_the_shortlog]] ==== The Shortlog (((git commands, shortlog))) diff --git a/book/07-git-tools/sections/revision-selection.asc b/book/07-git-tools/sections/revision-selection.asc index cc9675f57..90d718b68 100644 --- a/book/07-git-tools/sections/revision-selection.asc +++ b/book/07-git-tools/sections/revision-selection.asc @@ -1,3 +1,4 @@ +[[_revision_selection]] === Revision Selection Git allows you to specify specific commits or a range of commits in several ways. diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index 530a2fb1e..c53c66ff9 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -298,10 +298,25 @@ This command is only mentioned and entirely covered in <<_git_submodules>>. ==== show +The `git show` command can show a Git object in a simple and human readable way. Normally you would use this to show the information about a tag or a commit. + +We first use it to show annotated tag information in <<_annotated_tags>>. + +Later we use it quite a bit in <<_revision_selection>> to show the commits that our various revision selections resolve to. + +One of the more interesting things we do with `git show` is in <<_manual_remerge>> to extract specific file contents of various stages during a merge conflict. + ==== shortlog +The `git shortlog` command is used to summarize the output of `git log`. It will take many of the same options that the `git log` command will but instead of listing out all of the commits it will present a summary of the commits grouped by author. + +We showed how to use it to create a nice changelog in <<_the_shortlog>>. + ==== describe +The `git describe` command is used to take anything that resolves to a commit and produces a string that is somewhat human-readable and will not change. It's a way to get a description of a commit that is as unambiguous as a commit SHA but more understandable. + +We use `git describe` in <<_build_number>> and <<_preparing_release>> to get a string to name our release file after. === Patching From a5033d377d0e8e3e076d048e1b1d1c20b78921f6 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 13 Oct 2014 15:44:24 +0200 Subject: [PATCH 11/26] debug and started on patching --- .../sections/maintaining.asc | 1 + book/07-git-tools/sections/debugging.asc | 2 + book/07-git-tools/sections/searching.asc | 1 + book/C-git-commands/1-git-commands.asc | 38 ++++++++++++++----- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/book/05-distributed-git/sections/maintaining.asc b/book/05-distributed-git/sections/maintaining.asc index d46360caf..c6552aa0d 100644 --- a/book/05-distributed-git/sections/maintaining.asc +++ b/book/05-distributed-git/sections/maintaining.asc @@ -28,6 +28,7 @@ $ git checkout -b sc/ruby_client master Now you're ready to add your contributed work into this topic branch and determine if you want to merge it into your longer-term branches. +[[_patches_from_email]] ==== Applying Patches from E-mail (((email, applying patches from))) diff --git a/book/07-git-tools/sections/debugging.asc b/book/07-git-tools/sections/debugging.asc index 707c00dae..775389c2e 100644 --- a/book/07-git-tools/sections/debugging.asc +++ b/book/07-git-tools/sections/debugging.asc @@ -3,6 +3,7 @@ Git also provides a couple of tools to help you debug issues in your projects. Because Git is designed to work with nearly any type of project, these tools are pretty generic, but they can often help you hunt for a bug or culprit when things go wrong. +[[_file_annotation]] ==== File Annotation If you track down a bug in your code and want to know when it was introduced and why, file annotation is often your best tool. @@ -62,6 +63,7 @@ This is really useful. Normally, you get as the original commit the commit where you copied the code over, because that is the first time you touched those lines in this file. Git tells you the original commit where you wrote those lines, even if it was in another file. +[[_binary_search]] ==== Binary Search Annotating a file helps if you know where the issue is to begin with. diff --git a/book/07-git-tools/sections/searching.asc b/book/07-git-tools/sections/searching.asc index 194954cbf..caf08d8e1 100644 --- a/book/07-git-tools/sections/searching.asc +++ b/book/07-git-tools/sections/searching.asc @@ -3,6 +3,7 @@ With just about any size codebase, you'll often need to find where a function is called or defined, or find the history of a method. Git provides a couple of useful tools for looking through the code and commits stored in it's database quickly and easily. We'll go through a few of them. +[[_git_grep]] ==== Git Grep Git ships with a command called `grep` that allows you to easily search through any committed tree or the working directory for a string or regular expression. For these examples, we'll look through the Git source code itself. diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index c53c66ff9..b5c887e6d 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -318,32 +318,52 @@ The `git describe` command is used to take anything that resolves to a commit an We use `git describe` in <<_build_number>> and <<_preparing_release>> to get a string to name our release file after. -=== Patching -==== apply +=== Debugging -==== cherry-pick +Git has a couple of commands that are used to help debug an issue in your code. This ranges from figuring out where something was introduced to figuring out who introduced it. -==== rebase +==== bisect -==== revert +The `git bisect` tool is an incredibly helpful debugging tool used to find which specific commit was the first one to introduce a bug or problem by doing an automatic binary search. +It is fully covered in <<_binary_search>> and is only mentioned in that section. -=== Debugging +==== blame -==== bisect +The `git blame` command annotates the lines of any file with which commit was the last one to introduce a change to each line of the file and what person authored that commit. This is helpful in order to find the person to ask for more information about a specific section of your code. -==== blame +It is covered in <<_file_annotation>> and is only mentioned in that section. ==== grep +The `git grep` command can help you find any string or regular expression in any of the files in your source code, even older versions of your project. + +It is covered in <<_git_grep>> and is only mentioned in that section. + +=== Patching + +A few commands in Git are centered around the concept of thinking of commits in terms of the changes they introduce, as thought the commit series is a series of patches. These commands help you manage your branches in this manner. + +==== cherry-pick + +==== rebase + +==== revert + === Email -==== am +Many Git projects, including Git itself, are entirely maintained over mailing lists. Git has a number of tools built into it that help make this process easier, from generating patches you can easily email to applying those patches from an email box. ==== apply +The `git apply` command applies a patch created with the `git diff` or even GNU diff command. It is similar to what the `patch` command might do with a few small differences. + +We demonstrate using it and the circumstances in which you might do so in <<_patches_from_email>>. + +==== am + ==== format-patch ==== send-email From ea4fa232c9d9abdc4f774cf33053257f25022fbb Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 13 Oct 2014 15:55:02 +0200 Subject: [PATCH 12/26] rebase --- book/05-distributed-git/sections/maintaining.asc | 1 + book/07-git-tools/sections/replace.asc | 1 + book/C-git-commands/1-git-commands.asc | 14 ++++++++++++++ 3 files changed, 16 insertions(+) diff --git a/book/05-distributed-git/sections/maintaining.asc b/book/05-distributed-git/sections/maintaining.asc index c6552aa0d..fe7ad2049 100644 --- a/book/05-distributed-git/sections/maintaining.asc +++ b/book/05-distributed-git/sections/maintaining.asc @@ -354,6 +354,7 @@ When a topic branch has finally been merged into `master`, it's removed from the The Git project also has a `maint` branch that is forked off from the last release to provide backported patches in case a maintenance release is required. Thus, when you clone the Git repository, you have four branches that you can check out to evaluate the project in different stages of development, depending on how cutting edge you want to be or how you want to contribute; and the maintainer has a structured workflow to help them vet new contributions. +[[_rebase_cherry_pick]] ===== Rebasing and Cherry Picking Workflows (((workflows, rebasing and cherry-picking))) diff --git a/book/07-git-tools/sections/replace.asc b/book/07-git-tools/sections/replace.asc index fbe561739..bba66082d 100644 --- a/book/07-git-tools/sections/replace.asc +++ b/book/07-git-tools/sections/replace.asc @@ -1,3 +1,4 @@ +[[_replace]] === Replace Git's objects are unchangable, but it does provide an interesting way to pretend to replace objects in it's database with other objects. diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index b5c887e6d..895bb0dff 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -347,8 +347,22 @@ A few commands in Git are centered around the concept of thinking of commits in ==== cherry-pick +The `git cherry-pick` command is used to take the change introduced in a single Git commit and try to re-introduce it as a new commit on the branch you're currently on. This can be useful to only take one or two commits from a branch individually rather than merging in the branch which takes all the changes. + +Cherry picking is described and demonstrated in <<_rebase_cherry_pick>>. + ==== rebase +The `git rebase` command is basically an automated `cherry-pick`. It determines a series of commits and then cherry-picks them one by one in the same order somewhere else. + +Rebasing is covered in detail in <<_rebasing>>, including covering the collaborative issues involved with rebasing branches that are already public. + +We use it in practice during an example of splitting your history into two seperate repositories in <<_replace>>, using the `--onto` flag as well. + +We go through running into a merge conflict during rebasing in <<_rerere>>. + +We also use it in an interactive scripting mode with the `-i` option in <<_changing_multiple>>. + ==== revert From e65216bc11d2441945d7b38a3df9da48df69d1e8 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 13 Oct 2014 15:56:59 +0200 Subject: [PATCH 13/26] revert --- book/07-git-tools/sections/advanced-merging.asc | 1 + book/C-git-commands/1-git-commands.asc | 3 +++ 2 files changed, 4 insertions(+) diff --git a/book/07-git-tools/sections/advanced-merging.asc b/book/07-git-tools/sections/advanced-merging.asc index a9ad50d69..cff31bbb2 100644 --- a/book/07-git-tools/sections/advanced-merging.asc +++ b/book/07-git-tools/sections/advanced-merging.asc @@ -514,6 +514,7 @@ The downside of this approach is that it's rewriting history, which can be probl Check out <<_rebase_peril>> for more on what can happen; the short version is that if other people have the commits you're rewriting, you should probably avoid `reset`. This approach also won't work if any other commits have been created since the merge; moving the refs would effectively lose those changes. +[[_reverse_commit]] ===== Reverse the commit If moving the branch pointers around isn't going to work for you, Git gives you the option of making a new commit which undoes all the changes from an existing one. diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index 895bb0dff..7442d5143 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -365,6 +365,9 @@ We also use it in an interactive scripting mode with the `-i` option in <<_chang ==== revert +The `git revert` command is essentially a reverse `git cherry-pick`. It creates a new commit that applies the exact opposite of the change introduced in the commit you're targeting, essentially undoing or reverting it. + +We use this in <<_reverse_commit>> to undo a merge commit. === Email From 8215864ee0407bfb88cb90956ae8732f3ad9c6b9 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 13 Oct 2014 18:08:47 +0200 Subject: [PATCH 14/26] am, format-patch, send-email and request-pull --- .../sections/contributing.asc | 1 + .../sections/maintaining.asc | 1 + book/06-github/sections/3-maintaining.asc | 1 + .../sections/rewriting-history.asc | 1 + book/08-customizing-git/sections/hooks.asc | 1 + book/C-git-commands/1-git-commands.asc | 19 +++++++++++++++++++ 6 files changed, 24 insertions(+) diff --git a/book/05-distributed-git/sections/contributing.asc b/book/05-distributed-git/sections/contributing.asc index 21cc9212a..f7301818f 100644 --- a/book/05-distributed-git/sections/contributing.asc +++ b/book/05-distributed-git/sections/contributing.asc @@ -615,6 +615,7 @@ Now you can send the maintainer a message that you've made the requested changes .Commit history after `featureBv2` work. image::images/public-small-3.png[Commit history after `featureBv2` work.] +[[_project_over_email]] ==== Public Project over E-Mail (((contributing, public large project))) diff --git a/book/05-distributed-git/sections/maintaining.asc b/book/05-distributed-git/sections/maintaining.asc index fe7ad2049..2f521758e 100644 --- a/book/05-distributed-git/sections/maintaining.asc +++ b/book/05-distributed-git/sections/maintaining.asc @@ -65,6 +65,7 @@ error: ticgit.gemspec: patch does not apply If there is no output, then the patch should apply cleanly. This command also exits with a non-zero status if the check fails, so you can use it in scripts if you want. +[[_git_am]] ===== Applying a Patch with `am` (((git commands, am))) diff --git a/book/06-github/sections/3-maintaining.asc b/book/06-github/sections/3-maintaining.asc index b6bc447cf..d3e9dd93a 100644 --- a/book/06-github/sections/3-maintaining.asc +++ b/book/06-github/sections/3-maintaining.asc @@ -62,6 +62,7 @@ Pull Requests can either come from a branch in a fork of your repository or they For these examples, let's assume you are ``tonychacon'' and you've created a new Arudino code project named ``fade''. +[[_email_notifications]] ===== Email Notifications Someone comes along and makes a change to your code and sends you a Pull Request. You should get an email notifying you about the new Pull Request and it should look something like <<_email_pr>>. diff --git a/book/07-git-tools/sections/rewriting-history.asc b/book/07-git-tools/sections/rewriting-history.asc index c74a39c35..79efa6f27 100644 --- a/book/07-git-tools/sections/rewriting-history.asc +++ b/book/07-git-tools/sections/rewriting-history.asc @@ -30,6 +30,7 @@ You stage the changes you want by editing a file and running `git add` on it or You need to be careful with this technique because amending changes the SHA-1 of the commit. It’s like a very small rebase – don’t amend your last commit if you’ve already pushed it. +[[_changing_multiple]] ==== Changing Multiple Commit Messages To modify a commit that is farther back in your history, you must move to more complex tools. diff --git a/book/08-customizing-git/sections/hooks.asc b/book/08-customizing-git/sections/hooks.asc index d24af1671..f2215c8a2 100644 --- a/book/08-customizing-git/sections/hooks.asc +++ b/book/08-customizing-git/sections/hooks.asc @@ -53,6 +53,7 @@ After the entire commit process is completed, the `post-commit` hook runs. It doesn't take any parameters, but you can easily get the last commit by running `git log -1 HEAD`. Generally, this script is used for notification or something similar. +[[_email_hooks]] ===== E-mail Workflow Hooks You can set up three client-side hooks for an e-mail-based workflow. diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index 7442d5143..d54471cff 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -381,12 +381,31 @@ We demonstrate using it and the circumstances in which you might do so in <<_pat ==== am +The `git am` command is used to apply patches from an email inbox, specifically one that is mbox formatted. This is useful for receiving patches over email and applying them to your project easily. + +We covered usage and workflow around `git am` in <<_git_am>> including using the `--resolved`, `-i` and `-3` options. + +There are also a number of hooks you can use to help with the workflow around `git am` and they are all covered in <<_email_hooks>>. + +We also use it to apply patch formatted GitHub Pull Request changes in <<_email_notifications>>. + ==== format-patch +The `git format-patch` command is used to generate a series of patches in mbox format that you can use to send to a mailing list properly formatted. + +We go through an example of contributing to a project using the `git format-patch` tool in <<_project_over_email>>. + ==== send-email +The `git send-email` command is used to send patches that are generated with `git format-patch` over email. + +We go through an example of contributing to a project by sending patches with the `git send-email` tool in <<_project_over_email>>. + ==== request-pull +The `git request-pull` command is simply used to generate an example message body to email to someone. If you have a branch on a public server and want to let someone know how to integrate those changes without sending the patches over email, you can run this command and send the output to the person you want to pull the changes in. + +We demonstrate how to use `git request-pull` to generate a pull message in <<_public_project>>. === External Systems From 38a302ddf5d92de47ffcaa6e086f2c30422c5ae1 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 13 Oct 2014 18:14:54 +0200 Subject: [PATCH 15/26] svn, import --- book/09-git-and-other-scms/sections/client-svn.asc | 1 + .../sections/import-custom.asc | 1 + book/C-git-commands/1-git-commands.asc | 14 ++++++++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/book/09-git-and-other-scms/sections/client-svn.asc b/book/09-git-and-other-scms/sections/client-svn.asc index ab87796a8..90a5cde6e 100644 --- a/book/09-git-and-other-scms/sections/client-svn.asc +++ b/book/09-git-and-other-scms/sections/client-svn.asc @@ -1,3 +1,4 @@ +[[_git_svn]] ==== Git and Subversion (((Subversion)))(((Interoperation with other VCSs, Subversion))) diff --git a/book/09-git-and-other-scms/sections/import-custom.asc b/book/09-git-and-other-scms/sections/import-custom.asc index f03543204..88635b382 100644 --- a/book/09-git-and-other-scms/sections/import-custom.asc +++ b/book/09-git-and-other-scms/sections/import-custom.asc @@ -1,3 +1,4 @@ +[[_custom_importer]] ==== A Custom Importer (((git commands, fast-import))) diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index d54471cff..33bedf863 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -409,13 +409,23 @@ We demonstrate how to use `git request-pull` to generate a pull message in <<_pu === External Systems +Git comes with a few commands to integrate with other version control systems. + ==== svn +The `git svn` command is used to communicate with the Subversion version control system as a client. This means you can use Git to checkout from and commit to a Subversion server. + +This command is covered in depth in <<_git_svn>>. + ==== fast-import +For other version control systems or importing from nearly any format, you can use `git fast-import` to quickly map the other format to something Git can easily record. + +This command is coverd in depth in <<_custom_importer>>. === Administration + ==== clean ==== gc @@ -426,8 +436,6 @@ We demonstrate how to use `git request-pull` to generate a pull message in <<_pu ==== filter-branch -==== instaweb - ==== archive @@ -437,6 +445,8 @@ We demonstrate how to use `git request-pull` to generate a pull message in <<_pu ==== update-server-info +==== instaweb + === Plumbing Commands From c4601068eaab57c5a632291358ed1f64bf5c31c6 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 13 Oct 2014 18:49:40 +0200 Subject: [PATCH 16/26] rest of the commands --- book/02-git-basics/sections/undoing.asc | 2 +- .../sections/rewriting-history.asc | 1 + .../sections/stashing-cleaning.asc | 1 + .../sections/import-p4.asc | 1 + .../sections/import-tfs.asc | 1 + .../10-git-internals/sections/maintenance.asc | 3 +- book/C-git-commands/1-git-commands.asc | 35 ++++++++++++++----- 7 files changed, 34 insertions(+), 10 deletions(-) diff --git a/book/02-git-basics/sections/undoing.asc b/book/02-git-basics/sections/undoing.asc index 7dbecf2e3..4720e780b 100644 --- a/book/02-git-basics/sections/undoing.asc +++ b/book/02-git-basics/sections/undoing.asc @@ -126,5 +126,5 @@ Don't ever use this command unless you absolutely know that you don't want the f 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 <<_git_branching>>; these are generally better ways to go. 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). +Even commits that were on branches that were deleted or commits that were overwritten with an `--amend` commit can be recovered (see <<_data_recovery>> for data recovery). However, anything you lose that was never committed is likely never to be seen again. diff --git a/book/07-git-tools/sections/rewriting-history.asc b/book/07-git-tools/sections/rewriting-history.asc index 79efa6f27..1dc24a6bd 100644 --- a/book/07-git-tools/sections/rewriting-history.asc +++ b/book/07-git-tools/sections/rewriting-history.asc @@ -260,6 +260,7 @@ The command is `filter-branch`, and it can rewrite huge swaths of your history, However, it can be very useful. You’ll learn a few of the common uses so you can get an idea of some of the things it’s capable of. +[[_removing_file_every_commit]] ===== Removing a File from Every Commit This occurs fairly commonly. diff --git a/book/07-git-tools/sections/stashing-cleaning.asc b/book/07-git-tools/sections/stashing-cleaning.asc index e27faffa7..16546af77 100644 --- a/book/07-git-tools/sections/stashing-cleaning.asc +++ b/book/07-git-tools/sections/stashing-cleaning.asc @@ -233,6 +233,7 @@ Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359) This is a nice shortcut to recover stashed work easily and work on it in a new branch. +[[_git_clean]] ==== Cleaning your Working Directory Finally, you may not want to stash some work or files in your working directory, but simply get rid of them. The `git clean` command will do this for you. diff --git a/book/09-git-and-other-scms/sections/import-p4.asc b/book/09-git-and-other-scms/sections/import-p4.asc index 16c426816..a8501fba5 100644 --- a/book/09-git-and-other-scms/sections/import-p4.asc +++ b/book/09-git-and-other-scms/sections/import-p4.asc @@ -12,6 +12,7 @@ Just configure your project settings, user mappings, and branches using a config Git Fusion leaves you with what looks like a native Git repository, which is then ready to push to a native Git host if you desire. You could even use Perforce as your Git host if you like. +[[_git_p4]] ===== Git-p4 Git-p4 can also act as an import tool. diff --git a/book/09-git-and-other-scms/sections/import-tfs.asc b/book/09-git-and-other-scms/sections/import-tfs.asc index 4a4d8712d..f5e5bef72 100644 --- a/book/09-git-and-other-scms/sections/import-tfs.asc +++ b/book/09-git-and-other-scms/sections/import-tfs.asc @@ -1,3 +1,4 @@ +[[_git_tfs]] ==== TFS (((TFS)))(((Importing, from TFS))) diff --git a/book/10-git-internals/sections/maintenance.asc b/book/10-git-internals/sections/maintenance.asc index a590443aa..fee2d3483 100644 --- a/book/10-git-internals/sections/maintenance.asc +++ b/book/10-git-internals/sections/maintenance.asc @@ -3,6 +3,7 @@ Occasionally, you may have to do some cleanup – make a repository more compact, clean up an imported repository, or recover lost work. This section will cover some of these scenarios. +[[_git_gc]] ==== Maintenance Occasionally, Git automatically runs a command called ``auto gc''. @@ -54,7 +55,7 @@ However, if you can't find a reference in the `refs` directory, it's probably in Notice the last line of the file, which begins with a `^`. This means the tag directly above is an annotated tag and that line is the commit that the annotated tag points to. -[[data_recovery]] +[[_data_recovery]] ==== Data Recovery At some point in your Git journey, you may accidentally lose a commit. diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index 33bedf863..b648e5bec 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -150,6 +150,11 @@ The `git mv` command is a thin convience command to move a file and then run `gi We only briefly mention this command in <<_git_mv>>. +==== git clean + +The `git clean` command is used to remove unwanted files from your working directory. This could include removing temporary build artifacts or merge conflict files. + +We cover many of the options and scenarios in which you might used the clean command in <<_git_clean>>. === Branching and Merging @@ -288,6 +293,12 @@ This command is covered in detail in <<_remote_repos>>, including listing, addin It is used in nearly every subsequent chapter in the book too, but always in the standard `git remote add ` format. +==== archive + +The `git archive` command is used to create an archive file of a specific snapshot of the project. + +We use `git archive` to create a tarball of a project for sharing in <<_preparing_release>>. + ==== submodule The `git submodule` command is used to manage external repositories within a normal repositories. This could be for libraries or other types of shared resources. The `submodule` command has several sub-commands (`add`, `update`, `sync`, etc) for managing these resources. @@ -425,27 +436,35 @@ This command is coverd in depth in <<_custom_importer>>. === Administration - -==== clean +If you're administering a Git repository or need to fix something in a big way, Git provides a number of administrative commands to help you out. ==== gc +The `git gc` command runs ``garbage collection'' on your repository, removing unnecessary files in your database and packing up the remaining files into a more efficient format. + +This command normally runs in the background for you, though you can manually run it if you wish. We go over some examples of this in <<_git_gc>>. + ==== fsck +The `git fsck` command is used to check the internal database for problems or inconsistencies. + +We only quickly use this once in <<_data_recovery>> to search for dangling objects. + ==== reflog -==== filter-branch +The `git reflog` command goes through a log of where all the heads of your branches have been as you work to find commits you may have lost through rewriting histories. -==== archive +We cover this command mainly in <<_git_reflog>>, where we show normal usage to and how to use `git log -g` to view the same information with `git log` output. +We also go through a practical example of recovering such a lost branch in <<_data_recovery>>. -=== Server Admin +==== filter-branch -==== daemon +The `git filter-branch` command is used to rewrite loads of commits according to certain patterns, like removing a file everywhere or filtering the entire repository down to a single subdirectory for extracting a project. -==== update-server-info +In <<_removing_file_every_commit>> we explain the command and explore several different options such as `--commit-filter`, `--subdirectory-filter` and `--tree-filter`. -==== instaweb +In <<_git_p4>> and <<_git_tfs>> we use it to fix up imported external repositories. === Plumbing Commands From 57eb252076c5dcd781d22d040289a16e1b095b10 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Mon, 13 Oct 2014 18:52:36 +0200 Subject: [PATCH 17/26] add git to the subsections --- book/C-git-commands/1-git-commands.asc | 52 +++++++++++++------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/book/C-git-commands/1-git-commands.asc b/book/C-git-commands/1-git-commands.asc index b648e5bec..05e1c7014 100644 --- a/book/C-git-commands/1-git-commands.asc +++ b/book/C-git-commands/1-git-commands.asc @@ -243,7 +243,7 @@ We also cover how to create a GPG signed tag with the `-s` flag and verify one w There are not very many commands in Git that access the network, nearly all of the commands operate on the local database. When you are ready to share your work or pull changes from elsewhere, there are a handful of commands that deal with remote repositories. -==== fetch +==== git fetch The `git fetch` command communicates with a remote repository and fetches down all the information that is in that repository that is not in your current one and stores it in your local database. @@ -255,7 +255,7 @@ We use it to fetch a single specific reference that is outside of the default sp We set up highly custom refspecs in order to make `git fetch` do something a little different than the default in <<_getting_notes>> and <<_refspec>>. -==== pull +==== git pull The `git pull` command is basically a combination of the `git fetch` and `git merge` commands, where Git will fetch from the remote you specify and then immediately try to merge it into the branch you're on. @@ -267,7 +267,7 @@ We show how to use it with a URL to pull in changes in a one-off fashion in <<_c Finally, we very quickly mention that you can use the `--verify-signatures` option to it in order to verify that commits you are pulling have been GPG signed in <<_signing_commits>>. -==== push +==== git push The `git push` command is used to communicate with another repository, calculate what your local database has that the remote one does not, and then pushes the difference into the other repository. It requires write access to the other repository and so normally is authenticated somehow. @@ -285,7 +285,7 @@ In <<_other_client_hooks>> we talk briefly about the `pre-push` hook, which is a Finally, in <<_pushing_refspecs>> we look at pushing with a full refspec instead of the general shortcuts that are normally used. This can help you be very specific about what work you wish to share. -==== remote +==== git remote The `git remote` command is a management tool for your record of remote repositories. It allows you to save long URLs as short handles, such as ``origin'' so you don't have to type them out all the time. You can have several of these and the `git remote` command is used to add, change and delete them. @@ -293,13 +293,13 @@ This command is covered in detail in <<_remote_repos>>, including listing, addin It is used in nearly every subsequent chapter in the book too, but always in the standard `git remote add ` format. -==== archive +==== git archive The `git archive` command is used to create an archive file of a specific snapshot of the project. We use `git archive` to create a tarball of a project for sharing in <<_preparing_release>>. -==== submodule +==== git submodule The `git submodule` command is used to manage external repositories within a normal repositories. This could be for libraries or other types of shared resources. The `submodule` command has several sub-commands (`add`, `update`, `sync`, etc) for managing these resources. @@ -307,7 +307,7 @@ This command is only mentioned and entirely covered in <<_git_submodules>>. === Inspection and Comparison -==== show +==== git show The `git show` command can show a Git object in a simple and human readable way. Normally you would use this to show the information about a tag or a commit. @@ -317,13 +317,13 @@ Later we use it quite a bit in <<_revision_selection>> to show the commits that One of the more interesting things we do with `git show` is in <<_manual_remerge>> to extract specific file contents of various stages during a merge conflict. -==== shortlog +==== git shortlog The `git shortlog` command is used to summarize the output of `git log`. It will take many of the same options that the `git log` command will but instead of listing out all of the commits it will present a summary of the commits grouped by author. We showed how to use it to create a nice changelog in <<_the_shortlog>>. -==== describe +==== git describe The `git describe` command is used to take anything that resolves to a commit and produces a string that is somewhat human-readable and will not change. It's a way to get a description of a commit that is as unambiguous as a commit SHA but more understandable. @@ -334,19 +334,19 @@ We use `git describe` in <<_build_number>> and <<_preparing_release>> to get a s Git has a couple of commands that are used to help debug an issue in your code. This ranges from figuring out where something was introduced to figuring out who introduced it. -==== bisect +==== git bisect The `git bisect` tool is an incredibly helpful debugging tool used to find which specific commit was the first one to introduce a bug or problem by doing an automatic binary search. It is fully covered in <<_binary_search>> and is only mentioned in that section. -==== blame +==== git blame The `git blame` command annotates the lines of any file with which commit was the last one to introduce a change to each line of the file and what person authored that commit. This is helpful in order to find the person to ask for more information about a specific section of your code. It is covered in <<_file_annotation>> and is only mentioned in that section. -==== grep +==== git grep The `git grep` command can help you find any string or regular expression in any of the files in your source code, even older versions of your project. @@ -356,13 +356,13 @@ It is covered in <<_git_grep>> and is only mentioned in that section. A few commands in Git are centered around the concept of thinking of commits in terms of the changes they introduce, as thought the commit series is a series of patches. These commands help you manage your branches in this manner. -==== cherry-pick +==== git cherry-pick The `git cherry-pick` command is used to take the change introduced in a single Git commit and try to re-introduce it as a new commit on the branch you're currently on. This can be useful to only take one or two commits from a branch individually rather than merging in the branch which takes all the changes. Cherry picking is described and demonstrated in <<_rebase_cherry_pick>>. -==== rebase +==== git rebase The `git rebase` command is basically an automated `cherry-pick`. It determines a series of commits and then cherry-picks them one by one in the same order somewhere else. @@ -374,7 +374,7 @@ We go through running into a merge conflict during rebasing in <<_rerere>>. We also use it in an interactive scripting mode with the `-i` option in <<_changing_multiple>>. -==== revert +==== git revert The `git revert` command is essentially a reverse `git cherry-pick`. It creates a new commit that applies the exact opposite of the change introduced in the commit you're targeting, essentially undoing or reverting it. @@ -384,13 +384,13 @@ We use this in <<_reverse_commit>> to undo a merge commit. Many Git projects, including Git itself, are entirely maintained over mailing lists. Git has a number of tools built into it that help make this process easier, from generating patches you can easily email to applying those patches from an email box. -==== apply +==== git apply The `git apply` command applies a patch created with the `git diff` or even GNU diff command. It is similar to what the `patch` command might do with a few small differences. We demonstrate using it and the circumstances in which you might do so in <<_patches_from_email>>. -==== am +==== git am The `git am` command is used to apply patches from an email inbox, specifically one that is mbox formatted. This is useful for receiving patches over email and applying them to your project easily. @@ -400,19 +400,19 @@ There are also a number of hooks you can use to help with the workflow around `g We also use it to apply patch formatted GitHub Pull Request changes in <<_email_notifications>>. -==== format-patch +==== git format-patch The `git format-patch` command is used to generate a series of patches in mbox format that you can use to send to a mailing list properly formatted. We go through an example of contributing to a project using the `git format-patch` tool in <<_project_over_email>>. -==== send-email +==== git send-email The `git send-email` command is used to send patches that are generated with `git format-patch` over email. We go through an example of contributing to a project by sending patches with the `git send-email` tool in <<_project_over_email>>. -==== request-pull +==== git request-pull The `git request-pull` command is simply used to generate an example message body to email to someone. If you have a branch on a public server and want to let someone know how to integrate those changes without sending the patches over email, you can run this command and send the output to the person you want to pull the changes in. @@ -422,13 +422,13 @@ We demonstrate how to use `git request-pull` to generate a pull message in <<_pu Git comes with a few commands to integrate with other version control systems. -==== svn +==== git svn The `git svn` command is used to communicate with the Subversion version control system as a client. This means you can use Git to checkout from and commit to a Subversion server. This command is covered in depth in <<_git_svn>>. -==== fast-import +==== git fast-import For other version control systems or importing from nearly any format, you can use `git fast-import` to quickly map the other format to something Git can easily record. @@ -438,19 +438,19 @@ This command is coverd in depth in <<_custom_importer>>. If you're administering a Git repository or need to fix something in a big way, Git provides a number of administrative commands to help you out. -==== gc +==== git gc The `git gc` command runs ``garbage collection'' on your repository, removing unnecessary files in your database and packing up the remaining files into a more efficient format. This command normally runs in the background for you, though you can manually run it if you wish. We go over some examples of this in <<_git_gc>>. -==== fsck +==== git fsck The `git fsck` command is used to check the internal database for problems or inconsistencies. We only quickly use this once in <<_data_recovery>> to search for dangling objects. -==== reflog +==== git reflog The `git reflog` command goes through a log of where all the heads of your branches have been as you work to find commits you may have lost through rewriting histories. @@ -458,7 +458,7 @@ We cover this command mainly in <<_git_reflog>>, where we show normal usage to a We also go through a practical example of recovering such a lost branch in <<_data_recovery>>. -==== filter-branch +==== git filter-branch The `git filter-branch` command is used to rewrite loads of commits according to certain patterns, like removing a file everywhere or filtering the entire repository down to a single subdirectory for extracting a project. From 45cc896d37bc351e978e04eade691af35a4476b0 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 13 Oct 2014 20:09:24 -0700 Subject: [PATCH 18/26] Porcelain --- book/B-embedding-git/sections/jgit.asc | 35 +++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/book/B-embedding-git/sections/jgit.asc b/book/B-embedding-git/sections/jgit.asc index c2cef6734..539263b9c 100644 --- a/book/B-embedding-git/sections/jgit.asc +++ b/book/B-embedding-git/sections/jgit.asc @@ -106,12 +106,45 @@ For large objects (where `.isLarge()` returns `true`), you can call `.openStream The next few lines show what it takes to create a new branch. We create a RefUpdate instance, configure some parameters, and call `.update()` to trigger the change. Directly following this is how to delete that same branch. -Note that `.setForceUpdate(true)` is required for this to complete. +Note that `.setForceUpdate(true)` is required for this to work; otherwise the `.delete()` call will return `REJECTED`. The last example shows how to fetch the `user.name` value from the Git configuration files. This Config instance uses the repository we opened earlier for local configuration, but will automatically detect the global and system configuration files and read values from them as well. +This is only a small sampling of the full porcelain API; there are many more methods and classes available. +Also not shown here is the way JGit handles errors: in classic Java fashion, these are specified as exceptions. +JGit APIs sometimes throw standard Java exceptions (such as `IOException`), but there are a host of JGit-specific exception types that are provided as well (such as `NoRemoteRepositoryException`, `CorruptObjectException`, and `NoMergeBaseException`). ==== Porcelain +The plumbing APIs are rather complete, but it can be cumbersome to string them together to achieve common goals, like adding a file to the index, or making a new commit. +JGit provides a higher-level set of APIs to help out with this, and the entry point to these APIs is the `Git` class: + +[source,java] +---- +Repository repo; +// construct repo... +Git git = new Git(repo); +---- + +The Git class has a nice set of high-level _builder_-style methods that can be used to construct some pretty complex behavior. +Let's take a look at an example – doing something like `git ls-remote`: + +[source,java] +---- +Collection remoteRefs = git.lsRemote() + .setRemote("origin") + .setTags(true) + .setHeads(false) + .call(); +for (Ref ref : remoteRefs) { + System.out.println(ref.getName() + " -> " + ref.getObjectId().name()); +} +---- + +This is a common pattern with the Git class; the methods return a command object that lets you chain method calls to set parameters, which are executed when you call `.call()`. +In this case, we're asking the `origin` remote for tags, but not heads. + +Many other commands are available through the Git class, including but not limited to `add`, `commit`, `clean`, `push`, `rebase`, `revert`, and `reset`. + ==== Further Reading From a923fcfb288be9c651dc86e7ca26fe57ee6d8649 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Fri, 17 Oct 2014 07:00:27 -0700 Subject: [PATCH 19/26] Further reading --- book/B-embedding-git/sections/jgit.asc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/book/B-embedding-git/sections/jgit.asc b/book/B-embedding-git/sections/jgit.asc index 539263b9c..9d0600795 100644 --- a/book/B-embedding-git/sections/jgit.asc +++ b/book/B-embedding-git/sections/jgit.asc @@ -148,3 +148,11 @@ In this case, we're asking the `origin` remote for tags, but not heads. Many other commands are available through the Git class, including but not limited to `add`, `commit`, `clean`, `push`, `rebase`, `revert`, and `reset`. ==== Further Reading + +This is only a small sampling of JGit's full capabilities. +If you're interested and want to learn more, here's where to look for information and inspiration: + +* The official JGit API documentation is available online at http://download.eclipse.org/jgit/docs/latest/apidocs[]. + These are standard Javadoc, so your favorite JVM IDE will be able to install them locally, as well. +* The JGit Cookbook at https://github.com/centic9/jgit-cookbook[] has many examples of how to do specific tasks with JGit. +* There are several good resources pointed out at http://stackoverflow.com/questions/6861881[]. From f66e5d5768dd75ec1334c41bf03de292db5b7987 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Fri, 17 Oct 2014 07:00:29 -0700 Subject: [PATCH 20/26] Tweaks --- book/B-embedding-git/sections/jgit.asc | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/book/B-embedding-git/sections/jgit.asc b/book/B-embedding-git/sections/jgit.asc index 9d0600795..7df3b024b 100644 --- a/book/B-embedding-git/sections/jgit.asc +++ b/book/B-embedding-git/sections/jgit.asc @@ -34,8 +34,7 @@ java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App ==== Plumbing JGit has two basic levels of API: plumbing and porcelain. -The terminology for these comes from Git itself, and JGit is divided into roughly the same kinds of areas. -Porcelain APIs are a friendly front-end for common user-level actions (the sorts of things a normal user would use the Git command-line tool for), while the plumbing APIs are for interacting with low-level repository objects directly. +The terminology for these comes from Git itself, and JGit is divided into roughly the same kinds of areas: porcelain APIs are a friendly front-end for common user-level actions (the sorts of things a normal user would use the Git command-line tool for), while the plumbing APIs are for interacting with low-level repository objects directly. The starting point for most JGit sessions is the `Repository` class, and the first thing you'll want to do is create an instance of it. For a filesystem-based repository (yes, JGit allows for other storage models), this is accomplished using `FileRepositoryBuilder`: @@ -67,7 +66,7 @@ Ref master = repo.getRef("master"); ObjectId masterTip = master.getObjectId(); // Rev-parse -ObjectId obj = repo.resolve("HEAD~~"); +ObjectId obj = repo.resolve("HEAD^{tree}"); // Load raw object contents ObjectLoader loader = r.open(masterTip); @@ -91,28 +90,28 @@ String name = cfg.getString("user", null, "name"); There's quite a bit going on here, so let's go through it one section at a time. The first line gets a pointer to the `master` reference. -JGit automatically grabs the _actual_ master ref, which lives at `refs/heads/master`, and returns an object that lets you get information about the reference (Ref instances are read-only). +JGit automatically grabs the _actual_ master ref, which lives at `refs/heads/master`, and returns an object that lets you fetch information about the reference. You can get the name (`.getName()`), and either the target object of a direct reference (`.getObjectId()`) or the reference pointed to by a symbolic ref (`.getTarget()`). Ref objects are also used to represent tag refs and objects, so you can ask if the tag is ``peeled,'' meaning that it points to the final target of a (potentially long) string of tag objects. The second line gets the target of the `master` reference, which is returned as an ObjectId instance. ObjectId represents the SHA-1 hash of an object, which might or might not exist in Git's object database. -The third line is similar, but shows how JGit handles the rev-parse syntax (for more on this, see <<_branch_references>>); you can pass any single-point branch specifier that Git understands, and JGit will return either a valid ObjectId for that object, or `null`. +The third line is similar, but shows how JGit handles the rev-parse syntax (for more on this, see <<_branch_references>>); you can pass any object specifier that Git understands, and JGit will return either a valid ObjectId for that object, or `null`. The next two lines show how to load the raw contents of an object. -In this example, we call `ObjectLoader.copyTo()` to stream the contents of the object directly to stdout, but ObjectLoader also has methods to read the type and size of an object, as well as return it as an array of bytes. -For large objects (where `.isLarge()` returns `true`), you can call `.openStream()` to get an InputStream-like object that can read the raw object data. +In this example, we call `ObjectLoader.copyTo()` to stream the contents of the object directly to stdout, but ObjectLoader also has methods to read the type and size of an object, as well as return it as a byte array. +For large objects (where `.isLarge()` returns `true`), you can call `.openStream()` to get an InputStream-like object that can read the raw object data without pulling it all into memory at once. The next few lines show what it takes to create a new branch. We create a RefUpdate instance, configure some parameters, and call `.update()` to trigger the change. -Directly following this is how to delete that same branch. -Note that `.setForceUpdate(true)` is required for this to work; otherwise the `.delete()` call will return `REJECTED`. +Directly following this is the code to delete that same branch. +Note that `.setForceUpdate(true)` is required for this to work; otherwise the `.delete()` call will return `REJECTED`, and nothing will happen. The last example shows how to fetch the `user.name` value from the Git configuration files. This Config instance uses the repository we opened earlier for local configuration, but will automatically detect the global and system configuration files and read values from them as well. -This is only a small sampling of the full porcelain API; there are many more methods and classes available. -Also not shown here is the way JGit handles errors: in classic Java fashion, these are specified as exceptions. +This is only a small sampling of the full plumbing API; there are many more methods and classes available. +Also not shown here is the way JGit handles errors, which is through the use of exceptions. JGit APIs sometimes throw standard Java exceptions (such as `IOException`), but there are a host of JGit-specific exception types that are provided as well (such as `NoRemoteRepositoryException`, `CorruptObjectException`, and `NoMergeBaseException`). ==== Porcelain @@ -132,7 +131,9 @@ Let's take a look at an example – doing something like `git ls-remote`: [source,java] ---- +CredentialsProvider cp = new UsernamePasswordCredentialsProvider("username", "p4ssw0rd"); Collection remoteRefs = git.lsRemote() + .setCredentialsProvider(cp) .setRemote("origin") .setTags(true) .setHeads(false) @@ -144,8 +145,9 @@ for (Ref ref : remoteRefs) { This is a common pattern with the Git class; the methods return a command object that lets you chain method calls to set parameters, which are executed when you call `.call()`. In this case, we're asking the `origin` remote for tags, but not heads. +Also notice the use of a `CredentialsProvider` object for authentication. -Many other commands are available through the Git class, including but not limited to `add`, `commit`, `clean`, `push`, `rebase`, `revert`, and `reset`. +Many other commands are available through the Git class, including but not limited to `add`, `blame`, `commit`, `clean`, `push`, `rebase`, `revert`, and `reset`. ==== Further Reading From 645ea3785412272530e629d8f88818009d4dff3b Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Sat, 18 Oct 2014 19:18:50 -0700 Subject: [PATCH 21/26] Expand Libgit2 content --- book/B-embedding-git/sections/libgit2.asc | 105 +++++++++++++++++----- 1 file changed, 82 insertions(+), 23 deletions(-) diff --git a/book/B-embedding-git/sections/libgit2.asc b/book/B-embedding-git/sections/libgit2.asc index 052fac8af..9cfda037e 100644 --- a/book/B-embedding-git/sections/libgit2.asc +++ b/book/B-embedding-git/sections/libgit2.asc @@ -1,27 +1,97 @@ === Libgit2 (((libgit2)))(((C))) -The other option at your disposal is to use Libgit2. +Another option at your disposal is to use Libgit2. Libgit2 is a dependency-free implementation of Git, with a focus on having a nice API for use within other programs. +You can find it at http://libgit2.github.com[]. -Here's what it looks like to read HEAD's commit message with Libgit2: +First, let's take a look at what the C API looks like. +Here's a whirlwind tour: [source,c] ----- +// Open a repository git_repository *repo; int error = git_repository_open(&repo, "/path/to/repository"); +// Dereference HEAD to a commit git_object *head_commit; error = git_revparse_single(&head_commit, repo, "HEAD^{commit}"); - git_commit *commit = (git_commit*)head_commit; -printf("%s", git_commit_message); + +// Print some of the commit's properties +printf("%s", git_commit_message(commit)); +const git_signature *author = git_commit_author(commit); +printf("%s <%s>\n", author->name, author->email); +const git_oid *tree_id = git_commit_tree_id(commit); + +// Cleanup +git_commit_free(commit); +git_object_free(head_commit); +git_repository_free(repo); ----- -Of course, it isn't very probable that you'll want to write C when using Libgit2. +The first couple of lines open a Git repository. +The `git_repository` type represents a handle to a repository with a cache in memory. +This is the simplest method, for when you know the exact path to a repository's working directory or `.git` folder. +There's also the `git_repository_open_ext` which includes options for searching, `git_clone` and friends for making a local clone of a remote repository, and `git_repository_init` for creating an entirely new repository. + +The second chunk of code uses rev-parse syntax (see <<_branch_references>> for more on this) to get the commit that HEAD eventually points to. +The type returned is a `git_object` pointer, which represents something that exists in the Git object database for a repository. +`git_object` is actually a ``parent'' type for several different kinds of objects; the memory layout for each of the ``child'' types is the same as for `git_object`, so you can safely cast to the right one. +In this case, `git_object_type(commit)` would return `GIT_OBJ_COMMIT`, so it's safe to cast to a `git_commit` pointer. + +The next chunk shows how to access the commit's properties. +The last line here uses a `git_oid` type; this is Libgit2's representation for a SHA-1 hash. + +From this sample, a couple of patterns have started to emerge: + +* If you declare a pointer and pass a reference to it into a Libgit2 call, that call will probably return an integer error code. + A `0` value indicates success; anything less is an error. +* If Libgit2 populates a pointer for you, you're responsible for freeing it. +* If Libgit2 returns a `const` pointer from a call, you don't have to free it, but it will become invalid when the object it belongs to is freed. +* Writing C is a bit painful. + +(((Ruby))) +That last one means it isn't very probable that you'll be writing C when using Libgit2. Fortunately, there are a number of language-specific bindings available that make it fairly easy to work with Git repositories from your specific language and environment. +Let's take a look at the above example written using the Ruby bindings for Libgit2, which are named Rugged, and can be found at https://github.com/libgit2/rugged[]. + +[source,ruby] +---- +repo = Rugged::Repository.new('path/to/repository') +commit = repo.head.target +puts commit.message +puts "#{commit.author[:name]} <#{commit.author[:email]}>" +tree = commit.tree +---- + +As you can see, the code is much less cluttered. +Firstly, Rugged uses exceptions; it can raise things like `ConfigError` or `ObjectError` to signal error conditions. +Secondly, there's no explicit freeing of resources, since Ruby is garbage-collected. +Let's take a look at a slightly more complicated example: + +[source,ruby] +---- +# TODO +---- + +==== Advanced Functionality + +// TODO: backend, remote + +==== What Libgit2 Can't Do + +// TODO + +==== Other Bindings + +Libgit2 has bindings for many languages. +Here we show how to get the commit message from HEAD with a few of the more mature bindings pakages; there are many others, including C++, Go, Node.js, Erlang, and the JVM. +The official collection of bindings can be found by browsing the repositories at https://github.com/libgit2[]. -==== LibGit2Sharp + +===== LibGit2Sharp (((.NET)))(((C#)))(((Mono))) If you're writing a .NET or Mono application, LibGit2Sharp (https://github.com/libgit2/libgit2sharp[]) is what you're looking for. @@ -35,7 +105,7 @@ new Repository(@"C:\path\to\repo").Head.Tip.Message; For desktop Windows applications, there's a NuGet package that will help you get started quickly. -==== objective-git +===== objective-git (((Apple)))(((Objective-C)))(((Cocoa))) If your application is running on an Apple platform, you're likely using Objective-C as your implementation language. @@ -49,20 +119,8 @@ GTRepository *repo = NSString *msg = [[[repo headReferenceWithError:NULL] resolvedTarget] message]; ----- -==== rugged - -(((Ruby))) -For Ruby programs, Rugged (https://github.com/libgit2/rugged[]) is the library to use. -Once again, HEAD's commit message: - -[source,ruby] ----- -repo = Rugged::Repository.new('path/to/my/repository') -msg = repo.lookup(repo.head.resolve.target).message ----- - -==== pygit2 +===== pygit2 (((Python))) The bindings for Libgit2 in Python are called Pygit2, and can be found at http://www.pygit2.org/[]. @@ -74,7 +132,8 @@ pygit2.Repository("/path/to/repo").head.resolve().get_object().message ---- -==== Others +==== Further Reading -Libgit2 has been bound for a wide variety of programming languages and environments, including C++, Go, Node.js, Erlang, and the JVM. -The official collection of bindings can be found by browsing the repositories at https://github.com/libgit2/[]. +Of course, a full treatment of Libgit2's capabilities is outside the scope of this book. +If you want more information on Libgit2 itself, there's API documentation at https://libgit2.github.com/libgit2[], and a set of guides at https://libgit2.github.com/docs[]. +For the other bindings, check the README and tests; there are often small tutorials and pointers to further reading there. From 25b2ad01dd2e63fa73956319d169564931f87f34 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Sat, 18 Oct 2014 20:53:05 -0700 Subject: [PATCH 22/26] Extended Rugged example --- book/B-embedding-git/sections/libgit2.asc | 35 +++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/book/B-embedding-git/sections/libgit2.asc b/book/B-embedding-git/sections/libgit2.asc index 9cfda037e..f8fe692d3 100644 --- a/book/B-embedding-git/sections/libgit2.asc +++ b/book/B-embedding-git/sections/libgit2.asc @@ -69,13 +69,44 @@ tree = commit.tree As you can see, the code is much less cluttered. Firstly, Rugged uses exceptions; it can raise things like `ConfigError` or `ObjectError` to signal error conditions. Secondly, there's no explicit freeing of resources, since Ruby is garbage-collected. -Let's take a look at a slightly more complicated example: +Let's take a look at a slightly more complicated example: crafting a commit from scratch [source,ruby] ---- -# TODO +blob_id = repo.write("Blob contents", :blob) # <1> + +index = repo.index +index.read_tree(repo.head.target.tree) +index.add(:path => 'newfile.txt', :oid => blob_id) # <2> + +sig = { + :email => "bob@example.com", + :name => "Bob User", + :time => Time.now, +} + +commit_id = Rugged::Commit.create(repo, + :tree => index.write_tree(repo), # <3> + :author => sig, + :committer => sig, # <4> + :message => "Add newfile.txt", # <5> + :parents => repo.empty? ? [] : [ repo.head.target ].compact, # <6> + :update_ref => 'HEAD', # <7> +) +commit = repo.lookup(commit_id) # <8> ---- +<1> Create a new blob, which contains the contents of a new file. +<2> Populate the index with the head commit's tree, and add the new file at the path `newfile.txt`. +<3> This creates a new tree in the ODB, and uses it for the new commit. +<4> We use the same signature for both the author and committer fields. +<5> The commit message. +<6> When creating a commit, you have to specify the new commit's parents. + This uses the tip of HEAD for the single parent. +<7> Rugged (and Libgit2) can optionally update a reference when making a commit. +<8> The return value is the SHA-1 hash of a new commit object, which you can then use to get a `Commit` object. + + ==== Advanced Functionality // TODO: backend, remote From 87a3648393acce816ff8bfea08a5857b117f4553 Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Sun, 19 Oct 2014 20:07:59 -0700 Subject: [PATCH 23/26] ODB backends part I --- book/B-embedding-git/sections/libgit2.asc | 33 ++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/book/B-embedding-git/sections/libgit2.asc b/book/B-embedding-git/sections/libgit2.asc index f8fe692d3..a93af9fd9 100644 --- a/book/B-embedding-git/sections/libgit2.asc +++ b/book/B-embedding-git/sections/libgit2.asc @@ -106,10 +106,41 @@ commit = repo.lookup(commit_id) # <8> <7> Rugged (and Libgit2) can optionally update a reference when making a commit. <8> The return value is the SHA-1 hash of a new commit object, which you can then use to get a `Commit` object. +The Ruby code is pretty clean, but since Libgit2 is doing the heavy lifting, this code will run pretty fast, too. + ==== Advanced Functionality -// TODO: backend, remote +Libgit2 has a couple of capabilities that are outside the scope of core Git. +One example is pluggability: Libgit2 allows you to provide custom ``backends'' for several types of operation, so you can store things in a different way than stock Git does. +Libgit2 allows custom backends for configuration, ref storage, and the object database, among other things. + +Let's take a look at how this works. +The code below is borrowed from the set of backend examples provided by the Libgit2 team (which can be found at https://github.com/libgit2/libgit2-backends[]). +Here's how a custom backend for the object database is set up. + +[source,c] +---- +git_odb *odb; +int error = git_odb_new(&odb); // <1> + +git_repository *repo; +error = git_repository_wrap_odb(&repo, odb); // <2> + +git_odb_backend *my_backend; +error = git_odb_backend_mine(&my_backend, repo, …); // <3> + +error = git_odb_add_backendodb, my_backend, 1); // <4> +---- + +_Note that error handling has been elided for this example. You should know better._ + +<1> Initialize an empty object database (ODB) ``frontend,'' which will act as a handle to the real ODB. +<2> Construct a `git_repository` around the empty ODB. +<3> Initialize a custom ODB backend. +<4> Set the repository to use the custom backend for its ODB. + +// TODO ==== What Libgit2 Can't Do From 659ef409bef0f50b0c3d271952f2d98f22576f7d Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 20 Oct 2014 07:41:50 -0700 Subject: [PATCH 24/26] Feedback --- book/B-embedding-git/sections/libgit2.asc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/book/B-embedding-git/sections/libgit2.asc b/book/B-embedding-git/sections/libgit2.asc index a93af9fd9..a710defce 100644 --- a/book/B-embedding-git/sections/libgit2.asc +++ b/book/B-embedding-git/sections/libgit2.asc @@ -106,7 +106,7 @@ commit = repo.lookup(commit_id) # <8> <7> Rugged (and Libgit2) can optionally update a reference when making a commit. <8> The return value is the SHA-1 hash of a new commit object, which you can then use to get a `Commit` object. -The Ruby code is pretty clean, but since Libgit2 is doing the heavy lifting, this code will run pretty fast, too. +The Ruby code is nice and clean, but since Libgit2 is doing the heavy lifting, this code will run pretty fast, too. ==== Advanced Functionality @@ -133,7 +133,7 @@ error = git_odb_backend_mine(&my_backend, repo, …); // <3> error = git_odb_add_backendodb, my_backend, 1); // <4> ---- -_Note that error handling has been elided for this example. You should know better._ +_Note that error handling has been left out for this example. You should know better._ <1> Initialize an empty object database (ODB) ``frontend,'' which will act as a handle to the real ODB. <2> Construct a `git_repository` around the empty ODB. @@ -142,10 +142,6 @@ _Note that error handling has been elided for this example. You should know bett // TODO -==== What Libgit2 Can't Do - -// TODO - ==== Other Bindings Libgit2 has bindings for many languages. From d9db71391c01d49f6e375e029a03b10c4f08124f Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 20 Oct 2014 19:24:31 -0700 Subject: [PATCH 25/26] More custom ODB backend content --- book/B-embedding-git/sections/libgit2.asc | 39 +++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/book/B-embedding-git/sections/libgit2.asc b/book/B-embedding-git/sections/libgit2.asc index a710defce..a0ef84ff5 100644 --- a/book/B-embedding-git/sections/libgit2.asc +++ b/book/B-embedding-git/sections/libgit2.asc @@ -128,7 +128,7 @@ git_repository *repo; error = git_repository_wrap_odb(&repo, odb); // <2> git_odb_backend *my_backend; -error = git_odb_backend_mine(&my_backend, repo, …); // <3> +error = git_odb_backend_mine(&my_backend, /*…*/); // <3> error = git_odb_add_backendodb, my_backend, 1); // <4> ---- @@ -140,7 +140,42 @@ _Note that error handling has been left out for this example. You should know be <3> Initialize a custom ODB backend. <4> Set the repository to use the custom backend for its ODB. -// TODO +But what is this `git_odb_backend_mine` thing? +Well, that's your own backend, and you can do whatever you want in there, so long as you fill in the `git_odb_backend` structure properly. +Here's what it _could_ look like: + +[source,c] +---- +typedef struct { + git_odb_backend parent; + + // Some other stuff + void *custom_context; +} my_backend_struct; + +int git_odb_backend_mine(git_odb_backend **backend_out, /*…*/) +{ + my_backend_struct *backend; + + backend = calloc(1, sizeof (my_backend_struct)); + + backend->custom_context = …; + + backend->parent.read = &my_backend__read; + backend->parent.read_prefix = &my_backend__read_prefix; + backend->parent.read_header = &my_backend__read_header; + // … + + *backend_out = (git_odb_backend *) backend; + + return GIT_SUCCESS; +} +---- + +The `my_backend_struct` structure contains a `git_odb_backend` member first, which ensures that the memory layout is what the Libgit2 code expects it to be. +The rest of it is arbitrary; this structure can be as large or small as you need it to be. +The initialization function allocates some memory for the structure, sets up the custom context, and then fills in the members of the `parent` structure that it supports. +Take a look at the `include/git2/sys/odb_backend.h` file in the Libgit2 source for a complete set of call signatures; your particular use case will help determine which of these you'll want to support. ==== Other Bindings From d3e117639b29ed31e75f5c76d73088a7c9e7840f Mon Sep 17 00:00:00 2001 From: Ben Straub Date: Mon, 20 Oct 2014 19:43:13 -0700 Subject: [PATCH 26/26] Libgit2 tweaks --- book/B-embedding-git/sections/libgit2.asc | 30 ++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/book/B-embedding-git/sections/libgit2.asc b/book/B-embedding-git/sections/libgit2.asc index a0ef84ff5..4ae45ff72 100644 --- a/book/B-embedding-git/sections/libgit2.asc +++ b/book/B-embedding-git/sections/libgit2.asc @@ -107,6 +107,7 @@ commit = repo.lookup(commit_id) # <8> <8> The return value is the SHA-1 hash of a new commit object, which you can then use to get a `Commit` object. The Ruby code is nice and clean, but since Libgit2 is doing the heavy lifting, this code will run pretty fast, too. +If you're not a rubyist, we touch on some other bindings in <<_libgit2_bindings>>. ==== Advanced Functionality @@ -117,7 +118,7 @@ Libgit2 allows custom backends for configuration, ref storage, and the object da Let's take a look at how this works. The code below is borrowed from the set of backend examples provided by the Libgit2 team (which can be found at https://github.com/libgit2/libgit2-backends[]). -Here's how a custom backend for the object database is set up. +Here's how a custom backend for the object database is set up: [source,c] ---- @@ -133,7 +134,7 @@ error = git_odb_backend_mine(&my_backend, /*…*/); // <3> error = git_odb_add_backendodb, my_backend, 1); // <4> ---- -_Note that error handling has been left out for this example. You should know better._ +_(Note that errors are captured, but not handled. We hope your code is better than ours.)_ <1> Initialize an empty object database (ODB) ``frontend,'' which will act as a handle to the real ODB. <2> Construct a `git_repository` around the empty ODB. @@ -141,7 +142,7 @@ _Note that error handling has been left out for this example. You should know be <4> Set the repository to use the custom backend for its ODB. But what is this `git_odb_backend_mine` thing? -Well, that's your own backend, and you can do whatever you want in there, so long as you fill in the `git_odb_backend` structure properly. +Well, that's your own ODB implementation, and you can do whatever you want in there, so long as you fill in the `git_odb_backend` structure properly. Here's what it _could_ look like: [source,c] @@ -172,16 +173,19 @@ int git_odb_backend_mine(git_odb_backend **backend_out, /*…*/) } ---- -The `my_backend_struct` structure contains a `git_odb_backend` member first, which ensures that the memory layout is what the Libgit2 code expects it to be. +The subtlest constraint here is that `my_backend_struct`'s first member must be a `git_odb_backend` structure; this ensures that the memory layout is what the Libgit2 code expects it to be. The rest of it is arbitrary; this structure can be as large or small as you need it to be. + The initialization function allocates some memory for the structure, sets up the custom context, and then fills in the members of the `parent` structure that it supports. Take a look at the `include/git2/sys/odb_backend.h` file in the Libgit2 source for a complete set of call signatures; your particular use case will help determine which of these you'll want to support. +[[_libgit2_bindings]] ==== Other Bindings Libgit2 has bindings for many languages. -Here we show how to get the commit message from HEAD with a few of the more mature bindings pakages; there are many others, including C++, Go, Node.js, Erlang, and the JVM. +Here we show a small example using a few of the more complete bindings pakages as of this writing; libraries exist for many other languages, including C++, Go, Node.js, Erlang, and the JVM, all in various stages of maturity. The official collection of bindings can be found by browsing the repositories at https://github.com/libgit2[]. +The code we'll write will return the commit message from the commit eventually pointed to by HEAD (sort of like `git log -1`). ===== LibGit2Sharp @@ -189,21 +193,21 @@ The official collection of bindings can be found by browsing the repositories at (((.NET)))(((C#)))(((Mono))) If you're writing a .NET or Mono application, LibGit2Sharp (https://github.com/libgit2/libgit2sharp[]) is what you're looking for. The bindings are written in C#, and great care has been taken to wrap the raw Libgit2 calls with native-feeling CLR APIs. -Here's what it looks like to read HEAD's commit message: +Here's what our example program looks like: [source,csharp] ----- new Repository(@"C:\path\to\repo").Head.Tip.Message; ----- -For desktop Windows applications, there's a NuGet package that will help you get started quickly. +For desktop Windows applications, there's even a NuGet package that will help you get started quickly. ===== objective-git (((Apple)))(((Objective-C)))(((Cocoa))) If your application is running on an Apple platform, you're likely using Objective-C as your implementation language. Objective-Git (https://github.com/libgit2/objective-git[]) is the name of the Libgit2 bindings for that environment. -Again, here's how to read HEAD's commit message: +The example program looks like this: [source,objc] ----- @@ -212,16 +216,20 @@ GTRepository *repo = NSString *msg = [[[repo headReferenceWithError:NULL] resolvedTarget] message]; ----- +Objective-git is fully interoperable with Swift, so don't fear if you've left Objective-C behind. + ===== pygit2 (((Python))) The bindings for Libgit2 in Python are called Pygit2, and can be found at http://www.pygit2.org/[]. -As always, HEAD's commit message: +Our example program: [source,python] ---- -pygit2.Repository("/path/to/repo").head.resolve().get_object().message +pygit2.Repository("/path/to/repo") # open repository + .head.resolve() # get a direct ref + .get_object().message # get commit, read message ---- @@ -229,4 +237,4 @@ pygit2.Repository("/path/to/repo").head.resolve().get_object().message Of course, a full treatment of Libgit2's capabilities is outside the scope of this book. If you want more information on Libgit2 itself, there's API documentation at https://libgit2.github.com/libgit2[], and a set of guides at https://libgit2.github.com/docs[]. -For the other bindings, check the README and tests; there are often small tutorials and pointers to further reading there. +For the other bindings, check the bundled README and tests; there are often small tutorials and pointers to further reading there.