git: разделить историю некоторых файлов на отдельную ветку - PullRequest
6 голосов
/ 25 ноября 2010

Скажем, я недавно представил и теперь заметил, что он должен был быть не частью моей main ветви, а скорее веткой feature. Можно ли использовать, например, git-filter-branch для автоматического перемещения всей истории из моей ветки main в ветку feature?

Ответы [ 2 ]

6 голосов
/ 25 ноября 2010

Похоже, вы делаете что-то довольно безумное! :)

Тем не менее, я вижу несколько вариантов, ни один из которых не является особенно автоматизированным.

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

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

  3. Если вы имеете дело с кучей истории, множеством чередующихся коммитов, и вы действительно не хотите, чтобы эта функция вообще присутствовала, вы могли бы написать небольшую оболочку скрипт, который принимает вывод git log и cherry выбирает его в новую ветку. Что-то вроде:

    $ cd git-repo
    $ git checkout -b feature-x
    $ the-perfect-shell-script `git log --pretty=format:"%H" path/to/feature.c`
    

    Как только у вас появится эта ветвь функций со всеми выделенными вишнями, вы можете использовать git filter-branch, чтобы отфильтровать все коммиты, которые ссылаются на этот файл. Страница man имеет простой пример, который делает именно это.

    Как только вы это получите, вы можете git rebase feature-x --onto <filtered-branch>, и вам следует идти.

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

1 голос
/ 26 ноября 2010

Хорошо, вот мой путь:

Если бы я не зафиксировал манипулирование , я мог бы получить ответвление от первого коммита , а затем использовать git cherry-pick с git log в цикле, как предложил по Тим Вишер . Начиная с мастера, я думаю, это должно работать:

#!/bin/bash
# create the feature branch starting from feature.c's first commit
FIRSTCOMMIT=$(git log --pretty=format:"%H" feature.c | tail -n1)
git checkout -b feature $FIRSTCOMMIT

# find all commits concerning feature.c...
for i in $(git log feature..master --reverse --pretty=format:"%H" feature.c)
do
  # ... cherry-pick them ...
  git cherry-pick $i
  # ... and copy ONE modified tag of it if existing
  git describe --tags --exact-match $i && xargs taghelperscript
done
# now eliminate feature.c from master
git filter-branch --prune-empty --tag-name-filter "cat" --index-filter 'git rm --cached --ignore-unmatch feature.c' $FIRSTCOMMIT..master

С taghelperscript что-то вроде git tag prefix.$1 (может быть, это можно сделать лучше?). Часть с тегами, вероятно, работает только для легких тегов, которые я использую. Также имейте в виду, что это не работает, если был переименован в какой-то момент, и если он уже существовал в начальном коммите, это может привести к двум отдельным историям, или (мое предположение) коммит в master, который содержит удаление , которое может позже вызвать конфликт слияния или путаницу.


Проблема в том, что некоторые из моих коммитов изменяют другие файлы, в результате чего git cherry-pick вызывает неразрешенное слияние или вводит эти другие файлы. Поэтому вместо этого я попробую немного магии. Позже. Оставайтесь с нами ...

...