howto/git

一行メモ


はじめてのGit

こちらへ howto/git/forthefirsttime

リマインド注意事項

リンク

The entire Pro Git book, written by Scott Chacon and Ben Straub

https://git-scm.com/book/ja/v2

ここからダウンロード(2021/04/15)したPDF版のファイル (ただしそのままでは不具合があるようだったので、macOSのプレビューで開いてから再度PDFで保存し作成した)。 2nd Edition (2014) のファイルです。 なお、旧版はDownloadsメニューにあるらしい。

このPDFは Scott Chacon and Ben Straubにより書かれたものであり、 ライセンスは CC BY-NC-SA 3.0です。

以下は古いもの。

ファイルの追加・名前変更・削除・変更維持

ファイルを追加(追跡対象にする。ステージに載せる)

git add .         # カレント以下のファイル(ディレクトリ含む)をステージに追加する
git add ファイル  # ファイルをステージに追加する
git add -u        # 追跡対象のファイルで修正があったものをステージに追加する

ファイル名変更

git mv 変更前のファイル名 変更後のファイル名

mv 変更前のファイル名 変更後のファイル名
git add -u
git add 変更後のファイル名
としても良い。

mv hoge.out hoge.out.chked
git add hoge.out.chked
をした。
リポジトリにある hoge.outを削除したいとき、
git add hoge.out
をするとよい。

ファイルの削除

git rm [--cached] 削除ファイル  # --cachedがあるとステージからも削除し、追跡対象からはずす。
                                # 間違ってaddしたファイルをステージだけからいったん削除したいときは、
                                # git reset HEAD file を使う(説明を参照のこと)。

作業ディレクトリでファイル hoge.outを削除した。
リポジトリからも削除したいとき
git add hoge.out
すればよい。

特定のファイルの維持

git update-index --skip-worktree ファイル名
  # 指定した作業領域上のファイルの変更を、維持するように登録する
  # (マージしても変更されなく、維持される)
git update-index --no-skip-worktree ファイル名
  # 上記の登録を解除する
git ls-files -v | grep  ^S
  # skip-worktreeしたファイルを確認する
git ls-files -o   #カレントディレクトリ以下で、追跡されていないファイルのリストを表示
git ls-files -o --exclude-standard  #git ls-files -o のうち、.gitignoreで無視したファイルを除くリスト

commit, reset, merge, clean

コミットするときの注意点

    ⇒ むずかしいのでほどほどで対応すればよい。

    ⇒ コミットメッセージは英語でする。日本語は使わないこと。

最初設定すると良いこと

git config --global user.name   "yourname"   # 実行すると ~/.gitconfigに保存される
git config --global user.email  "youremail"  # --global無しだとリポジトリ毎の.git/configに保存される
git config --global core.editor emacs
git config --global push.default simple      # simple(デフォルト)、matching(2.0以前のデフォルト)

git config --global credential.helper 'cache --timeout=1800'  # 数分間だけ認証をキャッシュする。
                                                              #httpsのみ?sshのヘルパーを動かす?

コミット

git commit -m 注釈     # ステージ済みをコミットする
git commit -a -m 注釈  # 追跡対象(のみ!)をステージしてコミットする
git commit --amend -m 注釈  # push前の直前のコミットを上書きする(直前のコミットをやり直せる)。
                              push後にすると、両者のmergeが必要となるのでしないこと。
                              なお、-m 注釈 無しだと、エディタが立ち上がる。

リセット

git checkout -- file   # fileをチェックアウトの時点にもどす(fileの修正箇所は削除される元に戻る!)
git reset HEAD file    # ステージにあるfileを取り除く。そのfileは作業ディレクトリに移動する(マージされるようだ)。
git reset --hard       # 現在のブランチを、チェックアウトの時点まで取り消す(修正中ファイルは削除される!)

マージ

clean

作業ブランチへのマージの仕方(まとめ)

       +------>o fixブランチ
       |
------>o masterブランチ
       |
       +------------->o----> 作業ブランチ
                       ~~~~~
                       未コミット部分A
       o 印はコミット

