9

是否可以修改默认git-merge-one-file程序以在不接触工作树的情况下完成索引中的所有操作,而使其完全不被修改?

更新和细节

所以我现在明白,如果不使用工作树,就无法进行文件级合并(合并作用于文件中的行而不是整个文件)。(与作用于整个文件的合并不同。)所以我将不得不使用工作树。

另一个细节:我同意该解决方案仅在无需手动解决即可自动完成合并的情况下工作。如果合并不是自动的,它只显示错误消息也没关系。(当然,让一切保持清洁。)

另一个细节:我没有git-merge-one-file直接使用,我在这个脚本中使用它:https ://gist.github.com/cool-RR/6575042

我尝试遵循@torek 的建议并使用临时工作树(如您在脚本中所见),因为这似乎是迄今为止最好的方向。问题是,我收到这些错误:

git checkout-index: my_file is not in the cache
error: my_file: cannot add to the index - missing --add option?

我用谷歌搜索了这些错误消息,但找不到任何有用的信息。

知道该怎么做吗?

4

5 回答 5

5

虽然 git 需要一个地方来完成它的工作,但您可以在“合并一个文件”操作期间将其指向不同的工作树位置。

我不知道这是否/如何“开箱即用” merge-one-file,但要设置的环境变量是GIT_WORK_TREE

env GIT_WORK_TREE=/some/where/else git ...

(您可以省略env大多数但不是全部的贝壳)。

一种或多或少等效的方法可能“感觉更安全”:-) 或更方便某些目的是在另一个目录中工作,并使用GIT_DIR到 repo 的位置:

cd /some/where/else
env GIT_DIR=/place/with/repo/.git git ...

您甚至可以组合它们,同时设置GIT_DIRGIT_WORK_TREE

于 2013-09-13T16:18:34.287 回答
2

要合并两个不同文件中的更改,您需要检查它们的内容:合并更改正在处理文件内容。内容工作在工作树中完成。在其他地方做工作并假装它不是工作树只是文字游戏。

如果您想在进行合并时保持当前工作树不变,请使用另一个工作树。git clone 很便宜,它是为这样的东西而构建的:

# merge into branch m2 from branch m1 but leave your (non-m2) worktree untouched:
git clone --no-checkout -b m2 . ../m2-work
cd ../m2-work
git reset    # this will warn about the empty worktree, you could instead do
#              git read-tree HEAD to get the same effect without the chatter
git merge origin/m1
git push origin m2

注意--no-checkout克隆上的 。Merge 确实必须有一个工作树来完成它的工作,但它不关心除了需要比较的内容之外的任何实际文件内容。

于 2013-09-15T18:20:42.683 回答
2

git 中的合并是以下之间的三向合并:

  • 源(' remote' 或 ' theirs',你要合并的)
  • 目的地(' local' 或 ' ours',它始终是工作树,HEAD 已在其中签出)
  • 共同祖先(或“ base”)

参见“ ”中所示的 ' local'、' base'、' remote'、' ' ,跟踪 ' ' 和 ' '您可以在“未按预期工作”中 看到一个示例。mergedgit rebaselocalremote
git revert

git read-tree“子树合并”和“ Git Objects ”(以及您在 gist 中使用的)中提到的是关于合并(用于子树合并),而不是文件内容(blob)。
git write-tree可用于创建树对象,但其文档确实提到“索引必须处于完全合并状态”。(当您想使用索引来合并文件时有点困难)。

git 索引(在此处记录)用于记录您在工作树中暂存的内容(“ merged”结果),作为合并解决方案的一部分。
它没有关于文件内容的所有信息,只有指向所述内容的指针(“索引条目”)。它根本不是进行合并的正确结构。


甚至git-merge-one-file.sh脚本本身也提到:

require_work_tree

该函数来自git-sh-setup.sh脚本(参见其文档):

test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = true ||
die "fatal: $0 cannot be used without a working tree."

该要求来自提交 6aaeca90 ( peff Jeff King ):

合并一个文件工具早于GIT_WORK_TREE.

在大多数情况下,merge-one-file只适用于GIT_WORK_TREE; 它的大部分繁重工作都是通过GIT_WORK_TREE适当尊重的管道命令完成的。


如果你真的不需要使用工作树,你可以尝试走为Merging notes选择的路线:
notes-merge.c确实会创建自己的工作树来合并git notes

于 2013-09-16T07:33:14.467 回答
2

不,但最简单的方法是 stash、merge、stage 和 unstash:

git stash save
git merge-file foo.txt base-foo.txt their-foo.txt
git add foo.txt
git stash pop

如果你不想隐藏,那么你就剩下 diff 和 patch 选项:将工作树更改保存到补丁,删除工作树更改,进行必要的更改,然后重新应用补丁

git diff -p --raw foo.txt > foo.txt.diff
git checkout -- foo.txt
git merge-file foo.txt base-foo.txt their-foo.txt
patch -p1 < foo.txt.diff    
于 2013-09-13T12:59:33.037 回答
1

Jeff King帮我解决了这个问题,我更新了脚本来工作:

https://gist.github.com/cool-RR/6575042

#!bash
if [ -n "$2" ]; then
  export SOURCE=$1 ;
  export DESTINATION=$2 ;
else
  export SOURCE=HEAD ;
  export DESTINATION=$1 ;
fi

export GIT_INDEX_FILE=`git rev-parse --show-toplevel`/.git/aux-merge-index ;
export GIT_WORK_TREE=`create_temporary_folder gm_`;
echo $GIT_INDEX_FILE
trap 'rm -f '"'$GIT_INDEX_FILE'"'; rm -rf '"'$GIT_WORK_TREE'" 0 1 2 3 15 ;
mkdir $GIT_WORK_TREE/.git
set -e ;
git read-tree -im `git merge-base $DESTINATION $SOURCE` $DESTINATION $SOURCE ;
#echo Finished read-tree
#sleep 1000
git merge-index git-merge-one-file -a
#echo Finished merge-index
git write-tree \
| xargs -i@ git commit-tree @ -p $DESTINATION -p $SOURCE -m "Merge $SOURCE into $DESTINATION" \
| xargs git update-ref -m"Merge $SOURCE into $DESTINATION" refs/heads/$DESTINATION ;
exit 0
于 2013-09-24T05:33:51.430 回答