如何设置git驱动程序忽略合并时的文件夹 [英] How to setup a git driver to ignore a folder on merge

查看:91
本文介绍了如何设置git驱动程序忽略合并时的文件夹的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经做了大量搜索,阅读了很多SO问题和解决方案,并尝试了不同的方式,但我一直无法做到自己想做的事情,这很简单。



我拥有所有主代码所在的主分支,以及由设计团队构建的rails应用程序布局的设计分支。他们在公用文件夹中添加了一个名为photoshop的文件夹,以便在版本控制下保留图片的来源。但我不希望将该文件夹复制到主分支上,因为它不是必需的。

显然,这样做的方法是通过合并驱动程序。所以,我创建了忽略驱动程序:

  [mergeignore] 
name = always ignore在合并期间
driver = ignore.sh%0%A%B

.b文件放在我的$ PATH中:

  exit 0 

我在public /中创建了.gitattributes文件,因为photoshop文件夹应该被忽略,它将出现在public /中:

  photoshop merge =忽略
photoshop / merge =忽略
photoshop / * merge =忽略
photoshop / ** / * merge = ignore

正如您所看到的,我尝试了几种不同的模式来忽略整个文件夹,但它不起作用。我相信这是因为主分支上没有文件夹,所以没有冲突,所以git不使用忽略驱动程序。有没有一种方法可以实现这一点,而无需在master上创建public / photoshop文件夹?

谢谢!

解决方案

正如我的其他答案所暗示的,这里是解决方案的扩展的,一般化的,工业级的版本。

>(是的,我在家里感到无聊,没有其他更好的事情要做:P)

这个脚本会添加一个新的 detached 根据您的 local 设计分支进行提交,因此它不会影响设计存储库或设计分支。提交将删除所有需要的文件。然后它执行合并。



对于那些懒得读完整代码的人来说,这些步骤的核心可以简化为:

original = $(gitbranch HEAD)#当前分支名称或sha1,如果不在分支中
branchsha = $ (gitsha$ branch)ref#的sha1,强制分离提交

git checkout$ branchsha&&
git rm -rf$ {files [@]}&&
git commit -m$ msgcommit&&
newsha = $(gitsha HEAD)&&
git checkout$ original&&
git merge -m$ msgmerge$ {mergeopts [@]}$ newsha

这里是完整的脚本: b
$ b

(稍微修改一下以应付弱的和有限的SO的语法着色,所以最好是获得来自以下链接的原始来源)



git-strip-merge


$ b

 #!/ bin / bash 

#git-strip-merge - 合并之前删除分支上的文件的git-merge

#版权所有(C)2012 Rodrigo Silva(MestreLion)< linux@rodrigosilva.com>

#这个程序是免费软件:您可以根据GNU通用公共许可证条款重新发布和/或修改
#它由
#免费软件基金会,许可证的第3版或
#(可选)任何更新的版本。

#这个程序分发时希望它有用,
#但没有任何保证;甚至没有隐含的保证
#适销性或针对特定用途的适用性。有关更多详细信息,请参阅
#GNU通用公共许可证。

#您应该收到GNU通用公共许可证
#的副本以及此程序。如果没有看到< http://www.gnu.org/licenses/gpl.html>

#回答如何设置git驱动程序忽略合并文件夹?
#请参阅http://stackoverflow.com/questions/3111515

#Defaults:
msgcommit =从合并前的<分支>'中移除文件
msgmerge =合并被剥离分支<分支>'
verbose = 0
quiet =( - quiet)

usage(){
cat< ;< - USAGE
用法:$ myname [git-merge options] [-M< commitmsg>]< branch> FILE ...
如果[[$ 1]];则使用
;然后
cat>& 2<< - USAGE
尝试'$ myname --help'以获取更多信息。
USAGE
exit 1
fi
cat <-USAGE
$ bgit-merge删除foreign上的文件< branch>在合并

之前,有用的是忽略< branch>中的一个文件夹,然后将它与
当前分支合并。通过删除基于
的分离提交中的FILE(S)然后在
当前分支中执行这个新提交的合并。注意< branch>不会被这个过程改变。
还要注意< branch>实际上可以是任何引用,如标签,
或远程分支,甚至是一个提交SHA。

有关更多信息,请参阅< http://stackoverflow.com/questions/3111515>

选项:
-h,--help
显示此页面。

-v,--verbose
不使用-q来压缩正常输出的内部步骤从git
checkout,rm,commit。默认情况下,只显示git merge输出。
然而,错误永远不会被抑制,

-M ,--msgcommit =< message> < branch>中的移除提交
消息。不要将
与由-m设置的合并提交消息混淆。默认的
消息是:$ msgcommit

-m ,--message =< message>合并提交的
消息。由于我们未合并<分支>直接
,而是一个基于它的分离提交,我们伪造了一个
的消息,类似于git默认的分支合并。否则
git会在消息中使用我们提交的完整和丑陋的SHA1。
默认消息是:$ msgmerge

对于两个提交消息,标记< branch>被替换为
实际<分支>名称。

其他选项未经检查传递给git合并。

所有选项必须先于< branch>和FILE(s),但-h和--help
可能出现在命令行的任何位置。

示例:
$ myname designphotoshop / *

版权所有(C)2012 Rodrigo Silva(MestreLion)< linux@rodrigosilva.com>
许可证:GPLv3或更高版本。参见< http://www.gnu.org/licenses/gpl.html>
USAGE
exit 0
}

