Чи існує простий спосіб введення незв'язаної гілки до сховища в git?


328

Допомагаючи товаришеві з проблемою зі шлунком сьогодні, я повинен був представити гілку, яка мала бути повністю відокремленою від masterгілки. Вміст цієї гілки насправді мав інше походження від того, що було розроблено на masterгілці, але вони збиралися бути об'єднані у masterфілію пізніше.

Я пам’ятав, як читав « Git» Джона Віглі знизу вгору, як гілки - це по суті мітка до комітету, який дотримується певної конвенції, і як фіксація прив’язана до дерева файлів і, можливо, до батьківських комітетів. Ми пішли створити безвідмовну комісію для існуючого сховища за допомогою сантехніки git:

Таким чином ми позбулися всіх файлів в індексі ...

$ git rm -rf .

... вилучені каталоги та файли з тарболу, додані до індексу ...

$ git add .

... і створив дерево об'єкта ...

$ git write-tree

( git-write-treeрозповів нам sha1sum створеного деревного об’єкта.)

Потім ми вчинили дерево, не вказуючи батьківські зобов'язання ...

$ echo "Imported project foo" | git commit-tree $TREE

( git-commit-treeрозповів нам sha1sum створеного об’єкта фіксації.)

... і створив нове відділення, яке вказує на наш щойно створений комітет.

$ git update-ref refs/heads/other-branch $COMMIT

Нарешті ми повернулися до masterфілії, щоб продовжити там роботу.

$ git checkout -f master

Здається, це спрацювало так, як планувалося. Але це явно не та процедура, яку я рекомендував би тому, хто тільки починає використовувати git, м'яко кажучи. Чи є простіший спосіб створення нової гілки, яка абсолютно не пов'язана з усім, що відбулося в сховищі досі?

Відповіді:


510

Існує нова функція (починаючи з V1.7.2), яка робить це завдання трохи більш високим рівнем, ніж те, що в будь-якому з інших відповідей.

git checkoutтепер підтримує цю --orphanопцію. Із чоловічої сторінки :

git checkout [-q] [-f] [-m] --orphan <new_branch> [<start_point>]

Створіть нову гілку- сироту під назвою <new_branch>, починаючи з <start_point> та перейдіть до неї. Перший вчинок, зроблений на цій новій гілці, не матиме батьків, і це буде коренем нової історії, повністю відключеною від усіх інших гілок і зобов'язань.

Це не робить саме те, що хотів запитувати, оскільки він заповнює індекс і робоче дерево з <start_point>(адже це, зрештою, команда оформлення замовлення). Єдина інша необхідна дія - видалити непотрібні елементи з робочого дерева та індексу. На жаль, git reset --hardце не працює, але git rm -rf .може бути використане натомість (я вважаю, це еквівалентно rm .git/index; git clean -fdxнаведеному в інших відповідях).


Підсумовуючи:

git checkout --orphan newbranch
git rm -rf .
<do work>
git add your files
git commit -m 'Initial commit'

Я залишив <start_point>не визначений, тому що це за замовчуванням для HEAD, і ми насправді не хвилюємося. Ця послідовність робить по суті те саме, що і послідовність команд у відповіді Артема , лише не вдаючись до страшних сантехнічних команд.


Чи знаєте ви, чи можна створити гілку-сироту, яка залишається видимою, коли ви переглядаєте будь-яку гілку з іншого "дерева"?
JJD

1
@JJD: Я думаю, що ти хочеш, це git merge. ( git checkout master && git merge --no-commit "orphan-branch" ) Деякі подібні хитрощі працюватимуть за допомогою git-reset або гри з індексом. Але це залежить від бажаного робочого процесу.
фрад

@Matthew Ось список змін для git 1.7.2 .
JJD

@phord Я більш-менш думав про сироту, щоб містити речі, такі як одиничні тести або документація, відокремлені від вихідного коду проекту.
JJD

2
@JJD: Сценарій, який я дав, повинен дати тобі те, що ти хочеш, якщо я неправильно тебе зрозумів. Коли ви сказали "залишається видимим", ви маєте на увазі, що файли залишаться у робочому каталозі, навіть якщо ви перевірили іншу гілку? Використання --no-commitна git mergeдоб'ється цього. Можливо, вам знадобиться подати наступні дії, git reset origin/masterщоб ваш наступний фіксатор пішов куди ви хочете, але тоді файли з вашої сироти-філії відображатимуться як "незафіксовані файли", якщо ви також не включите їх у свій файл .gitignore.
фрад

32

З книги Git Community :

git symbolic-ref HEAD refs/heads/newbranch 
rm .git/index 
git clean -fdx 
<do work> 
git add your files 
git commit -m 'Initial commit'

1
Наступна відповідь краще для сучасних версій git.
кікіто

14
@kikito: Re: "Наступна відповідь - краща" ... Порядок впорядкованості тут на SO не стабільний. Чи можете ви додати посилання, що вказує на те, що, на вашу думку, є кращою відповіддю.
Девід Дж.

2
Я мав на увазі stackoverflow.com/a/4288660/312586 . Ви маєте рацію, я не повинен був сказати "наступний". У ньому було менше балів, ніж ця відповідь, коли я коментував.
кікіто

1
rm .git/indexнекрасиво :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Це краще працює для випадку "Я хочу взяти на себе філію, створивши її, якщо вона раніше не існувала"
max630

22

Хоча рішення з git symbolic-refта видалення індексу працює, створити нове сховище може бути концептуальніше

