『独習Git』課題の解答およびヒント

<a href="https://www.vector.co.jp/soft/screen/win95/game/se394828.html">ふぁんふぁんまっちんぐ<br><img src="https://deliver.vector.co.jp/screenshot/394/394828_01.jpg" width="50%"></a>

■□■『独習Git』課題の解答およびヒント■□■

本書の課題の解答は、原著のWebサイトで順次公開されます。本ファイルでは翻訳時点で公開されている各課題の解答や訳者からのヒントなどをまとめます。最新の情報については、原著のWebサイトを随時ご確認ください。
http://tech.rickumali.com/learngit

■■第3章■■

【A1（著者から）】
 Gitのコンフィギュレーション（設定）は、/etc/gitconfig、$HOME/.gitconfig、.git/configの3箇所に置かれる。これについては第20章に詳しい情報があるけれど、いまの段階では（とくにGitの初心者には）難解と思われるかもしれない。完全な情報は、git config helpを参照。

【A2（著者から）】
 git help git

【A3（著者から）】
 git rebase

【A4（著者から）】
Directed Acyclic Graph（閉路のない有向グラフ）。git help glossaryを参照。日本語の文献としては、エイホ、ホップクロフト、ウルマン著、大野義夫訳の『データ構造とアルゴリズム』「6.6 閉路のない有向グラフ」を参照。グラフについては、ウィキペディアの「木（数学）」の項を参照。

【A5（著者から）】
git help tutorialを参照

【A6（著者から）】
表示される。

【A7（著者から）】
lessの表示を1行単位でスクロールするには、上下矢印キーまたは[J]と[K]のキーを使える。lessの日本語マニュアルページは、http://www.linux-cmd.com/less.html#manを参照。

■■第4章■■

【A1（著者が示すエラーの例）】
fatal: bad default revision ’HEAD

【A1（訳者が経験したエラー）】
fatal: your current branch 'master' does not have any commits yet

【A2（著者による解説）】
この課題を実行した結果、git sdtatusは、次の情報を出す。

------------------------------
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   file.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout --<file>..." to discard changes in working directory)

        modified: file.txt
------------------------------

結局、file.txtは、2箇所に現れる。

【A3（著者による解説）】
行末（End of Line：略してEOL）は、コンピュータの世界で悩みの種となる。Windowsでは、ほとんどのファイルの行末がCR+LFだ。ところが、Unix/Linuxマシンでは（Macも、そのひとつだが）、ほとんどのファイルの行末がLFである。その他の詳細は、Wikipediaの「改行コード」（Newline）を参照。もしあなたが、いつも同じプラットフォームで作業するのなら、この問題に遭遇しないかもしれない。けれどもGitでは、あなたとは別のプラットフォームを使っている人と、共同作業を行うことになるかもしれない。この問題について、Gitはスマートな解決策を提供しようとする。それが構成設定（configuration settings）の、core.autocrlfとcore.safecrlfだ。GitでEOLを扱う方法については、詳細なポストがStack Overflowにまとめられている（http://stackoverflow.com/q/170961/10030）。このポストには、EOL設定を管理する方法がいくつか推奨されているが、もしあなたが初心者ならばこれを読むのは早すぎる。Gitは、初期設定のままで、EOLを正しく管理するよう、ベストを尽くしてくれる。

【A3（訳者から）】
上記の構成設定が、どうなっているかは、次のコマンドでチェックできる。

------------------------------
git config --get core.safecrlf
git config --get core.autocrlf
------------------------------

訳者の環境（Windows 7と10）では、前者は何も出力せず、後者はtrue（真）と出力した。では、core.autocrlfがtrueだと、どうなるのか。濱野純著『入門Git』から引用する（p.194）。

------------------------------
12.3.2. core.autocrlf

ワークツリー内のファイルの行末記号がCR（Carriage Return）文字とLF（Line Feed）との2バイトの組合わせで表現されているシステム（主にWindows）で、リポジトリには改行をLF 1バイトだけで記録したいときに使います。
真に設定しておくと、ワークツリー内のファイルの行末記号CRLFをリポジトリに記録するときに自動的にLFに変換し、逆にリポジトリに記録された内容からワークツリーに書き出すときには、行末記号LFを自動的にCRLFに変換してから書き出すようになります。
------------------------------

