자식에서 관련되지 않은 분기를 저장소에 도입하는 간단한 방법이 있습니까?


328

오늘 자식 문제가있는 친구를 돕는 동안 나는 지점과 완전히 분리되어야하는 지점을 소개해야했습니다 master. 이 브랜치의 내용은 실제로 브랜치에서 개발 된 것과 다른 기원을 master가졌지 만 master나중에 브랜치 로 병합 될 것 입니다.

나는 John Wiegley 's Git을 아래에서 시작하여 브랜치가 본질적으로 특정 규칙을 따르는 커밋에 대한 레이블과 커밋이 파일 트리 및 선택적으로 부모 커밋에 연결되는 방식을 나타내는 레이블을 기억했습니다. 우리는 git의 배관을 사용하여 기존 저장소에 부모없는 커밋을 만들었습니다.

그래서 우리는 색인의 모든 파일을 제거했습니다 ...

$ git rm -rf .

... tarball에서 추출 된 디렉토리와 파일을 색인에 추가했습니다 ...

$ 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옵션을 지원합니다 . 로부터 man 페이지 :

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

<start_point>에서 시작하여 이름이 <new_branch> 인 새 고아 브랜치를 작성 하고 전환하십시오. 이 새로운 브랜치에서 첫 커밋은 부모가 없으며 다른 모든 브랜치와 커밋에서 완전히 분리 된 새로운 역사의 근원이 될 것입니다.

이것은 어 커가 원하는 것을 정확하게 수행하지 않습니다 . 왜냐하면 인덱스와 작업 트리를 채 웁니다 <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이기 때문에 지정되지 않은 채로 두 었으며 어쨌든 실제로 신경 쓰지 않습니다. 이 순서는 본질적 으로 무서운 배관 명령에 의지하지 않고 Artem의 답변 의 명령 순서와 본질적으로 동일 합니다.


다른 "트리"에서 분기를 체크 아웃 할 때 표시되는 고아 분기를 만들 수 있는지 알고 있습니까?
— JJD

1
@ JJD : 원하는 것은 git merge라고 생각합니다. ( git checkout master && git merge --no-commit "orphan-branch" ) 비슷한 트릭은 git-reset을 사용하거나 인덱스를 사용하여 작동합니다. 그러나 원하는 워크 플로에 따라 다릅니다.
— phord

@Matthew 다음은 git 1.7.2 의 변경 로그입니다 .
— JJD

@phord 나는 프로젝트의 소스 코드와 분리 된 단위 테스트 나 문서와 같은 것들을 포함하는 고아를 생각했다.
— JJD

2
@ JJD : 내가 당신에게 오해하지 않는 한, 내가 준 스크립트는 당신이 원하는 것을 줄 것입니다. "보이는 상태"라고했을 때 다른 지점을 체크 아웃 했는데도 파일이 작업 디렉토리에 남아 있다는 것을 의미합니까? --no-commiton git merge을 사용하면 이 를 달성 할 수 있습니다. git reset origin/master다음 커밋이 원하는 곳으로 이동 하기 위해 후속 조치가 필요할 수 있지만 .gitignore 파일에 포함시키지 않으면 고아 지점의 파일이 "추적되지 않은 파일"로 표시됩니다.
— phord

32

에서 힘내 커뮤니티 도서 :

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에 더 좋습니다.
— kikito

14
@kikito : Re : "다음 답변이 낫다"... SO에 대한 주문은 안정적이지 않습니다. 더 나은 답변이라고 생각되는 것을 가리키는 링크를 추가 할 수 있습니까?
— David J.

2
stackoverflow.com/a/4288660/312586 을 참조하고있었습니다 . 당신 말이 맞아요, "다음"이라고 말해서는 안됩니다. 내가 댓글을 달았을 때이 답변보다 점수가 떨어졌습니다.
— kikito


이 방법은 "지점에 커밋하고 이전에 존재하지 않았 으면이를 생성하고
— 싶습니다

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

이제 / path / to / unrelated를 삭제할 수 있습니다


제 생각에는 깨끗한 개념에는 git branch또는에 대한 옵션이 포함됩니다 git checkout. git이 이런 종류의 것들을 가능하게 해줘서 기쁘지만 왜 쉽지 않습니까?
— hillu

3
그렇기 때문에 드문 일입니다. 관련없는 분기가있는 경우 일반적으로 기존 저장소에 채워 넣지 않고 관련없는 저장소에 속합니다 (예외는 있음).
— Jakub Narębski

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 Pages를 만드는 방법 gh-pages입니다. 여기에 예쁜 단계가 설명되어 있습니다.

https://help.github.com/articles/creating-project-pages-manually

기본적으로이를 설정하는 git 명령은 다음과 같습니다.

  1. git checkout --orphan gh-pages (리포지토리에 gh-pages라는 부모없는 지점을 만드십시오)
  2. git rm -rf . (분기 작업 트리에서 파일을 제거합니다)
  3. rm '.gitignore' (gitignore조차도)
  4. 이제 웹 사이트 콘텐츠를 추가하고 (index.html 등 추가) 커밋하고 푸시하십시오.
  5. 이익.

또한 Github이 웹 사이트를 구축하는 데 사용하는 "프로젝트 사이트"의 소스가되도록 리포지토리에 / docs 폴더 를 지정할 수도 있습니다.

도움이 되었기를 바랍니다!


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 rebase -i --root" 의 구현 이 시퀀서 기계를 더 많이 사용하도록 업데이트되었으므로 이제 (Git 2.18 Q2 2018) 해당 컨텐츠를 자체 새 고아 분기로 추출 할 수 있습니다 .

이 시퀀서는 이제 커밋 그래프의 전체 토폴로지를 다른 곳으로 이식 할 수있는 것 입니다.

참조 8fa6eea 커밋 , 9c85a1c 커밋 , ebddf39 커밋 , 21d0764 커밋 , d87d48b 커밋 , ba97aea 커밋 에 의해 (2018 5월 3일) (요하네스 Schindelin을 dscho) .
(가 합병 Junio C 하마노 - gitster- 에 c5aa4bc을 투입 , 2018 (30) 5 월)

시퀀서 : 새로운 루트 커밋 도입 허용

--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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.