문제

마스터하기로 약속한 마지막 몇 가지 커밋을 새 브랜치로 옮기고 해당 커밋이 이루어지기 전으로 마스터를 되돌리고 싶습니다.불행히도 내 Git-fu는 아직 충분히 강하지 않습니다. 도움이 필요합니까?

즉.여기서 어떻게 갈 수 있나요?

master A - B - C - D - E

이에?

newbranch     C - D - E
             /
master A - B 
도움이 되었습니까?

해결책

새 지점으로 이사합니다

경고: 이 메소드는 첫 번째 명령으로 새 지점을 생성하기 때문에 작동합니다. git branch newbranch. 커밋을 이동하려면 기존 지점 실행하기 전에 변경 사항을 기존 지점으로 병합해야합니다. git reset --hard HEAD~3 (보다 기존 지점으로 이동합니다 아래에). 변경 사항을 먼저 병합하지 않으면 손실됩니다.

다른 상황이없는 한, 이것은 분기 및 롤백으로 쉽게 수행 할 수 있습니다.

# Note: Any changes not committed will be lost.
git branch newbranch      # Create a new branch, saving the desired commits
git reset --hard HEAD~3   # Move master back by 3 commits (Make sure you know how many commits you need to go back)
git checkout newbranch    # Go to the new branch that still has the desired commits

그러나 얼마나 많은 커밋이 되돌아 갈 수 있는지 확인하십시오. 또는 대신 대신 할 수 있습니다 HEAD~3, 단순히 커밋의 해시를 제공하십시오 (또는 원산지/마스터) 당신은 주인 (/current) Branch, EG :

git reset --hard a1b2c3d4

*1 당신은 할 것입니다 마스터 브랜치에서 "지는"커밋이되지만 걱정하지 마십시오. 뉴 브랜치에서 커밋을받을 것입니다!

경고: git 버전 2.0 이상, 나중에 나중에 git rebase 원본의 새로운 지점 (master) 분기, 당신은 명시 적이 필요할 수 있습니다 --no-fork-point 운반 된 커밋을 잃지 않도록 리베이스 중 옵션. was branch.autosetuprebase always 세트는 이것을 더 가능성이 높습니다. 보다 존 멜로르의 대답 자세한 내용은.

기존 지점으로 이동합니다

커밋을 옮기고 싶다면 기존 지점, 그것은 다음과 같이 보일 것입니다 :

git checkout existingbranch
git merge master
git checkout master
git reset --hard HEAD~3 # Go back 3 commits. You *will* lose uncommitted work.
git checkout existingbranch

다른 팁

왜 그것이 작동하는지 궁금해하는 사람들을 위해(처음에는):

C로 돌아가서 D와 E를 새 분기로 이동하려고 합니다.처음에는 다음과 같습니다.

A-B-C-D-E (HEAD)
        ↑
      master

후에 git branch newBranch:

    newBranch
        ↓
A-B-C-D-E (HEAD)
        ↑
      master

후에 git reset --hard HEAD~2:

    newBranch
        ↓
A-B-C-D-E (HEAD)
    ↑
  master

브랜치는 단지 포인터일 뿐이므로, 주인 마지막 커밋을 가리켰습니다.당신이 만들었을 때 새로운 지점, 마지막 커밋에 대한 새로운 포인터를 만들었습니다.그런 다음 사용하여 git reset 당신이 옮겼어요 주인 두 개의 커밋을 다시 포인터합니다.하지만 당신이 움직이지 않았기 때문에 새로운 지점, 여전히 원래 커밋을 가리킵니다.

일반적으로 ...

이 경우 Sykora에 의해 노출 된 방법이 최선의 선택입니다. 그러나 때로는 가장 쉽지 않으며 일반적인 방법이 아닙니다. 일반적인 방법 사용 git cherry-pick:

OP가 원하는 것을 달성하기 위해 2 단계 프로세스 :

1 단계 - 당신이 원하는 마스터로부터 헌신하는 참고 newbranch

실행하다

git checkout master
git log

원하는 해시 (예 : 3) 커밋에 주목하십시오. newbranch. 여기에서 사용하겠습니다.
C 커밋 : 9aa1233
D 커밋 : 453ac3d
e 커밋 : 612ecb3

