轻便快速 Git 导出并获取提交 ID
Light and fast Git Export and fetch commit-id
如何将远程 git 存储库导出到本地 space,只获取给定分支的 head 修订版,然后对于每个导出的文件,获取该文件的提交 ID文件?
到目前为止我尝试了什么
执行这个:
git clone {gitUrl} {repoDir} --branch {branch}
然后对于每个这样导出的文件(忽略 .git 和内容),执行此:
git rev-list -1 HEAD {file}
... 以下位置标记是这样定义的:
{gitUrl}
是存储库的 http url。可以嵌入用户凭据。
{repoDir}
是您本地系统中导出的路径。
{file}
是您要为其提取提交 ID 的导出文件的完整路径。
虽然这可行,但问题是它太慢且效率低下。 git 克隆操作包括该分支的整个回购历史。而我们只对 HEAD 版本及其元数据感兴趣。
或者,我们可以执行导出:
git clone {gitUrl} {repoDir} --branch {branch} --depth 1
这样效率更高,因为它只是拉下 HEAD 版本。但问题在于,随后的 git rev-list -1 HEAD {file}
命令将 return 整个 HEAD 的提交 ID,而不是文件的提交 ID。
我可以把我的蛋糕也吃掉吗?
Can I have my cake and eat it too?
简短的回答是否定的。
长
从技术上讲,HEAD
提交 中每个文件的提交 ID 是 您使用 git rev-parse HEAD
获得的哈希 ID(或更长但等效的 git rev-list
你正在使用的命令)。那是因为每次提交都包含 每个 文件的完整快照 Git 知道。
当您使用 git rev-list
或 git log
或在 per-line-in-one-file、git blame
命令中回顾历史时得到的不是提交哈希 ID有问题的文件,因为那是微不足道的。相反,它是一些 较早 提交的提交哈希 ID,其中包含 相同的文件 或者,对于 git blame
,同一行.
也就是说,假设我们在 Git 存储库中有一个简单的线性历史记录,其中只有五次提交。我们可以这样绘制这五个提交:
A <-B <-C <-D <-E <--master
其中每个大写字母代表一个实际的提交哈希 ID。分支名称,在本例中为 master
,用于让我们找到提交 E
的实际哈希 ID,因为它看起来是随机的,否则很难或有时不可能找到。
提交 E
,当然,包含每个文件的完整快照,就像我们(或任何人)提交时的形式一样 E
。它还包含早期提交的哈希 ID D
。 Git 调用 D
提交 E
.
的 parent
但是提交 D
也有每个文件的完整快照,就像有人创建 D
时的形式一样,并且 link 回到 它的 parent C
。这重复 C
等等,回到整个历史(当我们点击 A
时结束,它没有 parent 提交)。
在这种情况下,我们想要的是Git 比较 某个文件的快照—README.md
, main.py
,或其他什么——出现在提交 E
中的那个和出现在其 parent 提交 D
中的那个。如果这两个快照 相同 ,我们希望 Git 将 D
与 C
进行比较。如果它们相同,Git 应该继续向后计算。它应该这样做,直到它用完 A
处的提交,或者比较显示两个文件不同。1
换句话说,我们在重复执行一个简单的比较操作:
- 文件 F 在提交 X 和 Y 中相同还是不同?
每 parent/child 对提交。一旦答案是“是的,它是不同的”,我们就会 Git 停止通过历史倒退 并打印此时到达的提交的哈希 ID。 (de-duplicates 文件跨提交的内部存储格式使这变得非常简单。使用 git blame
,计算相当困难和复杂,但它相当于同一件事,只是在 line-by-line 基础。)
不过,为了做到这一点,Git 必须能够访问 它需要遍历的每个提交,因为它会向后遍历历史。历史,在 Git 中, 是 存储库中的提交集。 Git必须有历史才能使用历史。
1Git 实际使用的一个简单而权宜的技巧是,当我们点击 parent-less(孤儿?)提交时 A
,它可以简单地假装在A
之前有一个完全空的提交。然后 A
中的每个文件都是新的,因此不同于它的 virtual/fake parent。这就是为什么每个 Git 存储库都包含 empty tree.
如何将远程 git 存储库导出到本地 space,只获取给定分支的 head 修订版,然后对于每个导出的文件,获取该文件的提交 ID文件?
到目前为止我尝试了什么
执行这个:
git clone {gitUrl} {repoDir} --branch {branch}
然后对于每个这样导出的文件(忽略 .git 和内容),执行此:
git rev-list -1 HEAD {file}
... 以下位置标记是这样定义的:
{gitUrl}
是存储库的 http url。可以嵌入用户凭据。{repoDir}
是您本地系统中导出的路径。{file}
是您要为其提取提交 ID 的导出文件的完整路径。
虽然这可行,但问题是它太慢且效率低下。 git 克隆操作包括该分支的整个回购历史。而我们只对 HEAD 版本及其元数据感兴趣。
或者,我们可以执行导出:
git clone {gitUrl} {repoDir} --branch {branch} --depth 1
这样效率更高,因为它只是拉下 HEAD 版本。但问题在于,随后的 git rev-list -1 HEAD {file}
命令将 return 整个 HEAD 的提交 ID,而不是文件的提交 ID。
我可以把我的蛋糕也吃掉吗?
Can I have my cake and eat it too?
简短的回答是否定的。
长
从技术上讲,HEAD
提交 中每个文件的提交 ID 是 您使用 git rev-parse HEAD
获得的哈希 ID(或更长但等效的 git rev-list
你正在使用的命令)。那是因为每次提交都包含 每个 文件的完整快照 Git 知道。
当您使用 git rev-list
或 git log
或在 per-line-in-one-file、git blame
命令中回顾历史时得到的不是提交哈希 ID有问题的文件,因为那是微不足道的。相反,它是一些 较早 提交的提交哈希 ID,其中包含 相同的文件 或者,对于 git blame
,同一行.
也就是说,假设我们在 Git 存储库中有一个简单的线性历史记录,其中只有五次提交。我们可以这样绘制这五个提交:
A <-B <-C <-D <-E <--master
其中每个大写字母代表一个实际的提交哈希 ID。分支名称,在本例中为 master
,用于让我们找到提交 E
的实际哈希 ID,因为它看起来是随机的,否则很难或有时不可能找到。
提交 E
,当然,包含每个文件的完整快照,就像我们(或任何人)提交时的形式一样 E
。它还包含早期提交的哈希 ID D
。 Git 调用 D
提交 E
.
但是提交 D
也有每个文件的完整快照,就像有人创建 D
时的形式一样,并且 link 回到 它的 parent C
。这重复 C
等等,回到整个历史(当我们点击 A
时结束,它没有 parent 提交)。
在这种情况下,我们想要的是Git 比较 某个文件的快照—README.md
, main.py
,或其他什么——出现在提交 E
中的那个和出现在其 parent 提交 D
中的那个。如果这两个快照 相同 ,我们希望 Git 将 D
与 C
进行比较。如果它们相同,Git 应该继续向后计算。它应该这样做,直到它用完 A
处的提交,或者比较显示两个文件不同。1
换句话说,我们在重复执行一个简单的比较操作:
- 文件 F 在提交 X 和 Y 中相同还是不同?
每 parent/child 对提交。一旦答案是“是的,它是不同的”,我们就会 Git 停止通过历史倒退 并打印此时到达的提交的哈希 ID。 (de-duplicates 文件跨提交的内部存储格式使这变得非常简单。使用 git blame
,计算相当困难和复杂,但它相当于同一件事,只是在 line-by-line 基础。)
不过,为了做到这一点,Git 必须能够访问 它需要遍历的每个提交,因为它会向后遍历历史。历史,在 Git 中, 是 存储库中的提交集。 Git必须有历史才能使用历史。
1Git 实际使用的一个简单而权宜的技巧是,当我们点击 parent-less(孤儿?)提交时 A
,它可以简单地假装在A
之前有一个完全空的提交。然后 A
中的每个文件都是新的,因此不同于它的 virtual/fake parent。这就是为什么每个 Git 存储库都包含 empty tree.