Memo/git

https://dexlab.net:443/pukiwiki/index.php?Memo/git
 


git


バックアップ/リストア


log: ログの表示

  • 日付フォマットの変更k
    • git version:1.8.3.1
    • 日本人的には isoが理解しやすい
    • --date=(relative|local|default|iso|rfc|short|raw)
      # --date=relative
      Date:   9 days ago
      
      # --date=local
      Date:   Wed Sep 12 17:05:44 2018
      
      # --date=default
      Date:   Wed Sep 12 17:05:44 2018 +0900
      
      # --date=iso
      Date:   2018-09-12 17:05:44 +0900
      
      # --date=rfc
      Date:   Wed, 12 Sep 2018 17:05:44 +0900
      
      # --date=short
      Date:   2018-09-12
      
      # --date=raw
      Date:   1536739544 +0900

add:

  • カレントディレクトリで追加してないファイルを一括で追加
    git add .

rebase:

作業ブランチで開発中に、先に進んだmasterからの差分に変えたい時。

git co working_branch

# origin masterが先に進んだ場合、そこまでbaseを進める
git pull --rebase origin master

# コンフリクトした場合、ファイルを修正してadd
git add path/to/file
git rebase --continue

git push origin working_branch

subversionからの移行


削除し忘れたlocal branchの処理

local branchが必要なのか分からなくなった場合。

  • 削除されたremote branchを、localからも消す
    # 確認
    git remote prune origin --dry-run
    
    # 削除
    git remote prune origin
    
    # fetchした時に消して欲しい場合
    git fetch --prune --dry-run
    git fetch --prune
  • merge済みbranchを消す
    # 確認
    git branch --merged
    
    # 削除
    git branch -d <branch name>
    # mergeしてないとエラーが出る。強制削除は -D
    # まとめて消す(y/n確認)
    # 確認不用であれば -p を削除
    git branch --merged | grep -vP '^\*|(master|develop)$' | xargs -p -I % git branch -d %

ファイル/ディレクトリの変更差分を全て表示

git log -p <file or directory>

show: 指定コミット内容表示

  • commit hashを省略すると、直前のコミット内容表示する
    git show <commit hash. HEAD, HEAD^2 >

SSL connect error

  • CentOS 6上
    git clone https://github.com/puppetlabs/puppetlabs-ntp.git
    ...
    Cloning into 'ntp'...
    fatal: unable to access 'https://github.com/puppetlabs/puppetlabs-ntp.git/': SSL connect error
    
    # debug
    export GIT_CURL_VERBOSE=1
    git clone https://github.com/puppetlabs/puppetlabs-ntp.git
    ...
    
    * NSS error -12286
  • 解決方法: nssを更新
    sudo yum update nss
    
    # 問題が出ないバージョン
    rpm -q nss
    nss-3.28.4-4.el6_9.x86_64

reflog: やりすぎたresetや削除したbranchを戻す

reset --hardをやりすぎた時に戻す。 削除したbranchを戻す。 ただし、コミットしてないファイルは戻ってこない。

  • resetを戻す
    # 直近4つまでの作業ログを見る
    git reflog -n 4
    
    # 戻したい所まで戻す
    git reset --hard <HEAD@{N} or commit id>
  • 削除したbranchを戻す
    # 直近4つまでの作業ログを見る
    git reflog -n 4
    
    # <HEAD@{N}>を元に <branch name> を作る
    git branch <branch name> <HEAD@{N} or commit id>

書籍

  • Git - Book 無償。web, pdf, epub, mobi形式で読める

.gitignore 特定パターンを無視

.gitignore に入れたパターンは「git status」等で差分として表示されなくなる 親フォルダにまとめて記載しておけば、子フォルダにも適用される。

# vimの作業ファイル
*.swp

# subversionのディレクトリ
.svn/

# macOSの不要ファイル
.DS_Store

# windowsの不要ファイル
Thumbs.db

# ansibleのリトライファイル
*.retry

