如何仅使用plumbing命令复制git-checkout?

17

我希望避免在我的脚本中调用porcelain命令,但是否有一种方法可以仅使用plumbing命令(例如checkout-index)获得git checkout <commit>的某些行为呢? 我特别关注对工作副本的影响:假设一切都很干净,checkout删除旧HEAD中跟踪的并且在新HEAD中不存在的文件。 checkout-index似乎没有任何删除文件的概念。我能想到的最接近的方法是调用:

git diff-tree -p <old> <new> | git apply

但计算整个差异似乎是不必要的昂贵操作。是否有更好的方法?


3
为什么不直接使用 git checkout ... 命令呢? - Oliver Charlesworth
是的,不要让你的生活变得不必要地艰难。 - ThiefMaster
1
最终我希望能更好地控制结账的过程。例如,checkout 命令可以清除被忽略的文件,但我希望避免这样做(增加安全性)。不过,我确实希望覆盖已删除的文件(降低安全性),而不使用 --force 参数来覆盖所有文件。这是一个使用 Git 存储文件树的脚本的一部分,checkout 命令与我期望脚本行为非常接近,但还不完全符合我的要求。我认为如果能通过内部命令获取 checkout 的功能,然后进行调整,但如果有其他方法可以实现这种控制,请告诉我。 - Jack O'Connor
1
你实际测试了diff-tree很慢吗?checkout基本上会进行所有差异比较以确定首先要做什么。(当然,checkout不会创建补丁然后应用它们,也可能您也不应该这样做。) - Edward Thomson
@EdwardThomson diff-tree 可能是我想要的,但我不确定要将其输出导入到哪里。除了上面的 git apply hack 之外,有没有一种方法可以将此 diff 应用于工作副本?编写一个 Python 脚本以获取删除列表并实际执行它们很容易,但我担心这会很慢。 - Jack O'Connor
1个回答

12
你正在寻找 两棵树的 git read-tree -um。它使用一个基础树(通常是HEAD),一个目标树,以及(隐式地)索引和工作树。描述其行为的表格对我来说很难理解,所以我有自己的备忘单,重新格式化后更容易理解。无论如何,它实现了git checkout
git read-tree -um H M  # `I` is the (implicit) index, GIT_INDEX_FILE

                    Legend

        H       Original tree (usually HEAD:)
        I       Indexed tree
        M       Merge target tree

        H->I     \
        H->M      } status in second relative to first
        I->M     /

        "-"     file exists in neither
       new      exists only in second
       deleted  exists only in first
       same     exists in both, unchanged
       changed  exists in both, different
      (blank)   irrelevant or all cases not otherwise given

        keep    keep current version
        fail    whole command fails, no changes
       delete   delete worktree file


      H->I      H->M      I->M

                          same     keep

     deleted   changed             fail
     deleted   deleted             delete
     deleted    same               delete unless Index empty, else use M
                same               keep

      same     changed             worktree clean: use M; dirty: fail
      same     deleted             worktree clean: deleted; dirty: fail

      new        -                 keep
      new       new      changed   fail
     changed   changed   changed   fail
     changed   deleted             fail


note: "index empty" identifies an initial checkout, where HEAD has been
set but never loaded.  git can't currently distinguish between a
delete-everything index and an initial-checkout index.

+1. 我喜欢这个速查表。我已经用 git read-tree -um 的示例完成了我的答案。 - VonC
谢谢!我从来没有想到过。 - Jack O'Connor
不客气。我也猜不到,有时候很难看出你可以让git做什么。我知道我真正理解这个命令是在我对文档中的表格感到生气并花时间制作自己的表格之后。 - jthill

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接