14

私はすでに広範な検索を行い、多くの SO の質問と解決策を読み、さまざまな方法で試しましたが、やりたいことができませんでした。これはかなり単純です。

すべてのメイン コードが存在するマスター ブランチと、デザイン チームが Rails アプリケーションのレイアウトを構築するデザイン ブランチがあります。彼らは、画像のソースもバージョン管理下に置くために、「photoshop」というフォルダーを public フォルダーに追加しました。しかし、マージ時にこのフォルダーを master ブランチにコピーしたくありません。

どうやら、これを行う方法は、マージ ドライバーを使用することです。そこで、「無視」ドライバーを作成しました。

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

$PATH に ignore.sh ファイルを作成しました。

exit 0

.gitattributes ファイルを public/ 内に作成しました。これは、photoshop フォルダー全体を無視する必要があり、public/ の下に表示されるためです。

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

ご覧のとおり、フォルダー全体を無視するためにいくつかの異なるパターンを試しましたが、うまくいきません。これは、master ブランチにフォルダーがないため、競合がなく、git が無視ドライバーを使用していないためだと思います。マスターに public/photoshop フォルダーを作成せずにこれを実現する方法はありますか?

ありがとう!

4

3 に答える 3

20

私の他の回答で示唆されているように、ソリューションの拡張された一般化された産業用強度のバージョンがここにあります。

(はい、私は家で退屈していて、他に何もすることがありませんでした:P)

このスクリプトは、ローカルのデザイン ブランチに基づいて新しい切り離されたコミットを追加するため、デザイン リポジトリにもデザイン ブランチにも影響しません。コミットにより、必要なファイルがすべて削除されます。次に、マージを実行します。

完全なコードを読むのが面倒な人のために、これらのステップの「コア」は次のように簡略化できます。

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"

そして、ここに完全なスクリプトがあります:

(弱く限定された SO の構文の色付けに対処するために少し変更されているため、以下のリンクから元のソースを取得することをお勧めします)

git ストリップ マージ

#!/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"

楽しみ!

画像は千の言葉よりも価値があります...

マージ前:

ここに画像の説明を入力

マージ後:

ここに画像の説明を入力

デタッチド コミット トリックのおかげで、「デザイン」ブランチのヒントは、たとえローカル ブランチであっても、まったく影響を受けないことに注意してください。それ以外は、両方のコミット (削除とマージ) は、適切なコミット メッセージと親を持つ通常のコミットです。そして、「マスター」ブランチには不要なファイルがありません。

于 2012-04-19T01:04:47.540 に答える
10

それ自体は答えではありませんが、いくつかの注意事項が.gitignoreあります。シナリオでは役に立ちません。

.gitignoreインデックス(ステージング領域)に追加される作業ツリーからのファイルを無視するためのものです。したがって、 を使用した場合にのみ有効であり、 を使用してオーバーライドすることもできます。不要なファイルが追加されるのを防ぐための便宜的なものですが、リポジトリ内のファイルには影響しませんgit add <files>git add --force <files>

あなたのシナリオでは、ローカルフォルダー.gitignoreがないため必要ありませ./photoshopん。そのため、マスター ブランチに追加する Photoshop ファイルはありません。ただし、念のため作成しても問題ありません。また、設計チームは、 Photoshop ファイルをブランチに追加することを望ん.gitignoreでいるため、歓迎されません。

したがって、マージはコミットされたデータを処理し、./photoshopファイルはすでにリポジトリ内にあるため、マージドライバーを使用するアプローチは正しかったです。

問題は...デフォルトでは、競合が発生した場合にのみマージドライバーがトリガーされることです。そして、masterブランチには./photoshopフォルダーやファイルがないため、競合はまったくなく、きれいにマージされます。したがって、パスパターンに関係なく、マージドライバーも効果がありませんでした(ちなみに、2番目のドライバーphotoshop/は正しいものでした)。競合していないファイルに対してもマージ ドライバーをトリガーするように git merge を構成できるかどうかはわかりませんが、グーグル検索する価値はあります。

前に言ったように、私の答えはあなたの問題に対する真の解決策ではありません。マージドライバーと .gitignore を使用した試みが失敗した理由を説明して、この件に光を当てることを望んでいました. (構成) マージ ドライバーの詳細を読むことをお勧めします。サブモジュールも調査する価値があります。

お役に立てれば!

アップデート

多分私の他の答えがあなたを助けるでしょう:

Usage: git-strip-merge [git-merge options] [-M <commitmsg>] <branch> FILE...

git ストリップ マージ

楽しみ!

于 2012-03-09T23:08:10.297 に答える
0

ディレクトリの内容を無視するため.gitignoreに、ブランチにファイルを追加しようとしましたか? 次に、 design から へのマージは、その新しいディレクトリを に追加するべきではありません。masterphotopshop
mastermaster

これが機能する場合でも、マージ ドライバーが必要ですが、今回は.gitignoreファイルの内容を管理する必要があります。

于 2010-06-24T16:23:02.260 に答える