【问题标题】:Git hook, modify commit filesGit钩子,修改提交文件
【发布时间】:2013-02-01 05:26:59
【问题描述】:

我正在尝试编写一个 Git 预提交挂钩脚本。它应该在修改文件的开头写提交日期。

我的问题是我无法将修改后的文件添加到之前的提交中。当我再次尝试调用 Git 提交时,它会递归运行。如何编写脚本,在修改文件末尾附加修改时间?

我的代码:

#!/bin/bash

files_modified=`git diff-index --name-only HEAD`

for f in $files_modified; do
    if [[ $f == *.groovy ]]; then
        $line = $(head -1 f)
        if [[ $line == "/%%*" ]];
           then
               sed -i 1d
           fi
           echo "/%% " + $(date +"%m_%d_%Y") + " %%\\" >> f
           git add f
    fi
done
git commit --amend #recursive
exit

【问题讨论】:

    标签: git bash hook commit pre-commit-hook


    【解决方案1】:

    您不能在 pre 提交挂钩中修改提交。
    而且您所做的类似于关键字扩展机制,这不是 Git(或任何 DVCS)的最佳实践,如“To put the prefix ?<revision-number> to codes by Git/Svn”中所述。

    其他方法包括:

    【讨论】:

      【解决方案2】:

      可能是git attributesmudge/clean 操作是您正在寻找的:

      相关: use git smudge/clean to replace file contents

      【讨论】:

        【解决方案3】:

        看看你的 pre-commit 钩子,你几乎得到了一些可以工作的东西。以下是我认为需要的最小更改:

            #!/bin/bash
            files_modified=`git diff --cache --name-only --diff-filter=ACM`
                    ### fix: use current branch; cached; and only files
            for f in $files_modified; do ### broken: if space in filename(s)
                if [[ $f == *.groovy ]]; then
                    line=$(head -1 $f) ### fix: forgot a $ before f
                    if [[ $line == "/%%*" ]];
                    then
                        sed -i 1d "$f" ### fix: forgot file argument
                    fi
                    echo "/%% " + $(date +"%m_%d_%Y") + " %%\\" >> $f
                            ### fix: forgot a $ before f
                    git add -u $f ### fix: forgot a $ before f
                fi
            done
            ### undesired ### git commit --amend #recursive
            ### unneeded ### exit
        

        但是,我注意到您的实施存在一些问题。您将从文件顶部删除匹配“/%%*”的行,并在底部附加一个新行。每次运行此程序时,您将永远在文件末尾附加一个新的/%% mm_dd_YYYY %%\ 行。这可能不是您想要的(1000 次提交之后,以前为空的文件将有 1000 行)。我认为你的意思是替换现有的生产线。在这种情况下,替换匹配行的 sed 翻译将起作用。

        这是一个我认为更接近你想要的食谱:

            #!/bin/sh
            TMPFILE="/tmp/${0##*/}.$$"
            for f in $( git diff --cached --name-only --diff-filter=ACM ); do
                    # XXX broken: if space in filename(s)
                    case "$f" in
                    *.groovy) : fall through ;;
                    *) continue
                    esac
                    cp "$f" "$TMPFILE" || continue
                    awk -v new="/%% $(date +%m_%d_%Y) %%\\" \
                            'NR==1{sub("^/%% .* %%\\\\$",new)}1' \
                            < "$TMPFILE" > "$f"
                    git add -u -- "$f"
            done
        

        如果文件的第一行与/%% ... %%\ 匹配,则使用当前日期/时间(在预提交挂钩时)进行更新。

        但是,这只是为了说明如何简单地完成它。这实际上不是一个完整的解决方案。上述脚本不适用于名称中包含空格、双引号、反斜杠、制表符等的文件。

        完整的解决方案:

        1. 使用以下预提交挂钩:

          #!/bin/sh
          git diff --cached --name-only -z --diff-filter=ACM |
                  xargs -r0 .filters/myfilter
          
        2. 使用以下内容创建“.filters/myfilter”:

          #!/bin/sh
          TMPFILE="/tmp/${0##*/}.$$"
          for f in "$@"; do ### the only difference from above recipe
                  case "$f" in
                  *.groovy) : fall through ;;
                  *) continue
                  esac
                  cp "$f" "$TMPFILE" || continue
                  awk -v new="/%% $(date +%m_%d_%Y) %%\\" \
                          'NR==1{sub("^/%% .* %%\\\\$",new)}1' \
                          < "$TMPFILE" > "$f"
                  git add -u -- "$f"
          done
          

        上面的实现可以处理你扔给它的任何文件名。

        【讨论】:

          猜你喜欢
          • 2018-05-21
          • 2013-12-15
          • 2011-01-15
          • 1970-01-01
          • 2012-04-27
          • 2012-06-06
          • 1970-01-01
          • 2015-07-21
          相关资源
          最近更新 更多