我有一个已重命名然后编辑的文件。我想告诉Git进行重命名,而不是内容修改。也就是说,我希望分阶段删除旧文件名,并使用新文件名添加旧文件内容。
所以我有这个:
Changes not staged for commit:
deleted: old-name.txt
Untracked files:
new-name.txt
但是想要这个:
Changes to be committed:
new file: new-name.txt
deleted: old-name.txt
Changes not staged for commit:
modified: new-name.txt
或这个:
Changes to be committed:
renamed: old-name.txt -> new-name.txt
Changes not staged for commit:
modified: new-name.txt
(相似度应为100%)。
我想不出一种简单的方法来做到这一点。
是否有语法来获取特定文件的特定修订版本的内容,并将其添加到指定路径下的git临时区域中?
使用的删除部分git rm
可以:
$ git rm old-name.txt
这是我努力使用的重命名的添加部分。(我可以mv
在外壳中保存新内容,在外壳中检出新副本(用于旧内容),git add
然后恢复新内容,但这似乎还有很长的路要走!)
谢谢!
Git并没有真正进行重命名。他们都计算在“事后”的时尚:git的比较,一个犯了另一个,并在比较时,决定是否有一个重命名。这意味着git是否认为某些“重命名”会动态更改。我知道您正在询问您甚至尚未做出的承诺,但是请忍受,这确实确实可以配合(但是答案会很长)。
当您询问git(通过git show
或git log -p
或git diff HEAD^ HEAD
)“上一次提交发生了什么情况”时,它会运行上一次提交的差异(HEAD^
或上一次提交HEAD~1
的实际原始SHA-1,其中的任何一个都会识别出它),并且当前提交(HEAD
)。在进行比较时,它可能会发现曾经有一个old.txt
,现在不再存在了。没有,new.txt
但现在有。
将这些文件名(曾经存在但不存在的文件,以及现在不存在的文件)放入堆中,并标记为“重命名的候选对象”。然后,对于堆中的每个名称,git会比较“旧内容”和“新内容”。精确匹配的比较非常容易,因为git可以将内容减少到SHA-1。如果完全匹配失败,则git切换到可选的“内容是否至少相似” diff来检查重命名。通过git diff
此可选步骤,由-M
标志控制。对于其他命令,它可以由您的git config
值设置,也可以硬编码到命令中。
现在,返回到暂存区域git status
:git在索引/暂存区域中存储的基本上是“下一次提交的原型”。当您执行git add
某些操作时,git会立即存储文件内容,在该过程中计算SHA-1,然后将SHA-1存储在索引中。当您执行git rm
某些操作时,git会在索引中存储一条注释,说明“在下次提交时有意删除此路径名”。
git status
然后,该命令仅执行一个差异(或实际上)两个差异:HEAD
vs索引,确定要提交的内容;以及索引与工作树的对比,以确认可能(但尚未)完成的工作。
在第一个差异中,git使用与以往相同的机制来检测重命名。如果HEAD
索引中的提交中有一条路径,而索引中的路径是新的而不是HEAD
提交中,则它是重命名检测的候选者。该git status
命令将重命名检测硬连线设置为“ on”(文件数限制为200;只有一个用于重命名检测的候选者,此限制就足够了)。
这对您的情况意味着什么?好了,您已重命名了文件(不使用git mv
,但这并不重要,因为git status
找到重命名或git status
一次找不到它),现在有了新文件的不同版本。
如果您使用的git add
是新版本,则该较新的版本将进入存储库,并且其SHA-1处于索引中,并且在进行git status
比较时,它将比较新旧版本。如果它们至少具有“ 50%相似”(的硬连线值git status
),则git会告诉您文件已重命名。
当然,git add
-ing修改后的内容并不是您所要求的:您想要进行一次中间提交,其中仅重命名文件,即,使用新名称的树进行提交,但使用旧内容。
你不必有这样做,因为所有的上述动态重命名检测的。如果您想这样做(无论出于何种原因)...好吧,git并没有那么容易。
最直接的方法就是您所建议的:将修改后的内容移到某个地方,先使用git checkout -- old-name.txt
,然后git mv old-name.txt new-name.txt
再提交。该git mv
都将重新命名索引/舞台区的文件,并重新命名工作树版本。
如果git mv
有--cached
类似的选择git rm
,那么您可以git mv --cached old-name.txt new-name.txt
然后选择git commit
。第一步将重命名索引中的文件,而无需触摸工作树。但事实并非如此:它坚持覆盖工作树版本,并且坚持旧名称必须存在于工作树中才能启动。
无需接触工作树即可执行此操作的单步方法是使用git update-index --index-info
,但这也有些混乱(无论如何,我会在稍后展示)。幸运的是,我们可以做的最后一件事。通过将旧名称重命名为新名称并修改文件,我设置了与您相同的情况:
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: old-name.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
new-name.txt
现在我们要做的是,首先手动将文件放回其旧名称下,然后使用git mv
再次切换到新名称:
$ mv new-name.txt old-name.txt
$ git mv old-name.txt new-name.txt
这次git mv
更新了索引中的名称,但是将原始内容保留为索引SHA-1,但是将工作树版本(新内容)移入了工作树中的位置:
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: old-name.txt -> new-name.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: new-name.txt
现在只是git commit
使用重命名而不是新内容进行提交。
(请注意,这取决于没有旧名称的新文件!)
那使用git update-index
呢?好吧,首先让我们回到“工作树已更改,索引匹配HEAD commit”状态:
$ git reset --mixed HEAD # set index=HEAD, leave work-tree alone
现在,让我们看看索引中的内容old-name.txt
:
$ git ls-files --stage -- old-name.txt
100644 2b27f2df63a3419da26984b5f7bafa29bdf5b3e3 0 old-name.txt
因此,我们需要git update-index --index-info
做的是清除的条目,old-name.txt
但在以下方面进行相同的输入new-name.txt
:
$ (git ls-files --stage -- old-name.txt;
git ls-files --stage -- old-name.txt) |
sed -e \
'1s/^[0-9]* [0-9a-f]*/000000 0000000000000000000000000000000000000000/' \
-e '2s/old-name.txt$/new-name.txt/' |
git update-index --index-info
(注意:我出于发布目的将上面的内容拆开了,当我键入时全部是一行;在sh / bash中,由于我添加了反斜杠以继续执行“ sed”命令,因此应该像这样分解它) 。
还有其他方法可以执行此操作,但是只需将索引条目提取两次,然后将第一个条目修改为删除项,然后使用新名称将第二个条目修改为最简单的方法,因此使用此sed
命令。第一个替换更改文件模式(100644,但任何模式都将变为全零)和SHA-1(与任何SHA-1匹配,替换为git的特殊全零SHA-1),第二个替换将更改文件模式和单独使用SHA-1替换名称。
更新索引完成后,索引记录了旧路径的删除和新路径的添加(模式和SHA-1与旧路径相同)。
请注意,如果索引具有未合并的条目,这可能会严重失败,old-name.txt
因为文件可能还有其他阶段(1到3)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句