ブランチの分岐が上図のようにあり、
作業ディレクトリのブランチに fixブランチをマージするには、
次の(1)-(4)のいずれかの方法でできる。

作業ブランチをコミット済みの状態にしておき、(2)の方法でコミット
するのがいちばん素直だろう。
(fixがmasterの進んだコミットであっても同じ)

(1)
git merge origin/fix
これは自動的にコミットされる。
たぶんA部分があればエラーとなる? もしくは、A部分もコミットされる? fixに関係
するファイルだけか?
コンフリクトしたら作業ディレクトリのファイルにその内容が入る。

(2)
git merge --no-commit --no-ff origin/fix
自動的にコミットしない。
コンフリクトしたら作業ディレクトリのファイルにその内容が入る。
確認後、
git merge --abort
で取り消すか(取り消してから(1)でマージしてもよい)、または、
コンフリクトがあれば修正して(無ければそのままで)、
git commit -m "hogehoge"
する。
(なお、コミットする前にはコミットするファイルを取捨選択もできる)。

(3)
git cherry-pick SHA1
fixのコミットのSHA1をマージする。master--->fixの間に複数のコミット
があれば順に全てに対してこのコマンドでマージする。
たぶんコンフリクトしたら作業ディレクトリにその内容が入る。

(4)
git stash
--skip-worktreeしたファイルは無いことが望ましい。
git merge origin/fix をする(または (1)-(3)のいずれかでもよい)。
git stash pop
たしか、コンフリクトしたら作業ディレクトリのファイルにその内容が入る。
そして stashは消されずに残る。

status, diff, log, blame, grep

status, diff

git status [-s]    # -sは簡潔表示であり、gitで管理していないファイルは「?? ファイル名」で表示される。

git diff [ファイル]           # 作業ディレクトリとステージの比較(ステージにファイルが無ければコミット済みと比較される)
git diff --cached [ファイル]  # ステージとコミット済みの比較

git diff A B    # 差分をみる。AやBは SHA1[:ファイル]|タグ
git diff A..B   # 〃
git diff A...B  # AとBとの共通の親と, Bの差分

git diff master..origin/master    # リモートリポジトリ(origin/master)との差分をみる(fetch済みであること)
git diff -w  #  ファイル内のスペースの違いを無視、改行コードの違いも無視
git diff -b  #  ファイル内のスペースの数の違いを無視、改行コードの違いも無視

git diff --name-only
  # ファイル名だけを比較する
  # 削除されたファイルは表示されないようだ(git diffをすると詳細がわかる)
 git diff --name-status    # ファイル名だけでなく、変更か追加か削除かも表示
git diff コミット名1 コミット名2 -- ファイル名
  # 両方のコミットで、ファイルを比較

git diff コミット名1:ファイル名1 コミット名2:ファイル名2
  # 各コミットのファイルを比較

git show オブジェクト[:ファイル]  # SHA1で指定したオブジェクト(コミット、ツリー、ファイル)を表示する。
                                  # :ファイル で限定もできる。

log

git log -5 --oneline --decorate --graph --all [--stat] [-p]  # --graphにより図形表示される
                                                             # --author=パタン でuser.nameの選択ができる
                                                             # --decorateによりHEADの位置がわかる
                                                             # -pはソースの差分が出る。
                                                             # --statはサマリーが出る。
                                                             # -5は 5件だけ表示

git log --since="50 minutes ago" [ファイル名]    # 50分前からのログのみ表示

git log --no-merges issue54..origin/master    #ログのフィルター記法
 #origin/masterには含まれるが、issue54には含まれないコミットのログだけを表示

git log contrib --not master  # masterに無くcontribブランチにあるコミットのログを表示
git log -p -S'hogehoge' file  # コミットの中で、fileのhogehogeを含む行が追加or削除された
                              # コミットを表示する。-pオプションがあるのでそのコミット時の
                              # diffも表示する。

行が追加・削除されたコミットを調べる