$ cd /path/to/unrelated
$ git init
[edit and add files]
$ git add .
$ git commit -m "Initial commit of unrelated"
[master (root-commit) 2a665f6] Initial commit of unrelated
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 foo

потім вийміть з нього

$ cd /path/to/repo
$ git fetch /path/to/unrelated master:unrelated-branch
warning: no common commits
remote: Counting objects: 3, done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From /path/to/unrelated
 * [new branch]      master     -> unrelated-branch

Тепер ви можете видалити / шлях / до / непов'язаний


На мою думку, чиста концепція передбачала б варіант до git branchабо git checkout. Я радий, що git робить подібні речі можливими, але чому це не може бути простіше?
Hillu

3
Тому що це є і має бути рідкісною справою. Якщо у вас є галузь, що не пов’язана між речами, вона зазвичай належить до незв'язаного сховища, а не заповнення у існуючому (хоча є винятки).
Якуб Нарубський

1
+1. Для новонароджених, що здобувають новачків, можна, очевидно, потім перелічити гілки через git branchта перемикатися між ними через git checkout BRANCH_NAME.
akavel

Дякую за це, я б не думав про це самостійно. Це дуже корисно, оскільки воно підтримує історію (якщо така є) для інших репо.
BM5k

13

У Github є функція під назвою «Сторінки проектів», за допомогою якої ви можете створити конкретну названу гілку у своєму проекті, щоб надавати файли, які обслуговуватиме Github. Їх інструкції такі:

$ cd /path/to/fancypants
$ git symbolic-ref HEAD refs/heads/gh-pages
$ rm .git/index
$ git clean -fdx

Звідти у вас порожнє сховище, до якого ви можете додати новий вміст.


10

Вибрана на даний момент відповідь правильна, я б просто додав це випадково ...

Ось саме так github.com дозволяє користувачам створювати сторінки Github для своїх репостів через осіроту гілку під назвою gh-pages. Тут наведено та пояснено непогані кроки:

https://help.github.com/articles/creating-project-pages- вручну

В основному команди git, щоб налаштувати це, наступні:

  1. git checkout --orphan gh-pages (створіть у вашій репо гілці бездітні відділення під назвою gh-сторінки)
  2. git rm -rf . (видаляє будь-які файли з робочого дерева гілки)
  3. rm '.gitignore' (навіть гітігнор)
  4. Тепер додайте вміст веб-сайту (додайте index.html тощо) та виконайте команду та натисніть.
  5. Прибуток.

Зверніть увагу, ви також можете призначити папку / docs на вашому репо, щоб бути джерелом "сайту проекту", який Github використовує для створення веб-сайту.

Сподіваюсь, це допомагає!


3

Іноді я просто хочу створити порожню гілку в проекті миттєво, а потім почати виконувати роботу, я просто виконую наступну команду:

git checkout --orphan unrelated.branch.name
git rm --cached -r .
echo "init unrelated branch" > README.md
git add README.md
git commit -m "init unrelated branch"

1

Якщо ваш наявний вміст уже було скоєно, ви тепер (Git 2.18 Q2 2018) можете витягнути його у свою власну нову гілку-сироту, оскільки реалізація " git rebase -i --root" оновлена, щоб більше використовувати механізми секвенсору.

Цей секвенсор - той, який тепер дозволяє пересадити всю топологію графа фіксації в інше місце .

Див. Виконувати 8fa6eea , фіксувати 9c85a1c , виконувати ebddf39 , фіксувати 21d0764 , здійснювати d87d48b , виконувати ba97aea (03 травня 2018 року) Йоханнеса Шинделіна ( dscho) .
(Об’єднав Хуніо С Хамано - gitster- в комітеті c5aa4bc , 30 травня 2018 року)

секвенсор: дозволяють вводити нові кореневі коміти

У контексті нового --rebase-mergesрежиму, який був розроблений спеціально для того, щоб дозволити вільно змінити існуючу топологію гілки, користувач може захотіти витягнути комісії в абсолютно свіжу гілку, що починається з новоствореної кореневої комісії .

Тепер це можливо, вставивши команду reset [new root]перед тим, як виконувати команду, pickяка хоче стати кореневою командою . Приклад:

reset [new root]
pick 012345 a commit that is about to become a root commit
pick 234567 this commit will have the previous one as parent

Це не суперечить іншим способам використання resetкоманди, оскільки [new root]не є (частиною) правильним ім'ям посилання: як вступна дужка, так і пробіл є незаконними у назвах посилань.


0

Знайшов цей сценарій на веб- сайті http://wingolog.org/archives/2008/10/14/merging-in-unrelated-git-branches, і він працює дуже добре!

#!/bin/bash

set -e

if test -z "$2" -o -n "$3"; then
    echo "usage: $0 REPO BRANCHNAME" >&2
    exit 1
fi

repo=$1
branch=$2

git fetch "$repo" "$branch"

head=$(git rev-parse HEAD)
fetched=$(git rev-parse FETCH_HEAD)
headref=$(git rev-parse --symbolic-full-name HEAD)

git checkout $fetched .

tree=$(git write-tree)

newhead=$(echo "merged in branch '$branch' from $repo" | git commit-tree $tree -p $head -p $fetched)
git update-ref $headref $newhead $head
git reset --hard $headref

1
Я вважаю, що такого ж ефекту можна досягти, використовуючи git fetch $REMOTE $REMOTE_BRANCH:$LOCAL_BRANCH. Я щось пропускаю?
hillu
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.