마지막으로 몇 가지 커밋을 새 지점으로 마스터하고 해당 커밋이 수행되기 전에 마스터로 다시 가져 가려고합니다. 불행히도 내 Git-fu는 아직 충분히 강하지 않습니다.
즉, 나는 이것을 어떻게 갈 수 있습니까
master A - B - C - D - E
이에?
newbranch C - D - E
/
master A - B
마지막으로 몇 가지 커밋을 새 지점으로 마스터하고 해당 커밋이 수행되기 전에 마스터로 다시 가져 가려고합니다. 불행히도 내 Git-fu는 아직 충분히 강하지 않습니다.
즉, 나는 이것을 어떻게 갈 수 있습니까
master A - B - C - D - E
이에?
newbranch C - D - E
/
master A - B
답변:
커밋을 기존 브랜치 로 옮기려면 다음과 같이 보일 것입니다.
git checkout existingbranch
git merge master # Bring the commits here
git checkout master
git reset --keep HEAD~3 # Move master back by 3 commits.
git checkout existingbranch
--keep
유사 무슨 - 옵션은 해당 변경 내용을 덮어했을 경우 관련없는 파일되거나 중단에있을 수 있음을 커밋되지 않은 변경 보존 git checkout
수행합니다. 중단 된 경우 git stash
변경 사항을 다시 시도하거나 --hard
커밋간에 변경되지 않은 파일에서도 변경 사항을 잃어 버릴 때 사용하십시오 !
이 방법은 첫 번째 명령 ( git branch newbranch
) 으로 새 분기를 작성 하지만 전환하지는 않습니다. 그런 다음 현재 지점 (마스터)을 롤백하고 새 지점으로 전환하여 작업을 계속합니다.
git branch newbranch # Create a new branch, containing all current commits
git reset --keep 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
# Warning: after this it's not safe to do a rebase in newbranch without extra care.
그러나 얼마나 많은 커밋을 되돌릴 수 있는지 확인하십시오. 또는 대신에 되돌리려 HEAD~3
는 커밋의 해시 (또는 같은 참조 origin/master
)를 간단히 제공 할 수 있습니다 .
git reset --keep a1b2c3d4
경고 : Git 버전 2.0 이상에서는 나중에 git rebase
새 분기 ( master
) 분기에 새 분기가있는 --no-fork-point
경우 마스터 분기에서 이동 한 커밋이 손실되지 않도록 리베이스 중에 명시적인 옵션 이 필요할 수 있습니다 . 데 branch.autosetuprebase always
설정하면이 가능성이 있습니다. 자세한 내용은 John Mellor의 답변 을 참조하십시오.
왜 그것이 효과가 있는지 궁금해하는 사람들을 위해 :
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
브랜치는 단지 포인터이기 때문에 마스터 는 마지막 커밋을 가리 켰습니다. newBranch 를 만들었 을 때 마지막 커밋에 대한 새로운 포인터를 만들었습니다. 그런 다음 사용 git reset
하여 마스터 포인터를 두 커밋으로 다시 이동했습니다 . 그러나 newBranch를 이동하지 않았 으므로 여전히 원래 커밋을 가리 킵니다.
git push origin master --force
메인 리포지토리에 변경 사항을 표시해야했습니다.
git rebase
에 3 개의 커밋이에서 자동으로 삭제됩니다 newbranch
. 자세한 내용과 더 안전한 대안 은 내 답변 을 참조하십시오 .
origin/master
위의 그림에 표시되지 않습니다. 당신이 밀고 origin/master
나서 위의 내용을 변경하면, 일이 재미있을 것입니다. 하지만 그건 "의사, 내가 할 때 아프다"같은 문제입니다. 그리고 그것은 원래의 질문에 대한 범위를 벗어났습니다. 시나리오를 가로채는 대신 시나리오를 탐색하기 위해 자신의 질문을 작성하는 것이 좋습니다.
git branch -t newbranch
"라고 말했다. 돌아가서 답을 다시 읽으십시오. 아무도 그렇게 제안 하지 않았습니다.
newbranch
기존 로컬 master
지점을 기반으로 하고 싶다는 것이 분명합니다 . 수락 된 답변을 수행 한 후 사용자가에서 실행 git rebase
을 시작 newbranch
하면 git은 업스트림 분기를 설정하는 것을 잊었 음을 알려주므로 실행 git branch --set-upstream-to=master
한 다음 git rebase
동일한 문제가 발생합니다. 그들은 git branch -t newbranch
처음부터 잘 사용할 수 있습니다 .
이 경우 sykora에 의해 노출되는 방법이 가장 좋습니다. 그러나 때로는 가장 쉬운 방법이 아니며 일반적인 방법이 아닙니다. 일반적인 방법으로 git cherry-pick을 사용하십시오 .
OP가 원하는 것을 달성하기 위해 2 단계 프로세스는 다음과 같습니다.
newbranch
실행
git checkout master
git log
에 대한 커밋 (예 : 3) 커밋에 주목하십시오 newbranch
. 여기서는 다음을 사용합니다.
C 커밋 : 9aa1233
D 커밋 : 453ac3d
E 커밋 :612ecb3
참고 : 처음 7 자 또는 전체 커밋 해시를 사용할 수 있습니다
newbranch
git checkout newbranch
git cherry-pick 612ecb3
git cherry-pick 453ac3d
git cherry-pick 9aa1233
git checkout newbranch
git cherry-pick 612ecb3~1..9aa1233
git cherry-pick 은 세 가지 커밋을 newbranch에 적용합니다.
단 두 개의 명령을 사용하여이를 수행하는 또 다른 방법입니다. 또한 현재 작업 트리를 그대로 유지하십시오.
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 -f
여기와 어떻게 다릅니 까?
.
은 현재 이사입니다. git은 REMOTES 또는 GIT URL로 푸시 할 수 있습니다. path to local directory
Git URL 구문이 지원됩니다. 의 GIT URL 섹션을 참조하십시오 git help clone
.
이 작업을 수행하지 마십시오 :
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
.newbranch
. 그들은 더 이상 지점에서 참조하고 있기 때문에, 자식의 사용하여 해당하지 않습니다 reflog를 : HEAD@{2}
(가) 커밋이다 HEAD
우리 1. 체크 아웃하기 전에이 작업 전에 예를 참조하는 데 사용 newbranch
과 2를 사용하는 git reset
3 개의 커밋을 취소 할 수 있습니다.경고 : reflog는 기본적으로 활성화되어 있지만 수동으로 비활성화 한 경우 (예 : "bare"git 리포지토리 사용) 실행 후 3 개의 커밋을 다시 가져올 수 없습니다 git reset --keep HEAD~3
.
reflog에 의존하지 않는 대안은 다음과 같습니다.
# 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
기본적으로 옵션을 사용할 수 있기 때문에 로컬 참조를 사용하여 업스트림 브랜치에 대해 강력한 푸시를 시도합니다.
커밋 M1, M2, M3을 포함 할 때 출발지 / 마스터에서 분기 한 다음 세 개의 커밋을 스스로 수행했다고 가정합니다.
M1--M2--M3 <-- origin/master
\
T1--T2--T3 <-- topic
그러나 누군가가 M2를 제거하기 위해 강제 푸시 원점 / 마스터로 기록을 다시 작성합니다.
M1--M3' <-- origin/master
\
M2--M3--T1--T2--T3 <-- topic
로컬 reflog를 사용 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
그들은 reflog를 잘못된 상태로두기 때문입니다. Git newbranch
은 3 개의 커밋을 포함하는 개정판에서 업스트림 브랜치에서 분기 한 것으로 확인한 다음 reset --hard
다시 커밋을 제거하기 위해 업스트림 히스토리를 다시 작성하므로 다음에 실행 git rebase
하면 업스트림에서 제거 된 다른 커밋처럼 삭제합니다.
그러나이 특별한 경우에 우리는이 3 개의 커밋이 토픽 브랜치의 일부로 간주되기를 원합니다. 이를 위해서는 3 개의 커밋이 포함되지 않은 이전 수정 버전에서 업스트림을 분기해야합니다. 그것이 내가 제안한 솔루션이하는 일이므로 둘 다 reflog를 올바른 상태로 둡니다.
자세한 내용 --fork-point
은 git rebase 및 git merge-base docs 의 정의를 참조하십시오 .
master
. 그래서, 그들은 위험하지 않습니다.
-t
당신이 언급 한 것은 git branch
암시 적 으로 발생합니다 git config --global branch.autosetuprebase always
. 그렇지 않은 경우에도 OP가 질문을 할 가능성이 있기 때문에 이러한 명령을 수행 한 후 추적을 설정하면 동일한 문제가 발생한다고 이미 설명 했습니다.
다음은 잘못된 브랜치에 대한 커밋을위한 훨씬 간단한 솔루션입니다. master
세 가지 잘못된 커밋이 있는 지점에서 시작 :
git reset HEAD~3
git stash
git checkout newbranch
git stash pop
master
master
하지만 모든 작업 파일은 그대로 둡니다.master
작업 트리를 HEAD ~ 3 상태와 정확히 동일하게 만듭니다.newbranch
당신은 지금 사용 git add
하고 git commit
평소처럼. 모든 새로운 커밋이에 추가됩니다 newbranch
.
OP는 목표는 변경 사항을 잃지 않고 "커밋하기 전에 다시 마스터"하는 것이 목표이며이 솔루션은이를 수행한다고 밝혔다.
나는 실수로 master
대신에 새로운 커밋을 할 때 적어도 일주일에 한 번이 작업을 수행합니다 develop
. 일반적으로 롤백 할 커밋은 하나뿐입니다.이 경우 git reset HEAD^
라인 1을 사용하는 것이 하나의 커밋을 롤백 하는 간단한 방법입니다.
마스터 변경 사항을 업스트림으로 푸시 한 경우이 작업을 수행하지 마십시오
다른 사람이 이러한 변경 사항을 가져 왔을 수 있습니다. 로컬 마스터 만 다시 작성하는 경우 업스트림으로 푸시해도 아무런 영향이 없지만 다시 작성된 기록을 공동 작업자에게 푸시하면 두통이 발생할 수 있습니다.
git add
과 git commit
명령을 모두 사용하여 위쪽 화살표를 누르고 몇 번 들어가서 붐을 일으켰습니다! 모든 것이 돌아 왔지만 지금은 오른쪽 지점에 있습니다.
이것은 기술적 의미에서 "이동"하지 않지만 동일한 효과가 있습니다.
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)
rebase
같은 것을 사용할 수 없습니까 ?
rebase
, 위 시나리오에서 분리 된 분기에서 대신 사용할 수 있습니다 .
기록을 다시 쓰지 않고이 작업을 수행하려면 (예 : 커밋을 이미 푸시 한 경우) :
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
커밋은 HEAD가 될 것이라고 기대했지만 L은 커밋입니다.
커밋의 해시로 작업하기가 더 쉬운 역사의 올바른 지점에 도달하기 위해
git branch newbranch
git reset --hard #########
git checkout newbranch
이걸 어떻게 할 수 있습니까
A - B - C - D - E
|
master
이에?
A - B - C - D - E
| |
master newbranch
두 명령으로
기부
A - B - C - D - E
|
newbranch
과
기부
A - B - C - D - E
| |
master newbranch
푸시되지 않은 커밋을 모두 새로운 브랜치 로 옮길 필요가 있다면 ,
만들 새로운 지점 현재의에서를 :git branch new-branch-name
당신의 새로운 지점을 밀어 :git push origin new-branch-name
복귀 하여 기존 (현재) 분기를 마지막 밀어 / 안정된 상태로 :git reset --hard origin/old-branch-name
어떤 사람들은 또한 다른 upstreams
것이 아니라 origin
적절한 것을 사용해야합니다.upstream
1) 새 브랜치를 작성하면 모든 변경 사항이 new_branch로 이동합니다.
git checkout -b new_branch
2) 그런 다음 오래된 지점으로 돌아갑니다.
git checkout master
3) 자식 리베이스 수행
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
당신이 할 수있는 것은 내가 사용한 3 단계입니다.
1) 최근 업데이트를 커밋하려는 지점을 새로 만듭니다.
git branch <branch name>
2) 새로운 지점에서 커밋 할 최근 커밋 ID를 찾습니다.
git log
3) 해당 커밋 ID를 복사하십시오. 가장 최근의 커밋 목록이 맨 위에 나타납니다. 커밋을 찾을 수 있습니다. 당신은 또한 메시지를 통해 이것을 찾을 수 있습니다.
git cherry-pick d34bcef232f6c...
커밋 ID를 제공 할 수도 있습니다.
git cherry-pick d34bcef...86d2aec
이제 당신의 일이 끝났습니다. 올바른 ID와 올바른 지점을 선택하면 성공합니다. 따라서이 작업을 수행하기 전에주의하십시오. 다른 문제가 발생할 수 있습니다.
이제 코드를 푸시 할 수 있습니다
git push