메모: 처음 7 자 또는 전체 커밋 해시를 사용할 수 있습니다.

2 단계 - 그것들을 newbranch

git checkout newbranch
git cherry-pick 612ecb3
git cherry-pick 453ac3d
git cherry-pick 9aa1233

또는 (GIT 1.7.2+에서, 사용 범위)

git checkout newbranch
git cherry-pick 612ecb3~1..9aa1233

git cherry-pick 이 세 커밋을 Newbranch에 적용합니다.

이 작업을 수행하는 또 다른 방법은 2 개의 명령 만 사용합니다. 또한 현재 작업 트리를 그대로 유지합니다.

git checkout -b newbranch # switch to a new branch
git branch -f master HEAD~3 # make master point to some older commit

구 버전 - 내가 배우기 전에 git branch -f

git checkout -b newbranch # switch to a new branch
git push . +HEAD~3:master # make master point to some older commit 

를 할 수있는 push 에게 . 알아야 할 좋은 트릭입니다.

대부분의 이전 답변은 위험합니다!

이것을하지 마십시오 :

git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch

다음에 달릴 때 git rebase (또는 git pull --rebase) 그 3 개의 커밋은 조용히 폐기 될 것입니다 newbranch! (아래 설명 참조)

대신 이것을하십시오 :

git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick ..HEAD@{2}
  • 먼저 가장 최근의 커밋을 버립니다 (--keep 처럼 --hard, 그러나 커밋되지 않은 변화를 버리기보다는 실패로 더 안전합니다).
  • 그런 다음 포크입니다 newbranch.
  • 그런 다음 3 개의 커밋이 다시 cherry- 픽입니다 newbranch. 그들은 더 이상 지점에서 언급되지 않기 때문에 Git 's를 사용하여 리플 로그: HEAD@{2} 커밋입니다 HEAD 2 번의 작업을 참조하는 데 사용됩니다. 즉, 1. 체크 아웃 newbranch 그리고 2. 사용 git reset 3 개의 커밋을 폐기합니다.

경고 : 리플 로그는 기본적으로 활성화되어 있지만 수동으로 비활성화 한 경우 (예 : "베어"git 저장소를 사용하여) 실행 후 3 개의 커밋을 다시 얻을 수 없습니다. git reset --keep HEAD~3.

리플 로그에 의존하지 않는 대안은 다음과 같습니다.

# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3

(원하는 경우 글을 쓸 수 있습니다 @{-1} - 이전에 확인 된 지점 대신 oldbranch).


기술적 인 설명

git rebase 첫 번째 예제 이후 3 개의 커밋을 폐기 하시겠습니까? 왜냐하면 git rebase 논쟁이없는 것은 다음을 가능하게합니다 --fork-point 기본적으로 로컬 리플 로그를 사용하여 업스트림 브랜치가 강제로 퍼지는 것에 대해 강력하게 노력하는 옵션.

Commit M1, M2, M3이 포함되어있을 때 Origin/Master를 분기 한 다음 스스로 Commits를 세 번 만들었습니다.

M1--M2--M3  <-- origin/master
         \
          T1--T2--T3  <-- topic

그러나 누군가가 강제로 푸싱 원산지/마스터를 통해 역사를 다시 작성하여 M2를 제거합니다.

M1--M3'  <-- origin/master
 \
  M2--M3--T1--T2--T3  <-- topic

로컬 리플 로그 사용, git rebase 원산지/마스터 브랜치의 초기 화신에서 물러서서 M2 및 M3 커밋은 실제로 주제 지점의 일부가 아님을 알 수 있습니다. 따라서 M2가 업스트림 브랜치에서 제거되었으므로 주제 지점이 다시 해동되면 주제 지점에서 더 이상 원하지 않는다고 합리적으로 가정합니다.

M1--M3'  <-- origin/master
     \
      T1'--T2'--T3'  <-- topic (rebased)

이 행동은 의미가 있으며, 일반적으로 재건 할 때해야 할 일입니다.

따라서 다음 명령이 실패하는 이유는 다음과 같습니다.

git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch

그들이 반사그를 잘못된 상태로 남겨두기 때문입니다. git을 본다 newbranch 3 개의 커밋을 포함하는 개정판에서 상류 브랜치를 포크로 만들었습니다. reset --hard 상류의 역사를 다시 작성하여 커밋을 제거하고 다음에 달리면 git rebase 그것은 상류에서 제거 된 다른 커밋처럼 그들을 버립니다.

그러나이 특별한 경우에 우리는 그 3 개의 커밋이 주제 지점의 일부로 간주되기를 원합니다. 이를 달성하기 위해서는 3 개의 커밋이 포함되지 않은 이전 개정판에서 업스트림을 포크해야합니다. 그것이 제 제안 된 솔루션이하는 일이므로 둘 다 리플 로그를 올바른 상태로 남겨 둡니다.

자세한 내용은 정의를 참조하십시오 --fork-point 에서 git rebase 그리고 git 병합 기반 문서.

git stash를 사용한 훨씬 간단한 솔루션

다음은 잘못된 지점에 커밋하기위한 훨씬 간단한 접근 방식입니다. 지점에서 시작합니다 master 그것은 세 가지 잘못된 커밋이 있습니다.

git reset HEAD~3
git stash
git checkout newbranch
git stash pop

언제 사용해야합니까?

  • 주요 목적이 롤백하는 것이라면 master
  • 파일 변경을 유지하고 싶습니다
  • 당신은 잘못된 커밋의 메시지를 신경 쓰지 않습니다.
  • 당신은 아직 밀리지 않았습니다
  • 당신은 이것을 쉽게 암기하기를 원합니다
  • 임시/새 지점, 커밋 해시 찾기 및 복사 및 기타 두통과 같은 합병증을 원하지 않습니다.

이것이 줄 번호별로하는 일

  1. 마지막 세 커밋 (및 메시지)을 취소합니다. master, 그러나 모든 작업 파일을 그대로 둡니다
  2. 모든 작업 파일이 변경되어 master 작업 트리는 머리 ~ 3 상태와 정확히 동등합니다.
  3. 기존 지점으로 전환합니다 newbranch
  4. 보관 된 변경 사항을 작업 디렉토리에 적용하고 은신처를 지 웁니다.

이제 사용할 수 있습니다 git add 그리고 git commit 평소처럼. 모든 새로운 커밋이 추가됩니다 newbranch.

이것이하지 않는 것

  • 무작위로 임시 가지가 나무를 어지럽히는 것은 아닙니다
  • 그것은 잘못된 커밋을 보존하지 않고 메시지를 저 지르지 않으며, 이 새로운 커밋에 새로운 커밋 메시지를 추가해야합니다.

목표

OP는 목표는 변경을 잃지 않고 "커밋이 이루어지기 전에 마스터를 되 찾는 것"이라고 진술 했으며이 솔루션은 그렇게합니다.

실수로 새로운 커밋을 할 때 적어도 일주일에 한 번이 작업을 수행합니다. master 대신에 develop. 보통 나는 롤백을 약속하는 경우에만 사용됩니다. git reset HEAD^ 1 행에서는 하나의 커밋 만 롤백하는 간단한 방법입니다.

마스터의 변경을 상류로 밀면 이렇게하지 마십시오.

다른 사람이 그 변화를 가져 왔을 수도 있습니다. 현지 마스터 만 다시 쓰는 경우 상류로 밀면 영향을 미치지 않지만 공동 작업자에게 다시 쓰여진 역사를 밀면 두통이 발생할 수 있습니다.

이것은 기술적 인 의미에서 그들을 "이동"하지는 않지만 동일한 효과가 있습니다.

A--B--C  (branch-foo)
 \    ^-- I wanted them here!
  \
   D--E--F--G  (branch-bar)
      ^--^--^-- Opps wrong branch!

While on branch-bar:
$ git reset --hard D # remember the SHAs for E, F, G (or E and G for a range)

A--B--C  (branch-foo)
 \
  \
   D-(E--F--G) detached
   ^-- (branch-bar)

Switch to branch-foo
$ git cherry-pick E..G

A--B--C--E'--F'--G' (branch-foo)
 \   E--F--G detached (This can be ignored)
  \ /
   D--H--I (branch-bar)

