概要
割と便利だったので勢いで書いた。
開発用に用意しているサーバー(以下remote)でcloneしてあるリポジトリに対して、「masterとかfeature branchを更新したいなー」と思って、おもむろにpushしようとすると怒られる場合があるんですよね。
git status
#=> On branch master
#=> Your branch is up-to-date with 'origin/master'.
#=> nothing to commit, working directory clean
git push remote master
#=> (中略)
#=> To takoba@123.45.67.89:/hoge/fuga
#=> ! [remote rejected] master -> master (branch is currently checked out)
#=> error: failed to push some refs to 'takoba@123.45.67.89:/hoge/fuga'
それが、最近リリースされたGit v2.3.0だと、receive.denyCurrentBranch = updateInstead
を設定しておけば怒られずに済むし、安全にPush to deployができるようになってて便利だよ、というエントリ。
通常の挙動
defaultでは、“(__non-bare__なリポジトリが)pushしたいbranchをremoteでcheckoutしている”状態だと、pushできないようになってます。
これはv2.3.0でも同様です。
git push remote master
#=> (中略)
#=> remote: error: refusing to update checked out branch: refs/heads/master
#=> remote: error: By default, updating the current branch in a non-bare repository
#=> remote: error: is denied, because it will make the index and work tree inconsistent
#=> remote: error: with what you pushed, and will require 'git reset --hard' to match
#=> remote: error: the work tree to HEAD.
#=> remote: error:
#=> remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
#=> remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
#=> remote: error: its current branch; however, this is not recommended unless you
#=> remote: error: arranged to update its work tree to match what you pushed in some
#=> remote: error: other way.
#=> remote: error:
#=> remote: error: To squelch this message and still keep the default behaviour, set
#=> remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
#=> To takoba@123.45.67.89:/hoge/fuga
#=> ! [remote rejected] master -> master (branch is currently checked out)
#=> error: failed to push some refs to 'takoba@123.45.67.89:/hoge/fuga'
こんなかんじに拒否られます。
なので、ぼくは以下のような流れで“擬似的なmaster(tmp)にmasterをmerge”していました。
git checkout -b tmp
#=> Switched to a new branch 'tmp'
git status
#=> On branch tmp
#=> nothing to commit, working directory clean
git push remote master
#=> (略)
git merge master
#=> Updating 1234567..abcdefg
#=> Fast-forward
#=> a.php | 16 ++++++++--------
#=> b.html | 20 ++++++++++++++++++++
#=> c.js | 28 +++++++++++++++++++++++++---
#=> d.css | 10 ----------
#=> e.css | 6 ++++++
#=> README.md | 1 +
#=> 5 files changed, 60 insertions(+), 21 deletions(-)
#=> create mode 100644 e.css
#=> delete mode 100644 d.css
“bareなリポジトリ”とは?
ちなみに、git clone
には--bare
というオプションがあります。
bareなリポジトリ(bare repository)とは、簡単に言えば“GitHubのようにソースコードをホスティングするサーバーで用意するリポジトリ”です。
git clone --bare https://github.com/takoba/fuga.git
というかんじでcloneしたリポジトリは、通常のリポジトリとディレクトリ構成が異なります。
通常ソースコードが配置されている“作業ディレクトリ”を持たず、commitデータやbranchのデータなどGitリポジトリとしての情報のみを主に保持しているリポジトリとなります。
git clone --bare https://github.com/takoba/fuga.git
#=> Cloning into bare repository 'fuga'...
#=> (中略)
#=> Checking connectivity... done.
# `.git/`がrepositoryのrootにそのまま展開されてるかんじ?
ls -al ./fuga
#=> total 32
#=> drwxr-xr-x 10 takoba takoba 340 2 16 11:41 .
#=> drwxr-xr-x+ 56 takoba takoba 1904 2 16 11:41 ..
#=> -rw-r--r-- 1 takoba takoba 23 2 16 11:41 HEAD
#=> -rw-r--r-- 1 takoba takoba 175 2 16 11:41 config
#=> -rw-r--r-- 1 takoba takoba 73 2 16 11:41 description
#=> drwxr-xr-x 11 takoba takoba 374 2 16 11:41 hooks
#=> drwxr-xr-x 3 takoba takoba 102 2 16 11:41 info
#=> drwxr-xr-x 4 takoba takoba 136 2 16 11:41 objects
#=> -rw-r--r-- 1 takoba takoba 291 2 16 11:41 packed-refs
#=> drwxr-xr-x 4 takoba takoba 136 2 16 11:41 refs
v2.3.0でPush to deployするには
git config
で、receive.denyCurrentBranch
をupdateInstead
に設定しておきます。
git config --get receive.denyCurrentBranch
#=> (empty)
git config receive.denyCurrentBranch updateInstead
git config --get receive.denyCurrentBranch
#=> updateInstead
git status
#=> On branch master
#=> Your branch is up-to-date with 'origin/master'.
#=> nothing to commit, working directory clean
git push remote master
#=> (中略)
#=> To takoba@123.45.67.89:/hoge/fuga
#=> 25da1ec..c967392 master -> master
無事pushできました。
receive.denyCurrentBranch = ignore
はこわい
v2.3.0以前でもreceive.denyCurrentBranch
にignore
を設定しておくとpushできたりしました。
ですが、割とリポジトリがぶっ壊れるようになるので微妙。
なので、なるべく利用しない方がよいです。
複数のclientから操作するケースでは__commitが闇に葬られる可能性がある__ので、使わないように...