なお、ワークツリー（work tree）とは、「リビジョンに記録されている内容を展開したディレクトリ領域」（同書、p.18）。git add .コマンドを使うと、「ワークツリーのすべてのファイルの状態を記録」できる（同書、p.43）。

■■第5章■■

【A1（著者から）】
file.txtは、Git GUIの左上ペイン（"Unstaged Changes"）に現れる。

【A2（著者から）】
git citoolは、git gui citoolの別名である（標準のエイリアス）。詳しくはgit gui --helpのCOMMANDSセクションを参照。 

【A3（著者から）】
file.txtは、Git GUIの左下ペイン（Staged Changes）に現れる。

【A4（著者から）】
file.txtは、両方に現れる。また、右上のペイン（Portions staged for commit）にも、何か出てくるだろう。

【A5（訳者の考え）】
Commitメッセージを入力してから、Commitボタンを押す？

【A5（著者の解答）】
これはちょっとトリッキーな課題だった。ここではgit addで変更を追加してから、同じファイルに対する別の変更を追加している。けれども、この手順では第1の変更が第2の変更で上書きされてしまう。両方とも保存する最良の方法は、まずgit commitを実行することだ。それで、ファイルの第1バージョンが保存される。コミットした後で、第2の変更に対してgit addとgit commitを実行する。これによって、ファイルの第2バージョンが保存される。

【A6（訳者の解答）】
使えない。man pageのgitk(1)を参照。

【A6（著者の解答）】
この章ではgitkプログラムをgit guiを介して起動した。けれどもgitkは、git guiを経由せず、ただgitkとタイプするだけでも起動できる。gitkに--helpスイッチはないが、コマンドラインで引数として何を渡せるかは、git help gitkとタイプすることによって知ることができる。

■■第6章■■

【A1（著者から）】
--stagedの代わりに--cachedを使える。git diff --helpを参照。

【A2（著者から）】
git add -n

【A3（著者から）】
cat -n <ファイル名>で、ファイルの内容が行番号付きで表示される。

【A4（著者から）】
git log --format=oneline --abbrev-commit

【A5（著者から）】
-all

■6.4.2 トラブルを切り抜ける

【著者のヒント】
git addによって追加した変更を取り消すコマンドは、git statusが教えてくれる。

【訳者から】
第4章のリスト 4.4に出てきた、（use "git rm --cached <file>..." to unstage）というのが、それに当たる。このコマンドの詳細は、今後の章で学ぶ。

■6.4.3 自分のファイルを追加する

【著者から】
あなたの好きなエディタで、readme.txtというファイルを、mathディレクトリのなかに作る。テキストを含んでいても、空のままでもよい。その後、次のようにタイプする。

------------------------------
git add readme.txt
git commit -m "Adding readme.txt"
------------------------------

■■第7章■■

【A1（著者から）】
ハンクは、@@ -1.7 +1,7 @@の"change here"、@@ -10,8 +10,7 @@の"deleted below"、@@ -29,6 +27,7 @@の"added a new line here do not be afraid added new line here do not be afraid"の合計で3個。

【A2（著者から）】
第2のハンクは@@ -10,8 +10,7 @@の"deleted below"を含むもの。編集では、このハンクだけを残し、あとは削除する。その方法は、リスト 7.16で行っているようにgit add -pで、最初のプロンプトにはn、第2のプロンプトにはy、第3のプロンプトにはnで答える。
ステージングされた変更をコミットするために、git commit -m "2nd hunk"とタイプする。

【A3（著者から）】
git_statusの出力には、次のように書かれている

------------------------------
use "git checkout -- <file>..." to discard changes in working directory
試訳：「作業ディレクトリ内の変更を破棄するには、git checkout -- <ファイル>を使う」
------------------------------

だから、git checkout -- lorem-ipsum.txtとタイプすればよい。この後、git statusとタイプすれば、作業ディレクトリがクリーンな状態で、何もコミットすべきものがないと報告される。

