我有一种方法来获取2个文件副本,其中第一个具有远程内容,第二个具有本地内容
答案 0 :(得分:3)
我认为没有git选项可以将文件的两个版本都保留为两个副本。
但是您可以使用以下命令轻松实现此目标:
git merge the_branch
git checkout --theirs -- path/to/file ; mv path/to/file path/to/file.theirs
git checkout --ours -- path/to/file ; mv path/to/file path/to/file.ours
git checkout -m -- path/to/file
最后,您有三个文件:
file.theirs
及其版本; file.ours
,以及您的版本; file
,带有版本和冲突标记。答案 1 :(得分:1)
考虑使用git mergetool
(尽管我自己从来没有这样做)或git show
(有时我这样做)。还可以考虑将merge.conflictStyle
设置为diff3
,这会使Git将基本版本以及左侧和右侧版本写入冲突的工作树副本中。我发现启用此功能后,我几乎不需要看到这两个输入。 (但只有几乎永远不会。)
实际上,该文件在所有三个版本中都已经存在 ,但它们都在索引中,而不在工作树中。因此,诀窍是使它们脱离索引(它们是特殊的仅Git格式),进入您的工作树,您可以在其中查看和使用它们。
让我们简要而详细地了解发生冲突时git merge
的工作方式。为了发生冲突,我们必须做这样的事情:
$ git checkout ours
Switched to branch 'ours'
$ git merge theirs
Git将查看提交图,发现ours
和theirs
有所不同,但是有一个常见的 merge base commit: 1
o--...--L <-- ours (HEAD)
/
...--o--B
\
o--...--R <-- theirs
提交 L 是左侧或 local 或--ours
提交。提交 R 是右侧或远程或--theirs
提交。提交 B 这是合并基础。然后,Git实际上执行了两个git diff
命令,一个命令找出自合并基础以来我们 发生了什么变化:
git diff --find-renames <hash-of-B> <hash-of-L> # what we changed
git diff --find-renames <hash-of-B> <hash-of-R> # what they changed
然后合并尝试使用与提交 B 相关的内容作为合并更改的基础,从而组合这两组更改。但是,我们更改了一些文件,他们更改了相同的文件,并且我们的更改与它们的更改发生了冲突,从而导致合并冲突。
这时,Git所做的是将文件的所有三个副本放入索引中,索引的临时插槽编号为非零:
工作树包含Git尝试使用冲突标记合并两组更改的尝试。请注意,此版本与三个输入版本中的任何一个都不相同!合并的某些部分可能已经解决。发生冲突的更改的默认样式为merge
,该样式仅显示左侧( B -vs- L )和右侧( B -vs- R )更改,而不会向您显示 B 本身的部分。在许多情况下就足够了,但是当更改纯粹是删除操作时,了解 B 中的哪些行将被删除通常非常有帮助,这不是您可以推断的。将冲突样式设置为diff3
会使Git还在两个更改部分之间记录 B 代码部分。
1 可能有多个合并基础提交。在这种情况下,Git默认通过合并合并基础来构造新的合并基础提交。这个过程有点混乱,但是幸运的是,它很少见,即使发生了,也很少会使情况变得更糟。
您可以使用git checkout-index
提取三个版本中的任何一个,尽管使用该命令有些麻烦:
git checkout-index --all -- path/to/file
这会将所有三个文件写入带有临时名称的文件,然后您必须重命名这些文件。 (此主题有多种变体,但都有些令人讨厌。)
您可以使用git mergetool
,它会自动提取所有三个版本,然后对所有三个版本调用您选择的合并工具命令。
或者,您可以手动提取一个或两个文件。 DogEata's answer中的方法可以使用,但是如果您不担心行尾问题,这种方法会更短:
git show :1:path/to/file > path/to/file.base
git show :2:path/to/file > path/to/file.ours
git show :3:path/to/file > path/to/file.theirs
这使用the git show
command和gitrevisions语法来访问索引副本,将它们显示为标准输出,并将输出重定向到新文件。
git add
写入插槽零Git知道合并正在进行中,并且还没有以几种方式完成,但是最重要的是在索引的某些路径的插槽1、2和/或3中有这些文件。找到该路径的正确内容并将其写入工作树中的该路径后,运行:
git add path/to/file
将文件复制回索引,进行常规格式的工作树复制,然后压缩为索引中包含的特殊的仅Git格式。
如果文件通常位于零位置的索引中,那只会用固定的工作树版本覆盖旧的索引副本。如果索引中的文件有多个副本,且插槽编号较高,则git add
still 会写入插槽0,但这一次,它也会删除编号较高的条目。现在文件已解决。
如果您使用git mergetool
,则git mergetool
命令可以自动为您运行git add
,从而隐藏了额外的步骤。有些人觉得这特别方便。
答案 2 :(得分:0)
从the official documentation中挑选樱桃的想法以及此处的其他评论,我想出了一个可能对您有所帮助的小功能。
此脚本也涵盖了基准冲突的情况,由于某种原因,使用git checkout --ours
的解决方案无法解决这些冲突。
在我的特定用例中,我有兴趣在每次运行命令时将所有文件分开,并根据需要进行调整。
鱼的功能:
function git-conflict-split
for file in (git ls-files -u | cut -c 51- | sort -u)
rm $file
git checkout-index --stage 3 -- $file
mv $file $file.THEIRS
git checkout-index --stage 2 -- $file
mv $file $file.OURS
git checkout-index --stage 1 -- $file
echo "meld $file.OURS $file $file.THEIRS"
end
end