Удалите бесполезные слияния (без фиксаций, не связанных с магистралью) после ответвления фильтра - PullRequest
0 голосов
/ 27 марта 2019

Я выполнил git filter-branch --index-filter 'git rm --cached --ignore-unmatched badfiles/ badfiles2/' --prune-empty (для здесь ), чтобы удалить кучу файлов при подготовке к перемещению оставшихся файлов в другой репозиторий. --prune-empty избавляется от любых возникающих пустых коммитов, но не влияет на слияния, что имеет смысл.

Теперь история этого конкретного репо выглядит довольно уродливо с кучей слияний, которые на самом деле ничего не добавляют, и слияниями, которые являются просто слияниями других слияний, которые фактически не добавляли никаких изменений (в переписанной истории; они возможно, был «полезен» до ответвления фильтра).

Рассмотрим этот аннотированный фрагмент (сгенерированный с git log --graph --oneline --shortstat):

*   575e3b5 Merge pull request #68 from chris/feature # KEEP THIS MERGE!
|\  
| * 5dbc3f1 Actual feature changes
| |  2 files changed, 2 insertions(+), 2 deletions(-)
| * 35abc98 Cleanup/prep
|/  
|    2 files changed, 22 insertions(+), 16 deletions(-)
*   c3b3d86 Merge pull request #46 from org/topic_branch-mods # USELESS-C
|\  
* \   892de05 Merge pull request #47 from org/topic_branch # USELESS-B
|\ \  
| |/  
|/|   
| *   e738d4b Merge branch 'master' into topic_branch # USELESS-A
| |\  
| |/  
|/|   
* | 4182dac CommitMsg #40 #SQUASHED-PR
| |  2 files changed, 15 insertions(+), 6 deletions(-)
* | 3b42762 CommitMsg
|/  
|    2 files changed, 29 insertions(+), 14 deletions(-)
* c4e62ba CommitMsg
|  2 files changed, 39 insertions(+), 16 deletions(-)
* c2bb13f CommitMsg
   4 files changed, 241 insertions(+)

Я хотел бы сократить это до (очевидно, с другими идентификаторами в зависимости от ситуации):

*   575e3b5 Merge pull request #68 from chris/feature # KEEP THIS MERGE!
|\  
| * 5dbc3f1 Actual feature changes
| |  2 files changed, 2 insertions(+), 2 deletions(-)
| * 35abc98 Cleanup/prep
|/  
|    2 files changed, 22 insertions(+), 16 deletions(-) 
* 4182dac CommitMsg #40 #SQUASHED-PR
|  2 files changed, 15 insertions(+), 6 deletions(-)
* 3b42762 CommitMsg
|  2 files changed, 29 insertions(+), 14 deletions(-)
* c4e62ba CommitMsg
|  2 files changed, 39 insertions(+), 16 deletions(-)
* c2bb13f CommitMsg
   4 files changed, 241 insertions(+)

Итак, я хотел бы избавиться от слияний 'USELESS', которые все являются слияниями empty (без изменений слияний), но я бы хотел сохранить историю / группировку, связанную с Кроме того, «пустое» СОХРАНИТЕ слияние вверху, которое объединяет эти коммиты в один «набор изменений».

Или посмотрите на другой пример в традиционной упрощенной истории:

A -- B -- C -- D   ==>  A -- B --- D'
 \----\--/   /                \-E-/
       \----E 

Я пробовал решения для удаления «пустых» слияний (например, this ), но они удаляют все пустых слияний, и я хочу сохранить «полезные» пустые слияния, как показано в примерах ...

Насколько я могу судить, "бесполезные" пустые слияния не содержат никаких коммитов, которые не являются полностью левыми / верхними в истории. Есть ли способ отфильтровать их чисто? Наверное, я даже не знаю, как их описать / определить ...

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

