Как объединить тайник после локального удаления файла и внесения изменений? - PullRequest
1 голос
/ 06 июня 2019

В настоящее время были проблемы с 'UserInterfaceState.xcuserstate' при работе с другим разработчиком и использовании Git в качестве источника контроля. Я сразу понял, что .gitignore не игнорирует этот файл, и решил удалить / удалить его с помощью 'git rm --cached'. Перед выполнением команды я спрятал текущие изменения в:

  1. Сохранить мои текущие изменения
  2. Создание быстрого коммита, отражающего удаление UserInterfaceState.xcuserstate

Я создал коммит, отражающий удаление UserInterfaceState.xcuserstate, и приступил к «git stash apply». Это была ошибка, которую я получил:

needs merge
unable to refresh index

Я знаю, что в тайнике все еще есть UserInterfaceState.xcuserstate, но у меня сложилось впечатление, что Git объединит вновь зафиксированное состояние главной ветви с тайником и заставит меня разрешить merge conflict.

Как бы я мог объединить тайник, чтобы вернуть мою предыдущую работу в только что созданную мастер-ветку, которой больше нет и не отслеживает UserInterfaceState.xcuserstate?

1 Ответ

3 голосов
/ 06 июня 2019

Всякий раз, когда у вас есть тайник, который не будет применяться, я рекомендую превратить этот тайник в ветвь.

Для этого сначала убедитесь, что у вас нет незавершенной работы. Это означает, что теперь вы должны фиксировать все, что делаете, или хранить его - последнее немного иронично и странно, но работает нормально, если вы помните, что преобразованный вами ключ теперь перенумерован. Теперь, когда все «чисто», выберите проблемный тайник по его идентификатору - stash@{1} или stash@{6} или как угодно, если это необходимо, или просто по умолчанию, если это текущий или единственный тайник - и используйте этот идентификатор (или по умолчанию) в качестве аргумент команды git stash branch:

$ git stash branch newbranch stash@{3}

Теперь вы находитесь в состоянии, в котором вы можете запустить git status, затем, возможно, git commit или git add и git commit и т. Д. - ваш stash@{3} тайник был повторно загружен в индекс, как если вы запустили git stash apply --index и в свое рабочее дерево, как если бы этой же командой. Как только вы сделаете коммит (ы), ваша новая ветка готова к использованию, как вам нравится.

(Фактически, Git действительно выполнил запустил команду: сначала Git запустил git checkout соответствующего коммита. Затем Git запустил git stash apply --index на тайнике, который восстановил сохраненный индекс и сохраненный work-tree. Затем, успешно применив, Git запустил git stash drop на этом сохраненном тайнике.)

В этом случае после git stash branch <em>name</em> <em>stash</em> вам, вероятно, понадобится один git add и git commit, который сохранит всю вашу работу, включая надоедливую не удаленную, возможно измененную, а может быть, не UserInterfaceState.xcuserstate файл. Но теперь вы можете git checkout ветку, над которой вы работали , применить и сбросить временный сундук, который вы сделали, если вы его сделали, и git cherry-pick -n коммит на ту новую ветку, которую вы сделали с вашего проблемного сундука. Если этот коммит не содержит изменений в файле pesky, а файл pesky здесь не существует, выбор вишни, скорее всего, пройдет довольно гладко, и все будет готово.

Обсуждение

Все это имеет определенный смысл, когда вы понимаете, что (a) объект git stash - это просто коммит коммитов; (b) коммиты всегда записывают свои родительские коммиты; и (c) ветвь - это просто серия коммитов, обозначаемых веткой name , идентифицирующей last коммит, который следует считать частью ветки.

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

...--o--o--*--o   <-- your-branch
            \
             i--w   <-- stash

и, следовательно, тайник действительно будет похож на любую ветку, за исключением того факта, что refs/stash не начинается с refs/heads/ (сравните с refs/heads/your-branch, который, очевидно, начинается с refs/heads/). Здесь * - это коммит, на котором вы были , когда запускали git stash. Вы добавили еще один коммит, который находится справа от *. Коммиты i и w будут содержать индекс и состояния рабочего дерева на момент запуска git stash.

Сложность в том, что git stash вообще не делает i и w такими. Вместо этого он делает:

...--o--o--*--o   <-- your-branch
           |\
           i-w   <-- stash

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

К счастью, git stash branch знает, как злоупотреблять форматом. Это:

  • проверка фиксации *;
  • создает новое имя ветки, чтобы помнить, где вы сейчас находитесь; и
  • применяет тайник, сохраняя его компоненты индекса и рабочего дерева отдельно (как они были при сохранении тайника) на случай, если это именно то, что вы намеревались.

Итак, теперь у вас есть:

             o   <-- your-branch
            /
...--o--o--*   <-- new-branch

с i в вашем индексе (готово для фиксации) и w в вашем рабочем дереве (готово к git add -ed) для обновления вашего индекса, после чего w будет в вашем индексе и готов быть преданным). В Commit *, конечно, есть файл pesky, поэтому оставьте файл pesky там, где он есть, без изменений, добавьте и зафиксируйте все остальное, и вы получите:

             o   <-- your-branch
            /
...--o--o--*--W   <-- new-branch

белыйere W - это обычная обычная фиксация состояния рабочего дерева, которое вы имели, готовый быть переданным в git cherry-pick (возможно, с -n) или использоваться как вам угодно.

В конце концов, вы можете просто удалить ветку new-branch (которую вы, вероятно, хотите назвать другим именем), и фиксация W будет отменена и в конечном итоге полностью исчезнет.

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