Как я могу сбросить * весь репо *? - PullRequest
0 голосов
/ 17 января 2019

Как я могу сбросить весь репо , т.е. все ветви вернутся в свое последнее состояние перед данным коммитом?

ТЛ; др

Предположим, у меня есть репо с четырьмя ветками: master, one, two и three:

git init
echo a > a.txt && git add . && git commit -m "added a"
git checkout -b one
echo b > b.txt && git add . && git commit -m "added b"
git checkout master
git checkout -b two
echo c > c.txt && git add . && git commit -m "added c"
git checkout -b three
echo d > d.txt && git add . && git commit -m "added d"

Вот мое дерево (из-за простоты три - это просто ускоренная перемотка вперед двух):

git checkout master
git --no-pager log --graph --oneline --decorate --all
* a7457d6 (one) added b
| * a7e62c6 (three) added d
| * c84c43b (two) added c
|/  
* 6ec61a1 (HEAD -> master) added a

Затем я делаю ошибку, которую позже хочу стереть, например, Мисс слияние ветки.

git merge --strategy=ours one -m "accidentally lose ability to merge one"

Я невольно распространяю его на некоторые из этих ветвей (две и три):

git checkout two
git merge master -m "propagating problem to two"
git checkout three
git merge master -m "propagating problem to three"

Дерево теперь выглядит так:

git checkout master
git --no-pager log --graph --oneline --decorate --all
*   83448b1 (three) propagating problem to three
|\  
* | a7e62c6 added d
| | *   f33efb4 (two) propagating problem to two
| | |\  
| |/ /  
|/| /   
| |/    
| *   69bee42 (HEAD -> master) accidentally lose ability to merge one
| |\  
| | * a7457d6 (one) added b
| |/  
* | c84c43b added c
|/  
* 6ec61a1 added a

Изучая рефлог, мы можем увидеть, где я ошибся и что на это повлияло:

git --no-pager reflog --oneline --all
69bee42 HEAD@{6}: checkout: moving from three to master
83448b1 refs/heads/three@{1}: merge master: Merge made by the 'recursive' strategy.
83448b1 HEAD@{7}: merge master: Merge made by the 'recursive' strategy.
a7e62c6 (three) HEAD@{8}: checkout: moving from master to three
69bee42 HEAD@{9}: checkout: moving from two to master
f33efb4 refs/heads/two@{1}: merge master: Merge made by the 'recursive' strategy.
f33efb4 HEAD@{10}: merge master: Merge made by the 'recursive' strategy.
c84c43b (two) HEAD@{11}: checkout: moving from master to two
69bee42 refs/heads/master@{1}: merge one: Merge made by the 'ours' strategy.
69bee42 HEAD@{12}: merge one: Merge made by the 'ours' strategy.
6ec61a1 (HEAD -> master) HEAD@{13}: checkout: moving from three to master
6ec61a1 (HEAD -> master) refs/heads/master@{2}: commit (initial): added a
a7457d6 (one) refs/heads/one@{0}: commit: added b
6ec61a1 (HEAD -> master) refs/heads/one@{1}: branch: Created from HEAD
a7e62c6 (three) refs/heads/three@{2}: commit: added d
c84c43b (two) refs/heads/three@{3}: branch: Created from HEAD
c84c43b (two) refs/heads/two@{2}: commit: added c
6ec61a1 (HEAD -> master) refs/heads/two@{3}: branch: Created from HEAD
a7e62c6 (three) HEAD@{14}: commit: added d
c84c43b (two) HEAD@{15}: checkout: moving from two to three
c84c43b (two) HEAD@{16}: commit: added c
6ec61a1 (HEAD -> master) HEAD@{17}: checkout: moving from master to two
6ec61a1 (HEAD -> master) HEAD@{18}: checkout: moving from one to master
a7457d6 (one) HEAD@{19}: commit: added b
6ec61a1 (HEAD -> master) HEAD@{20}: checkout: moving from master to one
6ec61a1 (HEAD -> master) HEAD@{21}: commit (initial): added a

Итак, я оглядываюсь назад и вижу, что моя ошибка была (первая) 69bee42. Теперь я хочу откатить весь репо к тому времени.

Единственный способ, которым я мог это сделать, - это наблюдать за рефлогом, чтобы увидеть, какие ветви я загрязнил, и по отдельности откатить их в состояние до того, как они были сломаны. Поскольку этот пример искусственно прост, все эти состояния ~ 1:

git checkout master
git reset --hard master~1
git checkout two
git reset --hard two~1
git checkout three
git reset --hard three~1

[[Редактировать: branch -f из ветви более элегантно. Мне не требуется обновление:

git checkout one
git branch -f master master~1
git branch -f two two~1
git branch -f three{,~1} # get cute with bash {} expansion

]]

В реальной жизни это было чрезвычайно подвержено ошибкам:

  1. Из-за некоторых дополнительных слияний ничего не было в ~ 1, поэтому я перешел на хэши SHA1.
  2. Если вы используете хэши, git не поможет вам убедиться, что ваш коммит был в истории ветви, которую вы сбрасываете. Сброс на относительное время также был проблематичным, потому что интервалы между хорошими и плохими коммитами были очень малы.

Git: откат к более ранней версии подразумевает вышеупомянутое решение по ветвям.

1 Ответ

0 голосов
/ 17 января 2019

Вы на самом деле делаете это правильно: вы должны использовать git reset или git branch -f, чтобы заставить каждое имя ветки указывать на желаемый коммит, а место для поиска коммита находится в соответствующем журнале веток. (Я рекомендую использовать git branch -f как можно больше. Единственная ветвь, которую вы не можете исправить с помощью git branch -f, это ветка current , что бы это ни было; там вы должны использовать git reset вместо этого, вероятно, с --hard - со всеми вытекающими git reset --hard.

Существует несколько ярлыков, которые вы можете использовать: синтаксис reflog позволяет <em>name</em>@{<em>when</em>}, например, master@{1.hour.ago} или three@{yesterday}. Режим @{<em>relative time offset</em>} преобразуется в любой хэш-идентификатор, который произвело бы это имя, если бы вы запустили его так давно. Вы также можете использовать абсолютное время. (Но вы отметили в своем ответе, что временное окно здесь было не очень большим, и, следовательно, это было не так уж и полезно.)

Чтобы просмотреть существующие reflogs с датами, используйте git reflog --date=local или git reflog --date=relative (есть больше вариантов; см. документацию .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...