Найти и извлечь файл из Git stash

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

Вопрос 1:

  • Как я могу найти имя файла во всех моих текущих записях?

Вопрос 2:

  • Как я могу извлечь этот файл в отдельную папку?

  • или другой вариант: как запустить средство визуального разграничения для этого файла с сохраненными файлами?

Ответ 1

Немного более важно отметить, что refs/stash является reflog псевдо-ветки (ref):

git rev-list --walk-reflogs stash # (long option)
git rev-list -g stash # (short option)

Итак, вы можете найти файл:

for sha in $(git rev-list -g stash); 
do 
     git ls-tree -r $sha:; 
done |
   grep "$SOMEFILENAME" | 
   sort --unique

(Уникальный вид - удалить дубликаты одной и той же версии в разных записях).

например:.

$ for sha in $(git rev-list -g stash); do git ls-tree -r $sha:; done | grep numeric.js | sort -u
100644 blob f1c9a61910ae1bbd562615444a45688b93e9d808    LSPO.Web/DaVinci/JScript/numeric.js

Итак, вы можете запустить визуальный diff, например,

kompare numeric.js <(git cat-file -p f1c9a61910ae1bbd562615444a45688b93e9d808)

Конечно, если у вас уже была догадка, в которой reflog содержал другой файл, это было бы намного проще:

git diff [email protected]{3} -- numeric.js 

Ответ 2

Ответ от @sehe дает отличный ответ для Вопроса 2.

Я пришел на эту страницу, чтобы найти лучший ответ на вопрос 1, чем то, что я сейчас использую. В настоящее время я использую оболочку script stashshowall.sh, а затем я выводит результат.

Разница в моем ответе заключается в том, что, в то время как другие ответы здесь говорят вам, был ли изменен файл, который вы ищете, они не сообщают вам, какой штамп находится в файле, если вы хотите apply занести.

Мой ответ - чистое использование "фарфоровых" команд git, но оно работает для меня.

#!/bin/sh
#  stashshowall.sh
for stash in `git stash list | sed 's/\(\w*\)\:.*/\1/'`
do
    echo
    echo "$stash"
    git stash show $stash
done

Итак, чтобы ответить на вопрос 1, я запустил

> stashshowall.sh | grep "stash\|some-file"

который дает мне

[email protected]{0}
[email protected]{1}
 .../some-dir/some-file     | 16 ++--
[email protected]{2}
[email protected]{3}
[email protected]{4}
 .../some-dir/some-file     | 2 ++--
[email protected]{5}

Таким образом, я знаю, что мне нужно apply или смотреть дальше на stash{1} или stash{4}

Ответ 3

TL;DR

grep stash для имени файла:

git reflog stash -- '*fileglob*'
git log -g stash -- '*fileglob*'

grep stash для контента:

git stash list -G<regex>

Поиск записи для имени файла

Из git help stash:

Последний созданный тэг хранится в refs/stash; более старые stashes найдены в reflog этой ссылки и могут быть названы с использованием обычного синтаксиса reflog (например, [email protected]{0}...)

Из git help reflog:

git reflog show является псевдонимом для git log -g --abbrev-commit --pretty=oneline

Из git журнал справки:

-g
- ходить reflogs
Вместо того, чтобы следовать цепочке родословной фиксации, пройдите записи рефлога от самых последних до более старых.

git синопсис журнала:

git log [<options>] [<revision range>] [[\--] <path>...]

Из git спецификации ревизий:

<refname>, например. мастер, руководители/мастер, refs/heads/master
Символическое имя ссылки....
При двусмысленности a <refname> устраняется неоднозначно, принимая первое совпадение в следующих правилах:

  • Если $GIT_DIR/<refname> существует, это то, что вы имеете в виду (обычно это полезно только для HEAD, FETCH_HEAD, ORIG_HEAD, MERGE_HEAD и CHERRY_PICK_HEAD);

  • в противном случае refs/<refname>, если он существует;

Теперь у нас есть все вместе:

git reflog stash -- '*fileglob*'
git log -g stash -- '*fileglob*'

Итак, мы stash будем решать refs/stash, а -g приведет к прохождению всей ветки, а `- 'fileglob будет соответствовать любым путям в этой фиксации.

Поисковый штамп для контента

git help stash:

... Команда принимает параметры, применимые к команде журнала git, чтобы контролировать, что показано и как. См. git-log.

Из git журнал справки:

-G <regex>
Ищите различия, в тексте патча которых добавлены/удалены строки, соответствующие <regex>.

Итак, простая команда:

git stash list -G<regex>

Другие команды pickaxe также должны работать.

Ответ 4

Я использую это для поиска файла среди штампов

git stash list | cut -d ":" -f 1 | xargs -L1 git diff --stat | grep <filename>

Вы можете создать новую ветку, содержащую stash (git checkout -b <new_branch> <stash>), а затем скопировать файл туда и обратно, чтобы слить его обратно.

Вы можете использовать git difftool, чтобы получить визуальное представление об отличии.

РЕДАКТИРОВАТЬ: Чтобы получить фиксацию кошелька вместе с именем файла, вы можете использовать эту оболочку script:

for i in $(git stash list | cut -d ":" -f 1 | xargs -L1 git show | grep commit |
  cut -d" " -f 2)
do
  if git show $i --oneline --stat | grep ht.h 
  then
    echo $i
  fi
done

Он распечатает фиксацию под именем файла.