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


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"

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

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


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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.