Program Tip

한 분기를 다른 분기처럼 만드는 git 명령

programtip 2020. 11. 1. 18:32
반응형

한 분기를 다른 분기처럼 만드는 git 명령


변경 사항이있는 분기를 가져 와서 분기 된 업스트림과 동일하게 되돌리려 고합니다. 변경 사항은 로컬이며 github 로 푸시되었으므로 이미 푸시 된 브랜치에서는 나쁜 일인 기록을 변경 하기 때문에 둘 다 git reset또는 git rebase실제로 실행 가능 하지 않습니다 .

나는 또한 git merge다양한 전략을 시도했지만 그들 중 어느 것도 로컬 변경 사항을 취소하지 않았습니다. 즉, 파일을 추가하면 병합으로 다른 파일을 다시 가져올 수 있지만 업스트림이 수행하지 않는 해당 파일은 계속 유지됩니다. 있다.

업스트림에서 새 분기를 만들 수는 있지만 수정 기록 측면에서 모든 변경 사항을 적용하여 분기를 가져와 다시 업스트림과 동일하게 만들어 해당 변경 사항을 안전하게 푸시 할 수 있도록 병합하고 싶습니다. 역사를 방해하지 않고. 그러한 명령이나 일련의 명령이 있습니까?


당신은 당신의 상류 지점을 병합 할 수 dev으로, 지점 사용자 정의 병합 드라이버 "keepTheirs" :
페이지의 " " git merge -s theirs"-하지만 존재하지 않는 알 필요 ".
귀하의 경우에는 하나만 .gitattributes필요하며 다음과 같은 keepTheirs스크립트 가 필요합니다 .

mv -f $3 $2
exit 0

git merge --strategy=theirs 시뮬레이션 # 1

첫 번째 상위가 업스트림 인 병합으로 표시됩니다.

Jefromimerge -s ours업스트림 (또는 업스트림에서 시작하는 임시 분기)에서 작업을 병합 한 다음 해당 병합의 결과로 분기를 빠르게 전달하여 주석에서를 언급합니다 .

git checkout -b tmp origin/upstream
git merge -s ours downstream         # ignoring all changes from downstream
git checkout downstream
git merge tmp                        # fast-forward to tmp HEAD
git branch -D tmp                    # deleting tmp

이는 업스트림 조상을 첫 번째 부모로 기록하는 이점이 있으므로 병합은 "이 주제 브랜치를 파괴하고 업스트림으로 교체"하는 대신 "이 오래된 주제 브랜치를 흡수"하는 것을 의미 합니다.

(2011 년 편집) :

이 워크 플로는 OP에 의해이 블로그 게시물에 보고되었습니다 .

왜 이걸 다시 원합니까?

내 저장소가 공개 버전과 아무 관련이없는 한 괜찮 았지만 이제는 WIP에서 다른 팀 구성원 및 외부 기여자와 공동 작업 할 수있는 기능을 원했기 때문에 공개 분기가 다른 사람들이 분기하고 가져올 수 있습니다. 즉, 이제 GitHub 및 공개에 있으므로 원격 백업에 푸시 한 항목을 더 이상 리베이스하거나 재설정 할 필요가 없습니다.

그래서 내가 어떻게 진행해야할지 남깁니다.
99 %의 시간 동안 내 사본이 업스트림 마스터로 이동하므로 대부분의 시간 동안 내 마스터를 작업하고 업스트림으로 푸시하고 싶습니다.
그러나 가끔씩, 내가 가진 것은 wip업스트림으로 들어가는 것에 의해 무효화되고 내 wip.
이 시점에서 마스터를 업스트림과 다시 동기화하고 싶지만 공개적으로 푸시 된 마스터의 커밋 포인트를 파괴하지는 않습니다. 즉, 업스트림과 동일한 복사본을 만드는 변경 집합으로 끝나는 업스트림과의 병합을 원합니다 .
그리고 그것이 git merge --strategy=theirs해야 할 일입니다.


git merge --strategy=theirs 시뮬레이션 # 2

첫 번째 부모 인 우리와 병합으로 표시됩니다.

( jcwenger 제안 )

git checkout -b tmp upstream
git merge -s ours thebranch         # ignoring all changes from downstream
git checkout downstream
git merge --squash tmp               # apply changes from tmp but not as merge.
git rev-parse upstream > .git/MERGE_HEAD #record upstream 2nd merge head
git commit -m "rebaselined thebranch from upstream" # make the commit.
git branch -D tmp                    # deleting tmp

git merge --strategy=theirs 시뮬레이션 # 3

블로그 게시물에 언급 된 내용 :

git merge -s ours ref-to-be-merged
git diff --binary ref-to-be-merged | git apply -R --index
git commit -F .git/COMMIT_EDITMSG --amend

때때로 당신은 이것을 하기를 원합니다. 당신의 역사에 "쓰레기"가있어서가 아니라 아마도 리베이스를 피해야하는 공용 저장소에서 개발을위한 기준을 변경하기를 원하기 때문일 것 입니다.


git merge --strategy=theirs 시뮬레이션 # 4

(동일한 블로그 게시물)

또는 로컬 업스트림 분기를 빨리 감기 가능하게 유지하려는 경우 잠재적 인 타협은 sid / 불안정한 경우 업스트림 분기가 수시로 재설정 / 재 기반 될 수 있음을 이해하고 작업하는 것입니다 (최종적으로 종료되는 이벤트를 기반으로 함). 업스트림 프로젝트 측에 대한 제어).
이것은 큰 문제가 아니며 그 가정에 따라 작업한다는 것은 로컬 업스트림 분기를 빠른 업데이트 만받는 상태로 유지하는 것이 쉽다는 것을 의미합니다.

