Git команда для создания одной ветки как другой

Я пытаюсь взять ветку с изменениями и вернуть ее, чтобы она была идентична восходящему потоку, от которого она расходилась. Изменения являются локальными и были перенесены в github, поэтому ни git reset, ни git rebase не являются действительно жизнеспособными, поскольку они меняют историю, что плохо с веткой, которая уже была нажата.

Я также пробовал git merge с различными стратегиями, но ни один из них не отменяет локальные изменения, т.е. если бы я добавил файл, слияние могло бы привести другие файлы обратно в строку, но у меня все еще будет этот файл что восходящий поток не имеет.

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

Ответ 1

Вы можете объединить свою ветвь вверх по течению в ветку dev с помощью настраиваемого драйвера слияния "keepTheirs" :
См. " "git merge -s theirs" , но я знаю, что этого не существует.
В вашем случае потребуется только один .gitattributes, а keepTheirs script как:

mv -f $3 $2
exit 0

git merge --strategy=theirs Моделирование # 1

Показывает как слияние, с восходящим потоком в качестве первого родителя.

Jefromi упоминает (в комментариях) merge -s ours, объединив вашу работу над восходящим (или на ветке temp, начиная с восходящего потока), и затем быстро переадресуйте свою ветку на результат этого слияния:

git checkout -b tmp origin/upstream
git merge -s ours downstream         # ignoring all changes from downstream
git checkout downstream
git merge tmp                        # fast-forward to tmp HEAD
git branch -D tmp                    # deleting tmp

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

(Edit 2011):

Этот рабочий процесс был опубликован в этом сообщении блога OP:

Почему я хочу снова это сделать?

Пока мое репо не имеет ничего общего с публичной версией, все было в порядке, но с тех пор я хочу, чтобы у меня была возможность сопоставлять WIP с другими членами команды и внешними участниками, я хочу убедиться, что моя публичные ветки надежны для других, чтобы отламывать и тянуть, т.е. больше не переустанавливать и reset по вещам, которые я нажал на удаленную резервную копию, так как теперь она находится на GitHub и публичной.

Итак, это оставляет меня тем, как я должен действовать.
В 99% случаев моя копия попадает в ведущего мастера, поэтому я хочу работать с моим мастером и в большинстве случаев нажимать вверх по течению.
Но время от времени то, что у меня есть в wip, становится недействительным по тому, что происходит в восходящем направлении, и я оставлю часть моего wip.
В этот момент я хочу вернуть моего мастера в синхронизацию с восходящим потоком, но не уничтожить какие-либо пункты фиксации на моем публично продвинутом главном устройстве. То есть Я хочу слияние с восходящим потоком, который заканчивается набором изменений, который делает мою копию идентичной вверху.
И это то, что должен git merge --strategy=theirs.


git merge --strategy=theirs Моделирование # 2

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

(предлагается jcwenger)

git checkout -b tmp upstream
git merge -s ours thebranch         # ignoring all changes from downstream
git checkout downstream
git merge --squash tmp               # apply changes from tmp but not as merge.
git rev-parse upstream > .git/MERGE_HEAD #record upstream 2nd merge head
git commit -m "rebaselined thebranch from upstream" # make the commit.
git branch -D tmp                    # deleting tmp

git merge --strategy=theirs Моделирование # 3

В этом сообщении в блоге указано:

git merge -s ours ref-to-be-merged
git diff --binary ref-to-be-merged | git apply -R --index
git commit -F .git/COMMIT_EDITMSG --amend

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


git merge --strategy=theirs Моделирование # 4

(тот же пост в блоге)

В качестве альтернативы, если вы хотите, чтобы локальные ветки upstream быстро пересылались, потенциальный компромисс должен работать с пониманием того, что для sid/unstable ветка восходящего потока может время от времени быть reset/rebased (на основе события, которые в конечном счете выходят из-под контроля на стороне проекта).
Это не имеет большого значения, и работа с этим предположением означает, что легко поддерживать локальную ветвь восходящего потока в состоянии, когда оно требует только быстрых обновлений.