【A4（著者から）】
このステップはセットアップの繰り返したが、リポジトリに入るファイルが違っている。

【A5（著者から）】
2つ。

【A6（著者から）】
この場合、ハンクを選択する必要はないので、ただ次のようにタイプする：

------------------------------
git add lorem-ipsum.txt
git commit -m "All hunks
------------------------------

■7.5.2 削除を取り消す

【A（訳者から）】
わからなくなったら、git guiで状態を確認しよう。訳者が確認したとき、右上のペインが"Staged for removal"となって、削除されたファイルの内容が表示された。つまり、「削除する」という変更がステージングされていた。

○スクリーンショット：Lab_7_5_2_Win7_GUI.jpg

このときgit statusの出力には、(use "git reset HEAD <file>..." to unstage)とあるので、これを実行すればアンステージできるはず。そこでgit reset HEAD lorem-ipsum.txtと打ち込んだ。これでステージングエリアが空になっただろう。もう一度、git statusを実行すると、今度は (use "git checkout -- <file>..." to discard changes in working directory)が出てくる、これを行えば、作業ディレクトリ内の変更を破棄できるはず。そこで、"git checkout -- lorem-ipsum.txt"と打ち込んだら、ファイルが復活した。

■7.5.3 課題図書

【A（著者から）】
ここでいう「形式」とは、Gitのドキュメントに書かれている「引数のパターン」のことだ。
git checkout -- math.shは、「チェックアウトによってワーキングツリーを元に戻す」ものであり、チェックアウトするファイルを指定している。--は、それ以降の文字列を「オプションとして解釈しないようにする」オプションで、この場合、それに続く文字列がファイルのパス名であることを示す。7.5.2で訳者が使った、git checkout -- lorem-ipsum.txtも同じである。この形式は、ドキュメントで次のように書かれているものだ：

------------------------------
git checkout [-p|--patch] [<tree-ish>] [--] <paths>... 
------------------------------

ただし、[と]の間にあるのはオプションの引数だから省略できる。上記のコマンドでは、[--patch]や[tree-ish]は使っていない。
オプション指定のない、git reset math.shは、git add math.shの逆の動作で、ファイルを「コミット予定」から外す（ステージングエリアから取り除く）ものだ。ちなみに、訳者が7.5.2で使ったgit reset HEAD lorem-ipsum.txtのHEADは、第8章で登場する。この形式は、ドキュメントで次のように書かれている：

------------------------------
git reset [-q] [<tree-ish>] [--] <paths>...
------------------------------

ただし、上記のコマンドでは、-qや[tree-ish]を使っていない。<tree-ish>というのは、特定の「コミットか、タグか、ツリー」を指定するもの。

■■第8章■■

【A1（訳者から）】
git logコマンドには、--reverseという「表示オプション」があり、これを指定すれば逆順に表示される。Gitのコミットヒストリーは、オブジェクトのリストで管理され、そのポインタは、最新のもの（master）から、その親へ、またその親へと、ルートまで連鎖している（図 8.1などを参照）。デフォルトのリストは、そのポインタを順にたどるのだから、処理が高速なのは、明らかに、逆順ではなくデフォルトのリストだろう。

【A2（訳者から）】
git logには、対象コミットを限定する-<n>オプションがある。これを指定すると、最近のn件のコミットメッセージが表示される。たとえばgit log -3とタイプすれば、最近の3件が表示される。もしgit log --reverse -3とタイプしたら、その3件が逆順に表示される。

【A3（訳者から）】
それにはgit logの「表示オプション」のひとつ、--dateを使う。これには表示形式のひとつとして、relative（相対的）がある。つまり、git log --date relativeとタイプすれば、時刻が「現在の時刻との差」で表示される（たとえば、"2 hours ago"、"5 days ago"など）。

【A3（著者から）】
git log --relative-date

【A4（訳者から）】
git log --onelineは、"--pretty=oneline --abbrev-commit"の2つを同時に指定するという意味のショートカット。

■8.5.3 別の形式でコミットを指定する

