有什么方法可以直接检出git的“两个已修改”或“未合并路径”文件?

时间:2018-08-20 01:54:58

标签: git

我知道通过以下命令签出两个修改后的文件有很长的路要走。

git add <filename>
git reset HEAD <filename>
git checkout <filename>

但是有一个命令可以检出所有“未合并的路径”吗?

1 个答案:

答案 0 :(得分:3)

您列出的命令序列将 not 生成--theirs版本。相反,它在工作树和索引中都生成--ours版本。有几种方法可以用更少的命令和多个路径名来实现这一目标。

第二种短路方法也许是您应该使用的方法:

git checkout --ours path1 path2 ... pathN

或:

git checkout --theirs path1 path2 ... pathN

后跟git add相同的路径。 请务必确定可以针对合并基础抛出他们或您所做的更改!请特别注意合并基础,以便您知道您保留的东西和扔掉的东西。

要缩短此步骤,可以使用git checkout HEADgit checkout MERGE_HEAD并跳过git add步骤;但请参见下文。


这里要理解的关键是,每当Git检测到冲突时,Git就会在索引中存储文件的所有三个版本。在这种情况下,您可以访问这三个版本中的任何一个或全部。例如,这就是git mergetool获得其称为BASE,LOCAL和REMOTE的版本的方式,Git通常将其称为 merge base HEAD或{{1 }}版本,以及另一个--ours版本。

请记住,索引是Git保留每个文件副本的位置,该副本将进入您的下一次提交。 (Git将此称为 index staging区域,有时甚至称为 cache ,具体取决于Git文档的哪一部分进行了调用。 )在正常操作中,任何此类文件只有一个副本。也就是说,如果您有一个名为--theirs的文件,该文件位于您检出的提交中,并且位于您可以使用的工作树中,那么您还可以在该文件中拥有相同的README.txt的副本。索引。

工作树中的副本是普通文件,其格式与计算机上的任何普通文件相同。存储在README.txt提交中的已提交副本具有特殊的,仅Git格式,该格式不仅被压缩,而且还完全是只读的:永远不会被提交改变了。当然,您可以提交具有不同版本HEAD new和different 提交,但是您要这样做的方法是首先复制该新的和不同的README.txt进入索引。

请注意,您随时可以使用README.txtHEAD提交中查看副本。同样,您可以使用git show HEAD:README.txt在索引中查看副本,其中前导冒号是索引中文件的特殊Git语法

通常,您通过git show :README.txt将新版本复制到索引中,该版本仅采用当前工作树中的所有内容,然后将其复制到索引/临时区域中,从而覆盖(单个)先前的副本。但是,当您在git add README.txtgit mergegit cherry-pickgit revert或执行 merging 操作的任何其他操作中遇到合并冲突时,我喜欢将 merge称为动词,索引将扮演一个新角色。

虽然索引通常仅保存git stash apply的一个一个副本,但是在发生冲突的合并期间,该索引保存(最多){{1的三个三个个副本}}。请记住,合并的工作方式是将文件版本README.txt与同一文件的某些合并基础版本进行比较,然后再比较 README.txt的版本与该相同的合并基本版本。通过进行这两个单独的比较,Git可以找出您更改了哪些哪些。然后,Git结合了这两组更改,将两者集应用于文件的合并基础版本。另请参见VonC's answer here

如果Git不能单独组合两组更改,那么Git此时要做的是在索引中使用其称为 stage slot 的内容。 Git不仅可以存储索引中的一个README.txt,还可以存储最多四个版本。但是,它最多使用三个,并为其编号:

  • 暂存槽零保存无冲突的README.txt
  • 暂存槽1容纳合并基础 README.txt
  • 暂存槽2容纳我们的{em>版本:README.txt
  • 暂存槽#3容纳版本`:3:README.txt。

1:README.txt(带有或不带有2:README.txt)显示为未合并的文件时,表示登台插槽1、2和3中有条目。在这种情况下,插槽0为未使用!

Git将git status的冲突副本写入工作树,以便您可以查看冲突并自行解决,但它还将所有三个输入存储在索引中。您可以检出其中任何一个,但是插槽2和3的语法可以简化操作:

--short

从插槽2中提取,而:

README.txt

从插槽3中提取。所有三个版本都保留在索引中,但是现在工作树包含我们的(git checkout --ours README.txt 版本)或它们的(git checkout --theirs README.txt 版本)。

运行HEAD会占用当前工作树中的所有内容,即使它中仍然存在合并冲突,并且将其写入插槽0,清除插槽1到3。这使Git认为冲突已解决。

您当然可以一次签出或添加多个文件名,因此可以使用:

MERGE_HEAD

生成所有未合并文件的列表(其简短状态为git add),并使用该列表创建要提取的文件列表。此方法不是很可靠(如果文件中包含有趣字符或空格,则失败),但满足简单情况即可:

git status --porcelain | grep '^UU ' | cut -f2-

删除一步

要缩短所有这一步,我们可以利用有关UU的一个特殊事实。使用files=$(git status --porcelain | grep '^UU ' | cut -f2-) git checkout --theirs $files git add $files git checkout可以使Git从索引(在那里以仅Git格式)提取文件到工作树(正常格式),这不会改变索引本身。但是,使用git checkout --ours path可以使Git从 commit 而不是从索引中提取文件。当Git执行此操作时,它将首先将该文件复制到索引中。只有在文件进入索引后,git checkout --theirs path才会将文件复制到工作树中。

将文件复制到索引具有删除文件的第1、2和3个阶段的插槽副本,并将文件写入暂存插槽零的副作用。因此,如果该文件以前是未合并的,则突然会合并。

请注意,如果我们处于冲突合并中,则我们要合并的提交的哈希ID存储在git checkout tree-ish path中。如果我们正处于樱桃选择的中间,则我们正在选择的提交的哈希ID在git checkout中。 (有关存储哈希ID的其他信息,请参见其他命令。)

因此,即使我们有意从{{1}中提取文件,即使暂存插槽2中的副本来自MERGE_HEAD提交,暂存插槽3中的副本也来自CHERRY_PICK_HEAD。 }}或HEAD进入索引,然后进入工作树,这会将文件写入暂存插槽零。效果是在解决合并的同时还选择了文件的(MERGE_HEAD版本或(HEAD)版本。

因此,对于没有困难名称的文件,命令:

MERGE_HEAD

诱骗选择HEAD,而:

MERGE_HEAD

巧妙地为git checkout HEAD $(git status --porcelain | grep '^UU ' | cut -f2-) 选择--ours(仅!)。 同样,除非您确切知道自己在做什么,否则不要使用它。