Подтвердить что ты не робот

Git для сохранения сохранения без изменения рабочего дерева?

Я хотел бы использовать команду git, которая сохраняет кошелек без изменения моего рабочего дерева, в качестве облегченной резервной копии, которая может быть сэкономлена от любых сбросов git или что бы я ни делал, чтобы испортить мой индекс. В основном функциональный эквивалент "git stash save & git stash apply", за исключением того, что рабочая копия никогда не затрагивается, так как это может сделать некоторые текстовые редакторы /IDE запутанными.

Что-то вроде этого приближается к тому, что я хочу, но не совсем:

git update-ref refs/stash `git stash create "Stash message"`

Это работает функционально, но проблема, с которой я сталкиваюсь, заключается в том, что в "git stash list" не появляется сообщение о зашифрованном виде, даже несмотря на то, что в фактическом фиксации stash есть мое сообщение. Учитывая, насколько большой может быть прикрытие, сообщения о зашифрованном виде очень важны.

4b9b3361

Ответ 1

Благодаря подсказке Чарльза я взломал сценарий bash, чтобы делать именно то, что я хотел (у меня возникали проблемы, реализующие это как только псевдоним). Он принимает необязательное сообщение, как git stash save. Если ни один не указан, он будет использовать сообщение по умолчанию, сгенерированное с помощью git stash.

#!/bin/sh
#
# git-stash-snap
# Save snapshot of working tree into the stash without modifying working tree.
# First argument (optional) is the stash message.
if [ -n "$1" ]; then
        git update-ref -m "$1" refs/stash "$(git stash create \"$1\")"
else
        HASH='git stash create'
        MESSAGE='git log --no-walk --pretty="tformat:%-s" "$HASH"'
        git update-ref -m "$MESSAGE" refs/stash "$HASH"
fi

Изменение: Как указано в комментарии ниже, сохранение этого скрипта в виде git-stash-snap где git-stash-snap то на вашем пути достаточно, чтобы вызвать его, набрав git stash-snap.

Приятно то, что даже если вы сбросите кошелек, сделанный с помощью этого метода, вы все равно сможете увидеть сообщение с помощью git log [commit-hash] из оборванного фиксации!

Изменение: поскольку git 2.6.0 вы можете добавить --create-reflog для update-ref а затем git stash list покажет это, даже если git stash не использовался.

Edit: Git ввел новую подкоманду stash под названием stash push поэтому я обновил свою рекомендацию по присвоению имени этого скрипта из git-stash-push для git-stash-snap.

Ответ 2

Вам нужно передать сообщение update-ref, а не stash create, так как stash create не принимает сообщение (он не обновляет никакой ссылки, поэтому он не имеет записи reflog для заполнения).

git update-ref -m "Stash message" refs/stash "$(git stash create)"

Ответ 3

Вдохновленный решением Элиот, я немного расширил его script:

#!/bin/sh
#
# git-stash-push
# Push working tree onto the stash without modifying working tree.
# First argument (optional) is the stash message.
#
# If the working dir is clean, no stash will be generated/saved.
#
# Options:
#   -c "changes" mode, do not stash if there are no changes since the
#      last stash.
if [ "$1" == "-c" ]; then
        CHECK_CHANGES=1
        shift
fi


if [ -n "$1" ]; then
        MESSAGE=$1
        HASH=$( git stash create "$MESSAGE" )
else
        MESSAGE=`git log --no-walk --pretty="tformat:%-s" "HEAD"`
        MESSAGE="Based on: $MESSAGE"
        HASH=$( git stash create )
fi

if [ "$CHECK_CHANGES" ]; then
        # "check for changes" mode: only stash if there are changes
        # since the last stash

        # check if nothing has changed since last stash
        CHANGES=$( git diff [email protected]{0} )
        if [ -z "$CHANGES" ] ; then
                echo "Nothing changed since last stash."
                exit 0
        fi
fi

if [ -n "$HASH" ]; then
        git update-ref -m "$MESSAGE" refs/stash "$HASH"
        echo "Working directory stashed."
else
        echo "Working tree clean, nothing to do."
fi

Я внедрил следующие изменения в Eliot script:

  • Когда рабочий каталог будет чистым, script выйдет изящно
  • Когда используется переключатель -c, если нет изменений по сравнению с последним типом, script выйдет. Это полезно, если вы используете этот script как "машину времени", делая автоматизированный тайник каждые 10 минут. Если ничего не изменилось, новый штамп не создается. Без этого переключателя вы можете закончить с n последовательными записями, которые являются одинаковыми.

Не для того, чтобы коммутатор -c работал правильно, должен существовать хотя бы один тайник, иначе script выдает ошибку на git diff [email protected]{0} и ничего не сделает.

Я использую этот script как "машину времени", моментальный снимок каждые 10 минут, используя следующий цикл bash:

 while true ; do date ; git stash-push ; sleep 600 ; done

Ответ 4

git stash store "$(git stash create)"

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

Если вы проверите список stash или посмотрите на весь граф коммитов (включая stash), то увидите, что он аналогичен результату, который вы получите при обычном вызове git stash. Просто сообщение в списке хранилищ отличается (обычно это что-то вроде "stash @{0}: WIP на master: 14e009e init commit", здесь мы получим "stash @{0}: созданный через" git stash store "")

$ git status --short
M file.txt
A  file2.txt

$ git stash list

$ git stash store "$(git stash create)"

$ git stash list
[email protected]{0}: Created via "git stash store".

$ git stash show '[email protected]{0}'
 file.txt  | 2 +-
 file2.txt | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

$ git log --oneline --graph --all
*   85f937b (refs/stash) WIP on master: 14e009e init commit
|\
| * 26295a3 index on master: 14e009e init commit
|/
* 14e009e (HEAD -> master) init commit

$ git status
M file.txt
A  file2.txt

Немного больше объяснений:

Запись git stash представлена с использованием обычных коммитов с некоторой определенной структурой. По сути, это обычный объект фиксации, у которого есть 2 родителя (или 3, если вы используете опцию --include-untracked) (дополнительная информация 1, 2).

git stash create создает этот коммит, представляющий запись stash, и возвращает вам имя объекта (SHA-1) объекта коммита (тот, у которого есть 2 или 3 родителя). Это висячий коммит (вы можете проверить его, вызвав git fsck после git stash create). Вы должны указать refs/stash на этот висячий коммит и сделать это с помощью git stash store (или с помощью git update-ref как в других ответах, потому что git stash store использует git update-ref для своей работы).

Было бы полезно взглянуть на реальный исходный код git stash push и увидеть, что он в основном вызывает git stash create и git stash store а затем выполняет некоторую логику для очистки файлов (что зависит от того, какие опции вы использовали в git stash push).

Ответ 5

git stash && git stash apply

И если вы предпочитаете свой тайник с комментарием:

git stash save "stash comment" && git stash apply