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


257

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

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


Ответы:


196

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

$ git checkout staging
$ git merge -s ours email # Merge branches, but use our branch head

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


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

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


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

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


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

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)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.