#帮助函数
$ myname =$ {0 ## * /}
argerr(){printf%s:%s\\\
$ {0 ## * /}$ {1:-error} >& 2; usage 1;}
invalid(){argerrinvalid option:$ 1;}
missing(){argerrmissing $ {2:+ $ 2} operand $ {1 :$ from $ 1}。;}

#选项处理
files =()
mergeopts =()$ b $ for arg in$ @; do case $ argin -h | --help)用法;; esac;完成
while(($#)); do
case $ 1 $ in
-v | --verbose )verbose = 1 ;;
-M)shift; msgcommit = $ 1 ;;
-m)shift; msgmerge = $ 1 ;;
--msgcommit = *)msgcommit = $ {1# * =} ;;
--message = *)msgmerge = $ {1#* =} ;;
- *)mergeopts + =($ 1);;
*)branch = $ 1
shift; break ;;
esac
shift
done
files + =($ @)

#参数处理

msgcommit = $ {msgcommit //< branch> / $ branch}
msgmerge = $ {msgmerge //< branch> / $ branch}

[ [$ msgcommit]] ||缺少msgcommitMSG
[[$ branch]] ||缺少< branch>
(($ {#files [@]}))||缺少FILE

((详细))&&安静=()

#这里的乐趣开始...
gitsha(){git rev-parse$ 1; }
gitbranch(){
git symbolic-ref$ 12> / dev / null | sed's / refs \ / heads\ ///'||
gitsha$ 1
}

原始= $(gitbranch HEAD)
branchsha = $(gitsha$ branch)

trap'git checkout --quiet$ original'EXIT

git checkout$ branchsha$ {quiet [@]}&&
git rm -rf$ {files [@]}$ {quiet [@]}&&
git commit -m$ msgcommit$ {quiet [@]}&&
newsha = $(gitsha HEAD)&&
git checkout$ original$ {quiet [@]}&&
git merge -m$ msgmerge$ {mergeopts [@]}$ newsha

Enjoy!

一张图片胜过千言万语......



合并之前:





合并后:




请注意,设计分支提示根本没有受到影响,即使是本地分支,也要感谢分离的提交技巧。除此之外,提交(删除和合并)都是常规提交,并提供合适的提交消息和父代。 主分支清理任何不受欢迎的文件。


I've already did an extensive search, read a lot of SO questions and solutions and tried it different ways, but I've been unable to do what I want, which is fairly simple.

I have the master branch, where all the main code resides, and the design branch, where the layout of the rails application is built by the design team. They have added a folder called "photoshop" to the public folder to keep their sources for the images also under version control. But I don't want this folder to be copied on merge to the master branch because, well, it is not needed.

Apparently, the way to do this is through a merge driver. So, I've created the "ignore" driver:

[merge "ignore"]
name = always ignore during merge
driver = ignore.sh %0 %A %B

And created the ignore.sh file on my $PATH:

exit 0

I've created the .gitattributes file inside public/, because the photoshop folder should be ignored in whole and it is going to appear under public/:

photoshop  merge=ignore
photoshop/ merge=ignore
photoshop/* merge=ignore
photoshop/**/* merge=ignore

As you can see, I've tried several different patterns to ignoring the whole folder, but it does not work. I believe this is because there is no folder on the master branch, so there's no conflict and so git doesn't use the ignore driver. Is there a way to achieve this without having to create a public/photoshop folder on master?

Thanks!

解决方案

As suggested by my other answer, here goes the extended, generalized, industrial-strength version of the solution.

(yes, I was bored at home and had nothing else better to do :P)

This script will add a new, detached commit based on your local design branch, so it won't affect neither the design repository or your design branch. The commit will have all desired files removed. Then it performs the merge.

For those too lazy to read the full code, the "core" of these steps can be simplified as:

original=$(gitbranch HEAD)    # current branch name, or sha1 if not in a branch
branchsha=$(gitsha "$branch") # sha1 of a ref, to force detached commit

git checkout "$branchsha"   &&
git rm -rf "${files[@]}"    &&
git commit -m "$msgcommit"  &&
newsha=$(gitsha HEAD)       &&
git checkout "$original"    &&
git merge -m "$msgmerge" "${mergeopts[@]}" "$newsha"

And here is the full script:

(a bit modified to cope with the weak and limited SO's syntax coloring, so it's better to get the pristine source from the link below)

git-strip-merge

#!/bin/bash
#
# git-strip-merge - a git-merge that delete files on branch before merging
#
#    Copyright (C) 2012 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program. If not see <http://www.gnu.org/licenses/gpl.html>
#
# Answer for "How to setup a git driver to ignore a folder on merge?"
# See http://stackoverflow.com/questions/3111515

#Defaults:
msgcommit="remove files from '<branch>' before merge"
msgmerge="Merge stripped branch '<branch>'"
verbose=0
quiet=(--quiet)

usage() {
    cat <<- USAGE
    Usage: $myname [git-merge options] [-M <commitmsg>] <branch> FILE...
    USAGE
    if [[ "$1" ]] ; then
        cat >&2 <<- USAGE
        Try '$myname --help' for more information.
        USAGE
        exit 1
    fi
    cat <<-USAGE

    "git-merge that delete files on "foreign" <branch> before merging

    Useful for ignoring a folder in <branch> before merging it with
    current branch. Works by deleting FILE(S) in a detached commit based
    on <branch>, and then performing the merge of this new commit in the
    current branch. Note that <branch> is not changed by this procedure.
    Also note that <branch> may actually be any reference, like a tag,
    or a remote branch, or even a commit SHA.

    For more information, see <http://stackoverflow.com/questions/3111515>

    Options:
      -h, --help
         show this page.

      -v, --verbose
         do not use -q to supress normal output of internal steps from git
         checkout, rm, commit. By default, only git merge output is shown.
         Errors, however, are never supressed

      -M <message>, --msgcommit=<message>
         message for the removal commit in <branch>. Not to be confused
         with the message of the merge commit, which is set by -m. Default
         message is: "$msgcommit"

      -m <message>, --message=<message>
         message for the merge commit. Since we are not merging <branch>
         directly, but rather a detached commit based on it, we forge a
         message similar to git's default for a branch merge. Otherwise
         git would use in message the full and ugly SHA1 of our commit.
         Default message is: "$msgmerge"

      For both commit messages, the token "<branch>" is replaced for the
      actual <branch> name.

    Additional options are passed unchecked to git merge.

    All options must precede <branch> and FILE(s), except -h and --help
    that may appear anywhere on the command line.

    Example:
      $myname design "photoshop/*"

    Copyright (C) 2012 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
    License: GPLv3 or later. See <http://www.gnu.org/licenses/gpl.html>"
    USAGE
    exit 0
}

# Helper functions
myname="${0##*/}"
argerr()  { printf "%s: %s\n" "${0##*/}" "${1:-error}" >&2 ; usage 1 ; }
invalid() { argerr "invalid option: $1" ; }
missing() { argerr "missing ${2:+$2 }operand${1:+ from $1}." ; }

# Option handling
files=()
mergeopts=()
for arg in "$@"; do case "$arg" in -h|--help) usage ;; esac; done
while (( $# )); do
    case "$1" in
    -v|--verbose  ) verbose=1            ;;
    -M            ) shift ; msgcommit=$1 ;;
    -m            ) shift ; msgmerge=$1  ;;
    --msgcommit=* ) msgcommit=${1#*=}    ;;
    --message=*   ) msgmerge=${1#*=}     ;;
    -*            ) mergeopts+=( "$1" )  ;;
    *             ) branch="$1"
                    shift ; break        ;;
    esac
    shift
done
files+=( "$@" )

# Argument handling

msgcommit=${msgcommit//<branch>/$branch}
msgmerge=${msgmerge//<branch>/$branch}

[[ "$msgcommit" ]]  || missing "msgcommit" "MSG"
[[ "$branch"   ]]   || missing ""          "<branch>"
(( ${#files[@]} ))  || missing ""          "FILE"

((verbose)) && quiet=()

# Here the fun begins...
gitsha()    { git rev-parse "$1" ; }
gitbranch() {
    git symbolic-ref "$1" 2> /dev/null | sed 's/refs\/heads\///' ||
    gitsha "$1"
}

original=$(gitbranch HEAD)
branchsha=$(gitsha "$branch")

trap 'git checkout --quiet "$original"' EXIT

git checkout "$branchsha"  "${quiet[@]}" &&
git rm -rf "${files[@]}"   "${quiet[@]}" &&
git commit -m "$msgcommit" "${quiet[@]}" &&
newsha=$(gitsha HEAD)                    &&
git checkout "$original"   "${quiet[@]}" &&
git merge -m "$msgmerge" "${mergeopts[@]}" "$newsha"

Enjoy!

An image is worth more than a thousand words...

Before merge:

After merge:

Note that "design" branch tip wasn't affected at all, even being a local branch, thanks to the detached commit trick. Other than that, both commits (the removal and the merge) are regular commits, with suitable commit messages and parents. And "master" branch is clean of any undesired files.

这篇关于如何设置git驱动程序忽略合并时的文件夹的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