*   3d37e42 Merge pull request #239 from jim/topic-dev
|\  
| *   05eaf9e Merge pull request #7 from org/master
| |\  
| |/  
|/|  
* |   1576482 Merge pull request #193 from john/master
|\ \  
| * \   187100e Merge branch 'master' of github.com:org/repo into master
| |\ \  
| * \ \   067cc55 Merge branch 'master' of github.com:org/repo into master
| |\ \ \  
| * \ \ \   a69e3d2 Merge branch 'master' of github.com:org/repo into master
| |\ \ \ \  
| | |/ / /  
* | | | |   0ce6813 Merge pull request #212 from jim/feature
|\ \ \ \ \  
| | |_|_|/  
| |/| | |   
| * | | |   0f5352e Merge pull request #5 from org/master
| |\ \ \ \  
| |/ / / /  

Ответы [ 2 ]

1 голос
/ 27 марта 2019

В этом суть проблемы:

Полагаю, я даже не знаю, как их описать / определить ...

Git is,По сути, это программа для работы с графами, предназначенная для создания групп DAG (направленных ациклических графов), где каждый узел графа является коммитом.Тот факт, что каждая фиксация содержит снимок источника как своего рода полезную нагрузку данных, не имеет отношения к этому процессу.(Конечно, это очень важно для Git, который в конечном итоге полезен .)

Вы хотите взять существующий (после фильтрации) DAG и создать другой DAG.Вам необходимо определить алгоритм преобразования нежелательной группы доступности базы данных в требуемую группу доступности базы данных.Вам не обязательно использовать git filter-branch для достижения преобразования, но если вы намерены это сделать, вам придется дополнительно усовершенствовать это преобразование в алгоритм, который работает с "пока" знаниями: он может видетьхэш-идентификатор текущего коммита коммита, который ветвь фильтра предлагает скопировать.Это в $GIT_COMMIT.Он может прочитать этот коммит (используя команды Git) и может найти отображение из других уже скопированных коммитов, используя функцию оболочки map, как описано в документации git filter-branch .

Я тоже не совсем понимаю, как определить «полезное слияние».Я думаю, что наиболее очевидным является алгоритм, который (по крайней мере, напрямую) не подходит для ответвления фильтра: это алгоритм итеративной релаксации, в котором вы начинаете с полного графа и неоднократно отбираете узлы слияния, соединяя их родителей с их родителями.дети, когда эти узлы бесполезны.(Вы все еще можете определить бесполезно .) В конце концов, у вас есть список сохраняемых узлов и удаляемых узлов. Этот список полезен для фильтра, который вы пишете для filter-branch: теперь вы запускаете git filter-branch с --commit-filter, который либо запускает git commit-tree как обычно, либо с предоставленной функцией skip_commit, как описанов документации.Решение "сохранить" или "пропустить" основано на списке, который вы создали с помощью алгоритма релаксации.

0 голосов
/ 29 марта 2019

ОК, я не думаю, что это идеально, но это решает проблему в данном конкретном случае;Есть случаи, когда он не вполне очищает столько, сколько возможно, но это шаг, если кому-то интересно:

git filter-branch --commit-filter '
if ! git rev-parse --verify "$GIT_COMMIT^2" 1>/dev/null 2>&1 ||
  [ "$(git log --no-merges "$GIT_COMMIT^2" "^$GIT_COMMIT^1" --oneline | wc -l)" -gt 0 ];
then
  #echo take $GIT_COMMIT >&2
  # Pick one:
  git_commit_non_empty_tree "$@" # Drop empty commits
  #git commit-tree "$@" # Keep empty commits
else
  #echo "breakup $GIT_COMMIT ($*)" >&2
  skip_commit "$1" "$2" "$3" # (quietly) only keep the first parent
fi' -f HEAD

