Нужно сбросить ветку git на исходную версию

440

Я случайно работал над веткой, которой я не должен был какое-то время быть, поэтому я отделился от нее, дав ей подходящее название. Теперь я хочу переписать ветку, на которой я не должен был работать, до версии от origin (github). Есть простой способ сделать это? Я попытался удалить ветку, а затем сбросить ветку отслеживания, но она просто дает мне версию, над которой я снова работал.

Брэд херман
источник
С Git 2.23 (август 2019): git switch -C mybranch origin/mybranch. Смотрите мой отредактированный ответ ниже
VonC

Ответы:

817

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

git checkout mybranch
git reset --hard origin/mybranch

(Убедитесь, что вы ссылаетесь на ваш последний коммит в отдельной ветке, как вы упомянули в своем вопросе)

Обратите внимание, что сразу после сброса, mybranch@{1}ссылается на старый коммит, до сброса.

Но если вы уже нажали, см. « Создание ветки git и возврат исходного состояния в исходное состояние » для других опций.


С Git 2.23 (август 2019) , которая была бы одна команда: git switch.
А именно:git switch -C mybranch origin/mybranch

пример

C:\Users\vonc\git\git>git switch -C master origin/master
Reset branch 'master'
Branch 'master' set up to track remote branch 'master' from 'origin'.
Your branch is up to date with 'origin/master'.

Это восстанавливает индекс и рабочее дерево, как если git reset --hardбы.


Как прокомментировал Брэд Герман , reset --hardбы удалить любой новый файл или восстановить измененный файл ГОЛОВУ .

На самом деле, чтобы быть уверенным, что вы начинаете с «чистого листа», git clean -f -dпосле сброса гарантируется, что рабочее дерево будет точно таким же, как ветвь, в которую вы только что сбросили.


Этот пост в блоге предлагает эти псевдонимы ( masterтолько для веток, но вы можете адаптировать / расширить их):

[alias]
   resetorigin = !git fetch origin && git reset --hard origin/master && git clean -f -d
   resetupstream = !git fetch upstream && git reset --hard upstream/master && git clean -f -d

Затем вы можете ввести:

git resetupstream

или

git resetorigin
VonC
источник
26
это будет УДАЛИТЬ НЕСТАГАТИРОВАННЫЕ / УСТАНОВЛЕННЫЕ изменения (из --hard)
Питер Эрлих
5
Я использовал git reset --hard origin/mybranchкоманду несколько раз, когда меня не волновали какие-либо локальные изменения, и я просто хотел получить чистую копию, которая соответствует оригиналу. Тем не менее, сегодня это не сработало - у меня все еще было несколько новых, неустановленных файлов, и git продолжал обещать мне, что это было в HEAD. Заметка о git clean -f -dтом, что исправил это, уничтожив все новые файлы, которые я не хотел.
Мэтью Кларк
@MatthewClark Что ожидается: см. Комментарий на stackoverflow.com/q/4327708/6309
VonC
1
Большой! Также много раз я использовал, git reset --hard HEADчтобы вернуться к предыдущему
коммиту
Это возможно с sourctree тоже?
Лонзак
20

Предполагая, что это то, что произошло:

# on branch master
vi buggy.py                 # you edit file
git add buggy.py            # stage file
git commit -m "Fix the bug" # commit
vi tests.py                 # edit another file but do not commit yet

Тогда вы понимаете, что вносите изменения не в ту ветку.

git checkout -b mybranch    # you create the correct branch and switch to it

Но masterвсе же указывает на ваш коммит. Вы хотите, чтобы это указывало туда, куда оно указывало ранее.

Решение

Самый простой способ это:

git branch --force master origin/master

Другой способ это:

git checkout master
git reset --soft origin/master
git checkout mybranch

Обратите внимание, что использование reset --hardприведет к потере незафиксированных изменений ( tests.pyв моем примере).

user28667
источник
Это кажется безопаснее, чем в моем ответе;) +1
VonC
8

У меня есть частное репо на сервере, и я регулярно перезагружаюсь / принудительно нажимаю на него, что делает необходимым часто перезагружать локальную ветку на моем другом компьютере. Поэтому я создал следующий псевдоним "catchup", который позволяет делать это для текущей ветви. В отличие от другого ответа в этом псевдониме нет жестко закодированного имени ветви.

Держись крепче.

[alias]
  catchup = "!f(){ echo -n \"reset \\033[0;33m$(git symbolic-ref -q --short HEAD)\\033[0m to \\033[0;33m$(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD))\\033[0m? (Y/n) \"; read -r ans; if [ \"$ans\" = \"y\" -o \"$ans\" = \"Y\" -o -z \"$ans\" ]; then git reset --hard $(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD)); else echo \"catchup aborted\"; fi }; f"

Правильно отформатированный (не будет работать с символами новой строки в .gitconfig) это выглядит так:

"
!f(){
  echo -n \"reset \\033[0;33m$(git symbolic-ref -q --short HEAD)\\033[0m to \\033[0;33m$(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD))\\033[0m? (Y/n) \";
  read -r ans;
  if [ \"$ans\" = \"y\" -o \"$ans\" = \"Y\" -o -z \"$ans\" ]; then
    git reset --hard $(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD));
  else
    echo \"catchup aborted\";
  fi
}; f
"
  • \\033[0;33mИ \\033[0mявляется для выделения текущей ветви и выше с цветом.
  • $(git symbolic-ref -q --short HEAD) текущее название ветви
  • $(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD)) вверх по течению от текущей ветви.

Поскольку сброс - это потенциально опасный вызов (особенно с параметром --hard, вы потеряете все незафиксированные изменения), он сначала сообщает вам, что он собирается делать. Например, если вы находитесь в ветке dev-container с удаленным именем qcpp / dev-container и вводите git catchup, вам будет предложено:

сбросить dev-container в qcpp / dev-container? (Y / N)

Если вы затем наберете y или просто нажмете клавишу return, произойдет сброс. Если вы введете что-либо еще, сброс не будет выполнен.

Если вы хотите быть сверхбезопасным и программно предотвратить потерю непостановленных / незафиксированных изменений, вы можете дополнительно увеличить указанный выше псевдоним с помощью соответствующих проверок diff-index .

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

DerManu
источник
1

Я попробовал это, и это не сбросило мою текущую ветку на мой удаленный GitHub последней. Я гуглил и нашел https://itsyndicate.org/blog/how-to-use-git-force-pull-properly/

который предложил

git fetch origin master
git reset --hard origin/master

Я хотел сбросить ветку V8, поэтому я сделал

git fetch origin v8
git reset --hard origin/v8

и это сработало

SimpleSi
источник
Хорошо, что вы упомянули fetch. Я сделал это один раз без и сбросил все до 2 лет назад :)
Адам