Переместить указатель ветки на другой коммит без проверки


760

Чтобы переместить указатель ветки извлеченной ветви, можно использовать git reset --hardкоманду. Но как переместить указатель ветки не проверенной ветки, чтобы он указывал на другой коммит (сохраняя все остальные вещи, такие как отслеживаемая удаленная ветка)?


11
Похоже, все, что вы хотели сделать, - это ветка из другого коммита, отличного от того, из которого он был создан. Если мое понимание верно, то почему бы вам просто не создать новую ветку из коммита, который вы хотите создать, используя git branch <branch-name> <SHA-1-of-the-commit>и сбросить старую ветку?
yasouser

6
@yasouser - я не уверен, что какая-то дамповая ветка master будет хорошей идеей.
Bulwersator

Ответы:


578

Вы можете сделать это для произвольных ссылок. Вот как переместить указатель ветки:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

Общая форма:

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

Вы можете выбрать nits в сообщении reflog, если хотите - я думаю, что branch -fоно отличается от того reset --hard, и это не совсем одно из них.


39
Где сообщение хорошо для? Где он хранится и как его прочитать позже?
Mot

4
ПРИМЕЧАНИЕ. Это не работает с открытыми хранилищами. В пустых репозиториях вы должны использовать 'git branch -f master <commit>', чтобы обновить ветку (см. Ответ ниже).
Июнь, Родос,

37
Если, как и я, вы случайно используете <branch> вместо refs /heads / <branch>, вы получите новый файл в каталоге .git по адресу .git / <branch> и получите такие сообщения, как "refname 'master' является неоднозначным", когда вы пытаетесь работать с ним. Вы можете удалить файл из вашего каталога .git, чтобы исправить.
Дэвид Минор

34
К удовлетворению не было объяснено, почему это лучше, чем git branch -f. Чтобы быть конкретным, этот метод выглядит следующим образом: (A) труднее использовать (B) труднее запомнить и (C) более опасно
Стивен Лу

10
«что именно подразумевается под произвольными ссылками» - ветви - не единственный вид ссылки, указывающий на коммит. Существуют теги, и вы также можете создавать произвольные ссылки refs / whatevs / myref в стиле себя, которые не являются ни ветвями, ни тегами. Я считаю, что это также отвечает на вопрос Стивена Лу о том, что это может быть «лучше». Я согласен, ветвь -f проще всего, если вы работаете с ветками.
Адам

966
git branch -f <branch-name> <new-tip-commit>

24
Или для произвольных ссылок git update-ref -m "reset: Reset <branch> to <new commit>" <branch> <commit>. (Вы можете выбрать nits в сообщении reflog, если хотите - я думаю, что branch -fоно отличается от того reset --hard, и это не совсем одно из них.)
Cascabel

4
Джефроми, пожалуйста, напишите отдельный ответ, чтобы вы могли получить голоса. :)
Mot

16
Это лучший ответ, поскольку он обрабатывает 99% случаев и фактически соответствует документации. git help branchговорит "-f, --force Сбросить <branchname> в <startpoint>, если <branchname> уже существует. Без -f git branch отказывается изменить существующую ветку."
AlexChaffee

12
Я делаю, git branch -f master <hash>и это говорит мне, fatal: Cannot force update the current branch.мммм, я должен сделать то, что сейчас, проверить какую-то другую случайную ветку, прежде чем мне разрешат использовать эту команду?
Qwertie

20
Это не сработает, если ветка, которую вы пытаетесь переместить, является вашей текущей веткой ( HEADуказывает на нее).
Владимир Пантелеев

135

Вы также можете передать git reset --hardссылку на коммит.

Например:

git checkout branch-name
git reset --hard new-tip-commit

Я нахожу, что я делаю что-то вроде этого редко:

Предполагая эту историю

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master

Это имеет смысл в том смысле, что обычно используют HEAD или HEAD ^, чтобы переместить наконечник ветви назад во времени. Так что это согласованно, чтобы указать коммит вперед.
Джастингордон

11
Это хорошо, если ваше рабочее дерево чистое. Если у вас много поэтапных или неустановленных изменений, вероятно, лучше сделать, git update-refкак описано выше.
платный ботаник

16
Вы заметили, что ваш «ответ» не добавляет ничего, что уже не является частью вопроса ?? - OP сказал: если это проверено ... вы можете использовать git reset --hard ...Нет необходимости повторять это здесь! :-(
Роберт Симер

6
@ Роберт: я не согласен. Вопрос не сказал, как использовать это, и это делает. Было приятно не идти искать это как.
Уилсон Ф

7
@WilsonF, может быть, вам было приятно найти это здесь, но он не отвечает на вопрос вообще. Может быть, это ответ на какой-то другой вопрос, но здесь это неправильно .
Роберт Симер

52

Просто чтобы обогатить обсуждение, если вы хотите переместить myBranchветку в ваш текущий коммит, просто пропустите второй аргумент после-f

Пример:

git branch -f myBranch


Я обычно делаю это, когда нахожусь rebaseв состоянии Detached HEAD :)