間違ったmergeを取り消す

  • Git-flowって何? - Qiita
    • 通常:developブランチからreleaseブランチを作る。「git co -b release/1.10」
    • 誤り:developブランチをreleaseブランチへマージする。「git merge release/1.10」
    • 誤り:developブランチをdevelopブランチへマージする。「git merge develop」
  • git log --graphで見た時、以下のようなツリーになってしまう
    *   a1234567 - user01 -  Merge branch 'develop' into release/1.10 (x hours ago)
    |\  
    | *   b1234567 - user02 -  Merge branch 'release/1.10' into develop (x days ago)
    | |\  
    | * \   c1234567 - user03 -  Merge branch 'release/1.10' into develop (x days ago)
    | |\ \  
    | * \ \   d1234567 - user04 -  Merge tag 'v1.10.0' into develop (x days ago)
    | |\ \ \  
    | * \ \ \   e1234567 - user04 -  Merge branch 'release/1.10' into develop (x days ago)
    | |\ \ \ \  
    | * \ \ \ \   f1234567 - user03 -  Merge branch 'release/1.10' into develop (x days ago)
    ...
  • 修正: release/1.10へのマージ「a1234567」 が間違っているので、「a1234567」 を取り消す
# git log --graph で誤り前のコミットidを探す。この例では「aa123456」とする
git reset aa123456 --hard

# treeを見て間違ったマージより先に取り込みたいコミットがあれば、cherry-pickやmergeで取り込む
git cherry-pick <commid it>
git merge <commid it>

# force pushで強制的に修正
git push -f origin release/1.10
  • localリポジトリも更新する必要がある
    git fetch
    git co origin/release/1.10
    git pull -p

git logから削除されたファイルを探す

git log --diff-filter=D --summary <path>

--force-with-lease

「--force」より安全らしい

  • git push --force
    • ローカルリポジトリでリモートリポジトリを上書きする
  • git push --force-with-lease
    • 他人がpushしていたら、失敗する。
    • 自分の修正後に、他人がpushしていたら「--force」を使うしかない

authorを後から変更

git commit --amend --author="user <user@example.com>"

パーミッション変更を無視する

Linuxで開発しているリポジトリをWindowsでcloneして編集しようとすると、パーミッションの違いが検出されて邪魔な時がある。

git config core.filemode false

# 確認
git config -l | grep core.filemode

空白を無視して比較

  • diff
    diff -uw file-a file b
  • git (-b でインデントを無視)
    git diff -w
  • GitHub?: URLの末尾に「?w=1」を付ける
  • BitBucket?: URLの末尾に「?w=1」を付ける
    • または「・・・」をクリックして「ignore whitespace」にチェック

git-secrets: AWSキー等をgithubに流出するのを防ぐ

うっかりAWSキー等がgithubに流出している事故が多い。
(実際に流出するとAWSからメールが来て、AWSアカウントが制限状態になる。該当キーを削除するまで続く)

  • https://github.com/awslabs/git-secrets
    • AWSキー等を誤ってコミットする事を防いでくれるフックが追加される
    • スペースを含むファイルのcommitに失敗する場合、「git pull;make install」で直った
  • CentOS6.xの場合
    # インストール
    git clone https://github.com/awslabs/git-secrets.git
    cd git-secrets/
    sudo make install
    
    # 全体設定に追加
    git secrets --register-aws --global
    git secrets --install ~/.git-templates/git-secrets
    git config --global init.templatedir '~/.git-templates/git-secrets'
    
    # 既存プロジェクトに追加
    git secrets --install /path/to/repository
    
    # 既存ディレクトリをチェック
    git secrets --scan -r /path/to/repository
  • フックを削除したい場合
    # 確認
    find /path/to/repository/.git/hooks/ -type f ! -name "*.sample"
    
    # 削除
    find /path/to/repository/.git/hooks/ -type f ! -name "*.sample" -delete

merge: マージ

  • マージする履歴を残す (--no-ff)
    git merge --no-ff topic

リモートブランチとローカルブランチを強制的に一致させる

  • 例:masterブランチを一致させる。ローカルの変更点はすべて破棄されるので注意
    git fetch origin
    git reset --hard origin/master

git-flow

CentOS6.xにgit v2.xをインストール

  • iusリポジトリにある
    # 古いgitは削除
    sudo yum erase git
    # EPELリポジトリも必要
    sudo yum install http://dl.iuscommunity.org/pub/ius/stable/CentOS/6/x86_64/epel-release-6-5.noarch.rpm
    sudo yum install http://dl.iuscommunity.org/pub/ius/stable/CentOS/6/x86_64/ius-release-1.0-14.ius.centos6.noarch.rpm
    sudo yum install git2u
    
    # バージョン確認
    git --version
    git version 2.4.3

