如果在存储库中安装此钩子并将分支foo-automerge推到此存储库,则此钩子将合并到工作副本中,如果:
foo。我需要它的原因是在我对此的疑问上概述的,所以我只想请你在这里信任我。
我主要是寻求来自git人员的建议,如果和如何这将爆炸和搞乱我的存储库。然而,对python的任何批评也是受欢迎的。
这将用于简单的情况,其中有两个存储库A和B,一个在我的笔记本电脑上,一个在网格上。我将配置网格存储库,以便在每次推送时签出。这两个存储库都是我的,存储库中的程序不需要任何安装后步骤。
我知道这里有很多问题,但我真的不知道如何解决:
GIT_DIR是other_repo/.git/modules/something),那么这将需要我手动设置FORCE_WORKING_DIR。我不知道找到子模块的工作副本在哪里有多容易。我加入了github专家,但这里也有:
#!/usr/bin/env python
"""
Description
-----------
Update hook that automatically merges changes inside the repository.
It's creation was sparked by
`my question on SO <https://stackoverflow.com/q/25207942/7918>`_.
Especially by `this answer <https://stackoverflow.com/a/25209198/7918>`_.
Logic is as follows:
--------------------
If repository recleives a push we will merge pushed branch to curren branch if
following conditions are met:
* This repo is not bare. It is bare **push will fail**
* pushed branch has a special suffix (by default ``-automerge``). If
pushed branch has no suffix push will not be aborted.
* Currently checked out branch is named as branch we push to without suffix.
so if push was to ``foo-automerge``, we will merge iff checked out branch
is ``foo``. If other branch is checked out push will not be aborted.
* Working directory is clean. If working directory is dirty (and previous
condition are met) **push will fail**.
* We can guess working copy directory. If not can't **push will fail**.
* Merge is fast-forward if not **push will fail**.
Installation:
-------------
Copy this file to .git/hooks, and link it to **both**, ``update``
and ``pre-update``. You need to add it to both hooks because ``pre-update`` is
needed to fail push when error conditions are met, and ``update`` is needed
to actually do merge.
Add executable permissions to both hooks.
"""
from __future__ import unicode_literals, print_function
import os, sys, subprocess, logging
logging.basicConfig(level=logging.INFO)
"""
Set do ``DEBUG`` for debug info, or to ``ERROR`` to get error conditions only.
"""
AUTOMERGE_SUFFIX = "-automerge"
FORCE_WORKING_DIR = None
"""
You may override working copy by setting this to a path
"""
CAN_GUESS_GIT_WORK_TREE = True
"""
If false we will not quess working tree directory, so either set ``GIT_WORK_TREE``
envvar or ``FORCE_WORKING_DIR`` python variable.
"""
def get_working_copy_dir():
"""
Tries to guess and returns working copy directory.
"""
if FORCE_WORKING_DIR:
return FORCE_WORKING_DIR
working_copy = os.environ.get("GIT_WORK_TREE", None)
if working_copy is not None:
return working_copy
if not CAN_GUESS_GIT_WORK_TREE:
logging.error("Can't quess working copy dir and 'GIT_WORK_TREE' was "
"not set")
sys.exit(1)
path = os.path.abspath(os.environ['GIT_DIR'])
working_copy, git_dir = os.path.split(path)
git_dir = git_dir.strip()
if git_dir != ".git":
logging.error("Can't guess working copy dir, because GIT_DIR does not "
"point to directory named '.git'")
sys.exit(1)
return working_copy
def strip_branch(branch):
"""
Removes git decorations from branch name.
>>> strip_branch("refs/heads/feature/master-automerge")
'feature/master-automerge'
>>> strip_branch("refs/heads/master-automerge")
'master-automerge'
>>> strip_branch('refs/heads/master-automerge ')
'master-automerge'
"""
return "/".join(branch.split("/")[2:]).strip()
def checked_out_branch_is_valid(pushed_branch):
"""
Check whether checked out branch mathes branch we are pushing to.
"""
pushed_branch_sans_automerge = pushed_branch[:-len(AUTOMERGE_SUFFIX)]
checked_out_branch = get_checked_out_branch()
if checked_out_branch != pushed_branch_sans_automerge:
logging.info("Other branch is checked out, will not merge working copy")
sys.exit(0)
def is_this_repo_bare():
"""
:return: True if this repository is bare, False otherwise.
"""
result = subprocess.check_output("git rev-parse --is-bare-repository".split()).strip()
if result == "true":
return True
if result == "false":
return False
raise ValueError("Can't guess whether this repository is bare")
def git_subprocess(args):
"""
Utility function to call git process in the working copy directory.
:param list args: list of string containing command to call
"""
new_cwd = get_working_copy_dir()
logging.debug("Working copy dir %s", new_cwd)
new_env = dict(os.environ)
new_env["GIT_DIR"] = os.path.abspath(os.environ['GIT_DIR'])
return subprocess.check_output(args, cwd=new_cwd, env=new_env)
def get_checked_out_branch():
"""
:return: String with currently checked out branch
"""
return git_subprocess("git rev-parse --symbolic-full-name --abbrev-ref HEAD".split()).strip()
def check_working_directory_clean():
"""
This is adapted from here: https://stackoverflow.com/a/3879077/7918
Will exit id working copy is dirty.
"""
try:
# Update the index
git_subprocess("git update-index -q --ignore-submodules --refresh".split())
# Disallow unstaged changes in the working tree
git_subprocess("git diff-files --quiet --ignore-submodules --".split())
# Disallow uncommitted changes in the index
git_subprocess("git diff-index --cached --quiet HEAD --ignore-submodules --".split())
except subprocess.CalledProcessError:
logging.error("Working directory here is not clean. Will not merge")
sys.exit(1)
def validate(pushed_branch):
"""
If we can't merge ``pushed_branch`` to current branch this function will
print error and call ``sys.exit`` with apropriate exit code.
"""
if is_this_repo_bare():
logging.error("Sorry this hook will not work on bare repository")
sys.exit(1)
logging.debug("Updating branch %s", pushed_branch)
if not pushed_branch.endswith(AUTOMERGE_SUFFIX):
logging.debug("Branch has no automerge suffix, will not automatically merge")
sys.exit(0)
checked_out_branch_is_valid(pushed_branch)
check_working_directory_clean()
logging.debug("OK to merge")
def update_hook(pushed_branch):
validate(pushed_branch)
def post_update_hook(pushed_branch):
validate(pushed_branch)
try:
git_subprocess(['git', 'merge', '--ff-only', pushed_branch])
except subprocess.CalledProcessError:
logging.error("Couldn't merge --- merge was not fast forward")
sys.exit(1)
def main():
script_name = sys.argv[0]
pushed_branch = sys.argv[1]
pushed_branch = strip_branch(pushed_branch)
if script_name.endswith('/update'):
update_hook(pushed_branch)
if script_name.endswith('/post-update'):
post_update_hook(pushed_branch)
if __name__ == "__main__":
main()发布于 2015-02-02 21:52:46
我主要是寻求从git的人的建议,如果和如何这将爆炸和搞乱我的储存库。
就Git行动而言,我看不出有什么大问题或危险。这并不是说根本就没有。
这些命令有一个尾随的--,这似乎很奇怪,但是您可能有自己的原因,或者我遗漏了一些东西:
git diff-files --quiet --ignore-submodules --
git diff-index --cached --quiet HEAD --ignore-submodules --然而,对python的任何批评也是受欢迎的。
总的来说,代码非常好。它也大多通过PEP8。文件写得很好。但有些改进是可能的。
而不是这样:
导入os、sys、子进程、日志记录
将其拆分为多行:
import sys
import subprocess
import logging
import os上
我不太熟悉这种评论风格,而且经常使用它:
logging.basicConfig(level=logging.INFO)“”将do
DEBUG设置为调试信息,或设置为ERROR仅获取错误条件。
我更希望这样做:
# Set do ``DEBUG`` for debug info, or to ``ERROR`` to get error conditions only.
logging.basicConfig(level=logging.INFO)这可以写得更简单:
working_copy = os.environ.get("GIT_WORK_TREE",None)如果working_copy不是None:返回working_copy
如下所示:
working_copy = os.environ.get("GIT_WORK_TREE")
if working_copy:
return working_copy这种代码经常出现:
Logging.error(“一些消息”) sys.exit(1)
我建议添加一个助手方法:
def fatal(message, exit_code=1):
logging.error(message)
sys.exit(exit_code)另一种经常出现的模式:
Git_subprocess(“一些命令”.split()).strip()
我建议改变git_subprocess,以处理分裂和剥离也。
script_name = sys.argv0 pushed_branch = sys.argv1 pushed_branch = strip_branch(pushed_branch) if script_name.endswith('/update'):update_hook(pushed_branch) if script_name.endswith(‘/post update’):post_update_hook(pushed_branch)
可以简单地一步创建pushed_branch,而且由于script_name不能同时以/update和/post-update结尾,所以最好用elif编写:
script_name = sys.argv[0]
pushed_branch = strip_branch(sys.argv[1])
if script_name.endswith('/update'):
update_hook(pushed_branch)
elif script_name.endswith('/post-update'):
post_update_hook(pushed_branch)https://codereview.stackexchange.com/questions/59596
复制相似问题