简体   繁体   English

从单个分支获取文件的所有版本

[英]Get all versions of a file from a single branch

Given a single branch in a git repository, how do I grab all versions of a file? 给定git存储库中的单个分支,如何获取文件的所有版本? The final desired output is one new output file per version (although printing all of the versions to STDOUT is fine as well, as long as it's easy to determine the extent of each version). 最终所需的输出是每个版本一个新的输出文件(尽管打印所有版本到STDOUT也很好,只要很容易确定每个版本的范围)。

Here's what I'm currently using: 这是我目前正在使用的:

branch=master
filename=...whatever...

myids=( $(git rev-list --objects $branch -- $filename | grep $filename | perl -e 'for (<>) { print substr($_, 0, 40) . "\n"; }') )

for (( i=0,j=1; i < ${#myids[@]}; i++,j++ )) 
    do
        echo $i $j
        name="output_$j.txt"
        git cat-file -p ${myids[$i]} > $name
    done

Explanation of what I'm doing: 解释我在做什么:

  • use rev-list to find relevant hashes 使用rev-list查找相关的哈希值
  • strip the hashes of commits and trees, leaving just the hashes of the files (these lines also include the filename) 剥离提交和树的哈希,只留下文件的哈希(这些行也包括文件名)
  • strip the filenames 剥离文件名
  • run the hashes through cat-file and generate output files 通过cat-file运行哈希并生成输出文件

The two main problems I have with this are that 1) it's not robust, because the grep could have false positives, and I'm not sure if it would follow file renames, and 2) it feels super hacky. 我遇到的两个主要问题是:1)它不健壮,因为grep可能有误报,我不确定它是否会跟随文件重命名,2)它感觉超级hacky。

Is there a better way to do this, perhaps making better use of git's API? 有没有更好的方法来做到这一点,也许更好地利用git的API?

Not the best solution, but it's one possibility 不是最好的解决方案,但这是一种可能性

If this is just a one-off thing that you're trying to do, you could try this with the following script, but it uses Git porcelain from version 1.9.4 though , so it's definitely not a robust, reliable solution, since it's dependent on what version of Git you're using: 如果这只是你想要做的一次性事情,你可以尝试使用以下脚本,但它使用1.9.4版本的Git瓷器 ,所以它绝对不是一个强大,可靠的解决方案,因为它是取决于您使用的Git版本:

#!/bin/bash
mkdir temp
filepath=osx/.gitconfig

for sha in $(git log --format="%H" $filepath); do
  git show $sha:$filepath > temp/$sha.file
done

It simply uses git log to find all commits that modified the file: 它只是使用git log来查找修改文件的所有提交:

$ git log --format="%H" osx/.gitconfig
338243aa6b68edad1dc3b2eebf66e108e9a4d685
7a4667138a519691386940ac23f9c8271ce14c77
475593a612141506f59a141e38b8c6a3a2917f85
03fa0711032cfdfc37fb431d60567ef22d75c7e5
3f7d8f0fc7e1d7a614f2aef8f53947ec2ce61296
c5fef8fccef3fc13f9dea17db209f2ceaab70002
287dadd8bcaf7e9197c6a16d57d3bacb72a41812
1f34ee1ab6965635a8f412bf3387f9dfdf197a1d

Then uses the <revision>:<filepath> syntax to output the version of the file from that revision. 然后使用<revision>:<filepath>语法从该修订版输出文件的版本。

git log can sometimes simplify your graph history though, so you might even want to pass the --full-history flag to git log , though I'm not exactly sure if it would be necessary for this particular use case. git log有时可以简化你的图形历史记录,所以你甚至可能希望将--full-history标志传递给git log ,尽管我不确定这个特定用例是否有必要。

How well would this follow renamed files though? 这会重命名文件的效果如何? You'd probably need to make the script a little smarter about keeping track of that, in order to use the right file path. 为了使用正确的文件路径,您可能需要使脚本更加智能地跟踪它。

Again, however, I'd like to emphasize that this is not the best solution , a better solution would make use of Git plumbing commands instead, since they won't be so dependent on the Git version, and will be more backward and forward compatible. 但是,我想再次强调, 这不是最佳解决方案 ,更好的解决方案是使用Git管道命令,因为它们不会如此依赖于Git版本,而且会更加落后和前进兼容。

Documentation 文档

I would suggest using git-log on the file itself, instead of git-rev-list : 我建议在文件本身使用git-log ,而不是git-rev-list

#!/bin/bash

filename=...whatever...

i=1
for hash in `git log --pretty=format:%H -- $filename`
do
    git show $hash:$filename > output_$i.txt
    ((i++))
done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM