我知道通过以下命令签出两个修改后的文件有很长的路要走。
git add <filename>
git reset HEAD <filename>
git checkout <filename>
但是有一个命令可以检出所有“未合并的路径”吗?
答案 0 :(得分:3)
您列出的命令序列将 not 生成--theirs
版本。相反,它在工作树和索引中都生成--ours
版本。有几种方法可以用更少的命令和多个路径名来实现这一目标。
第二种短路方法也许是您应该使用的方法:
git checkout --ours path1 path2 ... pathN
或:
git checkout --theirs path1 path2 ... pathN
后跟git add
相同的路径。 请务必确定可以针对合并基础抛出他们或您所做的更改!请特别注意是合并基础,以便您知道您保留的东西和扔掉的东西。
要缩短此步骤,可以使用git checkout HEAD
或git 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.txt
在HEAD
提交中查看副本。同样,您可以使用git show HEAD:README.txt
在索引中查看副本,其中前导冒号是索引中文件的特殊Git语法。
通常,您通过git show :README.txt
将新版本复制到索引中,该版本仅采用当前工作树中的所有内容,然后将其复制到索引/临时区域中,从而覆盖(单个)先前的副本。但是,当您在git add README.txt
或git merge
或git cherry-pick
或git 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
。README.txt
。: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
(仅!)。 同样,除非您确切知道自己在做什么,否则不要使用它。