Как исправить фиксацию в неправильной ветке Git?

621

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

mikewilliamson
источник

Ответы:

975

Если вы еще не отправили свои изменения, вы также можете выполнить программный сброс:

git reset --soft HEAD^

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

git checkout branch
git commit

Недостатком является то, что вам необходимо повторно ввести сообщение коммита.

Блэр Холлоуэй
источник
10
обратите внимание, что программный сброс оставляет ваши изменения подготовленными и готовыми к фиксации. Я немного запутался, когда моя среда IDE не показала, что файлы возвращаются в измененное состояние после мягкого сброса.
mtjhax
9
Идеальное исправление, на самом деле было несколько коммитов, так же как и HEAD ^^, и Бэм все в соусе
Пабло
8
Спасибо. Это спасло меня дважды. Если ветви несколько отличаются, после сброса и перед оформлением покупки вам, возможно, придется сохранить свои изменения, прежде чем вы сможете оформить извлечение из другой ветви. Повторно применить тайник после проверки
Кирби
17
Пользователи zsh: вам может понадобиться убежать от ^, например так:git reset --soft HEAD\^
Стивен Фури,
54
Если вы получите больше? в командной строке Windows используйте кавычки для окружения HEAD ^ примерно так: git reset --soft "HEAD ^"
Nate Cook
142

4 года с опозданием на тему, но это может быть полезно для кого-то.

Если вы забыли создать новую ветку перед фиксацией и зафиксировали все на master, независимо от того, сколько коммитов вы сделали, следующий подход проще:

git stash                       # skip if all changes are committed
git branch my_feature
git reset --hard origin/master
git checkout my_feature
git stash pop                   # skip if all changes were committed

Теперь ваша ветка master равна origin/masterи все новые коммиты включены my_feature. Обратите внимание, что my_featureэто локальная ветвь, а не удаленная.

fotanus
источник
Спасибо за ответ. Теперь я использую egit и мне интересно, смогу ли я сделать то же самое, выполнив следующие действия: 1) Переименуйте текущий «master» в «my_feature». 2) Воссоздать локального «мастера» из «происхождения / мастера». Я не уверен, что egit делает под капотом для этих операций, но это, кажется, жизнеспособное решение
mjj1409
почему слияние? Вы могли бы создать ветку непосредственно master, а затем сбрасывается masterв origin/master.
Цезарсоль
1
Это самая интересная часть: вам не нужно количество коммитов, потому что они origin/masterуже на коммите, который вы хотите сбросить! Кредит на кончике однако эту страницу: github.com/blog/...
caesarsol
4
Это должен быть принятый ответ. Простой, очевидный, простой, работает независимо от количества коммитов и использует только базовую функциональность Git. Я сделал эти шаги с TortoiseGit. Спасибо! :)
Ян Грейнджер
1
Я думал, что это был лучший ответ, но у него есть ограничение. Помогает только если вы недавно вытащили с пульта. И это предполагает, что у вас есть пульт для начала. Если у вас есть только локальные ветви "master" и ваше новое исправление функции, единственный правильный ответ - это сложная перезагрузка на master, возвращающая определенное количество коммитов.
pauljohn32
111

Если у вас есть чистая (неизмененная) рабочая копия

Чтобы откатить один коммит (обязательно запишите хеш коммита для следующего шага):

git reset --hard HEAD^

Чтобы перетащить этот коммит в другую ветку:

git checkout other-branch
git cherry-pick COMMIT-HASH

Если вы изменили или не отслеживали изменения

Также обратите внимание, что git reset --hardэто убьет любые неотслеживаемые и измененные изменения, которые вы можете иметь, поэтому, если у вас есть такие, вы можете предпочесть:

git reset HEAD^
git checkout .
Майкл Мрозек
источник
git rev-parse BRANCH_NAMEчтобы получить ша.
Вильгельмтелл
12
Если вы забыли сначала записать хеш, просто используйте git reflog show <branch>!
Каскабель
2
@Jefromi Я был напуган на минуту.
Ян Хантер
13
Для дополнительного чувства безопасности сначала выполните вишневую кирку на правильной ветви, а затем сбросьте неправильную ветку.
Возраст Mooij
1
Кроме того, в случае неотслеживаемых изменений, можно git stashвыполнить сброс до сброса и git stash popвпоследствии использовать его для восстановления, поэтому не нужно бояться --hardчасти
Клеменс Кляйн-Роббенхар
20