CentOS6.xにgit v1.7.2をインストール

  • CentOS6.x baseリポジトリだとgit v1.7.1がインストールされる
  1. rpmforge リポジトリを使えるようにする
  2. インストール
    sudo yum install --enablerepo=rpmforge-extras git
    
    git --version
    git version 1.7.12.4

gitの設定を表示

  • gitコマンドで取得
    git config -l --global
  • catでも同じ
    cat ~/.gitconfig

git bisect: 二分探索によって問題箇所を特定する


subtree: 外部リポジトリを取り込む

  • subtree
    • リモートブランチとして、repoを追加する
    • 複数のrepoを跨いで、更新する用途向き
    • 参照元repoでgit pullするだけで、参照先repoもfetchされる
  • submodule
    • 特定のcommit idを参照する。
    • .gitmodules で管理される
    • 完全にリポジトリを分けて管理したい用途
    • 参照元repoでgit pullでは、参照先repoはfetchされない(commit idが変わらない)。

submodule: 外部リポジトリを取り込む

  • submoduleの追加
    git clone https://github.com/example/example.git
    cd example/
    git submodule add https://github.com/example2/example2.git path/to/example2-test
  • submoduleを使用しているリポジトリの更新
    git clone https://github.com/example/example.git
    cd example/
    # 初回はinitしないとsubmoduleディレクトリが空のまま
    git submodule init
    git submodule update
    # または
    git clone --recursive https://github.com/example/example.git
  • submoduleの削除: git v1.8.5以降
    git submodule deinit path/to/submodule
    git rm path/to/submodule

Mac OS Xにgitクライアントのインストール

  • brewの場合
    brew install git
    echo 'export PATH=/usr/local/Cellar/git/2.7.0/bin:$PATH' >> ~/.bash_profile
    source ~/.bash_profile
  • MacPorts?を使う場合。後でブランチ名の表示等で +bash_completion が必須となるのでこちらの方がよさそう
    sudo port install git +svn +doc +bash_completion +gitweb
  1. git−1.7.2.2-intel.leopard.pkg を実行
  2. ターミナルからパスを通すスクリプトを実行
    ./setup\ git\ PATH\ for\ non-terminal\ programs.sh
  3. ターミナルの再起動。gitコマンドで使えるか確認

空ディレクトリをgitに入れる

そのままだと管理されないので".gitkeep"ファイルを入れる

mkdir dummy
touch dummy/.gitkeep
git add dummy

ワークフロー


リモートで削除されたブランチをローカルから削除

git fetch --prune origin

tag: 別名を付ける

  • コミットに別名を付ける release/1.00 等
  • tagを指定してチェックアウトが可能
  • tag自体はバージョン管理されない
  • 使い方
    # タグをリモートと同期
    git fetch --tags
    
    # タグの作成
    git tag release/1.00
    git tag release/1.01
    
    # タグ一覧 (-n でアノテーションタグも表示)
    git tag -n
    release/1.00
    release/1.01
    
    # ローカルタグ削除
    git tag -d release/1.01
    
    # リモートにpush。このままpushしてもリモートのタグは消えない
    git push origin release/1.01
    # または、以下(意図しないタグまでpushされる可能性がある)
    git push --tags
    
    # リモートのタグ削除
    git push --delete origin release/1.01
  • 注釈(アノテーション annotation)付タグ。タグ名以外に任意の注釈を付けられる
    git tag -a release/1.02 hogehoge
    
    git tag -n
    release/1.02    hogehoge
  • タグのリネーム。タグは同じcommit hashに複数付けられる
    git tag
    release/1.00
    release/1.01
    release/1.02
    
    # リネームしたいcommit hashを確認
    git rev-parse release/1.01
    e2f61a85745f777a720227594fa3442dfbd15647
    
    # git tag new-tag old-tag
    git tag release/1.01.new release/1.01
    
    # 新しいタグのcommit hashが同じか確認
    git rev-parse release/1.01.new
    e2f61a85745f777a720227594fa3442dfbd15647
    
    # delete local old tag
    git tag -d release/1.01
    
    git tag
    release/1.00
    release/1.01.new
    release/1.02
    
    git push origin --tags
    
    # delete remote old tag
    git push --delete origin release/1.01

cherry-pick: 特定のコミットだけを適用する

  • 例:別branchのコミット:99daed2 だけをmasterに適用する
    git checkout master
    git cherry-pick 99daed2