git log --cc --all -S"h5py.get_config().default_file_mode = 'a'" misc.py
  --ccで各コミットのdiff(実際はパッチ)をとる(マージコミットも対象とするために -pでない方がよい)
  -Sで検索にヒットしたコミットだけ表示する

コミットのSHA1やコミットメッセージがわかるので、
git show 287658 や、
gitkの Find欄にそのメッセージを入れて、コミットを検索表示できる(gitkだと親や子のSHA1がわかる)

log -p や --cc の例

/bin/rm -rf .git a b

git init
echo foo > a; git add a; git commit -m "add a"
git branch other; git checkout other
echo bar > b; git add b; git commit -m "add b"

git checkout master
git merge --no-commit --no-ff other
echo bart > a; git add a
git commit -m "merge branch other"

echo "*** log"; git log -25  --oneline --decorate --graph --all
echo "*** log -p";   git log -p
echo "*** log --cc"; git log --cc

blame

git blame [-C] -L n,m file    # fileに対して、n~m行目の最後のコミットをリストアップする
                              # -Cがあると別の所からのコピーがあれば示してくれる
                              # 行は1から数える。
 
その他 gitに bisectというものもあり(二分探索によるデバッグ支援)。

git log -p -S も見よ。

grep

git grep --heading --line-number -3 'readGrid'
    # ファイル名を先頭に、行番号を行頭に、検索文字列の前後各3行、をマッチしたもの
    # について表示する

git grep -w 文字列  # 単語境界での検索
         -F         # 正規表現を利用しない
         -l         # マッチしたファイル名だけ表示
    # 作業領域で追跡対象のファイルを対象に検索が行われる。

$ git grep -l 文字列 | xargs sed -i '' -e 's/文字列/置換文字列/g'
                        # なお、-iが空でなければその拡張子でバックアップが作られるらしい。

git rev-list {--all|ブランチ名} | xargs git grep '文字列'
    #すべてのブランチか、指定したブランチについて、検索が行われる。
git grep 文字列 [タグ|SHA1]      # 該当プロジェクトで文字列検索

branch, fetch, pull, push

ブランチ

git branch -a          #ローカルにある◯/◯のリモートブランチと、ローカルリポジトリのブランチをすべて表示
git branch ブランチ       # ブランチを作成
git branch -vv            # ブランチを表示
git branch -m 古いブランチ名 新しいブランチ名  #ブランチ名を変更する
git branch -m 新しいブランチ名                 #現在のブランチ名を変更する
git branch -d ブランチ            # ブランチを削除(ローカルのブランチ)
リモートリポジトリのブランチを削除し、ローカルのブランチも削除する
  git push origin --delete nwp2
  または git push origin :nwp2
  または git push origin :refs/heads/nwp2
次に、git fetch する(ローカルにあるその◯/◯のリモートブランチも自動で削除される)。
(備考)
・pullやcloneされた別のリポジトリでは、その人が消さない限りそのまま残る。消されたリモートブランチを
もつその人は、pushするとリモートリポジトリのブランチは再度作られる。
・detached branch(ブランチ名の付いていないブランチのようなもの)は、git logには出てこない。リポジトリに
残っていると思うが、どのように検索できるのか?

ローカルにある◯/◯のリモートブランチを削除する(あまり使わないだろう)
  git branch -d -r originfuji/masterfuji    #-dの代わりに -Dとするとマージしていなくても削除する
 (リモートにあるそのリモートブランチが削除されていなければ、fetchすると再度、〇/〇は作成される)
git branch --merged       # 現在作業中のブランチにマージされたブランチのリストを表示
git branch --no-merged    # 現在作業中のブランチにマージされていないブランチのリストを表示
git branch ブランチ1 リモートリポジトリ/ブランチ2    # リモートリポジトリ/ブランチ2を追跡
                                                       # するブランチ1を作る
git branch --set-upstream=リモートリポジトリ/ブランチ2 ブランチ1  # リモートリポジトリのブランチ2を追跡
                                                                    # するようにブランチ1を設定する

--set-upstream の省略形は -u である。