13

В gitk --all:

  • щелкните правой кнопкой мыши на коммите вы хотите
  • -> создать новую ветку
  • введите название существующей ветви
  • нажмите return в диалоговом окне, которое подтверждает замену старой ветви с таким именем .

Помните, что пересоздание вместо изменения существующей ветви приведет к потере информации о ветви отслеживания . (Как правило, это не проблема для простых случаев использования, когда есть только один удаленный узел, а ваша локальная ветвь имеет то же имя, что и соответствующая ветвь на удаленном устройстве. Дополнительные сведения см. В комментариях, спасибо @mbdevpl за указание на этот недостаток.)

Было бы здорово, если бы gitkимел функцию, где диалоговое окно имеет 3 варианта: перезаписать, изменить существующий или отменить.


Даже если вы обычно такой же любитель командной строки, как и я, git guiи gitkдовольно хорошо разработаны для подмножества использования git, которое они позволяют. Я настоятельно рекомендую использовать их для того, что у них хорошо получается (например, выборочное размещение фрагментов в / из индекса в git gui, а также просто фиксация. (Ctrl-s для добавления подписи: line, ctrl-enter для фиксации .)

gitk отлично подходит для отслеживания нескольких веток, когда вы сортируете свои изменения в симпатичную серию патчей для отправки в апстрим или что-то еще, где вам нужно отслеживать то, что вы находитесь в середине с несколькими ветками.

У меня даже нет графического браузера файлов, но я люблю gitk / git gui.


1
Так просто! Возможно, я только что перешел из Гитга в Гитка.
Майкл Коул

Однако при этом информация ветви отслеживания теряется.
mbdevpl

@mbdevpl: я на самом деле не эксперт по мерзавцам. Я думаю, что я понимаю, что вы имеете в виду, но не последствия. Я использовал это довольно часто, и все еще был в состоянии выдвинуть те ветви к ветвям с тем же именем на пульте. Что для вас делает связь между филиалом и его филиалом удаленного отслеживания?
Питер Кордес


1
@PeterCordes Ineed, когда имена ветвей не совпадают, это имеет значение. Также, когда есть более одного пульта. Также, когда вы используете подсказку git для отображения состояния ветки, она покажет расстояние фиксации до вашей ветки отслеживания (если она установлена). Кроме того, git statusвыход влияет. Кроме того, в некоторых случаях git fetchи git pushне будет работать без явного указания удаленного, если вы не установите ветвь отслеживания. Я не знаю обо всех случаях, но для меня общее эмпирическое правило заключается в том, что для удобства и скорости работы лучше иметь следящие ветви по порядку.
mbdevpl

7

Рекомендуемое решениеgit branch -f branch-pointer-to-move new-pointer в TortoiseGit :

  • "Git Show log"
  • Проверьте "Все филиалы"
  • В строке, на которую вы хотите переместить указатель ветки (new-pointer):
    • Щелкните правой кнопкой мыши «Создать ветку в этой версии»
    • Рядом с "Ветвь" введите название ветви для перемещения (ветка-указатель для перемещения)
    • В разделе «Base On» проверьте правильность нового указателя.
    • Проверьте «Сила»
    • Хорошо

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

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


4

Честно говоря, я удивлен, как никто не думал о git pushкоманде:

git push -f . <destination>:<branch>

Точка (.) Указывает на локальный репозиторий, и вам может понадобиться опция -f, потому что пункт назначения может находиться «за своим удаленным аналогом» .

Хотя эта команда используется для сохранения изменений на вашем сервере, результат точно такой же, как если бы перемещение удаленной ветви ( <branch>) выполнялось в том же коммите, что и в локальной ветви ( <destination>).


Вы также можете сделать это без того, -fчтобы избежать засорения чего-либо локального; например, git fetch origin && git push . origin/develop:developэто не git checkout develop && git pull --ff-only
требующая проверки кассовая

1

Откройте файл .git/refs/heads/<your_branch_name>и измените хэш, хранящийся там, на тот, куда вы хотите переместить заголовок вашей ветви. Просто отредактируйте и сохраните файл в любом текстовом редакторе. Просто убедитесь, что ветвь для изменения не является текущей активной.

Отказ от ответственности: Вероятно, не рекомендуемый способ сделать это, но выполняет свою работу.


1
Не уверен, что это хаотический или злой способ сделать это. Rus 😉
Кит Рассел

@KeithRussell может быть как: P
Гильермо Гутьеррес

0

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

git merge <commit>

Задан вопрос о том, что делать, если ветка не проверена.
Кит Рассел

К сожалению, я упустил этот момент. В этом случае вы можете сделать, git push . <commit>:<branch>как уже предложено.
Жан Поль
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.