cherry-pick中止

  • エラーが発生
    error: a cherry-pick or revert is already in progress
  • 中止
    git cherry-pick --abort

範囲を指定してcherry-pick

  • git v1.7.2以上
    git cherry-pick master..next

リモートリポジトリのURLを変更したい場合

git remote -v
git remote set-url origin <新しいリポジトリのURL>

bash用コマンド補完とプロンプトにブランチを表示

  • git [tabキー] または git log [tabキー]等でコマンドが補完できるようになる
  • 現在のブランチをプロンプトに表示 [host@user:path (branch)]
  • 以下を ~/.bashrc や ~/.bash.d/に追加
  • 90-bash_completion.sh
    if [[ -f /etc/bash_completion ]]; then
        # RHEL/CentOS 6, Ubuntu 12.04 LTS
        . /etc/bash_completion
    elif [[ -f /etc/profile.d/bash_completion.sh ]]; then
        # RHEL/CentOS 7
        [ -n "$BASH_COMPLETION" ] || BASH_COMPLETION=/etc/bash_completion
        [ -n "$BASH_COMPLETION_DIR" ] || BASH_COMPLETION_DIR=/etc/bash_completion.d
        [ -n "$BASH_COMPLETION_COMPAT_DIR" ] || BASH_COMPLETION_COMPAT_DIR=/etc/bash_completion.d
    elif [[ -f /usr/local/etc/bash_completion ]]; then
        # macOS: brew
        . /usr/local/etc/bash_completion
        [ -n "$BASH_COMPLETION" ] || BASH_COMPLETION=/usr/local/etc/bash_completion
        [ -n "$BASH_COMPLETION_DIR" ] || BASH_COMPLETION_DIR=/usr/local/etc/bash_completion.d
        [ -n "$BASH_COMPLETION_COMPAT_DIR" ] || BASH_COMPLETION_COMPAT_DIR=/usr/local/etc/bash_completion.d
    fi
  • 91-bash_completion_git.sh
    RS="\[\033[0m\]"
    HC="\[\033[1m\]"
    UL="\[\033[4m\]"
    INV="\[\033[7m\]"
    FBLK="\[\033[30m\]"
    FRED="\[\033[31m\]"
    FGRN="\[\033[32m\]"
    FYEL="\[\033[33m\]"
    FBLE="\[\033[34m\]"
    FMAG="\[\033[35m\]"
    FCYN="\[\033[36m\]"
    FWHT="\[\033[37m\]"
    BBLK="\[\033[40m\]"
    BRED="\[\033[41m\]"
    BWHT="\[\033[47m\]"
    
    GIT_PS1_SHOWDIRTYSTATE=1
    GIT_PS1_SHOWUPSTREAM=1
    GIT_PS1_SHOWUNTRACKEDFILES=
    GIT_PS1_SHOWSTASHSTATE=1
    
    if [[ ! -f ~/.git-prompt.sh ]]; then
        wget -q https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh -O ~/.git-prompt.sh
    fi
    
    if [[ -f ~/.git-prompt.sh ]]; then
        . ~/.git-prompt.sh
        # CentOS default
        # export PS1='[\u@\h \W]\$ '
        export PS1="[$FMAG\u$FWHT@$FCYN\h$FWHT: \W\$(__git_ps1)]\$ "
    fi

GUIクライアント

  • Github for Windows
    • msysGit ベース
    • Git Shellもインストールされる
    • シェルを複数から選べる。tools > option > default shell: Cmd, Git Bash, PowerShell?, Custom
    • 英語UIのみ

改行コードの自動変換を止める

git for windowsではデフォルトで、改行コードの自動変換される。

  • チェックアウト時:LFをCRLFへ変換
  • コミット時:CRLFをLFへ変換
vi ~/.gitconfig
----
[core]
    autoCRLF = false
----

reset:取り消し

  • 現在のコミットを取り消し、一つ前のコミットまで戻す
    # ワーキングディレクトリはそのままで、コミットだけ取り消す
    git reset --soft HEAD^
    
    # コミットを取り消し、ワーキングディレクトリも戻す
    git reset --hard HEAD^

diff:差分

  • 空白の違いを無視(-w)
    git diff -w
  • カラー表示
    git config --global color.ui auto
  • 直前の差分を表示
    git diff HEAD^ .
  • 単語単位で差分表示
    git diff --word-diff
  • 異なるブランチの同じファイルを比較
    git diff master branch1 path/foo.txt
  • 異なるブランチの異なるファイルを比較
    git diff master:path/foo.txt branch1:path/bar.txt