Если вы уже выдвинули свои изменения, вам нужно будет выполнить следующий толчок после сброса ГОЛОВКИ.

git reset --hard HEAD^
git merge COMMIT_SHA1
git push --force

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

На всякий случай, в Windows (с использованием командной строки Windows, а не Bash) их на самом деле четыре ^^^^вместо одного, поэтому

git reset --hard HEAD^^^^
Игорь Зевака
источник
6
Обратите внимание, что вы не должны принудительно нажимать на ветку, которую используют другие люди, за исключением случаев, когда это абсолютно необходимо - в противном случае они не смогут нажимать, пока не выполнят ребазинг. Если вы единственный разработчик, использующий git, это нормально.
Блэр Холлоуэй
2
Или до тех пор, пока вы не поймете достаточно быстро, прежде чем кто-либо еще потянет за ошибочные коммиты.
Майкл Миор
Если ваш более чем один коммит отключен, вы можете указать коммит, который вам нужен: git reset --hard COMMIT_HASH git push --force
Дэвид Крамблетт
17

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

Если вы только что перешли на неверную ветку и с тех пор ничего не изменили и не продвинулись в репо, вы можете сделать следующее:

// rewind master to point to the commit just before your most recent commit.
// this takes all changes in your most recent commit, and turns them into unstaged changes. 
git reset HEAD~1 

// temporarily save your unstaged changes as a commit that's not attached to any branch using git stash
// all temporary commits created with git stash are put into a stack of temporary commits.
git stash

// create other-branch (if the other branch doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// take the temporary commit you created, and apply all of those changes to the new branch. 
//This also deletes the temporary commit from the stack of temp commits.
git stash pop

// add the changes you want with git add...

// re-commit your changes onto other-branch
git commit -m "some message..."

ПРИМЕЧАНИЕ: в приведенном выше примере я перематывал 1 коммит с git reset HEAD ~ 1. Но если вы хотите перемотать n коммитов, вы можете выполнить git reset HEAD ~ n.

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

// save the not-ready-to-commit work you're in the middle of
git stash 

// rewind n commits
git reset HEAD~n 

// stash the committed changes as a single temp commit onto the stack. 
git stash 

// create other-branch (if it doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// apply all the committed changes to the new branch
git stash pop

// add the changes you want with git add...

// re-commit your changes onto the new branch as a single commit.
git commit -m "some message..."

// pop the changes you were in the middle of and continue coding
git stash pop

ПРИМЕЧАНИЕ: я использовал этот сайт в качестве ссылки https://www.clearvision-cm.com/blog/what-to-do-when-you-commit-to-the-wrong-git-branch/

Али Мизан
источник
Подобные вещи произошли со мной, я совершил несколько изменений в мастере, но я должен был сделать это в новой ветке и отправить пиар, в итоге я просто сделал git checkout -b new_branchправильное, оттуда коммиты были целы, просто нажали и создали пиар, не так ли не нужно совершать снова.
Нишаль Гаутам
11

Поэтому, если ваш сценарий состоит в том, что вы совершили, masterно намеревались выполнить another-branch(который может или не может уже существовать), но вы еще не отдалились, это довольно легко исправить.

// if your branch doesn't exist, then add the -b argument 
git checkout -b another-branch
git branch --force master origin/master

Теперь все ваши коммиты masterбудут включены another-branch.

Источник с любовью от: http://haacked.com/archive/2015/06/29/git-migrate/

Лоркан О'Нил
источник
кажется, самый простой подход! Не уверен, почему так мало любви и положительных отзывов
keligijus
4
Похоже, это не сработало для меня. another-branchуже существовал. В этом случае он просто обнажил коммиты, которые я сделал, чтобы освоить, и не надевал их another-branch.
Жизель Серат
6

Чтобы уточнить этот ответ, в случае , если у вас есть несколько коммитов , чтобы перейти от, например , developдля new_branch:

git checkout develop # You're probably there already
git reflog # Find LAST_GOOD, FIRST_NEW, LAST_NEW hashes
git checkout new_branch
git cherry-pick FIRST_NEW^..LAST_NEW # ^.. includes FIRST_NEW
git reflog # Confirm that your commits are safely home in their new branch!
git checkout develop
git reset --hard LAST_GOOD # develop is now back where it started
Арсениус
источник
1
У меня было три коммита, чтобы вернуться, и этот вопрос, похоже, вытащил мою задницу из огня. Спасибо!
holdenweb
3