【A1（訳者から）】
master~3は、masterから3つ前のコミット（masterの親の親の親）。
master@{3}は、masterを1番目として3番目のコミット（masterの親の親）。
master^^^は、master~3と同じコミット。
:/"Removed a and b"は、このログメッセージを持つコミット。

【A2（訳者から）】
:/<text>（1個のコロンの後に、1個のスラッシュ、その後にテキスト）は、ログメッセージが、テキストで指定する正規表現とマッチするコミットを指定する。詳しくは、マニュアルページ、gitrevisions(7)を参照。

【A2（著者から）】
第15章で、そのバリアント（変種）を示します。

【A3（著者から）】
使えます。git rev-parse four_files_galoreとタイプすれば、そのSHA1 IDが表示される。

【A4（著者から）】
はい。git rev-parseで使っている構文は、タグ名に対しても使えます。たとえばgit rev-parse four_files_galore^^とタイプすれば、four_files_galoreよりも前に行われたコミットのSHA1 IDが返される。

【A4（訳者から）】
逆に、これらの記号は、どれもタグ名には使えない。タグ名に使える記号には制限がある。スペース、ティルダ（~）、キャレット（^）、コロン（:）は使えない。疑問符（?）、アスタリスク（*）、開き角カッコ（[）も使えない。@{というシーケンスを含むこともできない。他にも制限がある。詳しくは、マニュアルページ、git-check-ref-format(1)を参照。

■8.5.6 ヒストリーを見る（第2部）

【A1（訳者から）】
「The very first commit. Hi!」と言っている。Dateは、Sat Oct 31 22:28:30 2015 +0900。これは、git log --reverseで見るのが手っ取り早い。

【A1（著者から）】
最初のコミットは、スクリプトを実行した日よりも5日前の日付になっている。

【A2（訳者から）】
git rev-parse :/"ubiquitous"とタイプするのが正解です。

【A3（訳者から）】
git log --author="rgu@freeshell.org"で表示されるコミット。

【A3（著者から）】
UNIXのgrepコマンドを使えば、git log | grep -B 1 rgu@freeshellとタイプするだけで正解が出る！

【A4（訳者から）】
git log --since=yesterday

【A5（訳者から）】
○参考スクリーンショット：Lab_8_5_6_5_Tree.jpg

■■第9章■■

【A1（訳者から）】
Branch（ブランチ）メニューのCheckout（チェックアウト）項目を選択すると、Checkout Branch（ブランチをチェックアウト）の画面になる。このとき、Local Branch（ローカル･ブランチ）にnew_featureがあるので、それを選択して［Checkout］（チェックアウト）ボタンを押す。ただし、現在はmath.shファイルの変更が残っているので警告が出る。warning（警告）画面の［OK］をクリックすると、元の状態に戻る。

【A2（訳者から）】
左上のブランチペインで、another_fix_branchと同じ行にあるRenaming c and d.の上にカーソルを置いてコンテキストメニューを出す。Create new branch（新規ブランチ生成）をクリック。makebranchウィンドウ（create new branch：新規ブランチ生成）で、Name（名前）テキストボックスに、新しいブランチの名前を入力。[Create：生成]ボタンをクリック。これで、新しいブランチの名前が、another_fix_branchの隣に現れる。

【A3（訳者から）】
git guiで、Repository（リポジトリ）メニューのVisualize All Branch History（全てのブランチの履歴を見る）を選択すればgitkが出る。その後の処理は同じ。従って、gitkを使うのが簡単。gitkの操作は、ステップ2と同じ。なお、git guiでは、Branch（ブランチ）メニューのCreate New Branch（作成）からブランチを作成できる。その場合は、Starting Revision（初期リビジョン）で、既存のTag（タグ）を選択する。

【A4（訳者から）】
（1）git guiを起動し、Branch（ブランチ）メニューからDelete Local Branch（削除）を選択。Delete Local Branch（ローカル･ブランチを削除）の画面が出る。上のリストで削除したいブランチを選択し、［Delete］をクリックする。カレントブランチは削除できないので注意！ 下側のリストでブランチを選択する必要があるかもしれない。

（2）gitkを起動し、削除したいブランチの上にカーソルを置いてコンテキストメニューを出す。Remove this branch（このブランチを除去する）をクリック。 

■9.5.2 頭の準備運動

【A1（訳者から）】
可能。git branch -m [<oldbranch>] <newbranch>を使う。<oldbranch>を指定しなければ、カレントブランチの名前が変更される。詳細は、git branch --helpを参照。

【A2（訳者から）】
git rev-parseコマンドでは、指定の文字列をログメッセージに含むコミットのSHA1 IDを調べることができる（例：git rev-parse :/"Renaming c and d"）。これは8.5.3項で学んだ。

【A3（著者から）】
長いgit logというのは、次のコマンドだった。

------------------------------
git log --graph --decorate --pretty=oneline --all --abbrev-commit
------------------------------

それぞれのスイッチが何を行うかを調べるには、git log --helpコマンドを使う。
この課題で重要なのは、git logのドキュメントを読むこと、とくに、特定のスイッチについて調べることである。たとえば--decorateスイッチを見ると、これはコミットの参照名をプリントするものだが、--decorateに対するスイッチが存在することも分かる（たとえば：--decorate=full）。

【A3（訳者から）】
--graphはコミット履歴をグラフ（ASCII文字）で表現する。--decorateは、参照名を持つコミットについて、それらの名前（HEAD、タグ名など）を表示する。--pretty=oneline --abbrev-commitは、ショートカット--onelineと同じ。[--allは、すべてのブランチのコミットメッセージを表示する。

【A4（訳者から）】
git branch -dコマンドでブランチを削除するとき、マージされていないブランチを削除しようとするとエラーになる。Git GUIで「Delete Local Branch」を行うと、エラーが出て削除できない。

【A4（著者から）】
これを正しく実行するには、mathディレクトリに入って、new_featureブランチの削除を試みるとよい（それには、make_math_repo.shをもう一度実行して、mathディレクトリを作り直すのが簡単かもしれない）。
このnew_featureブランチには、2つのコミットがある。そのメッセージは、"Starting a second new file"と、"Adding a new file to a new branch"だ。git branch -d new_featureとタイプすると、このブランチを本当に削除したいのか、と訊かれるだろう。それは、これらのコミットが他のブランチにマージされていないからだ。本当にブランチを削除したいときは、git branch -D new_featureとタイプする（小文字のdではなく、大文字のDを使っていることに注目）。これで、このリポジトリには、new_featureブランチが存在しなくなった。だから、このブランチに対して行ったコミットも、消え失せたと思われるだろう。ところが、それらはまだ利用できるのだ。それを示す最良の方法は、git reflogコマンドを使う。
git reflogとタイプすれば、次に示すようなリストが現れるだろう：

------------------------------
3522453 HEAD@{0}: checkout: moving from fixing_readme to another_fix_branch
3522453 HEAD@{1}: checkout: moving from master to fixing_readme
7fb5600 HEAD@{2}: commit: A small update to readme.
b06aec0 HEAD@{3}: checkout: moving from new_feature to master
c5aab93 HEAD@{4}: commit: Starting a second new file
6851702 HEAD@{5}: commit: Adding a new file to a new branch
b06aec0 HEAD@{6}: checkout: moving from master to new_feature
b06aec0 HEAD@{7}: commit: Adding printf.
------------------------------

上に挙げたリストを見ると、HEAD@{4}とHEAD@{5}というラベルの、2つのコミットがある。これらのラベルを指定してブランチを作り直せば、2つのコミットを、削除されたブランチから復活させることが可能だ！　それには、次のようにタイプする。

------------------------------
git checkout -b recovered_branch HEAD@{4}
------------------------------

git reflogについては、第16章で、詳しく述べる。

■9.5.3 another_fix_branchで作業を続ける

【A1（訳者から）】
これは「7.5.3 読書課題図書」に出てきました。

■9.5.4 複数のブランチを見る

【A1（訳者から）】
gitkを見ると、Adding four empty files.のコミットがmasterであり、そこからCommit for file_31618という先端まで、branch_01が伸びている。

【A2（訳者から）】
ショートカットのgit lolで見ると、branch_30の開始地点がわかりにくかった。gitkで見ると、branch_30はfour_files_galoreをフォローしていた。先端から親を順まで辿って、four_files_galoreにたどり着くまでのコミット数を数えた。

【A3（訳者から）】
これはgitkでも、git lolでも確認できる。訳者はgit lolの出力をスクロールして調べた。また、branch_40のanswers.txtは、gitkのTreeビューで調べた。このファイルに数字が3つ書かれていて、それが上記のブランチ番号である。

【A4（訳者から）】
上記の出力をスクロールしているときに、答えは分かってしまった（訳者の場合、branch_21だったが、それは乱数で決まるようだ）。正解かどうか不明だが、原文に"contains"（含まれている）という言葉が使われていたので、git branch --contains random_tag_on_fileコマンドを使った。warningでrefnameがambiguousだと指摘されたが、branch_21と正解が出た。

【A5（訳者から）】
--simplify-by-decorationというスイッチは、"Commits that are referred by some branch or tag are selected."と解説がある。「何らかのブランチまたはタグで参照されているコミットだけを選択する」という意味。
--graphスイッチを追加すると、斜線によるブランチの図式化が加わる（リストが長くなって1画面に収まらない）。

■■第10章■■

【A1（訳者から）】
git-merge(1) Manual Page（https://www.kernel.org/pub/software/scm/git/docs/git-merge.html）から引用する（マージしないケースについては、要旨のみ示す）。

------------------------------
競合を解決する方法

競合（conflict）を見つけた後、できることは次の2つです：

・マージしないことにする。
その場合は、git merge --abortを利用できます。

・競合を解決する。
Gitは、作業ツリー内の競合にマークを付けています。そのファイルを適切に編集し、git addでindex（ステージングエリア）に追加します。それから、git commitで決着をつけます。

競合を調査・解決するには、様々なツールを利用できます。

・マージツールを使う。
git mergetoolによって、グラフィカルなマージツールを起動し、その中でマージを調査・解決します。

・差分を見る。
git diffによって、3者間のdiff（three-way diff）が表示されます。そこでは、HEADおよびMERGE_HEADの両方のバージョンからの変更が強調されます。

・それぞれのブランチからの差分を見る。
git log --merge -p <path>を使えば、まずHEADバージョンとの差分、次にMERGE_HEADバージョンからの差分を見ることができます。

・オリジナルを見る。
git show :1:filenameは、共通祖先（the common ancestor）を表示します。
git show :2:filenameは、HEADバージョンを表示します。
git show :3:filenameは、MERGE_HEADバージョンを表示します。
------------------------------

【A2（訳者から）】
問題ないはず。masterは名称にすぎない。ただし思い違いから、つまらない間違いが発生するかもしれない（著者からの解答／ヒントを待ちます）。

【A3（訳者から）】
マージが完了した状態では、何も出力されない。git-diff(1) Manual Pageに詳しい記述があるが、あまりにも詳細で、難しい。ただし、ブランチの比較に限れば、EXAMPLESの項に、Comparing branchesというものがあり、そこには、git-diff topic...masterという例がある。これは、topicブランチの開始地点からmasterブランチに加えられた変更を見るもの、とのこと。

【A4（訳者から）】
変更されたファイルの名前と、その状態を示す1文字（この場合は'A'）が表示される。

------------------------------
$ git diff --name-status master...bugfix
A       newfile
------------------------------

Aは、Addedを意味する。

【A5（訳者から）】
git mergeのマニュアルページによれば、--ffオプションがデフォルトであり、これはfast-fowardマージの解決としてブランチポインタを更新するだけであり、マージコミットを作らない。--no-ffを指定すれば、たとえマージがfast-fowardとして解決してもマージコミットを作る。著者が言っているのは、おそらくこれだろう。

■■第11章■■

【A3（訳者から）】
可能。リスト 11.4 を参照。

【A4（訳者から）】
$ git checkout -b clone_another_fix_branch remotes/origin/another_fix_branch
Branch clone_another_fix_branch set up to track remote branch another_fix_branch from origin.
Switched to a new branch 'clone_another_fix_branch'

【A5（訳者から）】
開始地点が、ただ参照されるだけだとしたら、制限は存在しないはず。ただし、その地点に対して何かを変更する処理を行うとき、参照が多いと時間がかかるのではないか（著者の回答を待つ）。

【A6（訳者から）】
このコマンドの形式は、git clone --origin <name> <repository> <directory>
なお、--originは-oと略すことができる。

■■第13章■■

【A1（訳者から）】
git-push(1)のマニュアルページ該当部分の試訳を示す。

------------------------------
fast-forwardsについて
更新によって、コミットAを指していたブランチ（リファレンス）が、もうひとつのコミットBを指すように変更されるとき、もしBがAの子孫であれば（その場合に限り）、その更新はfast-forward（早送り）と呼ばれる。
AからBへのfast-forward更新において、オリジナルのコミットAを支えていたコミット群は、新しいコミットBを支えるコミット群の、部分集合（サブセット）である。したがって、ヒストリーは、まったく失われない。
その反対に、fast-forwardではない更新は、ヒストリーを失う。たとえば、あなたと、もうひとりの人が、同じコミットXを起点としたが、あなたの開発ヒストリーはコミットBに達し、もうひとりが、コミットAに達するヒストリーを作ったとしよう。このヒストリーは、次のように図式化される。

      B
     /
 ---X---A

さらに、もうひとりの人が、Aに至る変更を、元のリポジトリにプッシュしたものと想定しよう。それは、あなたがオリジナルのコミットXを取得したリポジトリだ。
その人がプッシュしたことにより、コミットXを指していたブランチは、コミットAを指すように更新された。これはfast-forwardである。
ところが、このときあなたがプッシュを試みたら、（いまはもうAを指している）ブランチをコミットBを指すように更新させることになる。それは、fast-forwardではない。もし、そのように更新したら、コミットAによって導入された変更は失われ、誰もがBから出直すことになってしまう。
pushコマンドが、デフォルトで、fasr-forwardではない更新を許可しないのは、このようなヒストリーの喪失を予防するためである。
もしあなたが、自分の仕事（XからBまでのヒストリー）も、もうひとりの仕事（XからAまでのヒストリー）も、失いたくなければ、ヒストリーをリポジトリから先にフェッチし（fetch first）、両者の変更を含むヒストリーを作って、その結果をプッシュする必要がある。
競合の可能性があれば、"git pull"を行って、その結果を"git push"できる。"git pull"によって、コミットAとコミットBの間に、マージコミットCが作られる。

      B---C
     /   /
 ---X---A

こうして作ったマージコミットによって、コミットAを更新するのは、fast-forwardだから、そのプッシュは許される。
（中略：まだ学習していないrebaseに関する項目なので飛ばします）
もうひとつ、プッシュが「fast-forwardではない」という理由で拒絶される一般的な状況がある。それは、あなた以外のひとが誰もプッシュしていないリポジトリに対するプッシュでも発生する可能性がある。あなたがプッシュしたコミットAを、"git commit --amend"コマンドによって、コミットBで置き換えたとしよう。それなのに（すでにAをプッシュしたことを忘れて）、Bをプッシュしようとしたら、この状況になる。そうなったとき、先にプッシュしたコミットAを、まだ誰もフェッチしていない（それをもとに開発を進めていない）ことが確実であるときに限り、"git push --force"によって、強制的に上書きできる。言い換えると、"git push --force"は、本当にヒストリーを失いたいときのための手段である。
------------------------------

【A2（訳者から）】
とくになし

【A3（訳者から）】
これはA1と同じドキュメントの、OPTIONの項に記述されている。git pullで使うrefspecを、本書では「リファレンス指定」と訳している。これは<src>:<dst>のフォーマットで、プッシュしたいオブジェクトがsrc、プッシュ先のリファレンスがdstである。ローカルブランチをsrc、リモートブランチをdstで指定すれば、そのリモートブランチに、ローカルブランチをプッシュすることになる。<src>なしの、:<dst>形式でプッシュすれば、<dst>をリモートリポジトリから削除できる。

【A4（訳者から）】
とくになし（A1の試訳を参照してください）。

【A7（訳者から）】
git configが使うファイルについては、『Pro Git』2nd Edition日本語版（https://git-scm.com/book/ja/v2）の、「1.6. 使い始める - 最初のGitの構成」に簡単な記述がある（push.defaultの説明は、13.6節の訳注を参照してください）。

■■第15章■■

【A1（訳者から）】
--min-parents=2。その意味は、「少なくとも2つの親を持つコミットだけを表示せよ」。同類に、--max-parrents=<number>などもある。

【A2（訳者から）】
次のように表示されるはず：

------------------------------
$ git log another_rename
fatal: ambiguous argument 'another_rename': both revision and filename
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
------------------------------

revisionは、ここではブランチ名のこと。ファイル名の前に前後を空白で区切った--を置くことで、それに続く引数がファイルのパスであることを、gitコマンドに伝えることができる。

【A3 （訳者よりヒント）】
コミットメッセージの表示方法は、<format>オプションでカスタマイズできる。ドキュメントでハッシュ（hash＿と書かれているのがSHA1 IDで、%H、%hなどによって指定する。色を変えるのは、%C。これらはプレースホルダー（placehokders）と呼ばれる。

【A4（訳者よりヒント）】
英文ドキュメントは、https://git-scm.com/docs/gitkで読むことができる。Filesというセクションに記述がある。

【A5（訳者から）】
「ビュー編集」（edit view）画面で、「含まれるファイル・ディレクトリを一行ごとに入力」（Enter files and directories to include, one per line）を使う。

【A6（訳者から）】
git blameコマンドの英文ドキュメントは、https://git-scm.com/docs/git-blameで読める。行の範囲を指定するスイッチは、-L <start>,<end>と、-L:<funcname>。SPECIFYING RANGESというセクションに例がある。

■■第16章■■

【A3（訳者から）】
git reflog --helpで表示されるマニュアルページから、対応する部分の試訳を示す。サブコマンドの"show"は、デフォルトであり、サブコマンドがひとつも指定されなければ、"show"になる。これは、コマンドラインで指定されたリファレンス（または、デフォルトのHEAD）のログを表示する。reflogは、最近行われたすべてのアクションを含んでいる。HEADのreflogは、ブランチの切替も記録する。git reflog showは、git log -g --abbrev-commit --pretty=onelineの別名である。

【A5（訳者から）】
git rev-parse --helpで表示されるマニュアルページの、SPECIFYING RANGESというセクションに説明がある。範囲指定でドットを2個並べる「ダブルドット」は、次の意味を持つ。

------------------------------
<rev1>..<rev2>
------------------------------

<rev2>から到達可能なコミットを含むが、<rev1>から到達可能なコミットは除外する。

オンラインで読める『Pro Git』2nd Edition日本語版（https://git-scm.com/book/ja/v2/）「7. Gitのさまざまなツール」-「7.1 リビジョンの選択」-「コミットの範囲指定」を参照（ダブルドット、複数のポイント、トリプルドットの解説がある）。

■■第17章■■

【A4（訳者から）】
日本語ウィキペディアに「Drupal」という項目がある。
https://ja.wikipedia.org/wiki/Drupal

【A5（訳者から）】
オンラインで読める『Pro Git』2nd Editionの日本語版（http://git-scm.com/book/ja/v2）では、「5. Gitでの分散作業」にワークフローや規約に関する記述がある。

■■第20章■■

【A2 （訳者から）】
マニュアルページ、git-config(1)の、OPTIONSを参照。セクションの削除には--remove-section、セクションの名前を変更するには--rename-sectionを使えそうだ。

【A3（訳者から）】
git-config(1)の、help.autoCorrectの項を参照。以下に試訳を示しす。

------------------------------
ミスタイプされたコマンドを、指定のデシセカンド（0.1秒）だけ待った後で、自動的に修正して実行します。入力されたテキストを、複数のコマンドに解釈できるときは、何も実行しません。このオプションの値が負の時は、修正したコマンドを即座に実行します。もし値が0なら、コマンドは、ただ表示するだけで実行しません。これがデフォルトです。
------------------------------