branch:ブランチ

  • ブランチ名の変更
    git branch -m <old branch> <new branch>
    # または、現在のブランチ名を変更
    git branch -m <new branch>
  • ローカルとリモートのブランチ一覧
    git branch -a
  • 作業用のローカルブランチを作成
    git checkout -b hoge-prototype
    
    git branch
    * hoge-prototype
      master
    
    # リモートに同名ブランチとしてpush
    git push origin hoge-prototype
  • 現在のローカルブランチをリモートへpush
    git push -u origin HEAD
  • ブランチを削除
    # カレントをmasterに変更
    git checkout master
    
    # ローカルブランチを削除
    # 強制削除: -D
    git branch -d hoge-prototype
    
    # 同名のリモートブランチを削除
    git push --delete origin hoge-prototype
    
    # または':'
    git push origin :hoge-prototype

patchコマンド用diffファイルの作成

git diff --no-prefix HEAD~ > hoge.patch
patch --dry-run -p0 < hoge.patch
patch -p0 < hoge.patch

stash:変更を一時的に待避

  • 誰かが変更中のファイルがあるが、最新に更新したい
    git pull
    error: Your local changes to the following files would be overwritten by merge:
            example/hoge.txt
    
    # 変更を待避(git stash saveと同じ)
    git stash
    
    # 最新に更新
    git pull
    
    # 保存したワークツリーを戻す
    git stash pop
    
    git push

brame:誰が行を変更したのかを探す

  • file.txtの5行目を誰が変更したかを見る
    git blame -L 5 file.txt
    d23bebd3 (username 2013-01-02 10:54:57 +0900  5) 05 change
    
    # 5-6行目を誰が変更したかを見る。オフセット指定もできる。-L 5,+1
    git blame -L 5,6 file.txt
    d23bebd3 (username 2013-01-02 10:54:57 +0900 5) 05 change
    469dbe58 (username 2013-01-02 11:04:25 +0900 6) 06 change

.gitconfig

  • 日付: --date=iso が理解しやすい
  • /.gitconfig

    [core]
            editor = vim
    [color]
    	ui = auto
    [alias]
    	ad = add
    	br = branch
    	ci = commit
    	cia = commit --amend
    	cih = commit --amend -C HEAD
    	cih1 = commit --amend -c HEAD@{1}
    	co = checkout
    	d = diff
    	dc = diff --cached
    	dn = diff --name-only
    	dw = diff --color-words
    	ft = fetch
    	l = log --oneline -n 20
    	lg = log --graph --pretty=format:'%Cred%h%Creset - %an - %C(yellow)%d%Creset %s %Cgreen(%cd)%Creset' --abbrev-commit --date=iso
    	lgraph = log --oneline --graph --decorate --all -n 20
    	lp = log --oneline -n 20 -p
    	ls = log --stat -n 1 --date=iso
    	pl = pull
    	ps = push
    	rb = rebase
    	rbh = rebase HEAD
    	rbo = rebase --onto
    	rl = reflog show -n 20
    	rs = reset
    	rsh = reset --hard
    	sb = show-branch
    	sh = show
    	share = daemon --verbose --base-path=/home/sinsoku/repos/ --enable=receive-pack
    	so = remote show origin
    	st = status -s

fatal: The remote end hung up unexpectedly

公開鍵(~/.ssh/id_rsa.pub)/秘密鍵(~/.ssh/id_rsa)が無いと起きる

  • 作成
    ssh-keygen -t rsa

svn exportと同様に使う

  • /tmp/foo を作らないと /tmp/直下にファイルが散乱する
    mkdir /tmp/foo
    git archive master | tar -x -C /tmp/foo

origin等の別名をつける

よくoriginやmasterといった名前が出てくるが、これは".git/config" に記載があるため。
直接編集しても結果は同じ

  • .git/configに記載がある
    cat .git/config
    
    [core]
            repositoryformatversion = 0
            filemode = true
            bare = false
            logallrefupdates = true
    [remote "origin"]
            fetch = +refs/heads/*:refs/remotes/origin/*
            url = git://github.com/heroku/ruby-sample.git
  • "origin"という別名を付ける
    git remote add origin git://github.com/heroku/ruby-sample.git

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-09-21 (金) 15:47:20 (4d)