git rebase, «будет перезаписано» и «без изменений - вы забыли использовать« git add »?» - PullRequest
9 голосов
/ 15 сентября 2010

git rebase не работает должным образом в некоторых случаях, когда файл добавляется в хранилище, затем удаляется из хранилища, а затем добавляется в рабочий каталог (но не в хранилище).

Вот более конкретное описание моей проблемы:

  • если ветка создана и переключена с какого-либо Ствол,

  • и файл X добавлен и зафиксирован в филиале

  • и впоследствии X удаляется и совершено в филиале,

  • и X снова создается в рабочем каталог, но не добавлен или совершено

  • и продвижение магистральной ветви,

  • тогда

  • ребаз, выполненный с использованием расширенного ствол в качестве базы не сможет, потому что он откажется перезаписать X,

  • и перебазировка не может быть продолжена даже если рабочий каталог X удалены или удалены с дороги.

Вот скрипт для воспроизведения моей проблемы в командной строке:

git init
echo foo > foo.txt
git add .
git commit -m 'foo'
echo foo >> foo.txt
git add .
git commit -m 'foo foo'
git checkout -b topic HEAD^
git log
echo bar > bar.txt
echo baz > baz.txt
git add .
git commit -m 'bar baz'
git rm bar.txt
git commit -m '-bar' 
echo bar > bar.txt
git rebase master 
# the following output is emitted:
# First, rewinding head to replay your work on top of it...
# Applying: bar baz
# Using index info to reconstruct a base tree...
# Falling back to patching base and 3-way merge...
# error: Untracked working tree file 'bar.txt' would be overwritten by merge.  Aborting
# Failed to merge in the changes.
# Patch failed at 0001 bar baz
# 
# When you have resolved this problem run "git rebase --continue".
rm bar.txt
git rebase --continue
# the following output is emitted:
# Applying: bar baz
# No changes - did you forget to use 'git add'?
# 
# When you have resolved this problem run "git rebase --continue".
# If you would prefer to skip this patch, instead run "git rebase --skip".
# To restore the original branch and stop rebasing run "git rebase --abort".

Я знаю, что могу прервать ребаз, используя git rebase --abort, удалить bar.txt, а затем git rebase master снова. Но как я могу продолжить ребаз, не прерывая его сначала?

Ответы [ 5 ]

4 голосов
/ 24 сентября 2010

Я нашел решение: примените патч проблемного коммита вручную и добавьте его в индекс.

$ patch -p1 < .git/rebase-apply/patch 
patching file bar.txt
patching file baz.txt
$ git add bar.txt baz.txt
$ git rebase --continue
Applying: bar baz
Applying: -bar
2 голосов
/ 22 сентября 2010

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

Похоже, что нет способа повторить только самый последний шаг перебазирования. Обычно, когда rebase делает паузу, это оставляет конфликты в индексе. Но в этом случае он не может пометить эту проблему в индексе, потому что при этом будет преобразован ваш неотслеживаемый файл в отслеживаемый файл. Это, вероятно, немного грубое место в пользовательском интерфейсе git rebase. Вы можете покопаться в каталоге, который он использует для хранения своего внутреннего состояния (.git/rebase-apply) и вручную применить «текущий» патч, но прерывание и перезапуск, вероятно, проще (но, возможно, не быстрее, если вы находитесь в процессе перебазирования очень долгого времени). серия).


Если добавление bar.txt считается ошибкой, то вы можете рассмотреть возможность использования git rebase -i, чтобы отделить и отбросить добавление и удаление bar.txt, поскольку вы все равно переписываете историю.
Вы все равно столкнетесь с конфликтом, но методы, описанные ниже, также можно применить с git rebase -i. Сценарий в конце должен быть разбит на две части («setup temp/» и «включить результат перебазирования», поскольку для интерактивной перебазировки обычно требуется несколько команд между этими двумя секциями.


Временно отодвиньте конфликтующий файл и повторите восстановление.

mv bar.txt +bar.txt
git rebase --abort
git rebase master

Если вы ожидаете много таких конфликтующих файлов, то вы можете подумать о том, чтобы выполнить перебазирование в отдельном клоне, где вы можете быть уверены, что у вас не будет никаких неотслеживаемых файлов. Возможно, самая хитрая часть - это проверка того, что ваши неотслеживаемые файлы не конфликтуют с результатом перебазирования (git checkout rebased-topic выполняет это; прерывается, если неотслеживаемые файлы конфликтуют с результатом перебазировки).

: "Note: will destroy
:     * 'rebased-topic' branch
:     * 'temp' directory"
( set -x &&
  : '*** Clearing temp/' &&
  rm -rf temp/ &&

  : '*** Making sure we have topic checked out' &&
  git checkout topic

  : '*** Cloning into temp/' &&
  git clone . temp && 

  : '*** Rebasing topic onto master in temp/ clone' &&
  ( cd temp &&
  git rebase origin/master
  ) &&

  : '*** Fetching rebase result from topic/ into local rebased-topic branch' &&
  git fetch -f temp topic:rebased-topic &&

  : '*** Checking rebased-topic for conflicts with untracked files' &&
  git checkout rebased-topic &&

  : '*** Resetting topic to tip of rebased-topic' &&
  git branch -f topic rebased-topic &&

  : '*** Returning to topic branch' &&
  git checkout topic &&

  : '*** Deleting rebased-topic branch' &&
  git branch -d rebased-topic &&

  : '*** Deleting temp/' &&
  rm -rf temp/
)
2 голосов
/ 16 сентября 2010

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

Если вы по какой-то причине некомфортно делаете коммит, вы можете по крайней мере использовать stash (что делает примерно то же самое).

0 голосов
/ 24 августа 2015

Это случалось со мной и несколькими членами команды несколько раз ... Обычно при работе над одной веткой и частых фиксациях.

Мы используем SmartGit для нашего клиента, и в результате получается, что, хотя SmartGit показывает чистое репо, git status показывает количество измененных случайных файлов.

Я просто столкнулся с этим снова и обнаружил, что git checkout . устранил проблему для меня. Он отбросил эти «невидимые локальные изменения» и позволил мне приступить к вытягиванию (и отмене моих исходящих коммитов).

Я решил записать это здесь для дальнейшего использования. Конечно, я предполагаю, что вы совершили свои преднамеренные изменения, и вы можете отказаться от непреднамеренных. Если это так, один git checkout . должен (надеюсь) сделать это.

Приветствия

0 голосов
/ 22 сентября 2010

Для того, чтобы GIT продолжал выполнять rebase после удаления файла, я добавил изменение пробела и затем «git add» файл с этим изменением.

...