перемещение зафиксированных (но не выдвинутых) изменений в новую ветвь после извлечения

460

Я проделал немалую работу («Ваша ветвь впереди« origin / master »на 37 коммитов».), Которая действительно должна была пойти в свою собственную ветку, а не в master. Эти коммиты существуют только на моей локальной машине и не были переданы origin, но ситуация несколько усложняется тем, что другие разработчики настаивали на этом, origin/masterи я внес эти изменения.

Как я могу задним числом переместить мои 37 локальных коммитов в новую ветку? Судя по документам, кажется, что git rebase --onto my-new-branch masterили ...origin/masterдолжен сделать это, но оба дают мне ошибку «роковая: нужна одна ревизия». man git-rebaseничего не говорит о предоставлении ревизии, rebaseи ее примеры не делают этого, поэтому я понятия не имею, как устранить эту ошибку.

(Обратите внимание , что это не является дубликат Move существующего, неподтвержденной работа нового филиала в Git или Как объединить мои местные неподтвержденные изменения в другую ветвь Git? Так как эти вопросы решать неподтвержденные изменения в локальном рабочем дереве, а не изменения , которые совершено на местном уровне.)

Дейв Шерохман
источник
Проверьте это решение . Кажется, легко и чисто.
Тони
Проверьте это решение . Кажется, легко и чисто.
Тони

Ответы:

518

Это должно быть хорошо, поскольку вы еще нигде не выдвигали свои коммиты, и вы можете переписать историю своей ветки после origin/master. Сначала я запустил бы, git fetch originчтобы убедиться, что origin/masterэто актуально. Предполагая, что вы в данный момент master, вы должны быть в состоянии сделать:

git rebase origin/master

... который будет воспроизведен все ваши коммиты, которые не origin/masterна origin/master. Действие rebase по умолчанию - игнорировать коммиты слияния (например, те, которые вы, git pullвероятно, представили), и он просто попытается применить патч, введенный каждым из ваших коммитов origin/master. (Возможно, вам придется разрешить некоторые конфликты по пути.) Затем вы можете создать новую ветку на основе результата:

git branch new-work

... а затем masterвернитесь к origin/master:

# Use with care - make sure "git status" is clean and you're still on master:
git reset --hard origin/master

При выполнении такого рода манипулирование ветвей с git branch, git resetи т.д. Я считаю , это полезно часто смотреть на коммит граф gitk --allили подобный инструмент, просто чтобы убедиться , что я понимаю , где все разные рефов указывают.

В качестве альтернативы, вы могли бы просто создать ветку темы, основываясь на том, где находится ваш мастер ( git branch new-work-including-merges), и затем сбросить, masterкак указано выше. Однако, поскольку ваша ветка темы будет включать в себя слияния origin/masterи вы еще не выдвинули свои изменения, я бы предложил сделать ребаз, чтобы история была более аккуратной. (Кроме того, когда вы в конечном итоге объедините ветку своей темы с главной, изменения станут более очевидными.)

Марк Лонгэйр
источник
8
@ Оли: Нет, ответ правильный с учетом предположений в вопросе и тех, которые я изложил в верхней части ответа. Коммиты, которые должны быть в отдельной новой ветке, уже находятся в master; rebase переписывает masterветвь так, чтобы новые коммиты были линейно сверху origin/master, затем git branch new-workсоздает new-workветвь, указывающую на вершину master(текущую ветвь), не переключая текущую ветвь в new-work. Так что теперь new-workсодержит все новые коммиты. Затем сброс перемещает текущую ветвь (неподвижно master) обратно в origin/master.
Марк Лонгэйр
1
@Quintesse: Мне очень жаль, если вы потеряли работу, но я уверен, что этот ответ правильный для ситуации, описанной первоначальным спрашивающим. (Я только что ответил на замечания Оли, надеюсь, с разъяснениями.) В любом случае, на всякий случай, если это поможет вернуть вашу работу, я должен сказать, что если ваша работа была совершена в течение последних нескольких дней (одно из предположений в этом вопросе и ответе ) вы должны легко получить его через git reflog.
Марк Лонгэйр
5
@Olie: возможно, лучший способ объяснить: ветви в git похожи на метки, указывающие на конкретный коммит; они автоматически перемещаются в новые коммиты, если вы создаете их в этой ветке или их можно перемещать git resetразличными способами. Это git branch new-workпросто говорит: «создайте ветку, указывающую на этот коммит, пока я остаюсь в моей текущей ветке (в данном случае это master)». Таким образом, нет необходимости иметь команду, которая перемещает коммиты от мастера к новой ветви - вы просто создаете новую ветку там, и когда вы сбрасываете мастер, новая ветвь остается там, где был мастер
Марк Лонгэйр
1
Немного опоздал на вечеринку, но @Olie, просто потому, что состояние git, когда в новой ветке не отображаются коммиты впереди master, не означает, что их на самом деле нет (если вы поэтому и волновались) Попробуйте подтолкнуть новую ветку к источнику: вы увидите, что коммиты есть
Феликс Ганьон-Гренье,
2
@ FélixGagnon-Grenier, не беспокойтесь о «опоздании» - всегда есть люди, которые ищут старые вопросы, и каждое разъяснение помогает. Спасибо! :)
Olie
148

