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


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.