Now you won't need to worry about the detached branch because it is basically
like they are in the trash can waiting for the day it gets garbage collected.
Eventually some time in the far future it will look like:

A--B--C--E'--F'--G'--L--M--N--... (branch-foo)
 \
  \
   D--H--I--J--K--.... (branch-bar)

재 작성 기록 없이이 작업을 수행하려면 (즉, 이미 커밋을 추진 한 경우) :

git checkout master
git revert <commitID(s)>
git checkout -b new-branch
git cherry-pick <commitID(s)>

그런 다음 두 가지 모두 힘없이 밀릴 수 있습니다!

이 상황이있었습니다.

Branch one: A B C D E F     J   L M  
                       \ (Merge)
Branch two:             G I   K     N

나는 공연했다 :

git branch newbranch 
git reset --hard HEAD~8 
git checkout newbranch

나는 그 커밋이 내가 머리가 될 것으로 예상했지만 Commit L은 지금 ...

역사상 올바른 자리에 착륙하려면 커밋의 해시와 함께 일하기가 더 쉽습니다.

git branch newbranch 
git reset --hard #########
git checkout newbranch

1) 모든 변경 사항을 New_Branch로 이동시키는 새 지점을 만듭니다.

git checkout -b new_branch

2) 그런 다음 오래된 지점으로 돌아갑니다.

git checkout master

3) git rebase를하십시오

git rebase -i <short-hash-of-B-commit>

4) 그런 다음 열린 편집기에는 마지막 3 개의 커밋 정보가 포함되어 있습니다.

...
pick <C's hash> C
pick <D's hash> D
pick <E's hash> E
...

5) 변화 pick 에게 drop 그 3 개의 커밋에서. 그런 다음 편집기를 저장하고 닫습니다.

...
drop <C's hash> C
drop <D's hash> D
drop <E's hash> E
...

6) 이제 마지막 3 개의 커밋이 현재 지점에서 제거됩니다 (master). 이제 가지를 강력하게 밀어 넣으십시오 + 분기 이름 앞에 서명하십시오.

git push origin +master

어떻게 이로부터 갈 수 있습니까?

A - B - C - D - E 
                |
                master

이에?

A - B - C - D - E 
    |           |
    master      newbranch

두 가지 명령으로

  • Git Branch -M Master Newbranch

기부

A - B - C - D - E 
                |
                newbranch

그리고

  • git 브랜치 마스터 b

기부

A - B - C - D - E
    |           |
    master      newbranch

당신은 이것을 할 수 있습니다. 내가 사용한 3 가지 간단한 단계입니다.

1) 최근 업데이트를 저지르고 싶은 새 지점을 만드십시오.

git branch <branch name>

2) 새 지점에서 커밋에 대한 최근 커밋 ID를 찾으십시오.

git log

3) COMMING ID를 복사하십시오. 가장 최근의 커밋 목록은 상단에서 이루어집니다. 당신은 당신의 커밋을 찾을 수 있습니다. 또한 메시지를 통해 이것을 찾을 수 있습니다.

git cherry-pick d34bcef232f6c...

Commit ID의 일부를 제공 할 수도 있습니다.

git cherry-pick d34bcef...86d2aec

이제 당신의 일이 끝났습니다. 올바른 ID와 올바른 지점을 선택하면 성공할 것입니다. 그래서 이것은 조심해야합니다. 그렇지 않으면 또 다른 문제가 발생할 수 있습니다.

이제 코드를 푸시 할 수 있습니다

git push

당신이 모든 것을 움직여야한다면 비적되지 않았다 a 새로운 지점, 그럼 당신은 그냥 필요합니다.

  1. 만들다새로운 지점 현재에서 :git branch new-branch-name

  2. 푸시 당신의 새로운 지점: git push origin new-branch-name

  3. 돌아가는 것 당신의 오래된 (현재) 지점 마지막으로 푸시/안정적인 상태로 : git reset --hard origin/old-branch-name

어떤 사람들은 다른 사람들도 있습니다 upstreams 보다는 origin, 그들은 적절한 것을 사용해야합니다 upstream

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top