Как изменить сообщение в git stash? - PullRequest
0 голосов
/ 16 мая 2018

Предположим, я слишком быстро поместил тайник в git и не предоставил информативного сообщения. Я хотел бы изменить сообщение в тайнике, но не могу найти способ сделать это из git docs. Я мог бы привести репозиторий в чистое состояние, а затем вытолкнуть тайник и повторно применить w / git stash сохранить «мое сообщение о сохранении», но мне было интересно, есть ли у кого-нибудь решение для изменения сообщения на месте.

1 Ответ

0 голосов
/ 17 мая 2018

Это технически невозможно, но легко достичь желаемой цели с помощью обмана. Git просто не имеет встроенного механизма для выполнения хитрости, даже если git commit имеет опцию --amend, которая делает именно это. (Для этого также нет чистого способа угнать git commit --amend.)

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

Технические подробности, если вы хотите создать скрипт

Под прикрытием команд и опций командной строки Git и т. Д. Запись Git stash на самом деле является коммитом. Точнее, это как минимум два коммита, а иногда три. Документация git stash описывает это (довольно легко и небрежно) в разделе, обозначенном ОБСУЖДЕНИЕ. Особенность коммитов git stash заключается в том, что они находятся на нет ветви - ну, что и что фиксация w (рабочее дерево) в кластере, то есть та, которую находит ссылка refs/stash, имеет форму фиксации слияния, так что она может перечислить несколько идентификаторов родительской фиксации. Я предпочитаю рисовать их так:

...--F--G   <-- branch
        |\
        i-w   <-- (the stash)

или

...--F--G   <-- branch
        |\
        i-w   <-- (the stash)
         /
        u

, который немного отличается от чертежа документации Git, но показывает, как то, что я называю шкатулкой (с необязательным u коммитом, содержащим неотслеживаемые файлы), свисает с коммитом это было актуально, когда вы сделали тайник. (Если вы еще не переместили ваш HEAD в другое место, этот коммит будет все еще текущего коммита.) Заглавные буквы здесь обозначают реальные хэши коммитов, которые большие и некрасивые и которые невозможно запомнить.

Как и во всех коммитах, специальные тайники являются только для чтения - их нельзя изменить, они могут забыть только свои хэш-идентификаторы (что делает git stash drop).

Обратите внимание, что git commit --amend фактически делает новый коммит, отодвигая текущий (HEAD) коммит в сторону. То есть, если мы начнем с:

...--F--G   <-- branch (HEAD)

и запустите git commit --amend, Git делает новый коммит - назовем это G2 - чей родитель F, а не обычная идея использования G в качестве G2 parent, затем записывает ID G2 в ветку, давая нам:

       G
      /
...--F--G2  <-- branch (HEAD)

До тех пор, пока старый коммит G не имеет имени, по которому мы можем его найти, Git никогда не показывает его нам и в конечном итоге полностью его отбрасывает, создавая впечатление, будто мы каким-то образом изменили коммит G на * 1060. *.

Чтобы существующая запись в stash имела другой комментарий о коммите, нам нужно было бы сделать то же самое: мы скопировали бы наш существующий w коммит в новый коммит, с другим сообщением о коммите , но сохраните w content и все его родительские хеши. Если мы позвоним на замену w2, мы получим:

...--F--G_  <-- branch
        |\`-.
        i-w2 \
         \    \
          -----w   <-- (the stash)

Если мы затем перенаправим refs/stash, чтобы указать w2 вместо w, и притворимся, что w больше не существует, мы получим то, что хотим:

...--F--G   <-- branch
        |\
        i-w2  <-- (the stash)

и фактически мы можем написать это как скрипт, начиная с следующих фрагментов кода:

# get the parents of refs/stash as $1 and $2; $3 exists if there is a u commit
set -- $(git rev-parse refs/stash^@)
# convert these to "-p $1 -p $2 -p $3"
case $# in
2) parents="-p $1 -p $2";;
3) parents="-p $1 -p $2 -p $3";;
*) fatal "refs/stash does not appear to be a valid stash";;
esac
# find the stashed w commit's tree
tree=$(git rev-parse refs/stash^{tree}) || exit
# optional: for editing purposes, gather the current message
existing_message=$(git log --no-walk --pretty=format:%B refs/stash)

# obtain an updated message in some fashion
[snip]

и затем:

# create a new w commit, suitable for "git stash store"
new_w_commit=$(git commit-tree $parents "$new_message" $tree)

и в конечном итоге:

git stash drop --quiet
git stash store --quiet -m "$new_message" $new_w_commit

, который использует сам скрипт git stash для замены stash@{0} новым тайником. (В случае прерывания может быть разумнее изменить порядок этих двух операций. Выяснение того, как сделать это с помощью ссылки stash@{n}, оставлено в качестве упражнения. Ничего из этого даже не проверено дистанционно.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...