Получить все версии файла из одной ветки

Если в git-репозитории есть одна ветка, как мне получить все версии файла? Конечный желаемый результат - один новый выходной файл на версию (хотя печать всех версий в STDOUT также хороша, если легко определить степень каждой версии).

Вот что я сейчас использую:

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

Объяснение того, что я делаю:

  • использование rev-list найти соответствующие хеши
  • убрать хеши коммитов и деревьев, оставив только хэши файлов (эти строки также включают имя файла)
  • лишить имена файлов
  • прогонять хеши cat-file и генерировать выходные файлы

У меня есть две основные проблемы: 1) это не очень надежно, потому что grep может иметь ложные срабатывания, и я не уверен, что он будет следовать за переименованием файлов, и 2) он чувствует себя супер хаки.

Есть ли лучший способ сделать это, возможно, лучше использовать API Git?

2 ответа

Решение

Не лучшее решение, но это одна из возможностей

Если это единственная вещь, которую вы пытаетесь сделать, вы можете попробовать это с помощью следующего сценария, но он использует фарфор Git версии 1.9.4, так что это определенно не надежное и надежное решение, так как зависит от того, какую версию 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

Он просто использует git log чтобы найти все коммиты, которые изменили файл:

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

Затем использует <revision>:<filepath> синтаксис для вывода версии файла из этой ревизии.

git log иногда может упростить историю вашего графика, так что вы можете даже передать --full-history флаг для git logХотя я не совсем уверен, будет ли это необходимо для этого конкретного случая использования.

Насколько хорошо это будет следовать за переименованными файлами? Вам, вероятно, нужно сделать скрипт немного умнее, чтобы отслеживать это, чтобы использовать правильный путь к файлу.

Опять же, однако, я хотел бы подчеркнуть, что это не лучшее решение, лучшее решение будет использовать вместо этого команды Git-системы, так как они не будут сильно зависеть от версии Git и будут более обратными и прямыми. совместимы.

Документация

Я бы предложил использовать 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
Другие вопросы по тегам