Как мне «перезаписать», а не «объединить» ветку в другой ветке в Git?

257

У меня есть две ветви, emailи staging. stagingэто последняя версия, и мне больше не нужны старые изменения в emailветке, но я не хочу их удалять.

Поэтому я просто хочу поместить все содержимое stagingв, emailчтобы они оба указывали на один и тот же коммит. Это возможно?

Рафид
источник
4
Возможный дубликат Изменить текущую ветку на master в git
Томас Кубес

Ответы:

196

Вы можете использовать «нашу» стратегию слияния:

$ git checkout staging
$ git merge -s ours email # Merge branches, but use our branch head
knittl
источник
26
Я пробовал это, и мне кажется это задом наперед? Разве это не сбрасывает содержимое электронной почты в постановку, а не наоборот?
Макс
27
@ Макс У меня было такое же замешательство, и это доставляло мне много хлопот. Вам нужно выполнить эту команду из новой ветки (промежуточная), а затем выполнить обычное слияние / PR со своей старой веткой (электронная почта).
MrGlass
7
Почему ;в конце каждой команды? Я сделал без ;и, кажется, работает. Кроме того, этот ответ неполон, третий шаг состоит в извлечении старой ветки (электронная почта) и затем объединении с подготовкой снова.
Росди Касим
4
git rebase -s theirs <oldbranc> <newbranch> работает также (независимо от того, какая вы ветвь). Обратите внимание, что в rebase «их» - это фактически новый филиал, потому что «наш» - это глава, к которому мы в настоящее время применяем коммиты.
Рольф
4
@Rolf: но rebase избавится от информации о слиянии и сгладит историю. Не обязательно то, что вы после. Также не очень хорошая идея, если вы работаете с уже опубликованной историей.
knittl
99

Если вы просто хотите, чтобы две ветви 'email' и 'staging' были одинаковыми, вы можете пометить ветку 'email', а затем сбросить ветку 'email' на 'staging':

$ git checkout email
$ git tag old-email-branch
$ git reset --hard staging

Вы также можете перебазировать ветку 'staging' на ветку 'email'. Но результат будет содержать модификацию двух веток.

Сильвен Дефресн
источник
1
вы, вероятно, имеете в виду git checkout, git checkне существует, насколько мне известно
knittl
4
Вы правы, я настолько привык к завершению команды git, что всегда пишу "git check <TAB>", чтобы написать "git checkout"! Исправлено.
Сильвен Дефресн
17
git reset нарушает репо других людей, которые клонировали ваше репо
Джеффри Де Смет
Я считаю, что это правильный ответ. emailруководитель ветви должен просто указывать на одну stagingи ту же главу, и у них обоих будут одинаковые коммиты, одна и та же история.
cicerocamargo
76

Я видел несколько ответов, и это единственная процедура, которая позволяет мне исправить это без каких-либо конфликтов.

Если вы хотите все изменения от branch_new в branch_old, то:

git checkout branch_new
git merge -s ours branch_old
git checkout branch_old
git merge branch_new

применив эти четыре команды, вы можете без проблем нажать на branch_old

Brugolo
источник
5
Ваш ответ лучше всего подходит для моей проблемы, так как я не хотел сбрасывать HEAD, просто указывал предпочтение новым файлам в более новой ветви при объединении вещей в более старую и работал без проблем! +1
печи
Я отправил свой branch_new в remote после «нашего слияния», и этот метод сработал для меня. Это было необходимо для меня, чтобы подтолкнуть? Или это бы сработало? (Не был уверен, будет ли он использовать локальный филиал или удаленный). Спасибо!
aspergillusOryzae
Почему вы не можете просто сделать ниже? git checkout branch_old git merge -s их филиала_new Подсказка взята из stackoverflow.com/questions/14275856/…
Рипу Даман
Там написано, что не удалось найти стратегию слияния «своих».
arango_86
Прекрасно работает для меня, имеет то преимущество, что ничего не сбрасывается
Ромен
68

Другие ответы дали мне правильные подсказки, но они не помогли полностью.

Вот что сработало для меня:

$ git checkout email
$ git tag old-email-branch # This is optional
$ git reset --hard staging
$
$ # Using a custom commit message for the merge below
$ git merge -m 'Merge -s our where _ours_ is the branch staging' -s ours origin/email
$ git push origin email

Без четвертого шага слияния с нашей стратегией продвижение считается обновлением без ускоренной перемотки вперед и будет отклонено (GitHub).

Шьям Хабаракада
источник
Это делает сообщение Merge-commit неправильным, но да, оно прекрасно работает.
cdunn2001
cdunn2001, мне любопытно. Каково было сообщение слияния-фиксации, которое вы ожидали, и как это запуталось с этим?
Шиам Хабаракада
Там написано «Объединить удаленную систему отслеживания« происхождение / электронная почта »в электронную почту». Это не касается постановки. Ничего страшного, хотя. Просто измените коммит или используйте merge -m 'This is not my beautiful house.' -s ours origin/email.
cdunn2001
@ShyamHabarakada, я делаю, как вы говорите, и у меня возникает проблема с обновлением без ускоренной перемотки вперед. потому что ничего не происходит, когда я делаю 4-й шаг.
kommradHomer
4-й шаг требует от вас использования источника / электронной почты, он не работает только с локальной электронной почтой.
Трэвис Ридер
45

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

