2009-09-23 3 views
23

Я пытаюсь иметь две ветви с бинарными файлами в git - одну «разработку» и одну «стабильную». В ветке разработки может быть несколько изменений этих файлов, прежде чем я хочу «освободить» их до стабильной ветви (и стабильная ветвь имеет эти файлы, переименованные, если это имеет значение).Git merge squash несколько раз

Я мог бы сделать нормальное слияние, это прекрасно работает, но сохраняет слишком много истории - когда тянет «стабильную» ветвь, все промежуточные фиксации из ветви «развития» также вытягиваются (потому что они являются родительскими) , Но мы говорим о двоичных файлах, которые не имеют разумной стратегии слияния (кроме их/наших), поэтому фактическая история файлов в ветке разработки бесполезна. Когда я тяну «стабильный» филиал, я получаю это:

 
      X-------------------G stable 
     /    /
    a---b---c---d---e---f---g development 

Поскольку G имеет родитель в отрасли разработки, я получаю всю историю отрасли разработки (объекты данных для C, D, E, F и g) в моем репозитории, который меня не интересует (X - это то же, что и b, с некоторым переименованием файлов).

Таким образом, я попытался до git merge --squash изменений от ветви развития до стабильной ветви. Первое такое слияние и совершить пошло КИ, результаты были, как и ожидалось (хороший журнал изменений в сообщении фиксации, никакого отношения к отрасли развития):

   X-------------------G stable 
     /     
    a---b---c---d---e---f---g development

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

 
a---b---X---G 

Но второе слияние не удалось (потому что мерзавец не было никакого способа узнать, сколько я слился уже и запутался).

  • Возможно ли каким-либо образом записать слияние, не производя «слияния» с двумя родителями?
  • Или можно сказать git, чтобы объединить только определенный «диапазон» ревизий, например, в SVN?
  • Или, возможно ли выполнить нормальное слияние без необходимости загружать все ссылки с другой ветки при потянув?
  • Или я должен предоставить пользовательский драйвер слияния для соответствующих файлов, который просто переименовывает «свою» версию в «наш», тем самым разрешая конфликты? Я все еще боюсь, что --squash всегда будет пытаться объединить всю историю, вплоть до общего родителя, решая только половину моей проблемы.

Update: перебазирования

Если я правильно понял перебазирования, я в конечном итоге с этим:

 
           X stable 
          /
    a---b---c---d---e---f---g development 

Который получает меня все данные, я не заинтересован в (с , d, e, f) и в качестве бонуса я потеряю информацию о том, что b является стабильной версией в ветке.

Каждый модификатор развития добавляет около 5 МБ к размеру репозитория (и переупаковка всего репо сокращает его примерно на 10%), «стабильная» ветвь приходит почти бесплатно (данные уже есть). Я хочу вытащить одну новую ревизию из стабильной ветки, чтобы вытащить только новые 5 МБ, но вместо этого обновление с X до G загружает 25 МБ, потому что я как-то не могу сказать, что меня не интересует содержимое c, d , e и f.

ответ

23

Начиная с

 X stable 
    /     
a---b---c---d---e---f---g development 

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

git checkout [email protected]{0} # get working tree from "development", detach HEAD 
git reset --soft stable # reposition detached HEAD on "stable" 
git commit # enter the appropriate commit message 
git branch temp # create a temporary branch "temp" at HEAD 
git checkout temp # get on the new temporary branch 
git branch -M stable # rename "temp" to "stable" 

так что вы в конечном до:

 X-------------------G stable 
    /     
a---b---c---d---e---f---g development 

Если продолжить работу над «развитием», например,

 X-------------------G stable 
    /     
a---b---c---d---e---f---g---h---i---j development 

вы можете повторить команды же мерзавец, как описано выше, и вы будете в конечном итоге с:

 X-------------------G-----------J stable 
    /     
a---b---c---d---e---f---g---h---i---j development 
+1

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

+0

@ kim-sullivan: «именно почему»: когда вы делаете фиксацию в приведенном выше примере, она перемещает 'HEAD', но не' stable', чтобы указывать на новую фиксацию - голова все еще «отсоединена», stable 'все еще указывает на предыдущую версию (X, в вашем исходном примере). Выполнение ветки и переименование (проверка является технически необязательной, но без нее вам нужно будет доставлять аргументы в 'git branch -M', и вы все равно будете отсоединены, что, вероятно, нежелательно) вызывает стабильную точку к J (за ответ). – lindes

+4

