Подтвердить что ты не робот

Как тривиально линеаризую мою историю git?

Вопрос

Учитывая, что у меня есть фиксация следующим образом:

A - B - C - D - G - H
     \         /
      - E - F -

Как получить совершенно линейную историю после первых родителей?

Например, я хочу получить:

A - B - C - D - G'- H'

Ожидается, что sha1 из G и H изменится, как указано выше. (По понятным причинам). Если sha1 для A, B, C и D также изменится, тогда я хочу знать, почему.

Фон

Цель состоит в том, чтобы избежать возможных коммандов слияния, которые возникли бы при выполнении наивной git rebase -i.

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

I - J - K - L - M
 \     /   /   / 
  - N - O - P -

Где N было объединено в K, но O было объединено с -strategy = ours в L, а P было объединено в M.

Я хочу, чтобы иметь возможность линеаризовать мою историю, чтобы такие проблемные фиксации можно было идентифицировать и проверить. Я хочу иметь дерево, где можно определить, что O не было помещено в ветвь вверх по течению, даже если я потенциально идентифицирую N и P как потенциально отсутствующие в ветке вверх по течению, используя git cherry, однако любые предложения здесь быть оцененным.

4b9b3361

Ответ 1

Как вы сказали, работает следующая команда:

git filter-branch --parent-filter 'cut -f 2,3 -d " "'

Почему?

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

Каждая фиксация имеет одну или несколько операндов. Merge commit - это тот, который получает больше одного. Git сохраняет это в каждом объекте фиксации истории.

Команда git filter-branch с параметром --parent-filter позволяет переписать каждый родитель фиксации, переданный фильтру как -p SHA1, повторяющийся, если имеется более одного родителя. Наш фильтр отсекает родителя и заставляет каждую фиксацию иметь одного родителя.

Для бонуса, здесь, как сделать это вручную при точном фиксации, путем повторного создания нового фиксации:

  • получить дерево фиксации и первый родительский

    tree=`git show -s --format=%T SHA1`
    parent=`git show -s --format=%P SHA1 | cut -d " " -f1`
    
  • сделать новую фиксацию с тем же деревом, тем же сообщением и сохранить только первого родителя в качестве предка

    git show -s --format=%B SHA1 | git commit-tree $tree -p $parent
    

Ответ 2

Сделайте это вручную со следующим:

git rebase -i D-sha1

Отредактируйте файл, чтобы установить G в "edit". Храните "pick" для H. Сохраните и закройте редактор.

Теперь Git позволяет редактировать G commit, а затем модифицировать его в сквош-слияние F-фиксации. Вы хотите:

#cancel the merge commit and position HEAD to D
git reset --hard HEAD~
#squash merge and continue
git merge --squash F-sha1
git rebase --continue

Обратите внимание, что вам придется решать те же конфликты, если вам пришлось в первом слиянии...

Как вы говорите, у вас будет только новый SHA1 для G и H.