git checkout email
git reset --hard staging
git push origin email --force

Примечание: это только в том случае, если вы ДЕЙСТВИТЕЛЬНО никогда больше не захотите видеть материал по электронной почте.

jsarma
источник
1
git push origin email --force у меня не сработал, так как левые ветви Step2 разошлись. Итак, после шага 2, это то, что я сделал: git reset origin / email и затем git push
user3505394
2
Это именно то, что было задано в вопросе - «как переписать, а не объединить». Должен быть принят ответ.
jozols
17

Я хотел объединить две ветви, чтобы все содержимое old_branchбыло обновлено содержимым изnew_branch

Для меня это работает как шарм:

$ git checkout new_branch
$ git merge -m 'merge message' -s ours origin/old_branch
$ git checkout old_branch
$ git merge new_branch
$ git push origin old_branch
Мадху
источник
10

Как насчет:

git branch -D email
git checkout staging
git checkout -b email
git push origin email --force-with-lease
Арек С
источник
@emptywalls, потому что он принудительно нажимает, не предупреждая пользователя, что он может быть отклонен сервером, и не объясняет, зачем это нужно. Тем не менее, это жизнеспособный вариант для проекта с одним разработчиком
Дэвид Коста
@DavidCosta, почему это будет отклонено сервером? это просто удалить ветку электронной почты и скопировать стадию в электронную почту »... Так что я просто хочу поместить все содержимое« постановки »в« электронную почту », чтобы они оба указывали на один и тот же коммит» - это именно то, что происходит Вот.
Arek S
@ArekS может быть отказано с помощью ловушки на стороне сервера, если ветка установлена ​​как «защищенная», например, в GitLab. Проблема в том, что если кто-то извлек свою ветку из электронной почты перед этой операцией, а затем попытается отправить, ссылки больше не совпадают (потому что некоторые коммиты просто исчезли)
Дэвид Коста
1
Я отредактировал оригинал с --force на --force-with-lease, что делает дело неразрушающим образом.
frandroid
1
Это лучший способ, если вы просто хотите удалить ветку и начать ее чистую из исходной ветки.
Шейн
6

Другие ответы выглядели неполными.
Я попробовал ниже в полном объеме, и он работал нормально.

НОТА:
1. Сделайте копию своего хранилища, прежде чем пытаться сделать это ниже, чтобы быть в безопасности.

Детали:
1. Вся разработка происходит в ветке dev.
2. Ветвь q - это та же самая копия dev.
3. Время от времени код dev должен быть перемещен / переписан в ветку qa

поэтому нам нужно переписать ветку qa из ветки dev

Часть 1:
С помощью приведенных ниже команд старый qa был обновлен до более нового dev:

git checkout dev
git merge -s ours qa
git checkout qa
git merge dev
git push

Автоматический комментарий для последнего нажатия дает ниже:

// Output:
//  *<MYNAME> Merge branch 'qa' into dev,*  

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

Часть 2:

Ниже приведены неожиданные новые локальные коммиты в dev, ненужные,
поэтому нам нужно выбросить и сделать dev нетронутым.

git checkout dev

// Output:
//  Switched to branch 'dev'  
//  Your branch is ahead of 'origin/dev' by 15 commits.  
//  (use "git push" to publish your local commits)


git reset --hard origin/dev  

//  Now we threw away the unexpected commits

Часть 3:
Убедитесь, что все как положено:

git status  

// Output:
//  *On branch dev  
//  Your branch is up-to-date with 'origin/dev'.  
//  nothing to commit, working tree clean*  

Вот и все.
1. старый qa теперь перезаписывается новым кодом ветки dev
2. local чист (удаленный источник / dev не тронут)

Манохар Редди Поредди
источник
6

Самый простой способ сделать это:

//the branch you want to overwrite
git checkout email 

//reset to the new branch
git reset --hard origin/staging

// push to remote
git push -f

Теперь ветка электронной почты и сценарии совпадают.

B.Neo
источник
2
Предупреждение: это удаляет все коммиты в emailветке. Это все равно что удалить emailветку и создать ее заново во главе stagingветки.
Кэмерон Хадсон,
2
git checkout email
git merge -m "Making email same as staging disregarding any conflicts from email in the process" -s recursive -X theirs staging
Willa
источник
1
Этот ответ был бы более понятным для меня, если бы комментарий был сделан отдельно от объединяющего комментария в команде. Кратко объясните, что делает -X и как это влияет на это слияние. Спасибо хоть.
Заставил
@noelicus спасибо за комментарий, и вы правы. Я мог бы отредактировать ответ в будущем.
Willa
0

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

git checkout new -b tmp
git merge -s ours old -m 'irrelevant'
git checkout old
git merge --squash tmp
git branch -D tmp
#do any other stuff you want
git add -A; git commit -m 'foo' #commit (or however you like)
Ян Кью Пеблик
источник