git branch -m upstream-unstable upstream-unstable-save
git branch upstream-unstable upstream-remote/master
git merge -s ours upstream-unstable
git diff --binary ref-to-be-merged | git apply -R --index --exclude="debian/*"
git commit -F .git/COMMIT_EDITMSG --amend

git merge --strategy=theirs 시뮬레이션 # 5

( Barak A. Pearlmutter 제안 ) :

git checkout MINE
git merge --no-commit -s ours HERS
git rm -rf .
git checkout HERS -- .
git checkout MINE -- debian # or whatever, as appropriate
git gui # edit commit message & click commit button

git merge --strategy=theirs 시뮬레이션 # 6

(동일한 Michael Gebetsroither가 제안 ) :

Michael Gebetsroither는 내가 "속임수"라고 주장하면서 차를 댔고;) 낮은 수준의 배관 명령으로 또 다른 해결책을 제시했습니다.

(git 전용 명령으로 가능하지 않다면 git이 아닙니다. diff / patch / apply를 사용하는 git의 모든 것은 실제 솔루션이 아닙니다.)

# get the contents of another branch
git read-tree -u --reset <ID>
# selectivly merge subdirectories
# e.g superseed upstream source with that from another branch
git merge -s ours --no-commit other_upstream
git read-tree --reset -u other_upstream     # or use --prefix=foo/
git checkout HEAD -- debian/
git checkout HEAD -- .gitignore
git commit -m 'superseed upstream source' -a

당신이해야 할 일처럼 들립니다.

$ git reset --hard origin/master

업스트림을 푸시 할 변경 사항이없고 단순히 업스트림 분기를 현재 분기로 설정하려는 경우 이렇게하면됩니다. 이 작업을 로컬에서 수행하는 것은 유해하지 않지만 마스터로 푸시되지 않은 로컬 변경 **은 손실됩니다.

** Actually the changes are still around if you have committed them locally, as the commits will still be in your git reflog, usually for at least 30 days.


You can do this rather easily now:

$ git fetch origin
$ git merge origin/master -s recursive -Xtheirs

This gets your local repo in-sync with the origin, and preserves the history.


Another simulation for git merge -s theirs ref-to-be-merged:

git merge --no-ff -s ours ref-to-be-merged         # enforce a merge commit; content is still wrong
git reset --hard HEAD^2; git reset --soft HEAD@{1} # fix the content
git commit --amend

An alternative to the double reset would be applying the reverse patch:

git diff --binary ref-to-be-merged | git apply -R --index

There's also a way with little help of plumbing command - IMHO the most straightforward. Say you want to emulate "theirs" for 2 branches case:

head1=$(git show --pretty=format:"%H" -s foo)
head2=$(git show --pretty=format:"%H" -s bar)
tree=$(git show --pretty=format:"%T" -s bar)
newhead=$(git commit-tree $tree -p $head1 -p $head2 <<<"merge commit message")
git reset --hard $newhead

This merges arbitrary number of heads (2 in the example above) using tree of one of them (bar in the example above, providing 'theirs' tree), disregarding any diff/file issues (commit-tree is low level command, so it doesn't care about those). Note that head can be just 1 (so equivalent of cherry-pick with "theirs").

Note, that which parent head is specified first, can influence some stuff (see e.g. --first-parent of git-log command) - so keep that in mind.

Instead of git-show, anything else capable of outputting tree and commit hashes can be used - whatever one's is used to parsing (cat-file, rev-list, ...). You can follow everything with git commit --amend to interactively beautify commit message.


change to the remote upstream branch and do a git merge with the merge strategy set to ours.

git checkout origin/master
git merge dev --strategy=ours
git commit ...
git push

All the history will still be present, but you'll have an extra merge commit. The important thing here is to start from the version you want to be at and merge ours with the branch github is actually at.


Heavy handed, but hell, what can possibly go wrong?

  • Check out the branch X you want to look like the Y
  • cp -r .git /tmp
  • Check out branch Y
  • rm -rf .git && cp -r /tmp/.git .
  • Commit & push any difference
  • DONE.

Use git reset BACKWARDS!

You can make a branch look like any other commit with git reset, but you have to do it in a round-about way.

To make a branch on commit <old> look like a commit <new>, you can do

git reset --hard <new>

in order to make <new> the contents of the working tree.

Then do

git reset --mixed <old> 

to change the branch back to the original commit but leaving working tree in the <new> state.

Then you can add and commit the changes, in order to make your branch exactly match the contents of the <new> commit.

It's counter-intuitive that to move from the <old> state to the <new> you need to do a git reset from <new> to <old>. However with the option --mixed the working tree is left at <new> and the branch pointer set to <old>, so that when the changes are committed the branch looks how we want.

Warning

Don't lose track of your commits, e.g. forget what <old> is when doing git reset --hard <new>.


I followed those roles:

Fetching the origin, reset hard from the branch then recursive from theirs and then forced push to branch

ON YOUR OWN RISK

git fetch origin
git reset --hard origin/<branch>
git merge origin/<branch> -s recursive -Xtheirs
git push -f <remote> <branch>

참고URL : https://stackoverflow.com/questions/4911794/git-command-for-making-one-branch-like-another

반응형