Как создать новую (и пустую!) «Корневую» ветку?

135

Я хотел бы определить новую «корневую» ветку в этом репозитории git. Под «корневой» веткой я подразумеваю ветвь, которая полностью независима от всех других ветвей в репозитории 1 .

К сожалению, даже коммит (назовем его A) в самом основании дерева коммитов репо содержит множество файлов (это был репозиторий, который был инициализирован в уже достаточно зрелом проекте).

Это означает, что даже если бы я дал Aновую ветку <start-point>, эта новая ветка не начиналась бы с «чистого листа», а скорее содержала бы все файлы, которые были зафиксированы A.

Есть ли способ создать полностью голую ветку в этом репозитории, <start-point>максимально приближенную к ней A?


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


РЕДАКТИРОВАТЬ : ОК, это то, что я сделал, основываясь на ответе vcsjones :

# save rev of the current earliest commit
OLDBASE=$(git rev-list --max-parents=0 HEAD)

# create a new orphan branch and switch to it
git checkout --orphan newbranch
# make sure it's empty
git rm -rf .

# create a new empty commit in the new branch, and
# save its rev in NEWBASE
git commit --allow-empty -m 'base commit (empty)'
NEWBASE=$(git rev-list HEAD)

# specify $NEWBASE as the new parent for $OLDBASE, and
# run filter-branch on the original branch
echo "$OLDBASE $NEWBASE" > .git/info/grafts
git checkout master
git filter-branch

# NOTE: this assumes that the original repo had only one
# branch; if not, a git-filter-branch -f <branch> command
# need to be run for each additional branch.

rm .git/info/grafts

Хотя эта процедура немного сложна, конечный результат - пустая базовая фиксация, которая может служить в качестве <start-point>новой для любой новой «ветки с чистого листа»; все, что мне нужно сделать, это

git checkout -b cleanslate $(git rev-list --max-parents=0 HEAD)

В будущем я всегда буду создавать такие новые репозитории:

git init
git commit --allow-empty -m 'base commit (empty)'

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

KJo
источник
Дубликат stackoverflow.com/questions/13969050/…
Anonymoose
1
@Anonymoose: Для протокола (а не для обсуждения): я не согласен с вашим мнением.
kjo 04
1
Там , кажется, гораздо более простое решение на основе git rebase --onto, см stackoverflow.com/questions/645450/...
Стефан Горичон

Ответы:

223

Используйте --orphanпри создании ветки:

git checkout --orphan YourBranchName

Это создаст новую ветку с нулевым количеством коммитов, однако все ваши файлы будут поставлены. На этом этапе вы можете просто удалить их.
(«удалить их»: A git reset --hardочистит индекс, оставив вам пустое рабочее дерево)

Взгляните на страницу руководства для получения дополнительной информации о --orphan.

vcsjones
источник
По сути, это чистый лист? Как бы с нуля? Или он сохраняет все ваши предыдущие изменения, но только не в истории git?
Con Antonakos
4
@ConAntonakos Это создает новую ветку без родителя. Остальные ветки остаются без изменений, все их изменения сохраняются.
fuz
11

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

$ git checkout --orphan dev2
Switched to a new branch 'dev2'
$ git reset # unstage all the files, you probably don't want to commit all of them
$ git commit --allow-empty -m 'Initial empty commit'
[dev2 (root-commit) a515c28] Initial empty commit
Mr_and_Mrs_D
источник
1
Я считаю, что с 2012 года в этом нет необходимости, потому что вы можете выполнить переустановку на root .
Timmmm
1

Если вы используете Git 2.23 или выше , вы можете использовать , чтобы git switchиgit restore вместо git checkout. Если да, то флаг такой же, как указано в этом ответе .

git switch --orphan YourBranchHere
Капитан человек
источник
1

Есть ли способ создать полностью голую ветку в этом репозитории.

Фактическая команда, которую нужно использовать (с Git 2.28+):

git switch --discard-changes --orphan newBranch
# or
git switch -f --orphan newBranch

git switchдоступен с Git 2.23 (август 2019 г.) и заменяет старую запутанную git checkoutкоманду .

Но я бы порекомендовал Git 2.28 (Q3 2020), потому что git switch --discard-changes --orphanон был оптимизирован в этой версии.

См. Commit 8d3e33d , commit 8186128 (21 мая 2020 г.) Брайан М. Карлсон ( bk2204) .
(Объединено Junio ​​C Hamano - gitster- в коммите ded44af , 9 июня 2020 г.)

builtin/checkout: упростить инициализацию метаданных

Подписано: Брайан М. Карлсон
Рецензент: Деррик Столи

Когда мы вызываем init_checkout_metadataвreset_tree, мы хотим передать идентификатор объекта фиксации в вопросе , так что она не может быть передана на фильтры, или , если нет фиксации, дерева.

Мы ожидали, что последний случай может произойти в другом месте кода оформления заказа, но не может произойти здесь.

Единственный случай, когда у нас нет объекта фиксации, - это вызов git switchс помощью--orphan .

Более того, мы можем попасть в этот путь кода только без объекта фиксации дополнительно с помощью либо, --forceлибо--discard-changes .

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

  • (а) нет фиксации, только пустое дерево и
  • (б) мы никогда не будем использовать данные, так как никакие файлы не будут размазаны при проверке ветки без файлов.

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

Тест:

git switch master
echo foo >foo.txt
git switch --discard-changes --orphan new-orphan2
git ls-files >tracked-files
# test_must_be_empty tracked-files
VonC
источник