Сделайте две ветки git в одну - PullRequest
0 голосов
/ 14 марта 2019

Учитывая эту ситуацию

A--B
|  B1
|  B2
|  ...
|  Bn label:b-branch
|
C--D1
|  D2
|  ...
|  Dn label:d-branch
|
E

Я бы хотел подключить Bn к D1, чтобы у нас был хороший чистый путь, даже если Bn и D1 абсолютно не связаны.Мне не нужно делать какие-либо причудливые слияния или иным образом влиять на какой-либо фактический исходный код, поскольку ветвь D полностью заменяет ветвь B, я просто хочу как-то сказать, что Bn теперь является еще одним родителем D1с C, то есть:

A--B
|  B1
|  B2
|  ...
|  Bn label:b-branch
|  |  <- Only this link is new
C--D1
|  D2
|  ...
|  Dn label:d-branch
|
E

Код размещен на частном экземпляре GitLab, поэтому я знаю, что всем придется синхронизироваться при изменении истории.

1 Ответ

2 голосов
/ 14 марта 2019

Начните с git replace. Я не совсем уверен, каким способом читать ваш график, поэтому я просто скажу, что вы можете использовать это с --edit или с --graft. Это сделает замену некоторого коммита с заменой на любые изменения, которые вам нравятся.

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

A <-B <-C <-D <-E   <-- master

Commit E имеет D в качестве родителя, который имеет C в качестве родителя и т. Д.

Мы можем сделать новый коммит C', чей родитель A, используя git replace --graft <em>hash-of-C</em> <em>hash-of-A</em>, давая:

A--B--C--D--E   <-- master
 \
  C'   <-- refs/replace/hash-of-C

Когда git log или другие подобные команды идут по графику, они могут начинаться с E и показывать его, а затем переходить к D и показывать его. Сложный случай происходит следующим образом: они переходят на C, но в этот момент они замечают, что refs/replace/<em>hash-of-C</em> существует. Они полностью отпускают C, вместо этого переходят на C' и показывают это. Они переходят к C' родителю A и показывают это. В результате B кажется исчезло . Тот же трюк сработает для вашего случая: если вы хотите представить двух родителей там, где был только один, вы делаете замену, в которой вместо этих одного есть два родителя.

Недостатком этого типа замены является то, что git clone обычно пропускает пространство имен refs/replace/ и его фиксации. Таким образом, кто-то, клонирующий хранилище, видит исходные коммиты - их Git вообще не имеет refs/replace/<em>hash</em> и никогда не копировал коммиты замены.

Вы можете организовать их клонирование, но вместо этого теперь вы можете использовать 1047 * в противном случае, чтобы "зацементировать" замену на месте в новом хранилище. Например, после:

git filter-branch --tag-name-filter cat -- --all

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

A--B--C--D--E   <-- refs/original/refs/heads/master
 \
  C'   <-- refs/replace/hash-of-C
    \
     D'-E'  <-- master

Отбрасывая имена пространств имен refs/original/ и refs/replace/, создав еще один клон, вы получите:

A--C'-D'-E'  <-- master

, который сделал прививку постоянной. Таким образом, теперь вы можете либо клонировать репозиторий и использовать клон в качестве репозитория замены, либо просто отбросить имена refs/replace/ и refs/original/ из исходного репозитория, чтобы он выглядел так же, как и предлагаемая клонированная замена (за исключением того, что исходные объекты как правило, задерживаются на некоторое время - в основном, до тех пор, пока сборщик мусора не сможет их очистить).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...