我已经关注了
[attr]POFILE merge=merge-po-files
locale/*.po POFILE
在 .gitattributes
中,当相同的本地化文件(例如 locale/en.po
)被修改时,我希望 merge 分支以正常工作在平行分支中。我目前正在使用以下 merge 驱动程序:
#!/bin/bash
# git merge driver for .PO files (gettext localizations)
# Install:
# git config merge.merge-po-files.driver "./bin/merge-po-files %A %O %B"
LOCAL="${1}._LOCAL_"
BASE="${2}._BASE_"
REMOTE="${3}._REMOTE_"
# rename to bit more meaningful filenames to get better conflict results
cp "${1}" "$LOCAL"
cp "${2}" "$BASE"
cp "${3}" "$REMOTE"
# merge files and overwrite local file with the result
msgcat "$LOCAL" "$BASE" "$REMOTE" -o "${1}" || exit 1
# cleanup
rm -f "$LOCAL" "$BASE" "$REMOTE"
# check if merge has conflicts
fgrep -q '#-#-#-#-#' "${1}" && exit 1
# if we get here, merge is successful
exit 0
但是,msgcat
太笨了,这不是真正的三向 merge 。
例如,如果我有
基本版本
msgid "foo" msgstr "foo"
本地版本
msgid "foo" msgstr "bar"
远程版本
msgid "foo" msgstr "foo"
我会以冲突告终。 但是,真正的三向 merge 驱动程序会输出正确的 merge :
msgid "foo"
msgstr "bar"
请注意,我不能简单地将 --use-first
添加到 msgcat
,因为 REMOTE 可能包含更新的翻译。此外,如果 BASE、LOCAL 和 REMOTE 都是唯一的,我仍然希望发生冲突,因为那真的会发生冲突。
我需要更改什么才能使其正常工作?如果可能的话,比“#-#-#-#-#”更少疯狂的冲突标记的奖励积分。
最佳答案
[这是一个历史版本,请参阅我对 2021 年版本的 merge 驱动程序的另一个更新的回答。]
这是一个有点复杂的示例驱动程序,它似乎输出正确的 merge ,其中可能包含一些本应被本地或远程版本删除的翻译。
什么都不应该遗漏,所以这个驱动程序在某些情况下只会增加一些额外的困惑。
此版本使用 gettext
native 冲突标记,看起来像 #-#-#-#-#
结合 fuzzy
标记而不是普通的 git 冲突标记。
在 msgcat
中解决错误(或功能)的驱动程序有点难看和 msguniq
:
#!/bin/bash
# git merge driver for .PO files
# Copyright (c) Mikko Rantalainen <mikko.rantalainen@peda.net>, 2013
# License: MIT
ORIG_HASH=$(git hash-object "${1}")
WORKFILE=$(git ls-tree -r HEAD | fgrep "$ORIG_HASH" | cut -b54-)
echo "Using custom merge driver for $WORKFILE..."
LOCAL="${1}._LOCAL_"
BASE="${2}._BASE_"
REMOTE="${3}._REMOTE_"
LOCAL_ONELINE="$LOCAL""ONELINE_"
BASE_ONELINE="$BASE""ONELINE_"
REMOTE_ONELINE="$REMOTE""ONELINE_"
OUTPUT="$LOCAL""OUTPUT_"
MERGED="$LOCAL""MERGED_"
MERGED2="$LOCAL""MERGED2_"
TEMPLATE1="$LOCAL""TEMPLATE1_"
TEMPLATE2="$LOCAL""TEMPLATE2_"
FALLBACK_OBSOLETE="$LOCAL""FALLBACK_OBSOLETE_"
# standardize the input files for regexping
# default to UTF-8 in case charset is still the placeholder "CHARSET"
cat "${1}" | perl -npe 's!(^"Content-Type: text/plain; charset=)(CHARSET)(\\n"$)!$1UTF-8$3!' | msgcat --no-wrap --sort-output - > "$LOCAL"
cat "${2}" | perl -npe 's!(^"Content-Type: text/plain; charset=)(CHARSET)(\\n"$)!$1UTF-8$3!' | msgcat --no-wrap --sort-output - > "$BASE"
cat "${3}" | perl -npe 's!(^"Content-Type: text/plain; charset=)(CHARSET)(\\n"$)!$1UTF-8$3!' | msgcat --no-wrap --sort-output - > "$REMOTE"
# convert each definition to single line presentation
# extra fill is required to make sure that git separates each conflict
perl -npe 'BEGIN {$/ = "\n\n"}; s/#\n$/\n/s; s/#/##/sg; s/\n/#n/sg; s/#n$/\n/sg; s/#n$/\n/sg; $_.="#fill#\n" x 4' "$LOCAL" > "$LOCAL_ONELINE"
perl -npe 'BEGIN {$/ = "\n\n"}; s/#\n$/\n/s; s/#/##/sg; s/\n/#n/sg; s/#n$/\n/sg; s/#n$/\n/sg; $_.="#fill#\n" x 4' "$BASE" > "$BASE_ONELINE"
perl -npe 'BEGIN {$/ = "\n\n"}; s/#\n$/\n/s; s/#/##/sg; s/\n/#n/sg; s/#n$/\n/sg; s/#n$/\n/sg; $_.="#fill#\n" x 4' "$REMOTE" > "$REMOTE_ONELINE"
# merge files using normal git merge machinery
git merge-file -p --union -L "Current (working directory)" -L "Base (common ancestor)" -L "Incoming (applied changeset)" "$LOCAL_ONELINE" "$BASE_ONELINE" "$REMOTE_ONELINE" > "$MERGED"
MERGESTATUS=$?
# remove possibly duplicated headers (workaround msguniq bug http://comments.gmane.org/gmane.comp.gnu.gettext.bugs/96)
cat "$MERGED" | perl -npe 'BEGIN {$/ = "\n\n"}; s/^([^\n]+#nmsgid ""#nmsgstr ""#n.*?\n)([^\n]+#nmsgid ""#nmsgstr ""#n.*?\n)+/$1/gs' > "$MERGED2"
# remove lines that have totally empty msgstr
# and convert back to normal PO file representation
cat "$MERGED2" | grep -v '#nmsgstr ""$' | grep -v '^#fill#$' | perl -npe 's/#n/\n/g; s/##/#/g' > "$MERGED"
# run the output through msguniq to merge conflicts gettext style
# msguniq seems to have a bug that causes empty output if zero msgids
# are found after the header. Expected output would be the header...
# Workaround the bug by adding an empty obsolete fallback msgid
# that will be automatically removed by msguniq
cat > "$FALLBACK_OBSOLETE" << 'EOF'
#~ msgid "obsolete fallback"
#~ msgstr ""
EOF
cat "$MERGED" "$FALLBACK_OBSOLETE" | msguniq --no-wrap --sort-output > "$MERGED2"
# create a hacked template from default merge between 3 versions
# we do this to try to preserve original file ordering
msgcat --use-first "$LOCAL" "$REMOTE" "$BASE" > "$TEMPLATE1"
msghack --empty "$TEMPLATE1" > "$TEMPLATE2"
msgmerge --silent --no-wrap --no-fuzzy-matching "$MERGED2" "$TEMPLATE2" > "$OUTPUT"
# show some results to stdout
if grep -q '#-#-#-#-#' "$OUTPUT"
then
FUZZY=$(cat "$OUTPUT" | msgattrib --only-fuzzy --no-obsolete --color | perl -npe 'BEGIN{ undef $/; }; s/^.*?msgid "".*?\n\n//s')
if test -n "$FUZZY"
then
echo "-------------------------------"
echo "Fuzzy translations after merge:"
echo "-------------------------------"
echo "$FUZZY"
echo "-------------------------------"
fi
fi
# git merge driver must overwrite the first parameter with output
mv "$OUTPUT" "${1}"
# cleanup
rm -f "$LOCAL" "$BASE" "$REMOTE" "$LOCAL_ONELINE" "$BASE_ONELINE" "$REMOTE_ONELINE" "$MERGED" "$MERGED2" "$TEMPLATE1" "$TEMPLATE2" "$FALLBACK_OBSOLETE"
# return conflict if merge has conflicts according to msgcat/msguniq
grep -q '#-#-#-#-#' "${1}" && exit 1
# otherwise, return git merge status
exit $MERGESTATUS
# Steps to install this driver:
# (1) Edit ".git/config" in your repository directory
# (2) Add following section:
#
# [merge "merge-po-files"]
# name = merge po-files driver
# driver = ./bin/merge-po-files %A %O %B
# recursive = binary
#
# or
#
# git config merge.merge-po-files.driver "./bin/merge-po-files %A %O %B"
#
# The file ".gitattributes" will point git to use this merge driver.
关于此驱动程序的简短说明:
- 它将常规 PO 文件格式转换为单行格式,其中每行都是一个翻译条目。
- 然后它使用常规的
git merge-file --union
进行 merge , merge 后生成的单行格式将转换回常规 PO 文件格式。
实际的冲突解决是在此之后使用msguniq
完成的, - 然后最终将生成的文件与常规
msgcat
生成的模板 merge merge 原始输入文件以恢复可能丢失的元数据。
警告:此驱动程序将使用 msgcat --no-wrap
在 .PO
上文件并将强制UTF-8
如果未指定实际编码,则编码。
如果您想使用此 merge 驱动程序但始终检查结果,请更改最终的 exit $MERGESTATUS
看起来像exit 1
.
从该驱动程序获取 merge 冲突后,解决冲突的最佳方法是使用virtaal
打开冲突文件。并选择 Navigation: Incomplete
.
我发现此 UI 是解决冲突的非常好的工具。
关于git - .PO (gettext) 文件的 3 向 Git merge 驱动程序在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16214067/