как определить происхождение заначки - PullRequest
0 голосов
/ 07 ноября 2018

У меня проблемы с выполнением

git stash pop

из-за некоторых проблем с dos2unix. Я хочу вернуться к работе с тайником, не объединяя целые файлы, которые отличаются только окончаниями строк. Я думал о возвращении в тайник после выполнения

git checkout BRANCHNAME

но я не знаю, как определить BRANCHNAME, которая представляет происхождение этого тайника. У кого-нибудь есть подсказка?

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018

TL; DR

Используйте git stash branch до , создайте новую ветку и примените тайник:

git stash branch newbranch

Это всегда работает (ну, пока ваш текущий статус все чист: смотрите длинный раздел ниже) и является эквивалентом создания новой ветви, чей родитель является коммитом, который был текущим, когда вы сделали тайник, а затем запустил git apply --index (это означает, что он восстанавливает индекс и рабочее дерево отдельно).

Буквальный ответ на вопрос

Все, что вам нужно сделать, это выяснить, идентифицируют ли какие-либо имена ветвей тот же коммит, что и родительский элемент рассматриваемого тайника, поэтому:

git for-each-ref --format='%(refname:short)' \
    --points-at $(git rev-parse refs/stash~1) refs/heads

найдет возможные имена ветвей, если они есть. (Это опирается на относительно современные функции git for-each-ref.)

Long

Каждый тайник сам по себе - всего два, а иногда и три коммита. git stash делает то, что делает эти два (или три) коммита, но помещает их в no ответвление.

Слово branch в Git само по себе немного неоднозначно (см. Что именно мы подразумеваем под «веткой»? ), но здесь мы используем его в том смысле, что ветка имя , как master или develop, просто указывает на последний коммит в его ветке:

...--E--F--G   <-- master
         \
          H   <-- develop

Когда вы git checkout называете ветку типа develop, вы говорите Git:

  1. Извлечение содержимого этого коммита в индекс (место, где вы строите следующий коммит, также называемый промежуточной областью или иногда кеш )
  2. Извлеките из индекса индексированные, но все еще сжатые файлы Git-формы / сжатые и скопируйте их в рабочее дерево , где вы можете работать с ними.
  3. Прикрепите имя HEAD к имени ветки, чтобы Git знал, какой коммит вы уже извлекли:

    ...--E--F--G   <-- master
             \
              H   <-- develop (HEAD)
    

    Теперь Git знает, что коммит, хеш которого H, является текущим или HEAD коммитом, на что указывает имя develop.

Если в этот момент вы делаете обычный новый коммит (копируя обновленные или новые файлы из рабочего дерева обратно в область index / staging, а затем запускаете git commit, чтобы заморозить их в новый коммит), Git пишет: новый коммит с текущим коммитом в качестве родителя, а затем обновляет имя ветви:

...--E--F--G   <-- master
         \
          H--I   <-- develop (HEAD)

Имя HEAD остается присоединенным к имени ветви, но теперь имя ветви идентифицирует commit I вместо commit H.

Что делает git stash, так это делает две фиксации - одну для индекса и одну для рабочего дерева - чтобы не имели имени ветви . Вместо этого Git использует имя refs/stash, чтобы найти фиксацию ww находит как оригинальную фиксацию, так и фиксацию i):

...--E--F--G   <-- master
         \
          H   <-- develop (HEAD)
          |\
          i-w   <-- refs/stash

После сохранения коммитов i и w git stash запускает git reset --hard, чтобы вернуть индекс и рабочее дерево в соответствие с текущим коммитом (здесь H).

В этом случае в данный момент времени родительский коммит тайника также указывается существующим именем ветви develop. Но предположим, что вы сделали это git stash, а затем пошли на другой набор изменений и сделали новый коммит I? Тогда у вас есть:

...--E--F--G   <-- master
         \
          H--I   <-- develop (HEAD)
          |\
          i-w   <-- refs/stash

Теперь нет имени ветви, указывающего на существующий, исторический коммит H, хотя это единственный коммит, к которому гарантированно применяется refs/stash.

Итак, если ваш индекс и рабочее дерево теперь чистые (т. Е. Соответствуют содержимому коммита I, к которому прикреплен HEAD), и вы теперь запускаете git stash branch recover, что будет делать git stash это прикрепить новое имя ветки, recover, чтобы зафиксировать H, и проверить этот коммит и сделать новую ветку текущей веткой, прикрепив к ней HEAD:

...--E--F--G   <-- master
         \
          H   <-- recover (HEAD)
           \
            I   <-- develop

и, в качестве последнего шага операции git stash branch, примените и отбросьте тайник, чтобы индекс вернулся к тому же индексу, который был при извлечении H и запуске git stash, и работе -дерево вернулось к тому, как работало дерево, когда вы H проверили и запустили git stash. Теперь вы можете закончить git add ing и git commit, чтобы сделать новый коммит J:

...--E--F--G   <-- master
         \
          H--J   <-- recover (HEAD)
           \
            I   <-- develop

Что если develop все еще указывает на фиксацию H?

Если вы не не переместили предыдущую ветку, то теперь у вас есть новая ветка. То есть теперь вместо приведенного выше рисунка вы бы получили:

...--E--F--G   <-- master
         \
          H   <-- develop
           \
            J   <-- recover (HEAD)

(я оставил новый коммит здесь как J, чтобы было проще сопоставить его с предыдущей диаграммой). Там нет ничего плохого в этой настройке. Конечно, если вы не хотите ветку recover здесь, вам не нужно использовать git stash branch, но она все еще работает.

А как насчет трёхкомпонентного тайника?

Трехкомпонентные тайники сделаны git stash save -a (--all) или git stash save -u (--include-untracked). Применение (или выталкивание) такого тайника требует, чтобы файлы в третьем коммите не сталкивались с файлами в рабочем дереве. В общем, это означает, что рабочее дерево должно быть не только «чистым» в соответствии с git status, но также и чистым в том смысле, в котором оно запускается с помощью git clean с соответствующими параметрами. В этом конкретном случае даже git stash branch может иногда давать сбой. Если это не удается, он оставляет тайник без присмотра.

Подробнее см. Почему в git stash pop говорится, что он не может восстановить неотслеживаемые файлы из записи stash?

0 голосов
/ 07 ноября 2018

git stash list, вероятно, даст вам то, что вы хотите.

Если вы сохранили свой тайник с помощью git stash save или git stash push, то git добавил комментарий к тайнику, который включает в себя имя ветви и конкретный коммит:

$ git stash list
stash@{0}: WIP on master: 039142b Initial commit

Даже если вы дали своему тайнику собственное имя, git все равно сохраняет имя ветки:

$ git stash save "My stash"
Saved working directory and index state On master: My stash

$ git stash list
stash@{0}: On master: My stash
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...