Если 1) коммит неиметь второго родителя (git rev-parse возвращает ошибку, если ссылочный коммит ($GIT_COMMIT^2) не существует) ИЛИ 2) второй родитель ($GIT_COMMIT^2) содержит коммиты, которых не имеет первый родитель ($GIT_COMMIT^1) (см. здесь ), фиксация сохраняется (если она не пустая; используйте git commit-tree, если вы хотите сохранить пустые значения); если второй родитель существует и не добавляет ничего полезного , мы пропускаем коммит, и намеренно пропускает только первого родителя - я не уверен, что это «законно», ноон удаляет второго родителя из истории, и это сработало в моем случае ... (см. предостережения ниже)

снизу вверх:

*   575e3b5 Merge pull request #68 from chris/feature # KEEP THIS MERGE!
|\  
| * 5dbc3f1 Actual feature changes
| |  2 files changed, 2 insertions(+), 2 deletions(-)
| * 35abc98 Cleanup/prep
|/  
|    2 files changed, 22 insertions(+), 16 deletions(-)
*   c3b3d86 Merge pull request #46 from org/topic_branch-mods # USELESS-C
|\  
* \   892de05 Merge pull request #47 from org/topic_branch # USELESS-B
|\ \  
| |/  
|/|   
| *   e738d4b Merge branch 'master' into topic_branch # USELESS-A
| |\  
| |/  
|/|   
* | 4182dac CommitMsg #40 #SQUASHED-PR
| |  2 files changed, 15 insertions(+), 6 deletions(-)
* | 3b42762 CommitMsg
|/  
|    2 files changed, 29 insertions(+), 14 deletions(-)
* c4e62ba CommitMsg
|  2 files changed, 39 insertions(+), 16 deletions(-)
* c2bb13f CommitMsg
   4 files changed, 241 insertions(+)

Он сохранил все до SQUASHED-PR (обратите внимание, что идентификатор фиксации 4182dac и родители сохраняются, поскольку их история не изменилась).Было решено, что USELESS-A должен держаться рядом, потому что его второй родитель (4182dac) содержит коммиты, которые его первый родитель (c4e62ba) сделал не содержат, , но , затем он посмотрел наUSELESS-B, чей второй родитель ( включая USELESS-A) не не добавляет ничего полезного, поэтому он отбросил его (опять же, включая USELESS-A).Тогда USELESS-C был просто бесполезен, поэтому он был отброшен, а KEEP имел «что-то полезное» во втором родителе, поэтому оно было сохранено.Итак, вы заканчиваете:

*   63b4d39 Merge pull request #68 from chris/feature # KEEP THIS MERGE!
|\  
| * 9a5570d Actual feature changes
| |  2 files changed, 2 insertions(+), 2 deletions(-)
| * a251317 Cleanup/prep
|/  
|    2 files changed, 22 insertions(+), 16 deletions(-) 
* 4182dac CommitMsg #40 #SQUASHED-PR
|  2 files changed, 15 insertions(+), 6 deletions(-)
* 3b42762 CommitMsg
|  2 files changed, 29 insertions(+), 14 deletions(-)
* c4e62ba CommitMsg
|  2 files changed, 39 insertions(+), 16 deletions(-)
* c2bb13f CommitMsg
   4 files changed, 241 insertions(+)

Важные предостережения

  • Это работает только для простых историй, где есть только две ветви, так как мы явно проходим"$1" "$2" "$3" в этом случае пропускается "$4" "$5", который в противном случае был бы включен в "$@".Если у вас несколько родителей (точнее, если в вашем коммите есть несколько родителей), вам придется изменить это, чтобы учесть это;не должно быть слишком сложно, но я не исправляю это прямо сейчас для гипотетического - вы можете выбрать конкретных родителей, чтобы отбросить, idk.
  • Если после * 1055 был «полезный» коммитдо слияния с USELESS-B (что, возможно, тогда не будет бесполезным), USELESS-A будет не обрезаться / отбрасываться, поэтому, возможно, у вас все еще будет некоторое уродство.
  • Вероятно, есть другие сценарии, в которых это не работает или может быть улучшено.Пожалуйста, добавьте предложения в комментариях (как обычно), если вы их найдете!
...