fetch, pull, push

git fetch --all   # 登録されている全てのリモートリポジトリから最新情報を取得する
git fetch --tags  # リモートリポジトリにあるタグも取得する
git fetch [リモートリポジトリ] [ブランチ]  # リモートリポジトリから最新情報を取得する

git pull [リモートリポジトリ]    # fetchし、mergeする(pull=fetch+mergeに相当)

git push [リモートリポジトリ] [ブランチ] [--tags]
    # 競合が発生した場合は pushはできない(pullして競合解決してから pushする)。
    # --tagsはタグもプッシュする

tag

git tag                                      # すべてのタグを表示
git tag [-a] タグ [SHA1ハッシュ] [-m 注釈]   # タグを付ける(-aと-mで1行の注釈を入れれる。-aのみは注釈を入れるために
                                             # エディタが立ち上がる)
                                             # -sオプションで署名もできるらしい(詳しくは https://git-scm.com/book/ja/v2 の5章)
git tag -d タグ名     #タグ名を削除する
git show タグ名       #タグ名の情報を表示

git fetch --tags   #リモートリポジトリのタグを取得する
git push --tags                      #リモートリポジトリに無いタグを、全て送る(タグだけ送る)
git push --delete リポジトリ タグ名  #リポジトリ(originなど)のタグ名を削除

checkout

git checkout {SHA1|タグ|masterなど}    # 指定のものをチェックアウトする。
                       # ブランチ名(masterなど)ではなく、SHA1(ハッシュ値)を指定した時、detached HEADになるが、
                       # 普通どおり修正してコミットできる(ブランチ名を新たにつける方が取り扱いやすい)。
                       # 追跡対象外のファイルなどは、そのまま残される。
git checkout --track リモートリポジトリ/ブランチ    # git checkout -b ブランチ リモートリポジトリ/ブランチ と同じ。
                       # 作成されたブランチはリモートブランチ(追跡ブランチ、上流ブランチ)を追跡するように設定される。
git checkout -b ブランチ {タグ|リモートリポジトリ/ブランチ}    # -bで指定するブランチを作成後、移動する。
                       # タグがあれば、その所にブランチを作る(ただしコミットするとブランチは進む。タグは動かない)。

その他のコマンド等

gitk    # GUIツール
git help コマンド名
git diff差分はそのままでパッチファイルになっている。
また、パッチファイルを使って、リダイレクションでパッチをあてることが出来る。
patch [--dry-run] -p1 < パッチファイル    #パッチファイルをあてる場合
                                          #--dry-runは何が行われるかを表示するだけ。
$ git push
(gnome-ssh-askpass:hogehoge): Gtk-WARNING **: cannot open display:
error: unable to read askpass response from '/usr/libexec/openssh/gnome-ssh-askpass'
Username for 'https://github.com':
などと、表示される場合の対応。

- 無視して、つづけて問題無い。
 (GUI環境で無いために、パスワードキャッシュがうまく動かなかったらしい)

- unset SSH_ASKPASS
  をすると表示されなくなる。

新しいブランチを作り、追いかける手順(よく使う例)

作業領域やステージはcommit,push済であるとする。
$ git branch nwp      # 現在の状態で、ブランチnwpを作成
$ git checkout nwp    # ブランチnwpに移動(作業ディレクトリのファイルは同じものである)
なお、ここでaddやcommitをしても良い。
$ git push --set-upstream origin nwp  # リモートリポジトリoriginのブランチnwp(作成される)にpushする。
                                      # ブランチnwpは、origin/nwpを追跡するように設定される(オプション
                                      # --set-upstreamによる)。
$ git remote -v ; git branch -vv  # 確認
作業領域やステージはcommit,push済であるとする。
$ git fetch
$ git checkout --track origin/nwp
$ git remote -v ; git branch -vv  # 確認
「originfuji/masterをorigin/masterにマージする仕方」
masterブランチに限らなく、masterの代わりに適当なブランチ名でも利用可能。
必要に応じて、最初だけすること
  git remote add originfuji fujiのベアリポジトリURL
  git fetch originfuji
  git checkout -b masterfuji originfuji/master  #originfuji/masterを追うブランチmasterfujiの作成

