如何在不进行后续git编辑的情况下进行重命名?

大黄

我有一个已重命名然后编辑的文件。我想告诉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 showgit log -pgit 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然后,命令仅执行一个差异(或实际上)两个差异:HEADvs索引,确定要提交的内容;以及索引与工作树的对比,以确认可能(但尚未)完成的工作。

在第一个差异中,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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在不运行js或不进行后续请求的情况下使用Phantomjs打开页面?

如何在不进行迁移的情况下卸载 macports?

如何在不进行配置的情况下启动tmux?

如何在不进行提取的情况下预览git-pull?

如何在不清除终端的情况下进行编辑?

如何在不进行编组的情况下针对JAXB 2.0中的架构进行验证?

如何在不进行动态查询的情况下对字符串进行SQL查询

如何在不进行操作的情况下对熊猫数据框进行分组或聚合

如何在不进行“静音应用”操作的情况下进行持续的可穿戴设备通知

如何在不进行组合爆炸的情况下进行多个支撑扩展?

如何在不进行聚合的情况下进行数据透视,这可能吗?

如何在不进行高频交易的合计交易的情况下进行之前的报价汇总

如何在不进行不必要的重新编译的情况下使Git commit哈希在C ++代码中可用?

GIT-如何在不进行更改的情况下切换分支,反之亦然

如何验证GIT分支是否只能在不进行实际合并的情况下快速合并?

Python / Matplotlib-如何在不进行硬编码的情况下计算/绘制导数?

JavaScript:如何在不进行ISO日期转换的情况下JSON.Stringify Date对象

如何在不进行所有升级的情况下解决问题?

如何在不进行实际打印的情况下从(错误)对象中生成字符串?

如何在不进行任何导入的情况下随机播放N个大小的数组

对象如何在不进行 db 调用的情况下从 DB 获取最新值?

Glassfish服务器如何在不进行servlet映射的情况下提供静态资源

如何在不进行强制转换的情况下取消引用void变量

如何在不进行动态导入的情况下将Commons JS拆分?

如何在不进行外部缓存的情况下将“ this”传递到Promise中?

如何在不进行追溯的情况下创建Power BI数据透视表?

如何在不进行重新分区和copyMerge的情况下合并Spark结果文件?

如何在不进行类型转换的情况下将flatten实现为数组的扩展?

如何在不进行npm安装的情况下更新package-lock.json?