Как я могу отменить последний коммит в репозитории git bare?

94

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

git reset --hard HEAD^ 

не является решением для отмены последнего изменения в таком репозитории.

Поискав в Интернете, все, что я смог найти, связанное с этой темой, - это то , в котором мне представлены три способа сделать это:
1. "обновить ссылку вручную (что включает в себя сантехнику)";
2. " git push -fиз репозитория non-bare";
3. " git branch -f this $that".

Какое решение, по вашему мнению, более подходящее, или какие еще есть способы сделать это? К сожалению, документация, которую я нашел о репозиториях git bare, довольно скудна.

Лавиния-Габриэла Добровольски
источник
8
@ Lavinia-Garbriela Dobrovol Не используйте сложные вещи ниже. Вы пытаетесь переместить HEAD в другую фиксацию, и это то, для чего предназначен git reset, даже в чистом репо. В моем ответе ниже используйте: git reset --soft <commit> С --soft вы не пытаетесь изменить рабочее дерево и индекс, которые не существуют, поэтому git позволяет вам без проблем выполнить сброс.
Hazok

Ответы:

133

Вы можете использовать git update-refкоманду. Чтобы удалить последнюю фиксацию, вы должны использовать:

$ git update-ref HEAD HEAD^

Или, если вы не в ветке, из которой не можете удалить последнюю фиксацию:

$ git update-ref refs/heads/branch-name branch-name^

Вы также можете передать sha1, если хотите:

$ git update-ref refs/heads/branch-name a12d48e2

См. Документацию по команде git-update-ref .

Сильвен Дефресн
источник
@ Лавиния-Габриэла Добровольски: да, я не знала точный синтаксис.
VonC
@VonC Вы можете указать <ref> в git update-ref <ref> <newvalue>качестве правой ветви, например, "refs / Heads / master" вместо HEAD. Надеюсь, я правильно понял ваш вопрос.
Лавиния-Габриэла Добровольски
@Sylvain: +1 хорошее редактирование. @ Лавиния-Габриэла Добровольски спасибо за точность. Это гораздо практичнее (я полагаю, если у вас есть прямой доступ к удаленному серверу).
VonC
3
Примеры вводят в заблуждение относительно branch-nameаргументации. При использовании update-refс «веткой» вы обязательно должны указать полное ссылочное имя ветки (т.е. добавить refs/heads/к обычному короткому имени ветки). Если вы просто используете короткое имя, вы в конечном итоге создадите / обновите $GIT_DIR/branch-nameвместо $GIT_DIR/refs/heads/branch-name. Наличие обоих branch-nameи refs/heads/branch-nameвызовет предупреждения «имя ссылки… неоднозначно».
Крис Джонсен
Этот ответ намного сложнее того, что предложил Зак. И его решение отлично работает.
Кристиан
32

Если вы используете следующее в чистом репо:

git reset --soft <commit>

тогда вы не столкнетесь с проблемами, которые вы используете, --hardи --mixedпараметрами в голом репо, поскольку вы не пытаетесь изменить то, чего нет в голом репо (например, рабочее дерево и индекс). В вашем случае конкретно вы хотели бы использовать (из чистого репо):

git reset --soft HEAD^

Чтобы переключить ветки на удаленном репо, выполните:

git symbolic-ref HEAD refs/heads/<branch_name>

Чтобы увидеть текущую выбранную ветку, используйте:

git symbolic-ref HEAD

https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html

Hazok
источник
3
Как выбрать ветку, которую хотите переместить? Ваш пример отлично работает на мастере, но git checkout other_branchне работает на голом.
Готье
1
Хммм ... Мне интересно, кто проголосовал против меня по этому поводу. Вопрос не касался того, как переключать ветки в удаленном репо, он спрашивал, как выполнить сброс на голом репо. Чтобы изменить ветку по умолчанию в удаленном репо, используйте git symbolic-ref HEAD refs / Heads / <branch_name>.
Hazok
7

git push -fДолжен работать нормально:
если вы клонировать , что голое репо, удалить последний коммит ( git reset --hard HEAD^как вы уже, но в местном , не голую репо) и толчок назад ( -f):

  • вы не изменяете какой-либо SHA1 для других коммитов, предшествующих тому, который вы удаляете.
  • вы уверены, что отодвигаете точное содержимое голого репо за вычетом дополнительной фиксации (потому что вы только что клонировали его сначала).
VonC
источник
@ VonC Привет, Фон, я видел, как вы много отвечали на Git, поэтому хотел спросить вас ... Мне было любопытно, почему бы, git reset --soft <sha1>как показано в моем ответе ниже, не быть рекомендуемой практикой для перемещения HEAD на голом репо?
Hazok
Я предполагаю, что еще одна причина, по которой я спрашиваю, заключается в том, что использование мягкого сброса для голых репозиториев не является легкодоступной информацией, и многие форумы, похоже, имеют излишне сложные обходные пути, когда кажется, что мягкий сброс - лучшая практика из-за наименьшего количества ввода и наименьших шансов на ошибку.
Hazok
2
@Zach: a reset --softдолжен работать, если выполняется непосредственно на голом репо. Я подозреваю, что это делается редко, потому что голое репо - это обычно репо восходящего потока (то есть репо, в которое вы отправляете данные), и в большинстве случаев у вас нет прямого локального доступа к нему. Но если вы это сделаете, то это, безусловно, еще один хороший пример использования " reset --soft" (как в stackoverflow.com/questions/5203535/… ) Итак, +1 к вашему ответу.
VonC
2

Вы также можете использовать нотацию git refspec и сделать что-то вроде этого:

git push -f origin +<commit you want to revert to>:<destination_head | branch_name>

Это принудительно обновляет целевую ветку (как обозначено ссылкой) в исходную фиксацию, как обозначено +<object ref>частью.

Алуп
источник
2
кроме случаев, когда в ветке есть acl - что обычно бывает, если вам «нужно сделать это на самом голом репо» ...
Дэвид Шмитт