git branch -m upstream-unstable upstream-unstable-save
git branch upstream-unstable upstream-remote/master
git merge -s ours upstream-unstable
git diff --binary ref-to-be-merged | git apply -R --index --exclude="debian/*"
git commit -F .git/COMMIT_EDITMSG --amend

git merge --strategy=theirs Моделирование # 5

(предложенный Барак А. Перлмуттер):

git checkout MINE
git merge --no-commit -s ours HERS
git rm -rf .
git checkout HERS -- .
git checkout MINE -- debian # or whatever, as appropriate
git gui # edit commit message & click commit button

git merge --strategy=theirs Моделирование # 6

(предложенный тем же Michael Gebetsroither):

Майкл Гебсетромид взволнован, заявив, что я "обманывал";) и дал другое решение с командами сантехники нижнего уровня:

(это не будет git, если это будет невозможно с git только командами, все в git с diff/patch/apply не является реальным решением;).

# get the contents of another branch
git read-tree -u --reset <ID>
# selectivly merge subdirectories
# e.g superseed upstream source with that from another branch
git merge -s ours --no-commit other_upstream
git read-tree --reset -u other_upstream     # or use --prefix=foo/
git checkout HEAD -- debian/
git checkout HEAD -- .gitignore
git commit -m 'superseed upstream source' -a

Ответ 2

Вы можете сделать это довольно легко:

$ git fetch origin
$ git merge origin/master -s recursive -Xtheirs

Получает локальное репо в синхронизации с источником и сохраняет историю.

Ответ 3

Мне кажется, что вам просто нужно:

$ git reset --hard origin/master

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

** Фактически изменения все еще существуют, если вы их совершили локально, так как коммиты будут по-прежнему находиться в вашем git reflog, обычно в течение как минимум 30 дней.

Ответ 4

Еще одно симуляция для git merge -s theirs ref-to-be-merged:

git merge --no-ff -s ours ref-to-be-merged         # enforce a merge commit; content is still wrong
git reset --hard HEAD^2; git reset --soft [email protected]{1} # fix the content
git commit --amend

Альтернативой двойному reset будет применение обратного патча:

git diff --binary ref-to-be-merged | git apply -R --index

Ответ 5

Там также способ с небольшой помощью команды сантехники - ИМХО самый простой. Скажем, вы хотите подражать "их" для случая с двумя ветвями:

head1=$(git show --pretty=format:"%H" -s foo)
head2=$(git show --pretty=format:"%H" -s bar)
tree=$(git show --pretty=format:"%T" -s bar)
newhead=$(git commit-tree $tree -p $head1 -p $head2 <<<"merge commit message")
git reset --hard $newhead

Это объединяет произвольное количество головок (2 в приведенном выше примере), используя дерево одного из них (строка в приведенном выше примере, предоставляющая дерево "их" ), не обращая внимания на любые проблемы diff/file (commit-tree - команда низкого уровня, так что это не волнует их). Обратите внимание, что голова может быть только 1 (что эквивалентно вишневому кирку с "их" ).

Обратите внимание, что указанная родительская головка может влиять на некоторые вещи (см., например, - first-parent команды git -log) - так что имейте это в виду.

Вместо git -show можно использовать все, что может выводить хеши дерева и commit, независимо от того, что используется для синтаксического анализа (cat-file, rev-list,...). Вы можете следить за всем с помощью git commit --amend для интерактивного украшения сообщения фиксации.

Ответ 6

измените на удаленную ветвь вверх и выполните git merge с стратегией слияния, установленной на ours.

git checkout origin/master
git merge dev --strategy=ours
git commit ...
git push

Вся история будет по-прежнему присутствовать, но у вас будет дополнительное слияние. Здесь важно начать с версии, на которой вы хотите быть, и слить ours с веткой github на самом деле.

Ответ 7

Тяжелая рука, но, черт возьми, что может пойти не так?

  • Проверьте ветку X, которую вы хотите видеть как Y
  • cp -r.git/tmp
  • Отъезд ветки Y
  • rm -rf.git && & cp -r/tmp/.git.
  • Зафиксируйте и нажмите любую разницу.
  • DONE.