git checkout master  #origin/masterをチェックアウト
git merge masterfuji #masterfuji(これはoriginfuji/master)をmasterにマージする。
                     #masterfujiブランチを作っていなくても、
                     # git merge originfuji/master でも可能。
                     #Fast-forwardの場合はコミットされずに更新されるので、
                     #必要に応じて --no-commit --no-ff をつける。
git push             #origin/masterにプッシュ
「その他参考」
リモートリポジトリに無いブランチをpushする例
  master     8ed9219 [origin/master] Merge branch 'master' into HEAD
  masterfuji 8ed9219 [originfuji/master: ahead 3] Merge branch 'master' into HEAD
があり、今使っているブランチが masterfujiであり、pushしたいとして、git pushしたとする。
ブランチが、リモートリポジトリに無い(masterfuji?)ときに
  git push
すると、サゼッションが出る。それに従うとよい。すなわち、
  リモートリポジトリの masterとして pushする場合:
    git push originfuji HEAD:master    # HEAD:は無くてもよいらしい
  リモートリポジトリに今使っているブランチ名で新しく追加する場合:
    git push [--tags] originfuji masterfuji  #このやり方は、現在のブランチをoriginfuji/masterfujiという
                                    #ブランチ(新たに作成or更新するようだ)にpushするときにも有効である。
とする。

リポジトリの作成・移動

ベアリポジトリ

・作成方法1

cd ディレクトリ.git  # 拡張子を慣習的につける
git init --bare

ローカルリポジトリ

・作成方法1(新規作成)

cd 作業ディレクトリ
git init
・作成方法2(リモートリポジトリのクローン)

git clone リモートリポジトリ [作業ディレクトリ]
  # リモートリポジトリは [ssh://[user@]host.xz[:port]]/path_to_repo.git などのurlで指定する。
  # 自動的に、origin という登録名でurlが登録され、リモートブランチ(origin/master)を追跡するブランチ master が作られる。
  # 作業ディレクトリを省略すると、リモートリポジトリのディレクトリ名(ディレクトリ名.gitの.gitの前の部分)となる。
  # 作業ディレクトリを指定する場合は空ディレクトリでなくてはならない。

リモートリポジトリの移動に伴う設定の変更

リモートリポジトリの移動自体は単にまるごとディレクトリを移動するだけである。
これに追従しているリポジトリは
    git remote set-url origin 新しいリモートリポジトリ
をして、登録名の内容を上書き更新する(originを消してから作り直してもよい)。

空のリモートリポジトリ(ベアリポジトリ)にpushする(新規のベアリポジトリにファイルを追加する)例

git add ファイル
git remote add origin リモートリポジトリ  # リモートリポジトリを登録名originとして、登録する
git remote -v ; git branch -vv
git commit -m "注釈"
git push --set-upstream origin master     # --set-upstreamは現在のプランチの追跡先を、origin/masterとする設定も登録する

リモートリポジトリの登録、変更、削除

git remote add リモートリポジトリの登録名 リモートリポジトリのurl
git remote rename リモートリポジトリの変更前の登録名 リモートリポジトリの変更後の登録名
git remote rm 削除するリモートリポジトリの登録名
git remote set-url origin 変更後のリポジトリのURL

git remote [-v]  # 一覧表示
originリモートリポジトリを変更することができる(例)
$ git remote rm origin   #登録されているリモートリポジトリを削除
$ git remote add origin ssh://hogehoge/nl.git  #別のリモートリポジトリを登録

#このままの状態ではローカルのmastgerはどこも追跡していない(いったん削除したため)。
$ git fetch                                   #最初にまず origin/masterを取り込む
$ git branch --set-upstream-to=origin/master  #カレントブランチがorigin/masterを追従するための設定
or
$ git push --set-upstream origin master  #ローカルmasterがorigin/masterを追跡する設定

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS