Как передать только изменения "git add -p file" без других изменений в тот же файл и без поэтапного переименования? - PullRequest
1 голос
/ 07 марта 2019

Проблема в том, что я, очевидно, не могу сделать частичную фиксацию изменений в файле на четыре строки из примерно 200 или около того измененных строк в этом файле. Это может быть из-за команды, которую я ошибочно выполнил, а затем якобы исправил. Я опытный пользователь git, и раньше я выполнял подобные задачи, но всегда делал это, не ошибаясь ранее.

Вот что я сделал.

У меня есть файл с 3 или 4 изменениями, включая файл, который, на мой взгляд, может быть желательным, даже если другие изменения слишком экспериментальные.

У меня также есть несколько переименованных файлов, поэтому переименования являются поэтапными.

Я сделал обычный git add -p file шаг и убедился, что git diff --cached file показал именно то изменение, которое я хотел проверить.

Я случайно сделал git commit -m "Message" (опуская имя файла, которое я должен был включить), и он зафиксировал (поэтапные) переименования, что было нежелательно, а также file.

Затем я поддержал этот коммит с помощью git reset HEAD~1 --soft. Это отменило фиксацию, но оставило file в поэтапном состоянии, со ВСЕМИ изменениями, а не только add -p изменениями, как показано git diff --cached file.

Поскольку я не хотел, чтобы все изменения были подготовлены для фиксации, я сбросил файл с помощью git reset HEAD file. В этот момент git status и git diff, кажется, показывают, что я вернулся в состояние, в котором я находился до команды git add -p file.

Проблема в том, что на этом этапе, если я сделаю следующее только с желаемым изменением, принятым во время добавления,

git add -p file
git commit file -m "Message"

Статус показывает все изменения в file при получении. Количество строк показывает слишком много строк после завершения фиксации.

Как мне зафиксировать только то, что я выбрал во время git add -p file теперь, когда мне кажется, что я заблокирован от этого?

Комментарий: Обычно у меня нет поэтапных переименований, поэтому обычно мне не нужно пытаться указать файл, который я хочу зафиксировать. Я думаю, что значение git commit file - это не то значение, которое мне нужно для моих целей. Прочитав man-страницу, я думаю, что он пытается сказать, что не имеет значения, что ставится на file, когда вы делаете git commit file, он будет фиксировать полный набор изменений этого файла. Кроме того, git commit -p file будет делать правильные вещи для file после того, как позволит мне выбрать изменение в интерактивном режиме, но при этом будет также зафиксировано несвязанное переименование, которое ставится.

Ответы [ 2 ]

4 голосов
/ 07 марта 2019

Редактировать : практический подход, в отличие от фона, см. Ответ RomainValeri , за который я проголосовал. Обратите внимание, что git reset по умолчанию mixed; он восстановит старые имена файлов в вашем индексе, так что, сравнивая индекс и рабочее дерево, Git будет думать, что некоторые файлы удалены и созданы под новыми именами. Если содержимое файлов удаленных, но созданных под новыми именами достаточно похоже, Git вызовет , который "переименован".

(Вы также можете использовать git stash, хотя я обычно рекомендую избегать git stash. git stash делает два новых коммита, сохраняя текущее состояние индекса и текущее рабочее дерево состояние, которое не находится ни в одной ветви. Затем он сбрасывает индекс и рабочее дерево в порядке git reset --hard. Позже вы можете восстановить эти два коммита в вашем индексе и рабочем дереве, но обязательно используйте git stash apply --index или git stash pop --index при этом. --index, git stash игнорирует сохраненный индекс!)


Ошибка в упоминании file в git commit file -m "Message".

Ввод имени файла в git commit эквивалентен запросу git commit --only, как и , описанном в git commit документации , хотя, на мой взгляд, не все так хорошо.

Точные детали сложны, но, чтобы (сверх?) Немного упростить его и выразить более объяснимо, git commit --only file(s) примерно эквивалентно:

mv .git/index .git/index-save   # shelve your proposed commit away
git reset --mixed               # go back to the current commit
git add file(s)                 # set up new proposed commit
git commit                      # now MAKE that commit
mv .git/index-save .git/index   # restore the earlier proposed commit
git add file(s)                 # overwrite the same files in it as before

Это немного похоже, но явно более сложно, чем git commit --include file(s), что примерно эквивалентно:

git add file(s)                 # update the proposed commit
git commit                      # make the commit

Обратите внимание, что любая из них уничтожает третью версию file, которую вы тщательно настроили с помощью git add -p. Помните, что всегда есть три активных копии каждого файла:

  • замороженный в HEAD, который вы можете увидеть с git show HEAD:file,
  • податливый, но Git-ified в индексе, который вы можете увидеть с помощью git show :file и
  • обычный в вашем рабочем дереве, который вы можете видеть и работать с ним обычным способом, вообще не используя Git.

Что делает git add, это копирует файл рабочего дерева в индекс, перезаписывая все, что было раньше. git add -p выборочно выборочно обновляет единицу в индексе, сравнивая ее с единицей в рабочем дереве, показывая каждое различие и позволяя исправлять копию индекса, по одному фрагменту в время. Таким образом, git add -p создает копию index , которая отличается от и HEAD copy и копии рабочего дерева.

Обратите внимание, что индекс уже содержит копию всех остальных файлов . Вот что делает его новым предложенным коммитом: в нем всегда есть все файлы, готовые к работе.

2 голосов
/ 07 марта 2019

Если что-то еще в вашем контексте не делает это непрактичным, почему бы просто

git reset HEAD
git add -p file
git commit -m "Message"

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

...