Кроме того: вы можете найти пробег 'git log -graph -oneline -all -decorate' и' git status' в каждой точке этой серии команд, чтобы быть информативным. И/или просмотр содержимого различных файлов в .git /, возможно, с помощью команды grep. .git/HEAD .git/refs/heads/* ' – lindes

7

Это не подходящее место для использования merge --squash.Одно хорошее место, чтобы использовать его, - в ветви разветвленной темы, которую вы собираетесь объединить в свою основную ветку, а затем избавиться. Вся разработка, выполненная в ветке темы, показана как одна фиксация в основной ветке. В вашей ситуации вы должны нормально сходить из ветки разработки, а затем использовать git-rebase --interactive, чтобы выкачать необходимые коммиты.

Можно ли как-то записать слияние, не производя «слияние фиксации» с двумя родителями?

Если я правильно понял вопрос, нет. Абсолютно не.

Можно ли сказать, мерзавец слить лишь определенное «диапазон» изменений, как в SVN?

Да. git merge [commit hash]

Или это можно сделать нормальное слияние без необходимости загружать все реф из другой ветви при трогании?

См. Ответ на предыдущий вопрос.

Или я должен предоставить драйвер пользовательского слияния для файлов в вопросе, что просто переименовывает «свою» версию «наши», тем самое разрешающие конфликты? Я все еще боюсь, что -squash всегда будет пытаться объединить всю историю, вплоть до общего родителя, решая только половину моей проблемы.

Нет! Просто не используйте git merge --squash. Это не подходящее место для его использования!

+0

Спасибо за ваш ответ! Я не уверен, что перезагрузка - это то, что мне нужно. Мне нужно записать некоторую историю в «стабильной» ветке, поэтому я могу идти туда и обратно между «релизами».Это то, что я хочу: ' D -> S D | D | D -> S D | D -> S' Но мне нужна только история из ветки S - мне не нужна история из ветви D. Проблема, которую мне нужно решить, - это как вытащить S-ветвь, не вытаскивая все родительские ссылки из ветви D (если я правильно ее понимаю, перезагрузка избавляется от всех предыдущих S-коммитов, чего я не хочу). ' D -> х D D D -> х D D -> S' –

+0

Да, я понимаю, что вам нужно сохранить существующую историю с -ветви. Нет, rebasing не избавляется от всех предыдущих S-коммитов; перед слиянием разработки в стабильную, обратите внимание на хеш [commit hash], а затем git rebase -i [commit hash] - тогда вы эффективно будете только раздавить коммиты, которые вы только что объединили. Кроме того, что касается выпусков, почему бы не просто пометить конкретные коммиты как релизы? – artagnon

+0

Прошу прощения, я не совсем понимаю ваш D -> S D | D диаграмма слишком хорошо. Надеюсь, что мой предыдущий комментарий прояснил все. – artagnon

4

можно использовать git rebase -i (интерактивный режим), чтобы sqash все изменения, просто измените строки m или meld (обновление: для новой Git высвобождает типа s или squash)

вы, чем иметь одну фиксацию, которая вы можете слиться.если вы хотите, чтобы каждый ваш заказ зарезервирован, вам нужно создать еще одну ветку в вашей ветке взлома, прежде чем делать переустановку, это можно сделать с помощью git branch small-dirty-changes-i-don’t-want-anybody-to-see

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

# on branch "hacking": hack commit hack commit hack commit 

# create a reference to your history 
$ git branch dirty-history 

# sqash your commits by setting all lines to "meld" 
$ git rebase -i 

# checkout master or the branch you want to merge to 
$ git checkout master 

# merge your squashed commit 
$ git merge hacking 
# or: $ git pull hacking 
+0

Хм, я, вероятно, мог бы периодически менять изменения в ветке разработки («грязные») (фактически, до слияния с стабильной и выпуской), поэтому у меня нет всех этих промежуточных двоичных файлов, которые мне не нужны , Единственная важная вещь между стабильными версиями - хеш и сообщения фиксации ... Хэш важен для тестирования (сборка была протестирована, а какая нет). Мне придется подумать об этом еще немного. –

+0

хороший ответ, я думаю, что «meld» в наши дни означает «squash» (ваш ответ с 2009 года!) –

+1

Да, теперь это '' '' '' '' '' '' '' '' '' '' '' '' '' '' '. – knittl

-1

Я новичок в мерзавец, но похоже, что -squash - это то, что вы хотите, вам просто нужно обрабатывать ветку по-разному.

$ git merge --squash development 
$ git branch -d development 
$ git checkout -b development 
# continue work on development branch 

Это существенно усело бы историю развития ветки, и следующее слияние было бы только тем, что вы хотели. Глядя на страницу man, кажется, что git branch -f development может сделать то же самое, что удаление и воссоздание ветки.

Как я уже сказал, я довольно новичок в git, поэтому мне очень понравилась бы обратная связь по этой идее.

0

top voted answer эффективно разграничивает контуры стабилизации и развития и применяет все изменения, отсутствующие в конюшне, как один фиксатор. Существует альтернативный способ:

$ git checkout stable 
$ git diff stable development | git apply --index - 
$ git commit 

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

$ git reset --hard 

Вы можете повторить процесс любое количество раз, так как вы эффективно только дифф-ки концы обеих ветвей каждый раз, когда вам нужно объединить.

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

Если вы беспокоитесь об этом, каждый раз, когда вы совершаете фиксацию на стабильном уровне, вы можете поместить объединенный диапазон хеширования разработки в сообщение фиксации. Таким образом, у вас есть запись, если вам когда-нибудь понадобится отступить.

Смежные вопросы