Если вы столкнулись с этой проблемой, и у вас есть Visual Studio, вы можете сделать следующее:

Щелкните правой кнопкой мыши по вашей ветке и выберите View History:

введите описание изображения здесь

Щелкните правой кнопкой мыши на коммите, к которому вы хотите вернуться. И вернуть или сбросить при необходимости.

введите описание изображения здесь

Тревор
источник
3

Для нескольких коммитов на неправильной ветке

Если для вас это всего лишь 1 коммит, то есть множество других более простых решений сброса. Для меня у меня было случайно сделано около 10 коммитов masterвместо, давайте назовем этоbranch_xyz , и я не хотел терять историю коммитов.

То, что вы могли сделать, и что спасло меня, было использовать этот ответ в качестве ссылки, используя 4-х шаговый процесс, который -

  1. Создать новую временную ветку из master
  2. Слияние с веткой, изначально предназначенной для коммитов, т.е. branch_xyz
  3. Отменить совершает на master
  4. Удалить временную ветку.

Вот вышеупомянутые шаги в деталях -

  1. Создать новую ветку из master(где я случайно совершил много изменений)

    git checkout -b temp_branch_xyz
    

    Примечание: -bфлаг используется для создания новой ветви.
    Просто чтобы проверить, правильно ли мы это поняли, я бы сделал быстрое, git branchчтобы убедиться, что мы находимся в temp_branch_xyzветви, и a, git logчтобы проверить, правильно ли мы получили коммиты.

  2. Объединить временную ветвь в филиал первоначально предназначался для фиксаций, то есть branch_xyz.
    Во-первых, переключитесь на исходную ветвь, т. Е. branch_xyz(Вам может понадобиться, git fetchесли у вас нет)

    git checkout branch_xyz
    

    Примечание. Не используйте -bфлаг.
    Теперь давайте объединим временную ветку с веткой, которую мы сейчас извлекаем.branch_xyz

    git merge temp_branch_xyz
    

    Возможно, вам придется позаботиться о некоторых конфликтах здесь, если они есть. Вы можете нажать (я бы) или перейти к следующим шагам, после успешного объединения.

  3. Отмените случайные коммиты, masterиспользуя этот ответ в качестве ссылки, сначала переключитесь наmaster

    git checkout master
    

    затем отмените его полностью, чтобы соответствовать удаленному (или конкретному коммиту, если хотите)

    git reset --hard origin/master
    

    Опять же, я бы сделал git logдо и после, чтобы убедиться, что предполагаемые изменения вступили в силу.

  4. Стирание улик, то есть удаление временной ветки. Для этого сначала вам нужно проверить ветку, в которую был добавлен темп, т.е. branch_xyz(если вы останетесь masterи выполните команду ниже, вы можете получить error: The branch 'temp_branch_xyz' is not fully merged), так что давайте

    git checkout branch_xyz
    

    а затем удалите доказательство этой неудачи

    git branch -d temp_branch_xyz
    

Вот и ты.

Митали Сайрус
источник
1

Если ветвь, к которой вы хотели применить ваши изменения, уже существует (например, ветвь разработки ), следуйте инструкциям, предоставленным fotanus ниже, затем:

git checkout develop
git rebase develop my_feature # applies changes to correct branch
git checkout develop # 'cuz rebasing will leave you on my_feature
git merge develop my_feature # will be a fast-forward
git branch -d my_feature

И, очевидно, вы могли бы использовать tempbranch или любое другое имя ветви вместо my_feature если хотите.

Также, если применимо, откладывайте всплывающее окно (применять) до тех пор, пока вы не объединитесь с целевой веткой.

fbicknel
источник
Я думаю, что первая команда (разработка checkout) не нужна ... rebase будет просто извлекать "my_feature" как первое, что она делает.
JoelFan
Также вы можете не указывать параметр «my_feature» команды «rebase» (поскольку вы уже отметили «my_feature»). вы также можете не
указывать
1

Для меня это было решено путем возврата коммита, который я нажал, затем выбора вишни для коммита в другой ветке.

git checkout branch_that_had_the_commit_originally
git revert COMMIT-HASH
git checkout branch_that_was_supposed_to_have_the_commit
git cherry pick COMMIT-HASH

Вы можете использовать, git logчтобы найти правильный хеш, и вы можете отправить эти изменения, когда захотите!

arr0nax
источник