return 0;
}
-### 2.7 Recording changes in a new changeset
+### 2.7 Recording changes in a new commit
-We can modify files, build and test our changes, and use “hg status”
-and “hg diff” to review our changes, until we’re satisfied with what
+We can modify files, build and test our changes, and use “git status”
+and “git diff” to review our changes, until we’re satisfied with what
we’ve done and arrive at a natural stopping point where we want to
-record our work in a new changeset.
+record our work in a new commit.
-The “hg commit” command lets us create a new changeset; we’ll usually
+The “git commit” command lets us create a new changeset; we’ll usually
refer to this as “making a commit” or “committing”.
#### 2.7.1 Setting up a username
-When you try to run “hg commit” for the first time, it is not
-guaranteed to succeed. Mercurial records your name and address with
-each change that you commit, so that you and others will later be able
-to tell who made each change. Mercurial tries to automatically figure
-out a sensible username to commit the change with. It will attempt
-each of the following methods, in order:
-
- 1. If you specify a -u option to the “hg commit” command on the
- command line, followed by a username, this is always given the
- highest precedence.
- 2. If you have set the HGUSER environment variable, this is checked next.
- 3. If you create a file in your home directory called .hgrc, with a
- username entry, that will be used next. To see what the contents
- of this file should look like, refer to section [2.7.1][11]
- below.
- 4. If you have set the EMAIL environment variable, this will be used
- next.
- 5. Mercurial will query your system to find out your local user name
- and host name, and construct a username from these
- components. Since this often results in a username that is not
- very useful, it will print a warning if it has to do this.
-
-If all of these mechanisms fail, Mercurial will fail, printing an
-error message. In this case, it will not let you commit until you set
-up a username.
-
-You should think of the HGUSER environment variable and the -u option
-to the “hg commit” command as ways to override Mercurial’s default
-selection of username. For normal use, the simplest and most robust
-way to set a username for yourself is by creating a .hgrc file; see
-below for details.
-
-##### Creating a Mercurial configuration file
-
-To set a user name, use your favourite editor to create a file called
-.hgrc in your home directory. Mercurial will use this file to look up
-your personalised configuration settings. The initial contents of your
-.hgrc should look like this.
-
- # This is a Mercurial configuration file.
- [ui]
- username = Firstname Lastname <email.address@domain.net>
-
-The “[ui]” line begins a section of the config file, so you can read
-the “username = ...” line as meaning “set the value of the username
-item in the ui section”. A section continues until a new section
-begins, or the end of the file. Mercurial ignores empty lines and
-treats any text from “#” to the end of a line as a comment.
+When you try to run “git commit” for the first time, it might not do
+exactly what you want. Git records your name and address with each
+change that you commit, (as both author and committer unless you tell
+it otherwise), so that you and others will later be able to tell who
+made each change. Git tries to automatically figure out a sensible
+name and address to attribute to both author and committer. It will
+attempt each of the following methods, in order, (stopping for each field as soon as a value is found):
+
+ 1. If you specify a --author option to the “git commit” command on
+ the command line, followed by a "Real Name <email@example.com>"
+ string, then this name and addresss will be used for the author
+ fields. The committer fields will still be determined as
+ below. This option is very helpful for when applying a commit
+ originally authored by someone other than yourself.
+ 2. If any of the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL,
+ GIT_COMMITTER_NAME, or GIT_COMMITER_EMAIL environment variables
+ are set, then those values will be used for the corresponding
+ fields.
+ 3. If you have a file in your home directory called .gitconfig, with
+ name or email settings in the [user] section, then these values
+ will be used to set any remaining author and committer
+ fields. For more details on the contents of this file, refer to
+ section 2.7.1 below.
+ 4. If you have a file in the local repository called .git/config,
+ again with name or email settings in the [user] section, then
+ these values will be used to set any remaining author and
+ committer fields.
+ 5. If you have set the EMAIL environment variable, this will be used
+ to set author and committer email addresses if still unset.
+ 6. git will query your system to find out your real name from
+ available GECOS field and your username, hostname, and domain to
+ construct an email address, (or at least an identifier resembling
+ an email address).
+
+If all of these mechanisms fail, "git commit" will fail, printing an
+error message instructing you how to use "git config" to tell git your
+name and email address.
+
+You should think of the GIT_AUTHOR/COMMITER_NAME/EMAIL environment
+variables and the --author option to the “git commit” command as ways
+to override git’s default selection. For normal use, the simplest and
+most robust way to set your information is by creating a .gitconfig
+file, (either manually or with the "git config" command); see below
+for details.
+
+##### Creating a git configuration file
+
+To set your name and email address, just use the following commands:
+
+ git config --global user.name "Your Name"
+ git config --global user.email "you@example.com"
+
+The --global option means that this command will set global
+information, (affecting all repositories on this machine), in the
+.gitconfig file in your home directory. Alternately, you could omit
+the --global which would make the change take effect only in the local
+repository. This is convenient if you want to have different email
+addresses associated with different projects, for example.
+
+Of course, git's configuration file is a simple-to-edit plain-text
+file, so instead of using the above commands, you can also just edit
+the files directly. Use your favorite editor to create a file called
+.gitconfig in your home directory, (or if you ran the above commands
+then it will be there already). The initial contents of your
+.gitconfig should look like this.
+
+ # This is a git configuration file.
+ [user]
+ name = Your Name
+ email = you@example.com
+
+Similarly, you can make a repository-specific configuration by editing
+.git/config in the local repository. It will already have some
+sections present, (created by the "git clone"), just add a [user]
+section as above.
+
+The “[user]” line begins a section of the config file, so you can read
+the “name = ...” line as meaning “set the value of the name item in
+the user section”. This is the same notion expressed with the
+"user.name" syntax on the git-config command line. A section
+continues until a new section begins, or the end of the file. Git
+ignores empty lines and treats any text from “#” to the end of a line
+as a comment.
##### Choosing a user name
-You can use any text you like as the value of the username config
-item, since this information is for reading by other people, but for
-interpreting by Mercurial. The convention that most people follow is
-to use their name and email address, as in the example above.
-
-Note: Mercurial’s built-in web server obfuscates email addresses, to
-make it more difficult for the email harvesting tools that spammers
-use. This reduces the likelihood that you’ll start receiving more junk
-email if you publish a Mercurial repository on the web.
+You can use any text you like as the value of the name and email
+configuration items, since this information is for reading by other
+people, not for interpreting by git. It is conventional to use a valid
+email address, but some, (notably Linus Torvalds, the original author
+of git), actually like the default user@hostname convention that git
+falls back on without any additional information. There's no
+requirement that the email address actually be valid, and perhaps it's
+useful to be reminded which machine was used to create particular
+commits.
#### 2.7.2 Writing a commit message
-When we commit a change, Mercurial drops us into a text editor, to
+When we commit a change, git drops us into a text editor to
enter a message that will describe the modifications we’ve made in
-this changeset. This is called the commit message. It will be a record
-for readers of what we did and why, and it will be printed by “hg log”
+this commit. This is called the commit message. It will be a record
+for readers of what we did and why, and it will be printed by “git log”
after we’ve finished committing.
- $ hg commit
+ $ git commit -a
+
+Note: The -a on the command-line instructs git to commit all changes
+to tracked files. Without this, "git commit" will only commit changes
+that have been previously staged for committing with "git add
+file". The most common usage is to commit with "git commit -a" and
+only use "git add file; git commit" when there is a need to commit
+only some subset of changes that have been made.
-The editor that the “hg commit” command drops us into will contain an
-empty line, followed by a number of lines starting with “HG:”.
+The editor that the “git commit” command drops us into will contain an
+empty line, followed by a number of lines starting with “#”.
- empty line
- HG: changed hello.c
+ empty line
+ # Please enter the commit message for your changes.
+ # (Comment lines starting with '#' will not be included)
+ # On branch master
+ # Changes to be committed:
+ # (use "git reset HEAD <file>..." to unstage)
+ #
+ # modified: hello.c
+ #
-Mercurial ignores the lines that start with “HG:”; it uses them only
+git ignores the lines that start with “#”; it uses them only
to tell us which files it’s recording changes to. Modifying or
deleting these lines has no effect.
#### 2.7.3 Writing a good commit message
-Since “hg log” only prints the first line of a commit message by
-default, it’s best to write a commit message whose first line stands
-alone. Here’s a real example of a commit message that doesn’t follow
+A good commit message will generally have a single line that
+summarizes the commit, a blank line, and then one or more pargraphs
+with supporting detail. Since many tools only print the first line of
+a commit message by default, it’s important that the first line stands
+alone.
+
+One example of a first-line-only viewer is "git log
+--pretty=short". Other examples include graphical history viewers such
+as gitk and gitview, and web-based viewers such as gitweb and cgit.
+
+Here’s a real example of a commit message that doesn’t follow
this guideline, and hence has a summary that is not readable.
- changeset: 73:584af0e231be
- user: Censored Person <censored.person@example.org>
- date: Tue Sep 26 21:37:07 2006 -0700
- summary: include buildmeister/commondefs. Add an exports and install
+ $ git log --pretty=short
+ commit 3ef5535144da88a854f7930503845cd44506c2e2
+ Author: Censored Person <censored.person@example.org>
+
+ include buildmeister/commondefs. Add an exports and install
As far as the remainder of the contents of the commit message are
-concerned, there are no hard-and-fast rules. Mercurial itself doesn’t
+concerned, there are no hard-and-fast rules. git itself doesn’t
interpret or care about the contents of the commit message, though
your project may have policies that dictate a certain kind of
formatting.
My personal preference is for short, but informative, commit messages
that tell me something that I can’t figure out with a quick glance at
-the output of “hg log --patch”.
+the output of “git log -p".
#### 2.7.4 Aborting a commit
the file that it’s editing. This will cause nothing to happen to
either the repository or the working directory.
-If we run the “hg commit” command without any arguments, it records
-all of the changes we’ve made, as reported by “hg status” and “hg
-diff”.
-
#### 2.7.5 Admiring our new handiwork
-Once we’ve finished the commit, we can use the “hg tip” command to
-display the changeset we just created. This command produces output
-that is identical to “hg log”, but it only displays the newest
-revision in the repository.
+Once we’ve finished the commit, we can use the “git show” command to
+display the commit we just created. As discussed previously, this
+command produces output that is identical to “git log -p”, but for
+only a single revision, (and the most recent revision by default):
- $ hg tip -vp
- changeset: 5:fa1321bf0c80
- tag: tip
- user: Bryan O'Sullivan <bos@serpentine.com>
- date: Sun Jun 17 18:05:50 2007 +0000
- files: hello.c
- description:
- Added an extra line of output
+ $ git show
+ commit 018cfb742be6176443ffddac454e593e802ddf3e
+ Author: Carl Worth <cworth@cworth.org>
+ Date: Thu Sep 27 23:55:00 2007 -0700
+ Added an extra line of output.
+
+ If I would have been clever I would have fixed that old typo
+ while I was at it...
- diff -r b57f9a090b62 -r fa1321bf0c80 hello.c
- --- a/hello.c Tue Sep 06 15:43:07 2005 -0700
- +++ b/hello.c Sun Jun 17 18:05:50 2007 +0000
- @@ -8,5 +8,6 @@ int main(int argc, char ⋆⋆argv)
- int main(int argc, char ⋆⋆argv)
- {
- printf("hello, world!∖");
- + printf("hello again!∖n");
- return 0;
- }
+ diff --git a/hello.c b/hello.c
+ index 9a3ff79..6d28887 100644
+ --- a/hello.c
+ +++ b/hello.c
+ @@ -8,5 +8,6 @@
+ int main(int argc, char **argv)
+ {
+ printf("hello, world!\");
+ + printf("hello again!\n");
+ return 0;
+ }
+
+Note that you will not see the same commit identifier for your commit,
+even if the change you made is identical to mine. The commit
+identifier incorporates not only the contents of the files, but commit
+message, the author and committer names and emails, and the author and
+commit dates. (OK, so now you probably know enough to be able to guess
+the right command to produce a commit with exactly the commit
+identifier shown above. Can you do it?)
+
+#### 2.7.6 Fixing up a broken commit (before anyone else sees it)
+
+So now that we've cloned a local repository, made a change to the
+code, setup our name and email address, and made a commit with a
+careful message, we're just about ready to share our change with the
+world. But wait, we forgot to try to compile it didn't we?
+
+ $ make
+ cc -c -o hello.o hello.c
+ hello.c:10:9: warning: missing terminating " character
+ hello.c:10:9: warning: missing terminating " character
+ hello.c: In function ‘main’:
+ hello.c:10: error: missing terminating " character
+ hello.c:11: error: expected ‘)’ before ‘;’ token
+ hello.c:13: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast
+ hello.c:13: error: expected ‘;’ before ‘}’ token
+ make: *** [hello.o] Error 1
+
+Oh look. The code's broken and doesn't compile. We don't want to share
+code in this state. For situations where you notice one tiny detail
+that got left out of the last commit, (a silly syntax error, a
+misspelling in a comment or commit messsage), git provides a very
+handy tool for just changing the last commit.
+
+So fix that typo, (a missing 'n' between the '\' and the '"'), with
+your editor or with something like this:
+
+ sed -i 's/\\"/\\n"/' hello.c
+
+And then you can just amend the previous commit rather than creating a
+new one with the --amend option to "git commit":
+
+ $ git commit -a --amend
+
+Note that we use -a to include the code change here. And that helps
+point out a situation where "git commit" is useful without the -a
+option, "git commit --amend" is a useful command for amend just the
+last commit message, without committing any new code changes, even if
+some files have been modified in the working tree.
+
+And here's the final result:
+
+ $ git show
+ commit 839b58d021c618bd0e1d336d4d5878a0082672e6
+ Author: Carl Worth <cworth@cworth.org>
+ Date: Thu Sep 27 23:55:00 2007 -0700
+
+ Added an extra line of output and fixed the typo bug.
+ diff --git a/hello.c b/hello.c
+ index 9a3ff79..ca750e0 100644
+ --- a/hello.c
+ +++ b/hello.c
+ @@ -7,6 +7,7 @@
+
+ int main(int argc, char **argv)
+ {
+ - printf("hello, world!\");
+ + printf("hello, world!\n");
+ + printf("hello again!\n");
+ return 0;
+ }
-We refer to the newest revision in the repository as the tip revision,
-or simply the tip.
+I can't help but point out that this really was a poor example for
+--amend. The end result is a single commit that does two independent
+things, (fixes one bug and adds one new feature). It's much better to
+create a code history where each commit makes an independent change,
+(and as small as possible). This is important for several reasons:
+
+ * Small changes are easier to review
+
+ * Independent changes are easier to split up if only part of the
+ series gets accepted "upstream" for one reason or another.
+
+ * The smaller the changes are the more useful the history will be
+ when actually using the history, not just viewing it. This is
+ particularly important when doing "git bisect"---that's a powerful
+ tool for isolating the single commit that introduces a bug. And
+ it's much more powerful if the commit it isolates is as small as
+ possible.
+
+So it's a good thing this document is available under a license that
+allows for distribution of modified versions. Someone should clean up
+the --amend example to not teach bad habits like I did above. [Note:
+All this bad-habit stuff was introduced by me, and was not present in
+Bryan's original chapter. -Carl]
### 2.8 Sharing changes