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

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

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

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

8 ответов

Решение

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

mv -f $3 $2
exit 0

git merge --strategy=theirs Симуляция № 1

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

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

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

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

(Изменить 2011):

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

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

Пока мое репо не имело ничего общего с публичной версией, все было в порядке, но с тех пор я бы хотел иметь возможность объединяться в WIP с другими членами команды и сторонними участниками, я хочу убедиться, что мои публичные ветки Надежность для других пользователей: отводить и извлекать данные, т. е. больше не нужно перезагружать и сбрасывать то, что я отправил в удаленное резервное копирование, поскольку теперь оно доступно на 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

(то же сообщение в блоге)

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

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

(предложено тем же Майклом Гебетсройтером):

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

(это не было бы git, если бы это было невозможно с командами git only, все в 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

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

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

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

Для меня это звучит так:

$ git reset --hard origin/master

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

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

Еще одна симуляция для 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 HEAD@{1} # fix the content
git commit --amend

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

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

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

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 в приведенном выше примере), используя дерево одной из них (bar в примере выше, предоставляя "свое" дерево), игнорируя любые проблемы diff / file (commit-tree - команда низкого уровня, поэтому не заботится о тех). Обратите внимание, что голова может быть только 1 (так что эквивалент вишни с "их").

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

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

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

  • Посмотрите на ветку X, которую вы хотите выглядеть как Y
  • cp -r.git / tmp
  • Проверьте филиал Y
  • rm -rf.git && cp -r /tmp/.git.
  • Фиксируйте и продвигайте любую разницу
  • СДЕЛАННЫЙ.

Перейдите к удаленной ветке upstream и выполните git merge со стратегией слияния, установленной на ours,

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

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

Используйте git reset BACKWARDS!

Вы можете сделать ветку похожей на любой другой коммит с git reset, но вы должны сделать это в обход.

Сделать ветку на коммите <old> выглядеть как коммит <new>, ты можешь сделать

git reset --hard <new>

чтобы сделать <new> содержимое рабочего дерева.

Тогда делай

git reset --mixed <old> 

изменить ветвь обратно на исходный коммит, но оставив рабочее дерево в <new> состояние

Затем вы можете добавить и зафиксировать изменения, чтобы ваша ветка точно соответствовала содержимому <new> совершить.

Это нелогично, чтобы перейти от <old> государство к <new> вам нужно сделать git reset от <new> в <old>, Однако с возможностью --mixed рабочее дерево осталось в <new> и указатель ветви установлен в <old>, так что когда изменения зафиксированы, ветка выглядит так, как мы хотим.

Предупреждение

Не упускайте из виду ваши коммиты, например, забудьте, что <old> когда делает git reset --hard <new>,

Я следовал за этими ролями:

Извлечение источника, жесткий сброс из ветви, затем рекурсивный из их, а затем принудительный толчок к ветви

НА СВОЙ РИСК

git fetch origin
git reset --hard origin/<branch>
git merge origin/<branch> -s recursive -Xtheirs
git push -f <remote> <branch>
Другие вопросы по тегам