#author("2018-03-25T14:52:46+00: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 する)。 //------------------------------------------------------------------------------- *** 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> に一致してはいけない(仮に実行してもエラーになり成功しない) //=============================================================================== ** 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;複製元リポジトリ自体もミラーリポジトリだった場合は、その追跡ブランチなどの参照情報も、複製元から完全にコピーされる。| //=============================================================================== ** 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 を自動で設定しない //=============================================================================== ** git commit : 登録済みのファイルに変更が加えられた場合 [#git-commit] - 再び add, commit を行う $ git add <変更を加えたファイル> $ git commit //------------------------------------------------------------------------------- *** git commmit --amend : commit をやり直す [#git-commit--amend] - 既に commit 済みのものを修正して commit する場合、 (1)再度 commit する。履歴は全て別々に残る (2)commit をやり直す。履歴は別々にしない。 の2つの選択肢がある。やり直しの対象となる commit のログを残したくない場合、やり直し時に "--amend" オプションをつけることで実現できる。 $ git add hoge $ git commit --amend - --amend を指定した場合、統合対象(=1つ前)の commmit の 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 にする //=============================================================================== ** .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 で対象 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 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 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 を改変する必要がある場合にも使える | //=============================================================================== ** 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 が発生する。 //------------------------------------------------------------------------------- *** git cherry-pick -x <commit-ID> [#j8de21dd] - -x オプションは、cheery-pick 先のログに、cherry-pick 元の commit ID をログに自動で付加する。 //------------------------------------------------------------------------------- *** git cherry-pick -n -m1 [#git-cherry-pick-n-m1] - [[git stash drop>#git-stash-drop]] で消してしまった stash を復元する - 使い方 ++ git stash drop したときに出てくる hash を控えておく(下記の()の中) $ git stash drop Dropped refs/stash@{0} (60f116422281cfa289409787bfab79cdedd789a8) ++ 上記の stash を復元する $ git cherry-pick -n -m1 60f116422281cfa289409787bfab79cdedd789a8 //=============================================================================== ** 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> //=============================================================================== ** tag の命名規則 [#tag-naming-rules] - / で区切られる単位が . で始まってはならない - 下記の文字で終わってはならない / . - 下記の文字は使用出来ない ASCII制御文字 SPACE ~ | ^ : ? * [ \ DEL文字(\177) - 下記の文字列を含んではならない .. .lock @{ //=============================================================================== ** git clean : リポジトリで管理されていないファイルの表示・削除 [#o40b616e] - リポジトリで管理されていないファイルの一覧表示 |~option |~description |~remark | |-n |リポジトリで管理されていないファイルの一覧を表示。引数なしの場合のデフォルトの動作 | | |-f |リポジトリで管理されていないファイルを削除。ディレクトリ、.gitignore で無視されているファイルは対象外 | | |-d |リポジトリで管理されていないファイルとディレクトリを削除。 .gitignore で無視されているファイルは対象外。| | |-x |リポジトリで管理されていないファイルの削除。.gitignore で無視されているファイルも対象 | | //=============================================================================== ** 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 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 //------------------------------------------------------------------------------- *** 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 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 を実行していないことが条件となる) - 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 show : 詳細を表示する [#git-show] - git show <commit-ID> -- 指定した <commit-ID> の詳細を表示する - git show <tag> -- tag が -a や -m で付加情報付きで打たれている場合、Date, Tagger などの情報を表示する。 //=============================================================================== ** git name-rev : その 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 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 //------------------------------------------------------------------------------- *** 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 | --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 [#x10a66d0] - [[Fast-Forward>#fast-forward]] commit として解決出来る場合でも、強制的に merge commit を発生させる。 - merge commit を発生させることで、merge の記録を残したい場合に使用する。 //=============================================================================== ** 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 に書くほどではない注釈、レビューコメントなどの追加に使用出来る。 - いずれのコマンドも、 <commmit 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 の commmit 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 は初期化されていない。 # この場合は次のように手動で初期化する必要がある + 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 # 先ほど追加し、 commmit & 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 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 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 '' //------------------------------------------------------------------------------- *** 設定項目 [#zdb3844f] |~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> でも呼び出せるようにする | | //------------------------------------------------------------------------------- *** 設定をエディタで編集する [#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 : リポジトリを最適化する [#a810f7c7] |~option |~description | |--aggressive |最適化の度合いを大きくする。&br;処理時間がかかるが、その分最適化された状態にする。| |--prune=<date> |<date> で指定されたものより古いオブジェクトを破棄する。&br;右辺に何も指定しなかった場合のデフォルト値は "2 weeks ago" となる。&br;また、右辺に "now" を指定すると、全ての不要なオブジェクトが削除される。| //=============================================================================== ** .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 //=============================================================================== ** リポジトリからファイルを完全削除する [#e00a6570] - 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 ///////////////////////////////////////////////////////////////////////////////// * 用語 [#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> の書式による、ブランチ指定のこと。 ///////////////////////////////////////////////////////////////////////////////// * [[Subversion>VersionCtl/Subversion]] とのコマンド対比 [#q65add11] |~Git |~Subversion |~Description | |git init |svnadmin create |リポジトリ作成 | |git clone |svn checkout |リポジトリのコピー | |git add <file> |svn add <file> |ファイルの追加 | |git add <file>; git commit |svn commit [file] |ファイルの更新をリポジトリに反映 | |git rm <file> |svn rm <file> |ファイルの削除(別途、要 commit) | |git status |svn status | | |git log [file] |svn log [file] |ログを表示する | |git log --shortstat --name-status | svn log -v |追加・変更されたファイル名を含めたログを表示する | |git log -<number> | svn log -l <number> |最新から <number> 個のログエントリを表示する | |git blame <file> |svn blame <file> |<file> の各行がいつ誰によって変更されたかを表示する | |git checkout <branch> |svn switch <branch> | | |git merge <branch> |svn merge <branch> | | |git checkout <file> |svn revert <file> |ファイルに対して行った(リポジトリに未反映の)変更を元に戻す | |git clean -f |svn revert [dir] |~| |git pull <remote> <local> | svn up[date] |<remote> の最新状態を <local> に merge する | ///////////////////////////////////////////////////////////////////////////////// * 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 の機能はない //=============================================================================== ** git-gui [#git-gui] - 起動 $ git gui - git の公式な GUI である模様 - X 版は Tk で書かれている - Windows 版もある - merge, branch 操作、 commit など、ある程度の操作が出来る。 ///////////////////////////////////////////////////////////////////////////////// * 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