Если у вас низкое количество коммитов и вам все равно, если они объединены в один мегакмит, это работает хорошо и не так страшно, как при выполнении git rebase:

разархивируйте файлы (замените 1 на число коммитов)

git reset --soft HEAD~1

создать новую ветку

git checkout -b NewBranchName

добавить изменения

git add -A

сделать коммит

git commit -m "Whatever"
Stachu
источник
5
Чтобы показать простой для понимания график, пожалуйста, используйте git log --all --decorate --oneline --graph.
EliuX
Привет @EliuX - я скучаю по релевантности здесь. Вы можете расширить?
Стачу
Это что-то полезное, чтобы проверить, если вы получили
желаемый
4
Спасибо!! Это очень простое решение, и оно сработало идеально!
Крис Сим
91

Я застрял с той же проблемой. Я нашел самое простое решение, которым я хотел бы поделиться.

1) Создать новую ветку с вашими изменениями.

git checkout -b mybranch

2) (Необязательно). Нажмите новый код ветки на удаленном сервере.

git push origin mybranch

3) Оформить заказ обратно в главную ветку.

git checkout master

4) Сброс кода главной ветки с удаленного сервера и удаление локальной фиксации.

git reset --hard origin/master
Нирмала
источник
10
Это действительно самый простой способ
dhilt
4
Вы можете пропустить шаг 2. Я предполагаю, что за время, прошедшее с верхнего ответа, git изменился, и это prcedure ранее не разрешалось.
Себастьян
Это лучший ответ на мой взгляд.
Macindows
1
Этот ответ должен двигаться к вершине. Спасибо.
Амит
27

Еще один способ предположить, что branch1 - это ветка с зафиксированными изменениями branch2 - желательно ветка

git fetch && git checkout branch1
git log

выберите идентификаторы коммитов, которые вам нужно переместить

git fetch && git checkout branch2
git cherry-pick commit_id_first..commit_id_last
git push

Теперь верните unpressed коммиты из начальной ветки

git fetch && git checkout branch1
git reset --soft HEAD~1
Андрей
источник
5
Cherry-pick - действительно лучшая команда "копировать / переместить один коммит", esp. когда история является багажом для ваших целей.
Джон Нейгауз
Это пока самый удобный ответ на вопрос. Спасибо за команду!
Фара
Можете ли вы обновить свой последний комментарий, где 1 или n - это число невыполненных коммитов? Это все еще действительно хорошее решение для этого вопроса.
chAlexey
9

В качестве альтернативы, сразу после фиксации в неправильной ветке, выполните следующие действия:

  1. git log
  2. git diff {previous to last commit} {latest commit} > your_changes.patch
  3. git reset --hard origin/{your current branch}
  4. git checkout -b {new branch}
  5. git apply your_changes.patch

Я могу себе представить, что есть более простой подход к первым и вторым шагам.

Андреас Б
источник
6

Что о:

  1. Отделение от текущей головы.
  2. Убедитесь, что вы являетесь хозяином , а не вашей новой веткой.
  3. git reset вернуться к последнему коммиту до того, как вы начали вносить изменения.
  4. git pull чтобы восстановить только удаленные изменения, которые вы выбросили при сбросе.

Или это взорвется, когда вы попытаетесь объединить ветку?

Тим Китинг
источник
2
Ах, это в основном вариант B, описанный @ Mark-Longair выше
Тим Китинг
2

Вот гораздо более простой способ:

  1. Создать новую ветку

  2. В вашей новой ветке сделайте git merge master- это объединит ваши зафиксированные (не отправленные) изменения с вашей новой веткой

  3. Удалите свою локальную главную ветку git branch -D masterИспользуйте -Dвместо того -d, чтобы принудительно удалить ветку.

  4. Просто сделайте в git fetchсвоей основной ветке и сделайте это git pullв своей основной ветке, чтобы убедиться, что у ваших команд последний код.

Кок
источник
1

Более простой подход, который я использовал (предполагая, что вы хотите переместить 4 коммита):

git format-patch HEAD~4

(Посмотрите в каталоге, из которого вы выполнили последнюю команду для 4 .patchфайлов)

git reset HEAD~4 --hard

git checkout -b tmp/my-new-branch

Затем:

git apply /path/to/patch.patch

В любом порядке, который вы хотели.

user1429980
источник
0
  1. Оформить свежую копию ваших источников

    git clone ........

  2. Сделать ветку из желаемой позиции

    git checkout {position} git checkout -b {branch-name}

  3. Добавить удаленный репозиторий

    git remote add shared ../{original sources location}.git

  4. Получить удаленные источники

    git fetch shared

  5. Оформить заказ нужной ветке

    git checkout {branch-name}

  6. Слияние источников

    git merge shared/{original branch from shared repository}

Сергей Кабашнюк
источник
0

Для меня это был лучший способ:

  1. Проверьте наличие изменений и конфликты слияния git fetch
  2. Создайте новую ветку git branch my-changesи нажмите на удаленный
  3. Изменить восходящий поток на новую созданную ветку git master -u upstream-branch remotes/origin/my-changes
  4. Вставьте ваши коммиты в новую ветку upstream.
  5. Вернитесь к предыдущему git branch master --set-upstream-to remotes/origin/master
Себастьян
источник