#author("2024-04-14T09:24:11+09:00","","")
#author("2024-04-14T09:26:35+09:00","","")
#topicpath();
/////////////////////////////////////////////////////////////////////////////////
#contents();
#ls2(VersionCtl/git/);

/////////////////////////////////////////////////////////////////////////////////
* Links [#links]
** Git について [#about-git]
- [[Gitを使いこなすための20のコマンド>http://sourceforge.jp/magazine/09/03/16/0831212]]
- [[サルでもわかるGit入門>http://www.backlog.jp/git-guide/]]
- [[もっと早く知りたかった! Gitが鬼のようにわかるスライド厳選7選>http://www.find-job.net/startup/7-git-slides]]
- [[Git の基礎勉強 ~ Git によるバージョン管理>http://tracpath.com/bootcamp/learning_git_firststep.html]]
- [[Gitによるバージョン管理入門 for windows>http://www.plowman.co.jp/school/Git/Git.html]]

** Downloads [#xb3ff64e]
- [[Git 配布元>http://git-scm.com/]]



/////////////////////////////////////////////////////////////////////////////////
* 使い方 [#qe3c4374]
//===============================================================================
** git init : 新規リポジトリ作成 [#git-init]
+ 空リポジトリの作成
 $ mkdir hoge.git         # bare repository 用の空ディレクトリを作成
 $ cd hoge.git
 $ git init --bare --shared=true   # bare repository として初期化。管理ファイル群が生成される。共有にするには --shared=true にする
+ 作業用リポジトリの作成
 $ cd ..
 $ git clone hoge          # hoge.git から hoge という名前で bare ではないリポジトリとして複製する
+ 作業用リポジトリでファイルを登録
 $ cd hoge
 /* 何かしらの方法で新しいファイル fuga を置く */
 $ git add fuga           # ファイル "fuga" が登録対象になる(まだ登録されていない)
 $ git commit             # 前の git add で指定されたファイルが登録される 

//-------------------------------------------------------------------------------
*** ''--shared='' option [#wa0b28d2]
- ''--shared='' オプションの右辺には、true / false の他に、 UNIX permission も使用出来る。 
- 同一グループ内のみで共有したい場合は、
 --shared=0660
のようにする。

//===============================================================================
** git checkout [#git-checkout]
//-------------------------------------------------------------------------------
*** 分岐元となる remote branch を指定して local branch を切る [#xb409b6b]
 $ git checkout -b <local-branch-name> <remote-repository>/<remote-branch-name>
- <remote-repository>/<remote-branch-name> を、<local-branch-name> という名前の local branch として切る(checkout する)。
- git branch と異なり、作成した新ブランチが checkout された状態になる。(git branch では、作成されたブランチは checkout されない状態となる)

//-------------------------------------------------------------------------------
*** branch 作成 [#git-checkout-new-branch]
- 例として新しく作成する branch の名前を "work1" とする
- (例えば masterのディレクトリ内で)次の操作を行う
 $ git checkout work1

//-------------------------------------------------------------------------------
*** branch 切り替え [#git-checkout-branch-already-exists]
- 切り替えの時も git checkout を実行する。操作が成功すれば以下のようにブランチが切り替わったことを通知するメッセージが表示される
 $ git checkout work1
 Switched to branch 'work1'
-- この時、元の branch と work1 の間に差分があれば、現在のディレクトリの内容も work1 の最新の状態に切り替わる
-- 但し、元の branch で修正して commit さてていない変更点がある場合、その差分はそのまま残される。つまりその変更点が存在する状態で work1 に切り替わっている

//-------------------------------------------------------------------------------
*** tag 指定で branch を切る [#git-checkout-by-tag]
 $ git checkout -b <new-local-branch-name> refs/tags/<tag-name>
- <new-branch-name> は <tag-name> に一致してはいけない(仮に実行してもエラーになり成功しない)


//-------------------------------------------------------------------------------
*** 特定のファイルだけ revert したいとき [#git-checkout-revert-individual-file]
- [[git revert>#git-revert]] すると、指定した commit で変更した全てのファイルが revert されるが、その中の特定のファイルだけを revert したい場合は、git checkout で行う(コマンドは下記):
+ 変更を戻したいファイル、そのファイルの戻したい状態の commit-ID を指定して checkout する。
 $ git checkout <その状態に戻したい commit-ID> <revertしたいファイル>
+ 差分を確認する。このとき、指定したファイルは HEAD と checkout した commit-ID の状態との差分になっているので、戻したくない部分があれば手動による差分編集で修正する。
+ 想定通りの差分になったことを確認したら、 git add, git commit する。

//-------------------------------------------------------------------------------
*** ファイル名に NTFS の禁則文字が含まれるブランチを、 Windows 環境下で checkout するとき [#sec3b4a0]
- NTSF ファイルシステムの禁則文字が含まれるブランチを checkout しようとすると、以下のエラーが出て失敗する:
 $ git checkout master
 error: invalid path '.sane/xsane/CANON:Canoscan9000FMarkII.drc' # 注:ファイル名に禁則文字である ":" が含まれている
- checkout 出来るようにする為には、以下を設定する:
 # 禁則文字を含むファイルをチェックアウトするとエラーになる機能を無効化
 git config core.protectNTFS false
 
 # sparse-checkout を有効化
 git config core.sparsecheckout true


//===============================================================================
** git clone : git リポジトリの複製 [#git-clone]
- 書式:
 $ git clone [options...] <repository> [<directory>]
-- <repository> で指定したリポジトリを複製する
- オプション
|~option |~description |
|--recursive |リポジトリ内に含まれる [[submodule>#git-submodule]] も同時に複製する。|
|--bare |bare repository として clone する |
|-o (--origin) <origin-repository> |複製先で使用する、複製元のリポジトリ名を <oritin-repository> として指定する&br;指定しなかった場合は "origin" が使われる |
|-b (--branch) <branch-name> |複製先の HEAD が指すブランチの名前を <branch-name> で指定する。&br;指定しない場合は、複製元の HEAD が指すブランチが使われれる。 |
|--morror |ミラーリポジトリとして複製元リポジトリを複製する。&br;複製元リポジトリ自体もミラーリポジトリだった場合は、その追跡ブランチなどの参照情報も、複製元から完全にコピーされる。|
|--single-branch |clone 元に複数のブランチがあっても、1つのブランチだけを clone する |



//===============================================================================
** git branch : branch 操作 [#git-branch]
//-------------------------------------------------------------------------------
*** リポジトリの branch 名を表示 [#g036243a]
- local の banch 一覧を表示する
 $ git branch
 * work
   master
   hoge
-- current branch には、左側に "*" が表示される
-- ${TERM} が xterm-256color な端末の場合、current repository は緑色で表示されることが多い
- remote repository も含む branch 一覧を表示する
 $ git branch -a
 * master
   remotes/origin/BillyDonahue-patch-1
   remotes/origin/BillyDonahue-patch-2
   remotes/origin/BillyDonahue-patch-3
   remotes/origin/HEAD -> origin/master
   remotes/origin/master
   remotes/origin/rollback_808
- local branch に加え、 git remote で表示される remote に属する branch の一覧も表示する(但し remote branch は、最低でも1回は git fetch 若しくは git pull しなければ表示されないことに注意)


//-------------------------------------------------------------------------------
*** branch 名を変更する [#branch-rename]
- デフォルトでは "master" になっているが、用途に合わせて任意の名前を付けることが出来る。
- 変更するリポジトリ内にて、以下のようにする:

 $ git branch -m <元の名前> <新しい名前>

//-------------------------------------------------------------------------------
*** branch 切り替え [#git-checkout-branch-already-exists]
- 切り替えの時も git checkout を実行する。操作が成功すれば以下のようにブランチが切り替わったことを通知するメッセージが表示される
 $ git checkout work1
 Switched to branch 'work1'
-- この時、元の branch と work1 の間に差分があれば、現在のディレクトリの内容も work1 の最新の状態に切り替わる
-- 但し、元の branch で修正して commit さてていない変更点がある場合、その差分はそのまま残される。つまりその変更点が存在する状態で work1 に切り替わっている

//-------------------------------------------------------------------------------
*** 不要になった branch の削除 [#branch-delete]
- 不要になった branch work1 を削除するには、
 $ git branch -d work1

//-------------------------------------------------------------------------------
*** branch の複製 [#z292b1ac]
- current branch を別名で複製する
 $ git branch <new-branch-name>
- git checkout とは異なり、
-- 新たに作った branch を current branch に切り替えない
-- 新しい branch の upstream を自動で設定しない

//-------------------------------------------------------------------------------
*** 現在の branch を知る [#s9a5732d]
- git branch で、現在ローカルにあるブランチの一覧が表示される。'*' が付いているのが現在 checkout されているブランチになる。
 $ git branch
 * emacs-26.3
   emacs-27.1
   emacs-27.2
   emacs-28.2
   master
- 現在のブランチ名だけを表示
 $ git br | grep -F '*'
 * emacs-26.3
- 更に '*' を消したい場合
 $ git br | grep -F '*' | perl -pe 's/\*\ //'
 emacs-26.3
-- この方法だと、branch から detach された状態(commit ID 指定で checkout した場合。repo sync コマンドで使ってチェックアウトされている場合にもこうなる)でも正しく表示出来る。
 $ git br | grep -F '*' | perl -pe 's/\*\ //'
 (HEAD detached at d16af4d)


//===============================================================================
** git add : 変更差分を commit 対象に登録する [#git-add]
 $ git add <変更を加えたファイル>

//-------------------------------------------------------------------------------
*** git add -p : 変更をファイル単位ではなく差分単位で add する [#git-add-p]
- 書式
 $ git add -p <変更を加えたファイル>
- 例
++ コマンド実行する → 差分単位毎に add するかどうかを訊いてくる
 $ git add -p Makefile 
 diff --git a/c++/SIGSEGV/Makefile b/c++/SIGSEGV/Makefile
 index e65a48d..9c9e6a1 100644
 --- a/c++/SIGSEGV/Makefile
 +++ b/c++/SIGSEGV/Makefile
 @@ -14,7 +14,8 @@ ifeq ($(clang),1)
  CXXFLAGS += -O1 -g -fsanitize=address -fno-omit-frame-pointer
  else
  endif
 -CXXFLAGS += -O1 -D_FORTIY_SOURCE=1
 +CXXFLAGS += -O1
 +CXXFLAGS += -D_FORTIY_SOURCE=1
  
  #-fcheck-memory-usage \
  #-fprefix-function-name \
 (1/3) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? 
--- プロンプトに出てくる文字の説明を見るには、 "?" を type する
 (1/3) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? ?
 y - stage this hunk
 n - do not stage this hunk
 q - quit; do not stage this hunk or any of the remaining ones
 a - stage this hunk and all later hunks in the file
 d - do not stage this hunk or any of the later hunks in the file
 g - select a hunk to go to
 / - search for a hunk matching the given regex
 j - leave this hunk undecided, see next undecided hunk
 J - leave this hunk undecided, see next hunk
 e - manually edit the current hunk
 ? -  print help
++ 終わると、shell に戻る。
++ 一部の変更だけ add したファイルは、git status すると "Changes to be committed", "Changes not staged for commit" の両方にリストされる:
 $ git status
 Changes to be committed:
   (use "git restore --staged <file>..." to unstage)
 	modified:   Makefile
 
 Changes not staged for commit:
   (use "git add <file>..." to update what will be committed)
   (use "git restore <file>..." to discard changes in working directory)
 	modified:   Makefile
 	modified:   hogehoge.cpp
- コマンドラインでは、複数の変更差分を一方通行で処理する。最初から全体を見渡したり前後を行ったり来たりして確認しながら add していきたい場合は、 [[magit>VersionCtl/git/magit/v3.2.1#partical-staging-commit]] を使った方が良い。


//===============================================================================
** git commit : 変更差分を commit する [#git-commit]
- [[git add>#git-add]], commit を行う
 $ git add <変更を加えたファイル>
 $ git commit

//-------------------------------------------------------------------------------
*** git commit --amend : commit をやり直す [#git-commit--amend]
- 既に commit 済みのものを修正して commit する場合、
 (1)再度 commit する。履歴は全て別々に残る
 (2)commit をやり直す。履歴は別々にしない。
の2つの選択肢がある。やり直しの対象となる commit のログを残したくない場合、やり直し時に "--amend" オプションをつけることで実現できる。
 $ git add hoge
 $ git commit --amend
- --amend を指定した場合、統合対象(=1つ前)の commit の commit log 編集画面が表示され、これを編集してもしなくても commit は出来るが、ここで確定させたものが統合された commit の commit log となる。

//===============================================================================
** git push: リポジトリの変更を他のリポジトリに反映する [#git-push]
 $ git push <反映先> <反映元>
- options
|~option |~description |
|-u, --set-upstream |新規に作成したリポジトリやブランチを push する際に、ローカルリポジトリと push 先のリポジトリとのブランチ対応付けを行う。&br;対応付けを行うことにより、次回以降 push 時にブランチ名を省略できる。|
|--all |ブランチを全て push する |
|--tags |全ての tag を push する(*) |
|--mirror |リモートリポジトリに、ローカルリポジトリの内容をそのまま複製したいときに使用する。ローカルで削除されたブランチはリモートでも削除される |
|--delete <repository> <branch-to-be-deleted>|リモートリポジトリのブランチを削除する |
|<repository> :<branch-to-be-deleted> |~|
|-n, --dry-run |変更情報の送信とリモートリポジトリへの反映結果を確認する。実際にはリモートリポジトリへの反映は行われない |
|-f, --force |リモートブランチがローカルブランチの派生元でない場合でも、強制的に上書きする。&br;リモートブランチのコミット情報を失う場合があるので、注意が必要 |
|--progress |標準エラーに進捗状況を出力する |
|<repository> |push 対象となるリポジトリを指定する。リモート名または URI を指定する |
|<refspec> |<src>:<dst> のフォーマットで送信元:送信先ブランチを指定する。例えば、branch-a から branch-b に push する場合、次のように指定する:&br;branch-a:branch-b |
- (*): git push --tag では、ローカルの全てのタグが送信される。この場合は意図しないものまで送信してしまう可能性もある。タグの push は、以下のように1つずつ指定して行うのが安全である:
 $ git push <dst-branch> <local-tag-name>:<remote-tag-name>

//-------------------------------------------------------------------------------
*** branch を明示して push する [#p03ee305]
 $ git push <src-branch-name>:<dst-branch-name>

//-------------------------------------------------------------------------------
*** local で新規作成した branch を remote へ push する [#f9525e3f]
 $ git push <remote-repository> <local-new-branch-name>

//-------------------------------------------------------------------------------
*** push 出来ない [#gefdcd5c]
- push.default が設定されていない場合
-- push 先のリモートブランチが指定されてない場合に起きる
-- デフォルトリモートブランチを設定して解決する
 $ git config --add branch.<local-branch-name>.remote <remote-name>
 $ git config --add branch.<local-branch-name>.merge <remote-branch-name>
 $ git push -u <remote-branch-name> <local-branch-name>

//-------------------------------------------------------------------------------
*** commit の取り消しをリモートに push する [#ue90ec53]
- 以下のコマンドで、リモートリポジトリの履歴を1つ巻き戻すことが出来る。
 $ git push -f <repository> HEAD^:<branch-name-to-be-pushed>
-- 但し、通常、bare repository ではデフォルトで push -f が効かない設定になっていて、以下のようなエラーが出る:
 $ git push -f origin HEAD^:xemacs
 Total 0 (delta 0), reused 0 (delta 0)
 remote: error: denying non-fast-forward refs/heads/xemacs (you should pull first)
 To /home/kazu/git_repos/emacs/xemacs.git/
 ! [remote rejected] HEAD^ -> xemacs (non-fast-forward)
 error: failed to push some refs to '/home/kazu/git_repos/emacs/xemacs.git/'
--- そもそも、 "''push -f''" は安易に使うべきではない。
-- どうしても push する場合は、push 先となる bare repository の config を編集し、 denyNonFastforwards を false に編集する:
 vi <bare-repository>/config
 
  [core]
      repositoryformatversion = 0
      filemode = true
      bare = true
      sharedrepository = 1
  [receive]
      denyNonFastforwards = true   # ←これを false にする


//-------------------------------------------------------------------------------
*** push 出来る容量を変更する [#ye836ae2]
- 大きな容量の commit を remote に push しようとしたとき、以下のようなエラーになる場合がある:
 error: RPC failed; result=22, HTTP code = 404
 fatal: The remote end hung up unexpectedly
- この場合、下記のような設定を行うことで回避出来る場合がある:
 $ git config --global http.postBuffer 524288000
-- この例では 150MB までの git push が出来るようになる。



//===============================================================================
** .git [#dot-git]
- リポジトリの中に出来る .git の中身は以下のようになっている:
 $ ls -l .git/
 合計 60
 -rw-r--r--   1 user1 user1    24 11月 22 18:13 COMMIT_EDITMSG
 -rw-r--r--   1 user1 user1   293 10月 10 14:19 FETCH_HEAD
 -rw-r--r--   1 user1 user1    48 10月 28 02:13 GITGUI_MSG
 -rw-r--r--   1 user1 user1    23  5月  4  2015 HEAD
 -rw-r--r--   1 user1 user1    41 10月 10 14:19 ORIG_HEAD
 drwxr-xr-x   2 user1 user1     6  5月  4  2015 branches
 -rw-r--r--   1 user1 user1   315 10月 28 02:14 config
 -rw-r--r--   1 user1 user1    73  5月  4  2015 description
 drwxr-xr-x   2 user1 user1  4096  5月  4  2015 hooks
 -rw-r--r--   1 user1 user1 19357 11月 22 18:12 index
 drwxr-xr-x   2 user1 user1    20  5月  4  2015 info
 drwxr-xr-x   3 user1 user1    28  5月  4  2015 logs
 drwxr-xr-x 186 user1 user1  4096  9月 20 19:08 objects
 drwxr-xr-x   5 user1 user1    43  5月  4  2015 refs

- それぞれは、以下のように使われる 
|~name |~description |
|HEAD |現在チェックアウトされているブランチ(HEAD)がどういう参照情報かが書かれている |
|config |この git リポジトリの設定内容 |
|description |この git リポジトリの説明が記述される。&br;GitWeb でリポジトリを HTTP 公開したり、メールでコミットメッセージを送信するときなどに利用される。 |
|hooks/ |このディレクトリ配下にフックスクリプトを配置する |
|info/ |この git リポジトリで無視したいファイルを info/exclude に記述する |
|objects/ |この git リポジトリで管理する git オブジェクトの実体がここに配置される |
|refs/ |ブランチやタグが指す git オブジェクトがどれかという参照情報がここに置かれる |



//===============================================================================
** git revert : commit を取り消す [#git-revert]
- 「取り消す」とはいっても、 commit の痕跡自体は消せるわけではなく、単に元に戻すための commit ができますよ、という機能。
+ まず、[[git log>#git-log]] で対象 commit の hash を確認
 $ git log
 commit bdf1da8aecdfbe5a83ce93e78e2ad8a241b1530b
 Author: hogehoge <hogehoge@fuga.com>
 Date:   Mon May 4 13:33:13 2015 +0900
 
     fix build break for System
 
 commit 1072326e20c9dd482d5e1db46419b0412317d693
 Author: hogehoge <hogehoge@fuga.com>
 Date:   Mon May 4 13:12:33 2015 +0900
 
     delete Makefile.bak
 
 ...
+ 対象を確認したら、 hash を指定して revert する
 $ git revert bdf1da8aecdfbe5a83ce93e78e2ad8a241b1530b
-- 即座に commit log 編集画面になる。

- git revert で指し戻せるのは commit 単位となる。特定の commit の中の特定のファイルだけ差し戻したい場合は、[[git checkout>#git-checkout-revert-individual-file]] を使う。


//===============================================================================
** git restore : ワークツリーファイルを復元 [#git-restore]
- git version 2.23.0 で新規追加されたもの。
- [git checkout>#git-checkout] のファイル操作に関する機能を切り出したもの。(git checkout の機能が多過ぎることから、役割を明確に分けるために追加されたとのこと)
- [[git-restore – Git コマンドリファレンス(日本語版)>https://tracpath.com/docs/git-restore/]]



//===============================================================================
** git reset: git commit や git add をなかったことにする [#git-reset]
 $ git reset [commit-ID]
- [commit-ID] を取り消す
- [commit-ID] を指定しなかった場合、HEAD が指定されたとみなされる
- [commit-ID] には以下が使用出来る:
-- HEAD: 最新
-- <commi-ID>^ or <commit-ID>~1 : <commit-ID> の1個前
-- <commi-ID>^^ or <commit-ID>~2 : <commit-ID> の2個前
- 但し、remote へ push 済みの commit に対して reset を行なっても、 reset を remote には push 出来ないようなので注意が必要。
- --hard を使用すると、作業中のリポジトリに状態が反映される
- --soft (もしくは指定ナシ)の場合、git のステータスが変わるだけになる。

//-------------------------------------------------------------------------------
*** commit を取り消すには [#obe3c6fc]
- local にのみ commit されていて remote に push されていない commit は、commit 自体を取り消すことが出来る。~
これは [[git revert>#git-revert]] のように「commit を打ち消す内容の変更差分を生成して commit する」のとは違い、履歴から commit 自体を抹殺する。
- 取り消したい commit の hash を AAAA とすると、
 $ git reset --hard AAAA^   # AAAA の1個前の commit まで戻る
※コミット自体を取り消す場合には、少なくとも対象のより1個前の commit まで履歴を戻るのがポイント。

//===============================================================================
** git switch : [#git-switch]
- git version 2.23.0 で新規追加されたもの。
- [git checkout>#git-checkout] のブランチ切替操作に関する機能を切り出したもの。(git checkout の機能が多過ぎることから、役割を明確に分けるために追加されたとのこと)


//===============================================================================
** git merge : 他の branch に commit を反映する [#git-merge]
 $ git merge <反映先 branch>
- options
|~option |~description |~remark |
|--no-ff |[[Fast-forward merge>#fast-forward]] を強制的に抑止し、merge commit が必ず発生するようにする。 | |
|--squash <branch> |<branch> に commit されている複数のcommit を1つに纏める。 |merge commit は自動生成されないので、 git commit を手動で行う必要がある。&br;merge に際して committer や log を改変する必要がある場合にも使える |
|--strategy-option=patience |patience アルゴリズムを使用すると、関数やタグの不適切な括弧を調整する助けになる。| |



//===============================================================================
** git cherry-pick [#git-cherry-pick]
- git merge は branch 間差分を全て適用するのに対し、 git cherry-pick は「特定の commit のみを他の branch に適用」する
- git cherry-pick で特定 commit を取り込む場合、取り込んだ commit は、取り込み元の commit とは異なる commit ID が振られる。~
つまり、 branch A の commit aa を branch B へ cherry-pick すると、 branch B 上の commit ID は aaaa ではなく別の ID (仮に aabb とする)となる。~
そのため、この cherry-pick をした後で branch A を branch B に git merge しようとすると、異なる commit ID (=別々の修正)で同一箇所を変更したと認識されるため、conflict が発生する。

//-------------------------------------------------------------------------------
*** 取り込む commit ID を自動的にログに残して cherry-pick する [#t636e364]
- 書式
 $ git cherry-pick -x <commit-ID>
- -x オプションは、cheery-pick 先のログに、cherry-pick 元の commit ID をログに自動で付加する。

//-------------------------------------------------------------------------------
*** [[git stash drop>#git-stash-drop]] で消してしまった stash を復元する [#git-cherry-pick-n-m1]
- 書式
 $ git cherry-pick -n -m1
- 使い方
++ git stash drop したときに出てくる hash を控えておく(下記の()の中)
 $ git stash drop
 Dropped refs/stash@{0} (60f116422281cfa289409787bfab79cdedd789a8)
++ 上記の stash を復元する
 $ git cherry-pick -n -m1 60f116422281cfa289409787bfab79cdedd789a8

//-------------------------------------------------------------------------------
*** merge commit を cherry-pick する [#h155b9a0]
- 書式
 $ git cherry-pick <merge-commit-ID> -m <parent-number>
- 以下のような履歴から、B0-B1-B2 を纏めて他の branch に cherry-pick する場合
 * M0 [bash][vnc] Fix bug.
 *   M1 Merge remote-tracking branch 'novak/master'
 |\  
 | * B0 [bash] Add sample: getopts
 | * B1 [c++] Modify makefile.
 | * B2 [perl] Modify whois test
 * | A0 [bash][vnc] Add startvncserver
 |/  
 * M2 [c++] Add iine / dame.
 * M3 [perl] Add sample.
-- ここで、<parent-number> は merge commit M1 の取り込みたい側の親 B0 を示すために使うが、これは、 commit M1 を git show したとき
 $ git show M1
 commit M1
 Merge: A0 B0  ←これを確認したい
 Author: hoge <hoge@localhost>
 Date:   Fri Feb 4 20:21:13 2022 +0100
 
     Merge remote-tracking branch 'novak/master'
に現れる ''Merge:'' 行の2つの commit ID を、左を1, 右を2 とした場合の 1,2 どちらかを指定する。
-- この場合、取り込みたい側の親 B0 は右側に現れているので、<parent-number> には 2 を指定することになる。
-- 親番号の 1 or 2 は、以下の方法でも調べられる
 $ git rev-parse M1^1
 A0
  →親番号1 の commit は A0 である
 $ git rev-parse M1^2
 B0
  →親番号1 の commit は B0 である
- 取り込んだ結果は、git merge --squash のように、取り込んだ側の commit が全て1つの commit に纏められたものとなる。



//===============================================================================
** git tag  [#git-tag]
- 現在のリポジトリの最新に対してタグ <tag-name> を付ける場合
 $ git tag <tag-name>
- 特定の commit <commit-ID> に tag  を付ける場合
 $ git tag <tag-name> <commit-ID>
- 既に親 repository に push してしまった commit に後から tag を打っても、親 repository には反映できない。~
→ [[git push --tags を使う>#git-push-tag]]

//-------------------------------------------------------------------------------
*** tag を remote repository に push する [#git-push-tag]
- 全ての tag を push
 $ git push --tags # 全ての tag 情報を push する
- 特定の tag <tag-to-be-pushed> を remote repository へ push する
 $ git push <tag-to-be-pushed>

//-------------------------------------------------------------------------------
*** tag の削除 [#delete-tag]
- local repository の tag を削除する
 $ git tag -d <tag-name>
- remote-repository の tag を削除する
 $ git push <remote-repository> :<tag-name-to-be-deleted>

//-------------------------------------------------------------------------------
*** 特定の commit を含む全ての tag を検索する [#tag-contains]
- 書式
 $ git tag --contains <commit-ID>
- 実行例
-- commit ID d8c6a89b44e81ff46613db533ba1b20f2d556027 が含まれているタグを検索
 $ git tag --contains d8c6a89b44e81ff46613db533ba1b20f2d556027
 REL_2018-12-14
 REL_2019-01-21
 REL_2019-02-09

//===============================================================================
** tag の命名規則 [#tag-naming-rules]
- / で区切られる単位が . で始まってはならない
- 下記の文字で終わってはならない
 / .
- 下記の文字は使用出来ない
 ASCII制御文字 SPACE ~ | ^ : ? * [ \ DEL文字(\177)
- 下記の文字列を含んではならない
 .. .lock @{

//===============================================================================
** git describe : 最新の tag からの commit 情報を表示する [#git-describe]
- 書式
 $ git describe [option]
- 出力書式
 <tag>-<commit-num-from-tag>-g<commit-id-short-of-current-HEAD>
- option
|~option            |~description                                     |~remark |
|--tag              |全ての tag を対象とする                         | |
|--tag  <commit-id> |<commit-id> を基準として最新のtag を対象とする | |
|--match <pattern>  |<pattern> にマッチする tag を対象とする        | |
|--abbrev=<N>       | |<N>=0:タグ名のみ&br;<N>=1~5:タグ名-g<commit-id5桁>&br;<N>=6~40:タグ名-g<commit-id<N>桁> |

//-------------------------------------------------------------------------------
*** 最新の tag を取得する [#n610fbda]
 $ git describe --tags --abbrev=0


//===============================================================================
** git clean : リポジトリで管理されていないファイルの表示・削除 [#git-clean]
- リポジトリで管理されていないファイルの一覧表示
|~option |~description |~remark |
|-n      |リポジトリで管理されていないファイルの一覧を表示。引数なしの場合のデフォルトの動作 | |
|-f      |リポジトリで管理されていないファイルを削除。ディレクトリ、.gitignore で無視されているファイルは対象外 | |
|-d      |リポジトリで管理されていないファイルとディレクトリを削除。 .gitignore で無視されているファイルは対象外。| |
|-x      |リポジトリで管理されていないファイルの削除。.gitignore で無視されているファイルも対象 | |


//===============================================================================
** git fetch リモートリポジトリのデータを取得する [#git-fetch]
- git fetch は、リモートリポジトリの情報を「リモートリポジトリの情報として」リポジトリに取り込む。これによって、 [[git remote>#git-remote]] で接続したリモートリポジトリのブランチ一覧が見えるようになる他、[[git merge>#git-merge]] でブランチ間マージなどが出来るようになる。
//-------------------------------------------------------------------------------
*** リモートリポジトリで削除されたブランチの情報を反映する [#q71fe2c3]
 $ git fetch --prune ( git fetch -p )
- こういうオプションが面倒に感じる場合は、 [[git config で設定する。>#git-config-prune]]


//===============================================================================
** commit されていない変更点の確認 [#v1309767]
- 全ての差分を表示
 $ git diff
- 変更された管理対象のファイルの一覧を見る
 $ git clean [-n]
-- -n の代わりに -f を付けると、全ての変更を revert する
- 管理対象外のファイルも含め、変更ファイルの一覧を見る
 $ git status


//===============================================================================
** conflict への対処 [#conflict]
//-------------------------------------------------------------------------------
*** conflict を抑えるために [#gc113dd6]
- 未 push の commit が手許のリポジトリにある状態で remote から pull する場合は、 ''--rebase'' をつけて、同時に rebase されるようにする。
 $ git pull --rebase
- 未 commit の修正がある状態で pull する必要がある場合は、[[stash>#git-stash]] で一旦隠したうえで pull し、その後 git stash pop で修正を復活させる。(この時に conflict が起こる場合もあるが)

//-------------------------------------------------------------------------------
*** git pull --rebase した時の conflict への対処 [#git-pull-rebase-conflict]
 $ git pull --rebase
- conflict が発生したら、conflict を編集する。このとき、 branch は元いたところから Detach される。
-- Eitor で編集し、完了した場合は、そのファイルを逐次 git add する。←これにより git はそのファイルの conflict 編集が完了したことを認識する。
-- 全ての conflict を解消し、 git add したら、以下を実行する:
 $ git rebase --continue
--- 但し、途中でやめたくなった場合は代わりに下記を実行すれば、それまでの作業がなかったことになる。
 $ git rebase --abort
-- git rebase -continue を実行した結果、まだ他に merge すべき競合がある場合は更に conflict が発生する。これを逐次編集していく。
-- git rebase -continue を実行した結果、conflict が全て解消すると、変更差分が元の commit に amend され、同時に branch は Detach 状態から元いた branch に戻る。

//-------------------------------------------------------------------------------
*** 高度なマージ手法 (git-scm.com) [#bb5aeb9a]
- [[Git - 高度なマージ手法>https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E9%AB%98%E5%BA%A6%E3%81%AA%E3%83%9E%E3%83%BC%E3%82%B8%E6%89%8B%E6%B3%95]]

//-------------------------------------------------------------------------------
*** git pull や git merge 時に発生した conflict [#a52608a5]
- 競合する修正が入っている場合、手元のファイルが最新ではないと判断されるため、push に失敗する。そこで一旦 pull をすることになるが、ここで下記のようなエラーメッセージが表示される:
 $ git pull
 remote: Counting objects: 5, done.
 remote: Compressing objects: 100% (2/2), done.
 remote: Total 3 (delta 0), reused 0 (delta 0)
 Unpacking objects: 100% (3/3), done.
 From /home/kazu/work/git_test/a
    1413a9c..ac702ad  master     -> origin/master
 Auto-merging 1.txt
 CONFLICT (content): Merge conflict in 1.txt
 Automatic merge failed; fix conflicts and then commit the result.

- conflict の発生例
 AAAAA
 <<<<<<< HEAD
 BBBBBBBBB
 CCCCCCCCCCCCCCCCCCCCCCC
 DDDD
 EEEEEEEEEEEEE
 =======
 111111111111111111
 22222222222
 33333333333333333333
 4444444
 >>>>>>> ac702ad3f09388ac676c926b7a03c2a97a77f94f
-- 書式
  <<<<<<< HEAD
 (手元での修正)
 =======
 (<commit-name> によって変更された修正)
 >>>>>>> <commit-name>

- conflict の編集
-- git mergetool を実行すると merge 用のプログラムが呼び出される。
--- emacs + magit を使用している場合は、magit の画面から通常の手順で ediff を呼び出す
- conflict 解決後の処理
-- conflict 編集後、add, commit, push を行う。
 $ git add <file-name>
 $ git commit 
ここで conflict を解消した旨のコメントが予め用意された log 記入画面が表示される:
  Merge branch 'master' of /path/repos-dir
  
  Conflicts:
      1.txt
  #
  # It looks like you may be committing a merge.
  # If this is not correct, please remove the file
  #   .git/MERGE_HEAD
  # and try again.
  ...

//-------------------------------------------------------------------------------
*** ファイル単位で現在の branch の内容にするか、merge する branch の内容にするのかを決める [#i4e4f85c]
- 予めどちらを選択すべきかが明確な場合に有用な方法
- 書式
 $ git checkout <selection> <file-name>
-- <selection> には、次のいずれかを指定する
|~selection |~description |~remark |
|MERGE_HEAD |merge する branch の HEAD | |
|ORIG_HEAD  |現在の branch の HEAD | |





//===============================================================================
** git log : ログの表示(変更履歴の閲覧)[#git-log]
- オプション無し
 commit 772a23b56ce10fd0b986d84a265ed25d5723cee8
 Author: user-name <hoge@example.com>
 Date:   Sun Jul 5 12:16:20 2015 +0900
 
     [mod] disc.shtml: modify link URI

- --stat ファイル名を表示する
 commit 772a23b56ce10fd0b986d84a265ed25d5723cee8
 Author: user-name <hoge@example.com>
 Date:   Sun Jul 5 12:16:20 2015 +0900
 
     [mod] disc.shtml: modify link URI
 
  disc.shtml |    2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

- --name-status : ファイル名とステータスを表示する(svn log -v とほぼ同内容の情報)
 commit 772a23b56ce10fd0b986d84a265ed25d5723cee8
 Author: user-name <hoge@example.com>
 Date:   Sun Jul 5 12:16:20 2015 +0900
 
     [mod] disc.shtml: modify link URI
 
 M       disc.shtml

- --numstat
 commit 772a23b56ce10fd0b986d84a265ed25d5723cee8
 Author: user-name <hoge@example.com>
 Date:   Sun Jul 5 12:16:20 2015 +0900
 
     [mod] disc.shtml: modify link URI
 
 1       1       disc.shtml

- --name-only : ファイル名の情報のみ追加する
 commit 772a23b56ce10fd0b986d84a265ed25d5723cee8
 Author: user-name <hoge@example.com>
 Date:   Sun Jul 5 12:16:20 2015 +0900
 
     [mod] disc.shtml: modify link URI
 
 disc.shtml


- --graph : グラフ表示する
 $ git log --graph
 *   commit 3f726ce2feeaa9cbfedd26a8befb5d417986b8a3
 |\  Merge: 4835b978 ab67b5c1
 | | Author: Jonas Bernoulli <jonas@example.com>
 | | Date:   Fri Aug 5 18:31:55 2016 +0200
 | | 
 | |     Merge branch 'jb/list-submodules' [#2729]
 | | 
 | * commit ab67b5c1db1142f88d405dce4cabfbe3296b33fd
 |/  Author: Jonas Bernoulli <jonas@example.com>
 |   Date:   Wed Aug 3 19:56:14 2016 +0200
 |   
 |       magit-list-submodules: new command
 |       
 |       Closes #2705.
 | 
 * commit 4835b978509ad01d1dbb8ce2bf2a2121d28eb6d6



//-------------------------------------------------------------------------------
*** --date : 日付の書式を指定する [#mbface87]
- 日付書式のみ変更
 $ git log --date="format:%4Y-%2m-%2d %H:%M:%S"
 commit 3fe1c917770f9c9e3b8af1da91e79b8393460652
 Author: kazu <kazu@novak>
 Date:   2022-01-23 20:28:26
 
     [c++] Modify makefile.




//-------------------------------------------------------------------------------
*** git log -S <keyword> : <keyword> を差分に持つ commit の log を抽出する [#s97eb61f]
- 書式
 $ git log -S <keyword>
- 差分も表示したい場合は、 --patch を追加する
 $ git log --patch -S <keyword>


//-------------------------------------------------------------------------------
*** git log --no-merges : branch 間の差分を commit 単位で表示する [#s5b9bc6b]
- 書式
 $ git log --no-merges <branch-src>..<branch-dst>
- 出力例
 $ git log --no-merges origin/master..origin/pu
 commit 2f834a434d38765d43d2fe6b7a26eb9e89db48ef
 Author: Noam Postavsky <hoge@users.sourceforge.net>
 Date:   Fri Jun 10 23:16:44 2016 -0400
 
     magit-get{,-all,-boolean}: improve cache
     
     If magit--refresh-cache is activated, cache all config values at once.
     Add tests for known tricky cases.
 
 commit 5fac7343fb0c4b396ace43debbe479942c07debe
 Author: Noam Postavsky <hoge@users.sourceforge.net>
 Date:   Fri Aug 26 18:15:05 2016 -0400
 
     magit-branch-spinoff: use selected commit as base
 
 commit 43a129326412272e52d5e8529308a2601f08ba7d
 Author: Jonas Bernoulli <bar@bernoul.li>
 Date:   Thu Aug 25 19:13:05 2016 +0200
 
     magit-slow-confirm: new option
     
     TODO manual
     TODO relnotes

//-------------------------------------------------------------------------------
*** git log --pretty=<format> : 指定したフォーマットでログを出力する [#se001864]
- <format> の詳細は、
 $ man git log
または 
 $ git help log
にある、"PRETTY FORMATS" を参照のこと。また、 [[Git - pretty-formats Documentation>https://git-scm.com/docs/pretty-formats]] にも説明がある。


- oneline : 1 commit につき1行で出力する
 $ git log --pretty=oneline
 0e818e9dfd053eed6da8a40bbf6a65f2fa4b2ed8 magit-list-submodules: Handle buffer creation
 852c7593bd0be8dda1e1c9f0299ca628b34413ce magit-log-heading-re: Make the date field optional
 854fb0b08e9aa0c7151c158e7f1eb0540c5235a5 AUTHORS.md: Update list of contributors
 44da42b00ec4dc6c4257a91b3fe489a763cd3bf7 manual: Edit FAQ wording concerning handling of color
 865c5bdac4c50a23f47dba26aad1ecbec240b5c3 manual: Edit FAQ wording concerning handling of color
 30ccf86f1b55ba9a86582470de1c7dfea42852af magit-file-rename: Fix renaming file at top-level
 7dadfadd8e8e68dabf190a200fc63284b8f16706 Merge branch 'maint'
-- "--pretty=oneline" の代わりに、 "--oneline" でも同じ結果が得られる。

- email : email の形式で出力する
 $ git log --pretty=email
 From 0e818e9dfd053eed6da8a40bbf6a65f2fa4b2ed8 Mon Sep 17 00:00:00 2001
 From: Hoge Fuga <hoge@fuga.com>
 Date: Mon, 3 Sep 2018 19:39:36 -0400
 Subject: [PATCH] magit-list-submodules: Handle buffer creation
 
 As of 2113dfc3 (magit-create-buffer-hook: New hook, 2018-08-26),
 magit-mode-get-buffer callers are responsible for generating a new
 buffer if needed.
 
 Fixes #3575.

- commit ID と 日付
 $ git log --date="format:%4Y-%2m-%2d %H:%M:%S" --pretty="format:%H %cd"
 92c81063cb5c2b5748f887a6cb9b0b384a20a86d 2019-04-14 17:47:49
-- --date で指定した書式が、 "%cd" に適用される。

- --pretty オプションで指定する committer date (commit 日付) の書式
|~format |~description              |~example |
|%cd     |--date で指定した書式     |         |
|%cD     |RFC2822 style             | ex. "Fri, 12 Nov 2021 11:02:49 +0900" |
|%cr     |relative                  |2 years, 6 months ago     |
|%ct     |UNIX timestamp            |1639757130                |
|%ci     |ISO 8601-like format      |2020-07-02 23:54:11 +0900 |
|%cI     |strict ISO 8601 format    |2020-07-02T23:54:11+09:00 |
|%cs     |short format (YYYY-MM-DD) |2020-07-02                |




//-------------------------------------------------------------------------------
*** 色々組み合わせてみる [#p29d9f37]
- git log --oneline --graph --decorate
 $ git log --oneline --graph --decorate
 * d58dd6ae magit-branch-or-commit-at-point: also consider tag at point
 *   3c5f2694 Merge branch 'km/log-parent' [#2691]
 |\  
 | * ac177321 add magit-log-move-to-parent command
 |/  
 *   2e3abd43 Merge branch 'km/file-glob' [#2709]
 |\  
 | * 76d233ef support globbing in diff and log file arguments
 |/  
 * b924cdde magit.org: fix typos

- git log --pretty='format:%C(yellow)%h %C(green)%cd %C(cyan)[%an] %C(reset)%s %C(red)%d' --date=iso --graph
 $ git log --pretty='format:%C(yellow)%h %C(green)%cd %C(cyan)[%an] %C(reset)%s %C(red)%d' --date=iso --graph
 * d58dd6ae 2016-08-03 22:00:25 +0200 [Jonas Bernoulli] magit-branch-or-commit-at-point: also consider tag at point 
 *   3c5f2694 2016-08-03 17:51:39 +0200 [Jonas Bernoulli] Merge branch 'km/log-parent' [#2691] 
 |\  
 | * ac177321 2016-08-02 21:40:12 -0400 [Kyle Meyer] add magit-log-move-to-parent command 
 |/  
 *   2e3abd43 2016-08-02 12:30:59 +0200 [Jonas Bernoulli] Merge branch 'km/file-glob' [#2709] 
 |\  
 | * 76d233ef 2016-08-02 12:30:35 +0200 [Kyle Meyer] support globbing in diff and log file arguments 
 |/  
 * b924cdde 2016-08-02 00:21:26 -0400 [ivanbrennan] magit.org: fix typos 


//===============================================================================
** git reflog : リポジトリ上での git 作業履歴を表示する [#git-reflog]
- [[git log>#git-log]] が commit 履歴のみを表示するのに対し、git reflog では、 commit 以外の作業履歴、例えば pull reset の履歴も表示する。
- 操作例
 $ git reflog
 fff7841 HEAD@{9}: pull: Merge made by the 'recursive' strategy.
 9fdb195 HEAD@{10}: commit: Modify Link URI
 e56109d HEAD@{11}: reset: moving to HEAD^
 d5df2c7 HEAD@{12}: reset: moving to d5df2c7858f198496fca335d22dec36a50bb91b0
 69ab6a1 HEAD@{13}: pull: Fast-forward
 d5df2c7 HEAD@{14}: reset: moving to d5df2c7858f198496fca335d22dec36a50bb91b0
 69ab6a1 HEAD@{15}: pull: Fast-forward
 d5df2c7 HEAD@{16}: reset: moving to d5df2c7858f198496fca335d22dec36a50bb91b0
 69ab6a1 HEAD@{17}: commit: 再修正
 d5df2c7 HEAD@{18}: commit: リンク集 URI 修正

//-------------------------------------------------------------------------------
*** 消してしまった commit 履歴を元に戻す [#o2ae6c2f]
- git reset --hard HEAD^^ のような操作を行うと、commit 履歴がなくなる。それを元に戻したい場合、以下の2つの手段が考えられる。
-- remote から pull し直す(remote に push されている変更である場合)
-- reflog から復旧する(但し、それまでの間に [[git gc>#git-gc]] を実行していないことが条件となる)
- reflog からの復旧は、local にしか存在しなかった commit に関しても復旧できる。
- 以下、commit を消してから reflog による復旧までの手順を示す:
+ 現在の最新状況
 $ git log
 commit 47aea4296981269c1f3e4a779602ec0f649cfe5f
 Author: hoge <hoge@localhost>
 Date:   Sat Dec 24 00:28:19 2016 +0900
 
     Modify email page
     
     - input type of email-form (input type="email").
     - visual in confirm page.
 
 commit fe4cdb4c96822ab2ea5418b0627795b5bd6f83ce
 Author: hoge <hoge@localhost>
 Date:   Fri Dec 23 15:54:32 2016 +0900
 
     Modify comment.
 
 commit be940a58ff8b33e33e8211b390f4538a06b1803c
 Author: hoge <hoge@localhost>
 Date:   Fri Dec 23 15:51:12 2016 +0900
 
     Modify Design, remove unnesessary CSS definition.
 
 commit 85af578464c613ade32420a25c267dd2f77a31c4
 Author: hoge <hoge@localhost>
 Date:   Thu Dec 22 01:08:21 2016 +0900
 
     Modify design.
+ git reset で履歴を消す。
 $ git reset --hard HEAD^^
 $ git log
 commit be940a58ff8b33e33e8211b390f4538a06b1803c
 Author: hoge <hoge@localhost>
 Date:   Fri Dec 23 15:51:12 2016 +0900
 
     Modify Design, remove unnesessary CSS definition.
 
 commit 85af578464c613ade32420a25c267dd2f77a31c4
 Author: hoge <hoge@localhost>
 Date:   Thu Dec 22 01:08:21 2016 +0900
 
     Modify design.
+ やはり消した履歴を復旧したくなったので、reflog から戻すことにする。そこで reflog を確認
 $ git reflog
 be940a5 HEAD@{0}: reset: moving to HEAD^^
 47aea42 HEAD@{1}: reset: moving to 47aea42
 dc324eb HEAD@{2}: checkout: moving from 057c6eb522986eb442cfcb5a968c8467271af319 to dc324eb8481e1b0f9dd3f1ffc1b19177653bec4b
 057c6eb HEAD@{3}: checkout: moving from 49e4a499eb67f0eac4898241c52a6b7287d35d86 to 057c6eb522986eb442cfcb5a968c8467271af319
 49e4a49 HEAD@{4}: checkout: moving from ba052fa7aaf00cd0186cfb6b367d909f7f0f773b to 49e4a499eb67f0eac4898241c52a6b7287d35d86
 ba052fa HEAD@{5}: checkout: moving from 85af578464c613ade32420a25c267dd2f77a31c4 to ba052fa7aaf00cd0186cfb6b367d909f7f0f773b
 85af578 HEAD@{6}: checkout: moving from master to 85af578464c613ade32420a25c267dd2f77a31c4
 47aea42 HEAD@{7}: commit: Modify email page
 fe4cdb4 HEAD@{8}: commit: Modify comment.
 be940a5 HEAD@{9}: commit: Modify Design, remove unnesessary CSS definition.
 85af578 HEAD@{10}: commit: Modify design.
+ 元々の最新の commit を上記から特定する。ここでは下記に復旧することとする:
 47aea42 HEAD@{7}: commit: Modify email page
+ reflog から履歴を復旧する
 $ git reset --hard 47aea42
+ 結果を確認。
 $ git log
 commit 47aea4296981269c1f3e4a779602ec0f649cfe5f
 Author: hoge <hoge@localhost>
 Date:   Sat Dec 24 00:28:19 2016 +0900
 
     Modify email page
     
     - input type of email-form (input type="email").
     - visual in confirm page.
 
 commit fe4cdb4c96822ab2ea5418b0627795b5bd6f83ce
 Author: hoge <hoge@localhost>
 Date:   Fri Dec 23 15:54:32 2016 +0900
 
     Modify comment.
 
 commit be940a58ff8b33e33e8211b390f4538a06b1803c
 Author: hoge <hoge@localhost>
 Date:   Fri Dec 23 15:51:12 2016 +0900
 
     Modify Design, remove unnesessary CSS definition.
 
 commit 85af578464c613ade32420a25c267dd2f77a31c4
 Author: hoge <hoge@localhost>
 Date:   Thu Dec 22 01:08:21 2016 +0900
 
     Modify design.
-- 元に戻ったことを確認できた 
+ 以上。

//-------------------------------------------------------------------------------
*** git reflog のその他の利用方法 [#cd3a09e1]
- git reflog の利用シーンには、[[dangling object の削除>#remove-dangling-objects]] や [[指定したファイルを履歴毎削除する>#forcely-remove-file]] がある。


//===============================================================================
** git show : 詳細を表示する [#git-show]
- git show <object>
-- 指定した <object> の詳細を表示する
-- <object> には以下を指定出来る。
--- commit ID
--- tag
--- HEAD
--- reflog の ID
--- branch (そのブランチの HEAD の情報が表示される)
- git show <tag>
-- tag が -a や -m で付加情報付きで打たれている場合、Date, Tagger などの情報を表示する。
|~option                 |~description     |~remark |
|--no-patch              |差分を表示しない |特定の1つの commit の情報を見たいときに使える |
|--oneline               |patch 以外の部分を1行で表示する | |
|--pretty="format:<str>" |<str> で指定した書式で表示する   | |


//===============================================================================
** git show-branch [#z0485920]
- 2つのブランチの分岐点を表示する
 $ git show-branch --merge-base <branch-A> <branch-B>



//===============================================================================
** その commit が属する branch / tag の情報を表示する [#git-name-rev]
- git name-dev <commit-ID>
出力の書式は以下の通り:
 <commit-ID> <属するrepositorまたはtag>~<HEADから数えて幾つ前か>
-- 指定した <commit-ID>が、属する repository または tag の HEAD である場合、 "~" は付かない。
- 例
 $ git name-rev d827bb3b0304ec0abead4d44a3601c6a65417fde
 d827bb3b0304ec0abead4d44a3601c6a65417fde remotes/origin/np/extract-change~1
-- 上記の例では、指定した <commit-ID> は、origin の np/extract-change branch の HEAD の1つ前(~1)の commit であることを示している。
- git branch --all --contains <commit-ID>
-- <commit-ID> の commit を含んでいる branch の一覧を表示する。

//===============================================================================
** git blame [#git-blame]
 $ git blame <file-name>
- ファイルの行単位の改変履歴を表示する。svn blame とは殆ど機能的に変わらない。
- 下記のように、hash, filename, comitter, date, line-number などの情報と共に <file-name> の内容が出力される(下記は dash.el の例)
 75d29a26 dash.el (Magnar Sveen          2014-12-02 07:06:35 +0100  423)   `(-iterate (lambda (it) ,form) ,init ,n))
 75d29a26 dash.el (Magnar Sveen          2014-12-02 07:06:35 +0100  424) 
 f780322b dash.el (Matus Goljer          2014-05-03 17:22:03 +0200  425) (defun -flatten-n (num list)
 c6b92ae2 dash.el (Matus Goljer          2014-06-04 18:05:25 +0200  426)   "Flatten NUM levels of a nested LIST.
 c6b92ae2 dash.el (Matus Goljer          2014-06-04 18:05:25 +0200  427) 
 c6b92ae2 dash.el (Matus Goljer          2014-06-04 18:05:25 +0200  428) See also: `-flatten'"
 f780322b dash.el (Matus Goljer          2014-05-03 17:22:03 +0200  429)   (-last-item (--iterate (--mapcat (-list it) it) list (1+ num))))
 f780322b dash.el (Matus Goljer          2014-05-03 17:22:03 +0200  430) 
 f1c84533 dash.el (Magnar Sveen          2012-10-22 15:42:15 +0200  431) (defun -concat (&rest lists)
 c6b92ae2 dash.el (Matus Goljer          2014-06-04 18:05:25 +0200  432)   "Return a new list with the concatenation of the elements in the supplied LISTS."
 38028904 bang.el (Magnar Sveen          2012-10-22 15:26:40 +0200  433)   (apply 'append lists))
 ^302c8ea bang.el (Magnar Sveen          2012-09-24 21:02:58 +0200  434) 
 25c114c5 dash.el (Wilfred Hughes        2014-06-26 23:44:05 +0100  435) (defalias '-copy 'copy-sequence
 25c114c5 dash.el (Wilfred Hughes        2014-06-26 23:44:05 +0100  436)   "Create a shallow copy of LIST.")
 25c114c5 dash.el (Wilfred Hughes        2014-06-26 23:44:05 +0100  437) 
 174747ea dash.el (Matus Goljer          2014-06-04 17:26:41 +0200  438) (defun -splice (pred fun list)
 174747ea dash.el (Matus Goljer          2014-06-04 17:26:41 +0200  439)   "Splice lists generated by FUN in place of elements matching PRED in LIST.
 174747ea dash.el (Matus Goljer          2014-06-04 17:26:41 +0200  440) 
 


//===============================================================================
** git stash : ローカルの変更内容を隠蔽する [#git-stash]
- ローカルに変更がある状態では、 git pull, git push どちらも操作不可能になることがある。こうした場合に、一旦ローカルの変更内容を隠蔽した上で git pull し、競合などを解消させてからローカルの変更を push すれば良い。
//-------------------------------------------------------------------------------
*** git stash : ローカルの変更を隠蔽する [#jee86ab2]
 $ git stash
- オプション
|~option    |~description |
|-u         |Untracked file も含めた変更差分を退避保存する(-uがない場合、退避保存されるのは tracked file のみとなる) |
|save <msg> |stash のコメントに <msg> を指定する |

//-------------------------------------------------------------------------------
*** git stash list : 隠蔽したローカルの変更一覧を表示する [#l1f16854]
 $ git stash list

//-------------------------------------------------------------------------------
*** git stash pop : stash の最新を1つ適用し、stash のリストから削除する [#c4d0a3ba]
 $ git stash pop

//-------------------------------------------------------------------------------
*** git stash apply : stash を適用する [#qc1ff45f]
 $ git stash apply
- 実行後、 stash のリストは変更されない

//-------------------------------------------------------------------------------
*** git stash drop : stash のリストからエントリを削除する [#git-stash-drop]
 $ git stash drop
- もし、間違って実行した git stash drop を復元するには? → [[git cherry-pick>#git-cherry-pick-n-m1]]


//===============================================================================
** git rebase [#git-rebase]
- branch の分岐点を変更する、履歴の順番を入れ替える
- options

//-------------------------------------------------------------------------------
*** 分岐元のコミットを変更 [#l46bcfcf]
- branch_X から branch_Y が分岐した点を A から A2 に変更する場合
 $ git rebase A2 branch_Y
~
 == A0 ==== A1 ==== A2 ===== A3 ==== A4 ===== --- branch_X
     |
     +== B1 == B2 == B3 == B4 ===             --- branch_Y
 
                  ↓
 
 == A0 ==== A1 ==== A2 ===== A3 ==== A4 =====   --- branch_X
                    |
                    +== B1 == B2 == B3 == B4 =  --- branch_Y
 

- branch_X から branch_Y が分岐した点を A から branch_X の最新に変更する場合
 $ git rebase branch_X branch_Y
~
 == A0 ==== A1 ==== A2 ===== A3 ==== A4 ===== --- branch_X
     |
     +== B1 == B2 == B3 == B4 ===             --- branch_Y
 
                  ↓
 
 == A0 ==== A1 ==== A2 ===== A3 ==== A4 =====   --- branch_X
                                      |
                                      +== B1 == B2 == B3 == B4 =  --- branch_Y
 
//-------------------------------------------------------------------------------
*** 分岐元の branch を変更する [#pe4e10a8]
- branch_Z の分岐元を、元々の分岐元 branch_Y から branch_X に変更する~
→ branch_Z を、branch_Y の内容を含まない、branch_X から直接分岐した branch に変更する
 $ git rebase --onto branch_X branch_Y branch_Z
~
 == A0 ==== A1 ==== A2 ===== A3 ==== A4 ===== --- branch_X
     |
     +== B1 == B2 == B3 == B4 ===             --- branch_Y
                     |
                     +=== C1 ==== C2====      --- branch_Z
 
                  ↓
 
 == A0 ==== A1 ==== A2 ===== A3 ==== A4 =====   --- branch_X
     |
     +== B1 == B2 == B3 == B4 ===             --- branch_Y
     |
     +=== C1 ==== C2====      --- branch_Z
 
//-------------------------------------------------------------------------------
*** rebase の再開・スキップ・中止 [#pb771d9d]
 $ git rebase --continue | --skip | --abort
|~option |~description |
|--continue |競合解決中に、 rebase を再開したい場合に指定する |
|--skip |競合解決中に、 その commit を skip したいときに指定する。skip した commit は適用されない |
|--abort |競合解決中に、rebase を中止し、 rebase 開始前の状態に戻りたい場合に指定する |


//-------------------------------------------------------------------------------
*** git rebase -i 履歴の順番を入れ替える [#v9150474]
- 同一 branch 内で履歴を入れ替える
- 書式:
 $ git rebase -i <commits>
 <commits> 履歴編集する対象の commit の範囲を指定する
-- 履歴編集の対象の commit 範囲の指定方法は、
|~指定する書式 |~実際の挙動 |
|HEAD~<number> |HEADから <number> 個前までの履歴 |
+ このコマンドを実行すると、まずテキストエディタによる履歴編集画面が表示される。
  pick 028c868 [Process] Fix Unit build error.
  pick d4dbaa3 Modify for fix build error (In progress)
  pick 9581c48 add static
  
  # Rebase 60802d1..9581c48 onto 60802d1
  #
  # Commands:
  #  p, pick = use commit
  #  r, reword = use commit, but edit the commit message
  #  e, edit = use commit, but stop for amending
  #  s, squash = use commit, but meld into previous commit
  #  f, fixup = like "squash", but discard this commit's log message
  #  x, exec = run command (the rest of the line) using shell
  #
  # These lines can be re-ordered; they are executed from top to bottom.
  #
  # If you remove a line here THAT COMMIT WILL BE LOST.
  #
  # However, if you remove everything, the rebase will be aborted.
  #
  # Note that empty commits are commented out
ここで、
-- "pick" で始まる行が、各 commit のエントリになる
-- "pick" で始まる行は、上から下へ行くに従い、新しい履歴という扱いになっている。これらの行を入れ替えることにより、履歴順を操作することになる。
+ これを編集し終了すると、実際の履歴入れ替え処理が始まる。
+ 必要に応じて conflict の解消、git rebase --continue (途中で止める場合は --continue ではなく --abort を指定する)を実行する。



//===============================================================================
** git remote : リモートリポジトリ操作 [#git-remote]
//-------------------------------------------------------------------------------
*** git remote add : リモートリポジトリを追加する [#git-remote-add]
- リモート名<remote-repos-name> で、<url> の repository にアクセス出来るように設定する。
- <url> は、URL 形式と絶対パスが使用出来る(相対パスについては試したことがないので不明)。
- 書式
 $ git remote add [-t <branch>] [-f] [--tags|--no-tags] [--mirror] <remote-repos-name> <url>
- オプション
|~option |~description |~remark |
|-t <branch> |pull で更新内容を取得するリモートブランチを限定出来る。 |ブランチは複数指定可能 |
|-f |リモートを設定した後、リモートリポジトリから fetch する | |
|--tags &#x7c; --no-tags |remote コマンドでは、デフォルトではリモートブランチのHEAD から参照出来る tag のみ取得する。&br; このオプションが指定されると、tag を取得しない。 | |
|--mirror |リモートリポジトリがベアリポジトリの場合、push 実行時にローカルリポジトリの内容を常にリモートリポジトリに複製するようになる。 |バックアップ用途、他のサーバにリポジトリのコピーを置きたい場合に使用する。 |
|rm <remote-repos-name> |リモート名 <name> の設定とローカルリポジトリに取得されたリモートブランチ(リモート追跡ブランチ)を削除する | |

- git remote add <remote-repos-name> ; git fetch <remote-repos-name> を実行すると、その後は git branch -a で <remote-repos-name> にある branch が表示されるようになる。
- <remote-repos-name> は、URL や path を指定する代わりの alias のようなもの。
-- 識別出来ればどんな名前でもよい。
-- 実際の <remote-repos-name> で指された repository 自体は何ら変更されるわけではない。

- <url> の書式は、実際には ssh:// http:// file:// の所謂 URI 形式の他、絶対パスでも構わない。


//-------------------------------------------------------------------------------
*** git remote -v : リモートリポジトリ一覧を表示する [#git-remote-v]
- リポジトリ名と、その URL を表示する
 $ git remote -v
 origin	/home/hoge/work/hoge-repository.git (fetch)
 origin	/home/hoge/work/hoge-repository.git (push)


//-------------------------------------------------------------------------------
*** git remote rm : リモートリポジトリを削除する [#git-remote-rm]
- 書式
 $ git remote rm <remote-repos-name>
- remote repository として設定されているもののうち、 <remote-repos-name> で指定されたものの設定と、local repository に取得した remote branch を削除する。

//-------------------------------------------------------------------------------
*** git remote prune [#git-remote-prune]
- 書式
 $ git remote prune [-n] <remote-repos-name>
- <remote-repos-name> で指定された remote repository で削除済みの branch を、local repository から削除する
- -n を指定すると、 dry-run となる。(=実際には実行されない)

//-------------------------------------------------------------------------------
*** git remote rename : リモートリポジトリに付けた名前を変更する [#git-remote-rename]
- 書式
 $ git remote <old> <new>
- 設定済みの remote repository の名前を <old> から <new> に変更する。

//-------------------------------------------------------------------------------
*** git remote set-url : リモートリポジトリの URL を変更する [#git-remote-set-url]
- 書式
 $ git remote set-url [--push] <remote-repos-name> <new-url> [old-url]
- <remote-repos-name> の URI を <old-url> から <new-url> に変更する。
- [old-url] を省略した場合、URL 一覧の最初の URL が変更される。
- --push push 用にリモートリポジトリの URL を追加する。push 先と getch 先を変えたい場合に使用する。 









//===============================================================================
** git bundle : 直接通信できないリポジトリと同期を取る [#git-bundle]
- ファイルベースでリポジトリの差分をやり取りする方法
- 作成したバンドルファイルは、リポジトリと同様、 clone, fetch, pull の対象とすることが出来る。
- バンドルファイルの作成
 $ git bundle create <file> <git-rev-list-args>
-- <file> : 出力先のファイル
-- <git-rev-list-args> : branch や tag、commit などを指定する~
あるタグから特定ブランチの HEAD まで等、範囲指定も可能。
-- tag hoge-tag から branch <fuga> の HEAD までの範囲を指定して作成する場合は、次のようにする:
 $ git bundle create <file> hoge-tag..fuga
-- options
|~category |~git-rev-list-args |~description |~remark |
|limiting output| --max-count=<n>| | |
|~| --max-age=<epoch>| | |
|~| --min-age=<epoch>| | |
|~| --sparse| | |
|~| --no-merges| | |
|~| --min-parents=<n>| | |
|~| --no-min-parents| | |
|~| --max-parents=<n>| | |
|~| --no-max-parents| | |
|~| --remove-empty| | |
|~| --all|全ての commit を含める | |
|~| --branches| | |
|~| --tags| | |
|~| --remotes| | |
|~| --stdin| | |
|~| --quiet| | |
|ordering output| --topo-order| | |
|~| --date-order| | |
|~| --reverse| | |
|formatting output| --parents| | |
|~| --children| | |
|~| --objects | | |
|~| --objects-edge| | |
|~| --unpacked| | |
|~| --header | | |
|~| --pretty| | |
|~| --abbrev=<n> | | |
|~| --no-abbrev| | |
|~| --abbrev-commit| | |
|~| --left-right| | |
|special purpose| --bisect| | |
|~| --bisect-vars| | |
|~| --bisect-all| | |



- バンドルファイル <file> の妥当性を確認する
 $ git bundle verify <file> [refname]
-- [refname] : branch 名、 HEAD などを指定し、特定の branch 名や HEAD に関連する情報のみを表示する

- バンドルファイル <file> 内で定義されている commit などの情報を表示する
 $ git bundle list-heads <file> [<refname>...]
-- <refname> : branch 名、HEAD などを指定できる。指定したものに関連する情報のみ表示されるようになる。

- バンドルファイルを使った clone, fetch, pull
-- clone
+++ clone する
 $ ls
 hoge.bundle
 $ git clone hoge bundle hoge
 Cloning into 'hoge'...
 Receiving objects: 100% (1616/1616), 15.62 MiB | 0 bytes/s, done.
 Resolving deltas: 100% (629/629), done.
 Checking connectivity... done.
 warning: remote HEAD refers to nonexistent ref, unable to checkout.
+++ ここで clone した中身を見ると、.git しか存在しない
 $ cd hoge
 $ls -a
 . .. .git
+++ branch を checkout して、初めて管理下のファイルが姿を現す
 $ git checkout master
 Branch master set up to track remote branch master from origin.
 Already on 'master'
 $ ls
 archive  chat  index.shtml  menu.html   pukiwiki-plugins  wiki
 bbs      img   linux.css    menu.shtml  test


//===============================================================================
** git pull [#git-pull]
- git pull は、"git fetch; git merge" を実行するのと同じである。

//-------------------------------------------------------------------------------
*** git pull --rebase [#git-pull-rebase]
- local に未 push の commit がある状態で git pull --rebase を実行すると、その local commit を自動的に rebase する。つまり
 == A0 ==== A1 ==== A2 ===== A3 ==== A4 ===== --- remote branch
     |
     +== B1 == B2 : local repository に commit された変更(local の HEAD が A0から分岐したB2になった状態)
                  ↓
                git pull --rebase
                  ↓
 
 == A0 ==== A1 ==== A2 ===== A3 ==== A4 =====   --- remote branch
                                     |
                                     +== B1 == B2 : local repository に commit された変更(local の HEAD が A4から分岐したB2になった状態)
 
 
- conflict が発生した場合、 conflict したことを告げるメッセージが表示され、 branch が current から Detach される。この場合は以下の手順を実施する:
++ 各ファイルのマージ作業を行う
++ マージが済んだものは git add する
++ 全てのファイルのマージと git add が完了したら、rebase プロセスを進める
 $ git rebase --continue
--- これによって rebase が完了し、 branch は Detach 状態から元の current に戻り、自動的に commit される。
++ マージや rebase を途中で諦め、conflict 前の状態に戻すには、下記のコマンドで rebase を中止する
 $ git rebase --abort



//-------------------------------------------------------------------------------
*** branch を指定した pull [#dce3e1a8]
- [[refspec>#refspec]] を指定する
 $ git pull <refspec>

//-------------------------------------------------------------------------------
*** --all [#ba2446cc]
- 登録している全ての repository から変更を取得する。
- merge を行うのは、現在の branch に対してのみ。

//-------------------------------------------------------------------------------
*** --no-commit [#o125a10c]
- merge 後に自動で commit を行わない。

//-------------------------------------------------------------------------------
*** --no-ff [#git-pull--no-ff]
- [[Fast-Forward>#fast-forward]] commit として解決出来る場合でも、強制的に merge commit を発生させる。
- merge commit を発生させることで、merge の記録を残したい場合に使用する。

//===============================================================================
** git pull も git push も出来ない場合の対処 [#zcf33e52]
- git status を実行し、未 commit のファイルや git 管理外のファイルがないかを確認する。若しあれば  [[git stash>#git-stash]] で隠すか、[[git reset --hard>#git-reset]] や [[git clean>#git-clean]] を使って取り除く。
- git push で下記のようになる場合:
 $ git push origin master 
 To <path-to-remote-repository>
  ! [rejected]        master -> master (non-fast-forward)
 error: failed to push some refs to '<path-to-remote-repository>'
 hint: Updates were rejected because the tip of your current branch is behind
 hint: its remote counterpart. Integrate the remote changes (e.g.
 hint: 'git pull ...') before pushing again.
 hint: See the 'Note about fast-forwards' in 'git push --help' for details.
-- このような場合は、fast-forward な merge の出来ない差分が remote と local の間にあることを意味する。よって、先に [[git pull>#git-pull]] して merge (場合によっては conflict 編集の作業も発生し得る)してから push する必要がある。
- git pull で下記のようになる場合:
 $ git pull origin master 
 From <path-of-remote-repository>
  * branch            master     -> FETCH_HEAD
 fatal: Not possible to fast-forward, aborting.
-- このような場合は、remote branch から取ってきたオブジェクトが local と fast-forward な merge が出来ないことを意味する。よって [[git pull>#git-pull]] を [[--no-ff>#git-pull--no-ff]] オプション付きで実行する。

//===============================================================================
** fetch と pull [#o20ecc07]
- fetch と pull は、いずれも remote repository の変更を取得する
- 変更取得後、fetch はマージを行わず、 pull はマージを行う(pull = fetch + merge)
- 機械的な merge により競合が意図しない解決をされてしまうのを避けるには、pull の使用を避け、fetch と merge を別個に行うのが好ましい。

//===============================================================================
** git notes : commit に注釈を付ける [#w635d614]
- commit に対し、commit log とは別に注釈を追加することが出来る。
-- commit log に書くほどではない注釈、レビューコメントなどの追加に使用出来る。
- いずれのコマンドも、 <commit ID> を省略した場合は、HEAD の注釈についての操作となる。

//-------------------------------------------------------------------------------
*** git notes add : 注釈がまだ付けられていない commit に対して注釈を追加 [#y140a9be]
- 書式
 $ git notes add [-m <message> | -F <file>] [<commit ID>]
- -m オプションを省略した場合、 git notes edit と同様の動作となる。
- <commit> を省略した場合、HEAD に対する動作となる。
//-------------------------------------------------------------------------------
*** git notes : リポジトリに保存されている全ての注釈の hash 一覧を表示 [#d6541172]
- 書式:
 $ git notes [list [<commit> ID]]
-- 注釈の hash と、その注釈が付けられた commit ID の一覧が表示される。
-- 実際の注釈の内容を表示するには、下記の内いずれかを使う:
 $ git show <注釈の hash>
 $ git notes show <注釈が付けられている commit の commit ID>
- commit に対し、commit log とは別に注釈を追加することが出来る。
*** git notes edit : commit の注釈をエディタで編集 [#f39d733d]
- 書式:
 $ git notes edit [<commit ID>]
- 既に注釈が存在する commit の場合、既存の注釈を編集することが出来る。
//-------------------------------------------------------------------------------
*** git notes remove : commit に付けられた注釈を削除 [#v86867e0]
- 書式:
 $ git notes remove [<commit ID>...]
- commit ID を省略した場合、HEAD に付けられた注釈を削除する。
//-------------------------------------------------------------------------------
*** git notes append : 注釈を追記する [#m357e901]
- 書式:
 $ git notes append [-m <message> | -F <file>] [<commit ID>]
- 注釈を追記する。
//-------------------------------------------------------------------------------
*** notes の同期 [#s99c40af]
- git notes で追加された注釈は、 git push では同期されない。
- origin に注釈を push するには、以下のコマンドを実行する:
 $ git push origin refs/notes/commits
- 注釈を origin から取得するには、以下のコマンドを実行する:
 $ git fetch origin refs/notes/*:refs/notes/*





//===============================================================================
** git submodule : リポジトリに他のリポジトリを組み込む [#git-submodule]
- git のリポジトリの中に、他のリポジトリを組み込むためのもの

//-------------------------------------------------------------------------------
*** submodule の組み込み [#git-submodule-add]
- 既存のリポジトリ foo のディレクトリ構造の中に、別のリポジトリ bar を組み込む場合
 foo: http://foobar.com/foo.git   # aa.txt が commit されている
 bar: http://foobar.com/bar.git   # ps-ax.log が commit されている
+ foo.git の clone
 $ git clone http://foobar.com/foo.git
+ foo 内にディレクトリ baz を作り、外部リポジトリの http://foobar.com/bar.git を組み込む
 $ cd foo
 $ git submodule add http://foobar.com/bar.git baz  # ここでディレクトリ foo/baz が作成される
 Cloning into 'baz'...
 done.
 $ ls -a
 .  ..  .git  .gitmodules  aa.txt  baz  # .gitmodules と baz が追加された
 
 # ここで、baz が初期化される場合とされない場合がある。
 # git submodule とtype したときに表示される hash に "-" がついていれば、 baz は初期化されていない。
 # この場合は次のように手動で初期化する必要がある
-- git submodule add で以下のようなエラーが出ることがある:
 $ git submodule add http://foobar.com/bar.git
 Cloning into 'http://foobar.com/bar'...
 fatal: transport 'file' not allowed
 fatal: clone of 'http://foobar.com/bar.git' into submodule path '<path>/bar' failed
--- この場合は、以下を実行することで解決する:
 $ git config --global protocol.file.allow always
--- 上記 git config コマンドにより、${HOME}/.gitconfig には以下のように追記される:
 [protocol "file"]
 	allow = always
+ baz の初期化
 $ git submodule init baz
 Submodule 'baz' (http://foobar.com/bar.git) registered for path 'baz'
 $ git status
 # On branch master
 # Changes to be committed:
 #   (use "git reset HEAD <file>..." to unstage)
 #
 #	new file:   .gitmodules
 #	new file:   baz
 #
+ 組み込んだ submodule を commit & push する。この時 git add は不要。
 $ git commit
 $ git push


//-------------------------------------------------------------------------------
*** submodule を組み込んだリポジトリを clone する [#la4acbc3]
+ foo を clone する
 $ git clone http://foobar.com/foo.git new-foo
 $ cd new-foo
 $ ls
 aa.txt  baz  # 先ほど追加し、 commit & push した baz が出来ている
 $ ls -a baz
 .  ..     # 単にからディレクトリが出来ただけ。
 $ git submodule
 -386b630fd974b3f3147d462cda2c1f50813131fc baz    # hash に "-" が付いており、初期化されていないことが分かる
+ submodule を初期化する
 $ git submodule init baz
 Submodule 'baz' (http://foobar.com/bar.git) registered for path 'baz'
 $ ls -a baz
 .  ..     # この段階でも、まだ baz は空ディレクトリのままになっている
+ submodule の中身を最新にする
 $ git submodule update
 Cloning into 'baz'...
 done.
 Submodule path 'baz': checked out '386b630fd974b3f3147d462cda2c1f50813131fc'
 $ ls -a baz/
 .  ..  .git  ps-ax.log    # bar.git の中身が baz に clone される



//===============================================================================
** git diff : 差分を表示する [#git-diff]
- git diff を実行すると diff/patch 風の差分を表示するが、実はこのままでは余計な付加文字列があるために patch コマンドで使用することは出来ない。~
patch で使えるフォーマットで差分を出力したい場合には
 $ git diff --no-prefix
とする必要がある。
- 対象ファイルに改行が1つもなく、diff に失敗するときは、通常の diff 同様 ''-b'' を使うとよい。
 $ git diff -b <file>
- ブランチ間の差分を見る
 $ git diff <branch-A>..<branch-B>
- ブランチ B の、ブランチ A との分岐点からの差分を見る
 $ git diff <branch-A>...<branch-B>
-- ''..'' と ''...'' の挙動の違いに注意!


//===============================================================================
** git lfs : 大容量ファイルを扱う [#git-lfs]
- git に標準では組み込まれておらず、git の機能拡張的な存在である。
- GitHub などでは 100MB を超えるファイル
- 一次配布元: https://git-lfs.github.com/
//-------------------------------------------------------------------------------
*** 使い方 [#git-lfs-usage]
- 基本的に、通常の git と同じ引数を取る
- clone する
 $ git lfs clone <clone元>
- トラックされているファイルを確認する
 $ git lfs ls-files

//-------------------------------------------------------------------------------
*** 参考リンク [#git-lfs-links]
- [[Git LFS 1.2: クローンをもっと高速に>http://japan.blogs.atlassian.com/2016/04/git-lfs-12-clone-faster/]]
- [[Git LFSの導入方法>http://qiita.com/takish/items/4b397caa5549a39a8194]]


//===============================================================================
** git bisect [#git-bisect]

//-------------------------------------------------------------------------------
*** 参考リンク [#git-bisect-links]
--[[git bisect で問題箇所を特定する - Qiita>https://qiita.com/usamik26/items/cce867b3b139ea5568a6]]


//===============================================================================
** git config : 各種設定 [#git-config]
- 設定を記録するファイルは、下記の3つがある。
-- ${HOME}/.gitconfig --- ユーザのグローバルな設定
-- ${REPOSITORY_DIR}/.git/config --- git リポジトリ ${REPOSITORY_DIR} 内限定で有効な設定
-- ${prefix}/etc/gitconfig --- システムワイドな設定

//-------------------------------------------------------------------------------
*** ユーザアカウントに関する設定 [#git-config-user]
- ユーザアカウント、メールアドレスを登録出来る。これらは commit log で commit したユーザの情報として使用される。
- global で設定しても、 local で設定しても良い(が、通常は global になるだろう)。
 $ git config --global user.name "UserName"
 $ git config --global user.email "account@example.com"


//-------------------------------------------------------------------------------
*** alias の設定 [#git-config-alias]
- Subversion における "svn commit" に対する "svn ci" のようなエイリアスは git にはデフォルトでは存在しないが、しかし自分で好きなように設定することが出来る。
 $ git config --global alias.ci "commit"   # "git commit" を "git ci" でも実行できるようにする
 $ git config --global alias.co checkout
 $ git config --global alias.st status
 $ git config --global alias.br branch
 $ git config --global alias.bl blame
 $ git config --global alias.logs "log --name-status"
 $ git config --global alias.fe fetch
 $ git config --global alias.nr name-rev

//-------------------------------------------------------------------------------
*** defalut の設定を無効にする [#jb1a54c6]
- 設定項目に対して空文字列を指定する
- pager を使わないようにする
 $ git config --global core.pager ''

//-------------------------------------------------------------------------------
*** 設定項目 [#git-config-item]
|~configuration item |~description |~remark |
|user.name |ユーザ名を指定する | |
|user.email |ユーザのメールアドレスを指定する | |
|receive.denyNonFastFowards |true に設定すると、 push 時に repository 上の commit が含まれない commit を送信しようとしたときに branch の更新を拒否する |shared repository で設定する |
|receive.denyDeletes |true に設定すると、ブランチの削除を拒否する |shared repository で設定する |
|receive.fsckObjects |true にすると、push されたときにデータ一貫性のチェックを行う。信頼性が向上するが、 push 処理に時間が掛かるようになる。|shared repository で設定する |
|core.pager |pager を指定する |例えばless, lv など |
|alias.<alias-name> |任意の git コマンド(commit, checkoutなど)を <alias-name> でも呼び出せるようにする | |
|fetch.prune [#git-config-prune]       |true にすると、リモートリポジトリで削除されたブランチ情報が fetch 時に反映される   | |


//-------------------------------------------------------------------------------
*** 設定をエディタで編集する [#hde2f8b0]
 $ git config <--local|--global|--system> <-e|--edit>

//-------------------------------------------------------------------------------
*** 現在の設定を確認する [#vc27d4b7]
 $ git config <-l|--list>

//-------------------------------------------------------------------------------
*** メール送信の設定 [#l06f70b3]
- git config で、メール送信の設定が出来る。
|~config |~description |
|hooks.mailinglist  |push された時にコミットメッセージを送信する ML |
|hooks.announcelist |git tag <tag-name> -m <message> でタグを生成した時に通知される ML |
|hooks.emailprefix  |メールの Subject: の先頭につける文字列。&br;デフォルトは [SCM] |
|hooks.envelopesender |メールの From: に記載される送信者アドレス |
|hooks.showrev      |メールに添付するメッセージを生成するコマンド。デフォルトでは git revlist --pretty --stdin $revspec &br;差分情報を送るには、 git config hooks.showrev "git show -C \$t; scho" とする |

- 設定例
 $ git config hooks.mailinglist hoge-ml@example.com
 $ git config hooks.announcelist announce-ml@example.com
 $ git config hooks.emailprefix "[GIT]"
 $ git config hooks.envelopesender "git-admin@example.com"

//-------------------------------------------------------------------------------
*** 設定を削除する [#delete-config]
- 指定した <key> の設定を削除する
 $ git config [--local|--global|--system] --unset <key>
- 全ての設定を削除する
 $ git config [--local|--global|--system] --unset-all


//===============================================================================
** git gc : リポジトリを最適化する [#git-gc]
|~option |~description |
|--aggressive |最適化の度合いを大きくする。&br;処理時間がかかるが、その分最適化された状態にする。|
|--prune=<date> |<date> で指定されたものより古いオブジェクトを破棄する。&br;右辺に何も指定しなかった場合のデフォルト値は "2 weeks ago" となる。&br;また、右辺に "now" を指定すると、全ての不要なオブジェクトが削除される。|

//-------------------------------------------------------------------------------
*** reflog の削除 [#a6316d47]
- [[reflog>#git-reflog]] を削除するには、以下のコマンドを実行する:
 $ git reflog expire --expire=now --all


//===============================================================================
** .gitignore : git が無視するファイルを指定する [#cab5fdf3]
- ローカルの git リポジトリ上に存在し得るもので、且つ git の管理対象にしたくないことが分かっているファイルは、 .gitignore ファイルに記述する
- .gitignore に記述することで、git status で非表示に出来たり、git add などのコマンドでうっかり追加してしまったりすることを防ぐことが出来る。
- .gitignore の記述方法は、ファイル名や * を使って指定できる
- エスケープ文字を解釈する。
-- パスの途中に空白を含むエントリを記述する際は、空白文字の前に "\" を書くことで正しく空白と認識される。
- .gitignore の記述例
 *.bak
 *.o
 tmp
- 作成した .gitignore は、リポジトリにコミットしておく
 $ git add .gitignore
 $ git ci -m "[add] .gitignore"
 $ git push

//===============================================================================
** git fsck : git リポジトリを検査する [#git-fsck]
- fsck はリポジトリの状態の検査のみ行い、修復・更新はしない。
|~option       |~description |
|--no-full     |.git/objects 配下のみを検査する |
|--no-dangling |gangling object を表示しない |
- ''dangling'' とは
-- どのコミットからも参照されないオブジェクト
-- リポジトリが更新されるにつれて増えていく傾向にある

*** "missing blob <HSA1>" のようなエラーが出た場合の対処 [#l6065c83]
- git fsck で、下記のようなエラーが出る場合がある。
 Checking object directories: 100% (256/256), done.
 Checking objects: 100% (534/534), done.
 missing blob a596d0c47dc993e0b22f533930fa73422e776b53
- この例では、a596d0c47dc993e0b22f533930fa73422e776b53 の blob(ファイル)が失われていることを報告している。~
この場合、他のリポジトリに該当する blob があるなら、それを持ってきて、下記の名前で保存すると復旧出来る:
 .git/objects/a5/96d0c47dc993e0b22f533930fa73422e776b53


//===============================================================================
** dangling object を削除する [#remove-dangling-objects]
- [[git fsck>#git-fsck]] をした際に dangling object (宙ぶらりんのオブジェクト)が出てくることがある。
 $ git fsck
 Checking object directories: 100% (256/256), done.
 Checking objects: 100% (534/534), done.
 dangling commit 2a7217d80a46bf28a2e5d1dfb1eb762f40aaf7b4
 dangling blob f50d7df0cfb42bd5d8aaf85b94539088ee3accee
 dangling commit 2296d0c5adc7f360b00f538580fa73422e866a3a
 dangling tag 385f6da23daae6d9d7f00371e89b4c353412afb1
- dangling object を削除するには、下記を実行する:
 $ git reflog expire --expire=now --all
 $ git gc --prune=now


//===============================================================================
** リポジトリからファイルを完全削除する [#forcely-remove-file]
- git リポジトリで git rm すると、最新からは削除されるが履歴としては残っていて、履歴を辿れば復元することが出来る。しかし物によっては履歴にも残したくないものがある。~
そういったものを消去する方法
+ まず、 git filter-branch を実行
 $ git filter-branch --tree-filter 'git rm --ignore-unmatch <file-to-be-deleted>' --prune-empty -- --all
-- <file-to-be-deleted> の対象になるファイルが複数あり、パターンマッチで実行する場合は下記のようにする(例は *.o を消す場合)
 $ git filter-branch --tree-filter 'git rm --cached --ignore-unmatch "*.o"' --prune-empty -- --all
-- <file-to-be-deleted> がディレクトリの場合は、その下の階層も対象になるため、クォーテーションしている git rm に -r オプションが必要になる。
+ reflog にも残っているので、これも削除する
 $ git reflog expire --expire=now --all
 $ git gc --prune=now
 $ git gc --aggressive --prune=now
//-------------------------------------------------------------------------------
*** エラーになる場合の対処 [#o5cda9b5]
- git filter-branch を実行した際に以下のメッセージが出てエラーとなる場合がある:
 Cannot create new backup. A previous backup already exists in refs/original/
 Force overwriting the backup with -f
- この場合、既に filter-branch 操作を実行しています。 filter-branchの後、gitは何かがうまくいかない場合に備えて、古いコミットを参照し続ける。.git / refs / original / …でそれらを見つけることができます。そのディレクトリとその中のすべてのファイルを削除するか、-fフラグを使ってGitに古い参照を削除させます。
 $ git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch Rakefile' HEAD
- 参考リンク:[[コードログ:Gitリポジトリからのファイルの削除に失敗しました。新しいバックアップを作成できません>https://codeday.me/jp/qa/20181216/49998.html]]


//===============================================================================
** git worktree : 1つのローカルリポジトリで複数のブランチを同時使用する [#git-worktree]
- 2つ以上のブランチを同時に参照出来るようになる。
- 指定したブランチを指定したパス上に作成する。これは元のリポジトリと同じリポジトリとして扱える。
- git version 2.5.0 で機能追加された。
//-------------------------------------------------------------------------------
*** 別のブランチを新たな作業ツリーとしてチェックアウトする [#git-worktree-add]
- 書式:
 $ git worktree add <path-to-new-checkout-work-tree> <target-branch>
- 例:リポジトリ foo からブランチ bar を foo と同じ階層の別ディレクトリ foo1 にチェックアウトする
-- 元となるローカルリポジトリのパスを ${HOME}/work/hoo とすると
 $ cd ${HOME}/work/foo
 $ git workspace ../foo1 bar
- git workspace で作られた作業ツリーには、ディレクトリではなくファイルの .git が置かれる
-- この .git には、分岐元のローカルリポジトリに置かれた、このリポジトリの .git 実体へのパスが書かれている

//-------------------------------------------------------------------------------
*** 状態を見る [#git-worktree-list]
- 元リポジトリで git branch を実行すると、分岐した作業ツリーも含めたブランチ一覧が表示される
 $ git branch
 * master    # 元リポジトリでチェックアウトされているブランチ
 + bar       # 分岐した作業ツリーでチェックアウトされているブランチ
- git worktree list でパス、チェックアウト状態の一覧を表示する
-- 書式
 $ git worktree list [--porcelain]
-- 例
 $ git worktree list
 /home/username/work/foo   7f13bec [master]
 /home/username/work/foo1  e2cdad2 [bar]
-- 例:--porcelain は機械処理し易くすることを意図したフォーマットで出力する
 $ git worktree list --porcelain
 worktree /home/username/work/foo
 HEAD 7f13bec0c71ad2b6d37c71ef0d4833d541685a52
 branch refs/heads/master
 
 worktree /home/username/work/foo1
 HEAD e2cdad2c49812aef0d3e291f65d2dd1e89dce4ba
 branch refs/heads/bar

//-------------------------------------------------------------------------------
*** 不要になった作業ツリーを削除する [#git-worktree-remove]
- 書式
 $ git worktree remove <path-to-work-tree>


//-------------------------------------------------------------------------------
*** 未確認コマンド [#git-worktree-other]
 git worktree lock
 git worktree move
 git worktree prune
 git worktree repair
 git worktree unlock


/////////////////////////////////////////////////////////////////////////////////
* 用語 [#i3001c66]
//===============================================================================
** Fast-forward [#fast-forward]
- Fast-fowrward merge
-- topic branch が master から分岐してから再び master にマージされる際、master に変更がなければ、マージコミットは発生せず、master が指す場所を付け替えるだけの動作をする。これを git では Fast-forward merge という。
-- Fast-forward merge が行われると、「topic → master」のマージ情報が commit log に発生しないため、それがいつ行われたのかが log 上では分からなくなる。~
明確にその情報を残したい場合は、 git merge に ''--no-ff'' オプションをつけることにより、強制的にマージコミットのログを発生させることが出来る。


//===============================================================================
** <refspec> [#refspec]
- git の説明によく出てくる <refspec> とは、pull や push で指定する
 <src>:<dst>
の書式による、ブランチ指定のこと。



/////////////////////////////////////////////////////////////////////////////////
* tools [#tools]
//===============================================================================
** git-sh [#y50d6b1c]
- git コマンドを打つときに "git" と入力するのを省略できるようになる
- 現在のリポジトリと branch の名前がプロンプトに表示されるため、 branch コマンドを打つ必要もなくなる。



/////////////////////////////////////////////////////////////////////////////////
* tools on emacsen[#tools]
//===============================================================================
** [[magit>VersionCtl/git/magit]] [#magit]
- リポジトリ: https://github.com/magit/magit.git
- debian の場合、 magit パッケージを install すると、即使えるようになる。
- psvn.el のように、 "e" (※注: "E" ではない)で差分を ediff で閲覧・ merge 出来る

//===============================================================================
** git-gutter+ [#git-gutter-plus]
- リポジトリ: https://github.com/nonsequitur/git-gutter-plus.git
- [[git-gutter>#git-gutter]] よりも高速らしい

//===============================================================================
** git-gutter [#git-gutter]
- [[git-gutter.el>http://emacs-jp.github.io/packages/vcs/git-gutter.html]]


/////////////////////////////////////////////////////////////////////////////////
* GUI tools [#gui_tools]
//===============================================================================
** gitk [#gitk]
- 起動
 $ gitk
- Tk で書かれている。
- committer, commit 日時、 log, diff などを1画面で表示する UI になっており、個々の commit の内容を追いかける場合には非常に見やすい。
- 閲覧にはいいが、commit の機能はない。


//===============================================================================
** qgit [#qgit]
- Qt を使って書かれている。
- 機能、画面構成共に gitk とほぼ変わらない。

//===============================================================================
** git-gui [#git-gui]
- 起動
 $ git gui
- git の公式な GUI である模様
- X 版は Tk で書かれている
- Windows 版もある
- merge, branch 操作、 commit など、ある程度の操作が出来る。


/////////////////////////////////////////////////////////////////////////////////
* リポジトリのホスト間の移動 [#r238dd13]
- ホスト間でリポジトリを移動する際は、 git のコマンド([[git clone>#git-clone]] 等)若しくは git で想定されている方法([[git bundle>#git-bundle]] で生成した bundle ファイルをコピーする)で移動する必要がある。
- host A で使っていたリポジトリを host B に移動・コピーする際、 git clone や git bundle などを使わず、sftp 等でコピーすると、 host B で使っているうちにリポジトリが壊れ、以下のような症状が発生することがある。
-- 復旧不能な dangling object の発生
-- push / pull 等が出来なくなる。

/////////////////////////////////////////////////////////////////////////////////
* Subversion (svn) からの移行 [#adc70f53]

+ git-svn をインストールする
-- debian などでは、git とは別パッケージになっている
+ 最終的な移行先の git の bare リポジトリを作成しておく(ここでは仮に repos.git というディレクトリ名にした)。
 $ git init --bare --shared=true repos.git
+ 移行元の svn リポジトリに commit しているユーザのリストを下記の書式で authors.txt に書き出す(このあたりは、svn の log がユーザ名のみを記録しているのに対し、 git ではユーザ名とメールアドレスを記録することにもよる)
 $ vi authors.txt
 hoge = hoge <hoge@your-domain.com>
 fuga = fuga <foo@example.com>
 
+ svn リポジトリを clone する(作業リポジトリが出来る)
 $ git svn clone -A authors.txt --trunk= --branches=branches --prefix=svn/ ${SVN_REPOS_URL}
-- ${SVN_REPOS_URL} は、URL 形式でないと動作しない。
-- URL 形式の記述例
 file://<絶対パス>
 http://...
 https://...
 ssh://...
 ssh+svn://...
+ 上記で出来たリポジトリの中に入り、最終的な移行先リポジトリ(はじめの方に作成した repos.git)に push する
 $ git remote add origin ../repos.git
 $ git push origin --all


トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS