>개발 도구 >자식 >git-merge 상세 분석(정리 및 공유)

git-merge 상세 분석(정리 및 공유)

WBOY
WBOY앞으로
2022-03-07 17:24:035565검색

이 글은 git-merge와 관련된 문제를 주로 소개하는 Git 관련 지식을 제공합니다. git-merge 명령은 지정된 커밋에서 현재 브랜치로 병합하는 데 사용됩니다.

git-merge 상세 분석(정리 및 공유)

추천 학습: "Git Tutorial"

1.1 Summary

git-merge 명령에는 다음 세 가지 매개변수가 있습니다:

  • git merge [-n] [-- stat] [--no-commit] [--squash] [--[no-]edit] [-s ] [-X ] [-S[] ] [--[no-]rerere-autoupdate] [-m <msg>] [<커밋>...]
  • git merge [-n] [--stat] [--no-commit] [--squash] [--[no-]edit] [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]] [--[no-]rerere-autoupdate] [-m <msg>] [<commit>...]
  • git merge <msg> HEAD <commit>...
  • git merge --abort

1.2git-merge简介

git-merge命令是用于从指定的commit(s)合并到当前分支的操作。

注:这里的指定commit(s)是指从这些历史commit节点开始,一直到当前分开的时候。

git-merge命令有以下两种用途:

  1. 用于git-pull中,来整合另一代码仓库中的变化(即:git pull = git fetch + git merge)
  2. 用于从一个分支到另一个分支的合并

那么git merge topic命令将会把在master分支上二者共同的节点(E节点)之后分离的节点(即topic分支的A B C节点)重现在master分支上,直到topic分支当前的commit节点(C节点),并位于master分支的顶部。并且沿着master分支和topic分支创建一个记录合并结果的新节点,该节点带有用户描述合并变化的信息。

1.3git merge <msg> HEAD <commit>...命令

该命令的存在是由于历史原因,在新版本中不应该使用它,应该使用git merge -m <msg> <commit>....进行替代

1.4git merge --abort命令

该命令仅仅在合并后导致冲突时才使用。git merge --abort将会抛弃合并过程并且尝试重建合并前的状态。但是,当合并开始时如果存在未commit的文件,git merge --abort在某些情况下将无法重现合并前的状态。(特别是这些未commit的文件在合并的过程中将会被修改时)

警告:运行git-merge时含有大量的未commit文件很容易让你陷入困境,这将使你在冲突中难以回退。因此非常不鼓励在使用git-merge时存在未commit的文件,建议使用git-stash命令将这些未commit文件暂存起来,并在解决冲突以后使用git stash pop把这些未commit文件还原出来。

2.参数

本部分用于介绍git-merge命令中使用的参数

2.1--commit--no-commit

--commit参数使得合并后产生一个合并结果的commit节点。该参数可以覆盖--no-commit
--no-commit参数使得合并后,为了防止合并失败并不自动提交,能够给使用者一个机会在提交前审视和修改合并结果。

2.2--edit-e以及--no-edit

--edit-e用于在成功合并、提交前调用编辑器来进一步编辑自动生成的合并信息。因此使用者能够进一步解释和判断合并的结果。
--no-edit参数能够用于接受自动合并的信息(通常情况下并不鼓励这样做)。

如果你在合并时已经给定了-m参数(下文介绍),使用 --edit(或-e)依然是有用的,这将在编辑器中进一步编辑-m所含的内容。

旧版本的节点可能并不允许用户去编辑合并日志信息。

2.3--ff命令

--ff是指fast-forward命令。当使用fast-forward模式进行合并时,将不会创造一个新的commit节点。默认情况下,git-merge采用fast-forward模式。
关于fast-forward模式的详细解释,请看我的另一篇文章:一个成功的Git分支模型的“关于fast forward”一节。

2.4--no-ff命令

即使可以使用fast-forward模式,也要创建一个新的合并节点。这是当git merge在合并一个tag时的默认行为。

2.5--ff-onlygit merge <msg> commit>...

git merge --abort

1.2 git-merge 소개

🎜git-merge 명령이 사용됩니다 지정된 커밋을 현재 분기에 병합하는 작업입니다. 🎜
🎜참고: 여기에 지정된 커밋은 이러한 과거 커밋 노드에서 시작하여 현재 분리까지를 의미합니다. 🎜
🎜git-merge 명령은 다음 두 가지 용도로 사용됩니다. 🎜
    🎜 git-pull에서 다른 코드 저장소의 변경 사항을 통합하는 데 사용됩니다(예: git pull = git fetch + git merge)🎜한 브랜치에서 다른 브랜치로 병합
🎜그런 다음 git merge topic 명령은 뒤에 분리된 공통 노드(E 노드)(즉, A B C 노드)를 병합합니다. 토픽 브랜치의 현재 커밋 노드(C 노드)까지 마스터 브랜치에 다시 나타나며 마스터 브랜치의 최상위에 위치합니다. 그리고 병합 결과를 기록하기 위해 마스터 분기와 주제 분기를 따라 새 노드를 생성합니다. 이 노드는 병합 변경 사항을 설명하는 사용자 정보를 전달합니다. 🎜🎜1.3git merge <msg> HEAD <commit>... 명령 🎜🎜이 명령의 존재는 새 버전에서는 사용하면 안 됩니다. git merge -m <msg> <commit>....를 사용하여 🎜🎜1.4git merge --abort 명령🎜🎜을 대체하세요. 이 명령은 이후에만 충돌을 일으킵니다. 병합 사용. git merge --abort는 병합 프로세스를 중단하고 병합 전 상태를 다시 작성하려고 시도합니다. 그러나 병합이 시작될 때 커밋되지 않은 파일이 있으면 git merge --abort가 병합 전 상태를 재현하지 못하는 경우가 있습니다. (특히 커밋되지 않은 파일이 병합 프로세스 중에 수정되는 경우) 🎜
🎜경고: 많은 수의 커밋되지 않은 파일을 사용하여 git-merge를 실행하면 쉽게 문제가 발생할 수 있습니다. 갈등에 빠지면 뒤로 물러나기가 어렵습니다. 따라서 git-merge를 사용할 때 커밋되지 않은 파일을 두지 않는 것이 좋습니다. 커밋되지 않은 파일을 임시로 저장하고 충돌을 해결하려면 git-stash 명령을 사용하는 것이 좋습니다. . 커밋되지 않은 파일을 복원하려면 git stash pop을 사용하세요. 🎜
🎜2. 매개변수🎜🎜이 섹션은 git-merge 명령🎜🎜2.1--commit에 사용되는 매개변수를 소개하는 데 사용됩니다. -- no-commit🎜🎜--commit 매개변수는 병합 후 병합 결과의 커밋 노드가 생성되도록 합니다. 이 매개변수는 --no-commit을 재정의할 수 있습니다. 🎜--no-commit 매개변수는 병합 실패를 방지하기 위해 병합이 자동으로 제출되지 않도록 하여 사용자가 제출 전에 병합 결과를 검토하고 수정할 수 있는 기회를 제공합니다. 🎜🎜2.2 --edit-e--no-edit🎜🎜--edit 및 -e는 성공적인 병합 및 제출 전에 자동으로 생성된 병합 정보를 추가로 편집하기 위해 편집기를 호출하는 데 사용됩니다. 따라서 사용자는 합병 결과를 더 자세히 해석하고 판단할 수 있습니다. 🎜--no-edit 매개변수를 사용하여 자동으로 병합된 정보를 허용할 수 있습니다(일반적으로 권장되지 않음). 🎜
🎜병합 시 -m 매개변수를 지정한 경우(아래 설명 참조) --edit(또는 -e)를 사용하세요. 여전히 유용하며 편집기에서 -m에 포함된 콘텐츠를 추가로 편집합니다. 🎜
🎜이전 버전의 노드에서는 사용자가 병합 로그 정보를 편집하는 것을 허용하지 않을 수 있습니다. 🎜
🎜2.3 --ff 명령 🎜🎜--ff는 빨리 감기 명령을 나타냅니다. 빨리 감기 모드를 사용하여 병합하는 경우 새 커밋 노드가 생성되지 않습니다. 기본적으로 git-merge는 빨리 감기 모드를 사용합니다. 🎜 빨리 감기 모드에 대한 자세한 설명은 내 다른 기사: 성공적인 Git 분기 모델의 "빨리 감기 정보" 섹션을 참조하세요. 🎜🎜2.4 --no-ff 명령 🎜🎜빨리 감기 모드를 사용할 수 있는 경우에도 새 병합 노드를 생성합니다. 이는 git merge가 태그를 병합할 때의 기본 동작입니다. 🎜🎜2.5 --ff-only 명령🎜🎜현재 HEAD 노드가 최신 상태이거나(최신 노드로 업데이트됨) 빨리 감기 모드를 사용하여 병합될 수 없는 경우 병합은 거부되고 실패 상태를 반환합니다. 🎜

2.5 --log[=<n>]</n>--no-log--log[=<n>]--no-log

--log[=<n>]将在合并提交时,除了含有分支名以外,还将含有最多n个被合并commit节点的日志信息。
--no-log并不会列出该信息。

2.6 --stat, -n, --no-stat命令

--stat参数将会在合并结果的末端显示文件差异的状态。文件差异的状态也可以在git配置文件中的merge.stat配置。
相反,-n, --no-stat参数将不会显示该信息。

2.7--squash--no-squash

--squash 当一个合并发生时,从当前分支和对方分支的共同祖先节点之后的对方分支节点,一直到对方分支的顶部节点将会压缩在一起,使用者可以经过审视后进行提交,产生一个新的节点。

注意1:该参数和--no-ff冲突

注意2:该参数使用后的结果类似于在当前分支提交一个新节点。在某些情况下这个参数非常有用,例如使用Git Flow时(关于Git Flow,请参考:一个成功的Git分支模型),功能分支在进行一个功能需求的研发时,开发者可能在本地提交了大量且无意义的节点,当需要合并到develop分支时,可能仅仅需要用一个新的节点来表示这一长串节点的修改内容,这时--squash命令将会发挥作用。此外,如果功能分支的多次提交并不是琐碎而都是有意义的,使用--no-ff命令更为合适。
--no-squash的作用正好相反。

2.8 -s <strategy>--strategy=<strategy>

-s <strategy>--strategy=<strategy>用于指定合并的策略。默认情况如果没有指定该参数,git将按照下列情况采用默认的合并策略:

  1. 合并节点只含有单个父节点时(如采用fast-forward模式时),采用recursive策略(下文介绍)。
  2. 合并节点含有多个父节点时(如采用no-fast-forward模式时),采用octopus策略(下文介绍)。

2.9 -X <option>--strategy-option=<option>

-s <strategy>时指定该策略的具体参数(下文介绍)。

2.10 --verify-signatures, --no-verify-signatures

用于验证被合并的节点是否带有GPG签名,并在合并中忽略那些不带有GPG签名验证的节点。
(以下引用摘自一篇转载的文章,由于我没有找到原作者,因此无法提供原作者信息和原文链接,如果有所侵权请私信或者评论告知,我将删除以下引用内容。)

GPG是加密软件,可以使用GPG生成的公钥在网上安全的传播你的文件、代码。
为什么说安全的?以Google所开发的repo为例,repo即采用GPG验证的方式,每个里程碑tag都带有GPG加密验证,假如在里程碑v1.12.3处你想要做修改,修改完后将这个tag删除,然后又创建同名tag指向你的修改点,这必然是可以的。但是,在你再次clone你修改后的项目时,你会发现,你对此里程碑tag的改变不被认可,验证失败,导致你的修改在这里无法正常实现。这就是GPG验证的作用,这样就能够保证项目作者(私钥持有者)所制定的里程碑别人将无法修改。那么,就可以说,作者的代码是安全传播的。
为什么会有这种需求?一个项目从开发到发布,再到后期的更新迭代,一定会存在若干的稳定版本与开发版本(存在不稳定因素)。作为项目发起者、持有者,有权定义他(们)所认可的稳定版本,这个稳定版本,将不允许其他开发者进行改动。还以Google的repo项目为例,项目所有者定义项目开发过程中的点A为稳定版v1.12.3,那么用户在下载v1.12.3版本后,使用的肯定是A点所生成的项目、产品,就算其他开发者能够在本地对v1.12.3进行重新指定,指定到他们修改后的B点,但是最终修改后的版本给用户用的时候,会出现GPG签名验证不通过的问题,也就是说这样的修改是不生效的。

2.11 —summary,--no-summary

--stat--no-stat相似,并将在未来版本移除。

2.12 -q--quiet

静默操作,不显示合并进度信息。

2.13 -v--verbose

--log[=<n>]</n> 병합 및 제출 시 브랜치 이름 외에도 최대 n개의 병합된 커밋 노드의 로그 정보도 포함됩니다.
--no-log는 이 정보를 나열하지 않습니다.

2.6 --stat, -n, --no-stat 명령 🎜🎜--stat 매개변수 병합된 결과의 마지막 부분에 파일 차이 상태가 표시됩니다. 파일 차이점 상태는 git 구성 파일의 merge.stat에서 구성할 수도 있습니다.
이와 대조적으로 -n, --no-stat 매개변수는 이 정보를 표시하지 않습니다. 🎜🎜2.7 --squash--no-squash🎜🎜--squash 병합이 발생하면 현재 분기에서 분기하고 다른 지점 공통 조상 노드 이후의 다른 지점 노드와 다른 지점의 최상위 노드가 함께 압축됩니다. 사용자는 검토 후 제출하여 새 노드를 생성할 수 있습니다. 🎜
🎜참고 1: 이 매개변수는 --no-ff🎜
🎜와 충돌합니다. 참고 2: 이 매개변수를 사용한 결과는 에 새 매개변수를 제출하는 것과 유사합니다. 현재 분기 노드. 이 매개변수는 Git Flow를 사용할 때와 같은 일부 경우에 매우 유용합니다(Git Flow에 대해서는 성공적인 Git 분기 모델 참조). 그리고 의미 없는 노드를 개발 브랜치에 병합해야 하는 경우 이 긴 노드 목록의 수정 내용을 나타내기 위해 새 노드만 사용하면 됩니다. code> 명령이 실행됩니다. 또한 기능 브랜치의 여러 제출이 사소하지 않고 의미가 있는 경우 --no-ff 명령을 사용하는 것이 더 적절합니다.
--no-squash는 정반대의 작업을 수행합니다. 🎜
🎜2.8 -s <strategy>--strategy=<strategy>🎜🎜-s <strategy>--strategy=<strategy>는 병합 전략을 지정하는 데 사용됩니다. 기본적으로 이 매개변수를 지정하지 않으면 git은 다음 조건에 따라 기본 병합 전략을 사용합니다. 🎜
  1. 병합 노드에 단일 상위 노드만 포함된 경우(예: 빨리 감기 모드를 사용하는 경우) , 재귀 전략(아래 설명)).
  2. 병합된 노드에 여러 상위 노드가 포함된 경우(예: 빨리 감기 없음 모드를 사용하는 경우) 문어 전략(아래 설명)이 사용됩니다.
🎜2.9 -X <option>--strategy-option=<option>🎜🎜 in -s &lt ;strategy>는 전략의 특정 매개변수를 지정합니다(아래 설명). 🎜🎜2.10 --verify-signatures, --no-verify-signatures🎜🎜는 병합된 노드에 GPG 서명이 있는지 확인하는 데 사용되며 병합 시 무시됩니다. GPG 서명 확인이 없는 노드입니다.
(다음 인용문은 재인쇄된 기사에서 발췌한 것입니다. 원저자를 찾지 못해 원저자 정보와 원문 링크를 제공할 수 없습니다. 침해사항이 있는 경우 개인 메시지나 메시지로 알려주시기 바랍니다. 댓글을 남겨주시면 다음 인용문을 삭제하겠습니다.)🎜
🎜GPG는 암호화 소프트웨어로 GPG에서 생성한 공개 키를 사용하여 파일과 코드를 인터넷에 안전하게 퍼뜨릴 수 있습니다.
왜 안전하다고 말합니까? Google에서 개발한 저장소를 예로 들면, 저장소는 GPG 검증을 사용합니다. 각 마일스톤 태그에는 GPG 암호화 검증이 있습니다. 마일스톤 v1.12.3에서 변경하려면 수정 후 태그를 삭제하면 됩니다. 수정 지점을 가리키도록 동일한 이름의 태그를 생성합니다. 그러나 수정된 ​​프로젝트를 다시 복제하면 이 마일스톤 태그에 대한 변경 사항이 인식되지 않고 확인에 실패하여 여기에서 수정 사항이 정상적으로 구현되지 않는 것을 확인할 수 있습니다. 이는 프로젝트 작성자(개인 키 보유자)가 설정한 마일스톤을 다른 사람이 수정할 수 없도록 보장하는 GPG 검증의 역할입니다. 그러면 작성자의 코드가 안전하게 유포되었다고 할 수 있다.
왜 그러한 필요성이 있습니까? 프로젝트의 개발부터 릴리스, 이후 업데이트 반복까지 확실히 안정적인 버전과 개발 버전이 많이 있을 것입니다(불안정한 요소가 있음). 프로젝트 개시자 및 보유자로서 그들은 자신이 인식하는 안정 버전을 정의할 권리가 있습니다. 이 안정 버전은 다른 개발자가 변경하는 것을 허용하지 않습니다. Google의 repo 프로젝트를 예로 들어보겠습니다. 프로젝트 소유자는 프로젝트 개발 프로세스에서 포인트 A를 안정 버전 v1.12.3으로 정의합니다. 그런 다음 사용자는 v1.12.3 버전을 다운로드한 후 포인트 A에서 생성된 프로젝트와 제품을 확실히 사용하게 됩니다. 다른 개발자가 v1.12.3을 로컬에서 다시 지정하여 자신의 수정된 지점 B에 지정할 수 있다고 하더라도 최종적으로 사용자가 수정된 버전을 사용하게 되면 GPG 서명 검증이 실패하는 문제, 즉 수정 사항은 적용되지 않습니다. 🎜
🎜2.11 —요약, --no-summary🎜🎜 및 --stat--no- stat는 유사하며 향후 버전에서 제거될 예정입니다. 🎜🎜2.12 -q--quiet🎜🎜자동으로 작업하며 병합 진행 정보가 표시되지 않습니다. 🎜🎜2.13 -v--verbose🎜🎜자세한 병합 결과 정보를 표시합니다. 🎜

2.14 --progress--no-progress--progress--no-progress

切换是否显示合并的进度信息。如果二者都没有指定,那么在标准错误发生时,将在连接的终端显示信息。请注意,并不是所有的合并策略都支持进度报告。

2.15-S[<keyid>]--gpg-sign[=<keyid>]

GPG签名。

2.16-m <msg>

设置用于创建合并节点时的提交信息。
如果指定了--log参数,那么commit节点的短日志将会附加在提交信息里。

2.17--[no-]rerere-autoupdate

rerere即reuse recorded resolution,重复使用已经记录的解决方案。它允许你让 Git 记住解决一个块冲突的方法,这样在下一次看到相同冲突时,Git 可以为你自动地解决它。

2.18--abort

抛弃当前合并冲突的处理过程并尝试重建合并前的状态。

3.关于合并的其他概念

3.1合并前的检测

在合并外部分支时,你应当保持自己分支的整洁,否则的话当存在合并冲突时将会带来很多麻烦。
为了避免在合并提交时记录不相关的文件,如果有任何在index所指向的HEAD节点中登记的未提交文件,git-pull和git-merge命令将会停止。

3.2fast-forward合并

通常情况下分支合并都会产生一个合并节点,但是在某些特殊情况下例外。例如调用git pull命令更新远端代码时,如果本地的分支没有任何的提交,那么没有必要产生一个合并节点。这种情况下将不会产生一个合并节点,HEAD直接指向更新后的顶端代码,这种合并的策略就是fast-forward合并。

3.3合并细节

除了上文所提到的fast-forward合并模式以外,被合并的分支将会通过一个合并节点和当前分支绑在一起,该合并节点同时拥有合并前的当前分支顶部节点和对方分支顶部节点,共同作为父节点。
一个合并了的版本将会使所有相关分支的变化一致,包括提交节点,HEAD节点和index指针以及节点树都会被更新。只要这些节点中的文件没有重叠的地方,那么这些文件的变化都会在节点树中改动并更新保存。
如果无法明显地合并这些变化,将会发生以下的情况:

  1. HEAD指针所指向的节点保持不变
  2. MERGE_HEAD指针被置于其他分支的顶部
  3. 已经合并干净的路径在index文件和节点树中同时更新
  4. 对于冲突路径,index文件记录了三个版本:版本1记录了二者共同的祖先节点,版本2记录了当前分支的顶部,即HEAD,版本3记录了MERGE_HEAD。节点树中的文件包含了合并程序运行后的结果。例如三路合并算法会产生冲突。
  5. 其他方面没有任何变化。特别地,你之前进行的本地修改将继续保持原样。
    如果你尝试了一个导致非常复杂冲突的合并,并想重新开始,那么可以使用git merge --abort

关于三路合并算法:
三路合并算法是用于解决冲突的一种方式,当产生冲突时,三路合并算法会获取三个节点:本地冲突的B节点,对方分支的C节点,B,C节点的共同最近祖先节点A。三路合并算法会根据这三个节点进行合并。具体过程是,B,C节点和A节点进行比较,如果B,C节点的某个文件和A节点中的相同,那么不产生冲突;如果B或C只有一个和A节点相比发生变化,那么该文件将会采用该变化了的版本;如果B和C和A相比都发生了变化,且变化不相同,那么则需要手动去合并;如果B,C都发生了变化,且变化相同,那么并不产生冲突,会自动采用该变化的版本。最终合并后会产生D节点,D节点有两个父节点,分别为B和C。

3.4合并tag

当合并一个tag时,Git总是创建一个合并的提交,即使这时能够使用fast-forward模式。该提交信息的模板预设为该tag的信息。额外地,如果该tag被签名,那么签名的检测信息将会附加在提交信息模板中。

3.5冲突是如何表示的

当产生合并冲突时,该部分会以<<<<<<<, =======表示。在=======之前的部分是当前分支这边的情况,在=======

병합된 진행 정보 표시 여부를 전환합니다. 둘 다 지정하지 않으면 표준 오류가 발생할 때 연결된 터미널에 메시지가 표시됩니다. 모든 병합 전략이 진행 상황 보고를 지원하는 것은 아닙니다.

2.15-S[<keyid>]--gpg-sign[=<keyid>]

GPG 서명. 🎜🎜2.16-m <msg>🎜🎜병합 노드 생성 시 사용되는 커밋 정보를 설정합니다.
--log 매개변수가 지정되면 커밋 노드의 짧은 로그가 커밋 메시지에 추가됩니다. 🎜🎜2.17--[no-]rerere-autoupdate🎜🎜rerere는 기록된 해상도를 재사용하고 기록된 솔루션을 재사용하는 것입니다. 다음번에 동일한 충돌이 발생하면 Git이 자동으로 문제를 해결할 수 있도록 Git에게 블록 충돌 해결 방법을 기억하도록 요청할 수 있습니다. 🎜🎜2.18--abort🎜🎜현재 병합 충돌 처리 프로세스를 중단하고 병합 전 상태를 재구성해 보세요. 🎜🎜3. 병합에 대한 다른 개념🎜🎜3.1 병합 전 감지🎜🎜외부 분기를 병합할 때는 자체 분기를 깨끗하게 유지해야 합니다. 그렇지 않으면 병합 충돌이 발생할 때 많은 문제가 발생합니다.
커밋 병합 시 관련 없는 파일이 기록되는 것을 방지하기 위해 인덱스가 가리키는 HEAD 노드에 커밋되지 않은 파일이 등록되어 있으면 git-pull 및 git-merge 명령이 중지됩니다. 🎜🎜3.2fast-forward merge🎜🎜일반적으로 분기 병합은 병합 노드를 생성하지만 일부 특수한 경우에는 예외가 있습니다. 예를 들어 git pull 명령을 호출하여 원격 코드를 업데이트할 때 로컬 브랜치에 커밋이 없으면 병합 노드를 생성할 필요가 없습니다. 이 경우 병합 노드는 생성되지 않으며 HEAD는 업데이트된 상위 코드를 직접 가리킵니다. 이 병합 전략은 빨리 감기 병합입니다. 🎜🎜3.3 병합 세부 정보🎜🎜위에서 언급한 빨리 감기 병합 모드 외에도 병합된 분기는 병합 노드를 통해 현재 분기에 연결됩니다. 병합 노드에는 병합 전 현재 분기의 최상위 노드와 최상위 노드도 있습니다. 다른 분기의 노드를 상위 노드로 함께 사용합니다.
병합된 버전은 커밋 노드, HEAD 노드 및 인덱스 포인터를 포함하여 모든 관련 분기의 변경 사항을 일관되게 만들고 노드 트리가 업데이트됩니다. 이러한 노드의 파일이 겹치지 않는 한 이러한 파일에 대한 변경 사항은 노드 트리에서 수정 및 업데이트됩니다.
이러한 변경 사항을 명시적으로 병합할 수 없는 경우 다음과 같은 일이 발생합니다: 🎜
  1. HEAD 포인터가 가리키는 노드는 변경되지 않은 상태로 유지됩니다.
  2. MERGE_HEAD 포인터는 다른 분기 위에 배치됩니다.
  3. 병합된 정리 경로는 인덱스 파일과 노드 트리에서 동시에 업데이트됩니다.
  4. 충돌하는 경로의 경우 인덱스 파일은 세 가지 버전을 기록합니다: 버전 1 두 가지 모두의 공통 조상 노드가 기록됩니다. 버전 2는 현재 분기의 최상위, 즉 HEAD를 기록하고 버전 3은 MERGE_HEAD를 기록합니다. 노드 트리의 파일에는 병합 프로그램 실행 결과가 포함되어 있습니다. 예를 들어, 3방향 병합 알고리즘은 충돌을 일으킬 수 있습니다.
  5. 다른 변경사항은 없습니다. 특히 이전에 수행한 로컬 수정 사항은 그대로 유지됩니다.
    매우 복잡한 충돌을 일으킨 병합을 시도했고 다시 시작하고 싶다면 git merge --abort를 사용할 수 있습니다.
🎜약 3개 도로 병합 알고리즘:
3방향 병합 알고리즘은 충돌이 발생하면 3방향 병합 알고리즘은 로컬 충돌의 B 노드, C 노드의 세 가지 노드를 획득합니다. 다른 가지와 다른 가지의 B 노드, 즉 노드 C의 가장 가까운 공통 조상 노드입니다. 3방향 병합 알고리즘은 이 세 개의 노드를 기반으로 병합됩니다. 구체적인 프로세스는 노드 B와 C를 노드 A와 비교하는 것입니다. 노드 B와 C의 파일이 노드 A의 파일과 동일하면 노드와 비교하여 B 또는 C 중 하나만 변경되면 충돌이 없습니다. A를 선택하면 파일이 변경된 버전을 채택합니다. A와 비교하여 B와 C가 변경되고 변경 사항이 동일하지 않은 경우 B와 C가 변경되었으며 변경 사항이 동일하면 수동으로 병합해야 합니다. 을 선택하면 충돌이 발생하지 않으며 변경된 버전이 자동으로 적용됩니다. 최종 병합 후에는 D 노드가 생성됩니다. D 노드에는 B와 C라는 두 개의 상위 노드가 있습니다. 🎜
🎜3.4 태그 병합🎜🎜태그를 병합할 때 Git은 빨리 감기 모드를 사용할 수 있는 경우에도 항상 병합된 커밋을 생성합니다. 제출 정보의 템플릿은 태그 정보에 미리 설정되어 있습니다. 또한 태그가 서명되면 서명 감지 정보가 커밋 메시지 템플릿에 추가됩니다. 🎜🎜3.5 충돌 표현 방법🎜🎜병합 충돌이 발생하면 이 부분에 <code>====로 표시됩니다. = ==. ======== 앞 부분은 현재 브랜치의 상황이고, ======= 뒤 부분은 다른 브랜치의 상황입니다. 쪽의 가지. 🎜🎜3.6 충돌 해결 방법🎜🎜충돌을 확인한 후 다음 두 가지 방법을 선택할 수 있습니다.🎜
  • 병합하지 않기로 결정했습니다. 이때 해야 할 일은 인덱스를 HEAD 노드로 재설정하는 것 뿐이다. 이 경우 git merge --abort가 사용됩니다.
  • git merge --abort用于这种情况。
  • 解决冲突。Git会标记冲突的地方,解决完冲突的地方后使用git add加入到index中,然后使用git commit产生合并节点。
    你可以用以下工具来解决冲突:
  • 使用合并工具。git mergetool将会调用一个可视化的合并工具来处理冲突合并。
  • 查看差异。git diff将会显示三路差异(三路合并中所采用的三路比较算法)。
  • 查看每个分支的差异。git log --merge -p <path>将会显示HEAD版本和MERGE_HEAD版本的差异。
  • 查看合并前的版本。git show :1:文件名显示共同祖先的版本,git show :2:文件名显示当前分支的HEAD版本,git show :3:文件名显示对方分支的MERGE_HEAD版本。

4.合并策略

Git可以通过添加-s参数来指定合并的策略。一些合并策略甚至含有自己的参数选项,通过-X<option>设置这些合并策略的参数选项。(不要忘记,合并可以在git merge和git pull命令中发生,因此该合并策略同样适用于git pull)。

4.1resolve

仅仅使用三路合并算法合并两个分支的顶部节点(例如当前分支和你拉取下来的另一个分支)。这种合并策略遵循三路合并算法,由两个分支的HEAD节点以及共同子节点进行三路合并。
当然,真正会困扰我们的其实是交叉合并(criss-cross merge)这种情况。所谓的交叉合并,是指共同祖先节点有多个的情况,例如在两个分支合并时,很有可能出现共同祖先节点有两个的情况发生,这时候无法按照三路合并算法进行合并(因为共同祖先节点不唯一)。resolve策略在解决交叉合并问题时是这样处理的,这里参考《Version Control with Git》:

In criss-cross merge situations, where there is more than one possible merge basis, the resolve strategy works like this: pick one of the possible merge bases, and hope for the best. This is actually not as bad as it sounds. It often turns out that the users have been working on different parts of the code. In that case, Git detects that it's remerging some changes that are already in place and skips the duplicate changes, avoiding the conflict. Or, if these are slight changes that do cause conflict, at least the conflict should be easy for the developer to handle

这里简单翻译一下:在交叉合并的情况时有一个以上的合并基准点(共同祖先节点),resolve策略是这样工作的:选择其中一个可能的合并基准点并期望这是合并最好的结果。实际上这并没有听起来的那么糟糕。通常情况下用户修改不同部分的代码,在这种情况下,很多的合并冲突其实是多余和重复的。而使用resolve进行合并时,产生的冲突也较易于处理,真正会遗失代码的情况很少。

4.2recursive

仅仅使用三路合并算法合并两个分支。和resolve不同的是,在交叉合并的情况时,这种合并方式是递归调用的,从共同祖先节点之后两个分支的不同节点开始递归调用三路合并算法进行合并,如果产生冲突,那么该文件不再继续合并,直接抛出冲突;其他未产生冲突的文件将一直执行到顶部节点。额外地,这种方式也能够检测并处理涉及修改文件名的操作。这是git合并和拉取代码的默认合并操作。
recursive合并策略有以下参数:

4.2.1 ours

该参数将强迫冲突发生时,自动使用当前分支的版本。这种合并方式不会产生任何困扰情况,甚至git都不会去检查其他分支版本所包含的冲突内容这种方式会抛弃对方分支任何冲突内容。

4.2.2 theirs

正好和ours相反。
theirs和ours参数都适用于合并二进制文件冲突的情况。

4.2.2 patience

在这种参数下,git merge-recursive花费一些额外的时间来避免错过合并一些不重要的行(如函数的括号)。如果当前分支和对方分支的版本分支分离非常大时,建议采用这种合并方式。

4.2.3diff-algorithm=[patience|minimal|histogram|myers]

告知git merge-recursive使用不同的比较算法。

4.2.4 ignore-space-change, ignore-all-space, ignore-space-at-eol충돌을 해결하세요. Git은 충돌을 해결한 후 git add를 사용하여 이를 인덱스에 추가하고 git commit를 사용하여 병합 노드를 생성합니다.
다음 도구를 사용하여 충돌을 해결할 수 있습니다.

병합 도구를 사용하세요. git mergetool은 시각적 병합 도구를 호출하여 충돌하는 병합을 처리합니다.

차이점을 확인하세요. git diff는 3방향 차이점(3방향 병합에 사용되는 3방향 비교 알고리즘)을 표시합니다.

지점별 차이점을 확인해보세요. git log --merge -p <path>HEAD 버전과 MERGE_HEAD 버전 간의 차이를 표시합니다. 🎜합병 전 버전을 확인하세요. git show :1:파일 이름은 공통 조상 버전을 표시하고, git show :2:파일 이름은 현재 분기의 HEAD 버전을 표시합니다. git show :3 :파일 이름은 상대방 브랜치의 MERGE_HEAD 버전을 표시합니다.

4. 병합 전략

🎜Git은 -s 매개변수를 추가하여 병합 전략을 지정할 수 있습니다. 일부 병합 전략에는 -X<option>을 통해 설정할 수 있는 자체 매개변수 옵션도 있습니다. (병합은 git merge 및 git pull 명령 모두에서 발생할 수 있으므로 이 병합 전략은 git pull에도 적용됩니다.) 🎜

4.1resolve

🎜 3방향 병합 알고리즘을 사용하여 두 분기(예: 현재 분기와 가져온 다른 분기)의 최상위 노드를 병합하세요. 이 병합 전략은 두 분기의 HEAD 노드와 공통 하위 노드가 3방향 병합을 수행하는 3방향 병합 알고리즘을 따릅니다.
물론 우리를 정말 괴롭히는 것은 교차 병합(Cross-Cross Merge) 상황입니다. 소위 교차 병합은 여러 개의 공통 조상 노드가 있는 상황을 의미합니다. 예를 들어 두 개의 분기가 병합되는 경우 이때 두 개의 공통 조상 노드가 있을 가능성이 매우 높습니다. 3방향 병합 알고리즘에 적용됩니다(공통 조상 노드는 고유하지 않기 때문). 이것이 해결 전략이 교차 병합 문제를 처리하는 방법입니다. 다음은 "Git를 사용한 버전 제어"에 대한 참조입니다. 🎜
🎜두 개 이상의 가능한 병합 기반이 있는 교차 병합 상황에서 해결 전략이 작동합니다. 다음과 같이: 가능한 병합 기반 중 하나를 선택하고 최선을 다하십시오. 실제로는 사용자가 코드의 다른 부분에서 작업하고 있는 것으로 밝혀집니다. 이미 적용된 일부 변경 사항을 다시 병합하고 중복 변경 사항을 건너뛰어 충돌을 피합니다. 또는 이러한 변경 사항이 충돌을 일으키는 경우 최소한 개발자가 충돌을 쉽게 처리할 수 있어야 합니다🎜
🎜 다음은 간단한 번역입니다. 두 개 이상의 병합 참조 지점(공통 조상 노드)이 있는 교차 병합의 경우 해결 전략은 다음과 같이 작동합니다. 가능한 병합 참조 지점 중 하나를 선택하고 이것이 최선이기를 바랍니다. 병합의 결과. 실제로 이것은 들리는 것만큼 나쁘지는 않습니다. 일반적으로 사용자는 코드의 다른 부분을 수정하는데, 이 경우 많은 병합 충돌이 실제로 중복되고 반복됩니다. 병합을 위해 해결을 사용하면 생성된 충돌을 처리하기가 더 쉽고 코드가 실제로 손실되는 경우는 거의 없습니다. 🎜

4.2재귀

🎜두 가지 분기를 병합하려면 3방향 병합 알고리즘만 사용하세요. 해결과 달리 교차 병합의 경우 이 병합 방법은 공통 조상 노드 이후 두 분기의 서로 다른 노드에서 시작하여 충돌이 발생하면 재귀적으로 호출되어 병합됩니다. 파일 병합은 더 이상 계속되지 않으며 충돌이 직접 발생합니다. 충돌이 없는 다른 파일은 최상위 노드까지 실행됩니다. 또한 이 접근 방식은 파일 이름 수정과 관련된 작업을 감지하고 처리할 수 있습니다. 이는 git 병합 및 코드 가져오기에 대한 기본 병합 작업입니다.
재귀 병합 전략에는 다음 매개변수가 있습니다: 🎜

4.2.1 ours🎜🎜이 매개변수는 충돌이 발생할 때 현재 분기의 버전이 자동으로 사용되도록 합니다. 이 병합 방법은 문제를 일으키지 않으며 git도 다른 브랜치 버전에 포함된 충돌 내용을 확인하지 않습니다. 이 방법은 다른 브랜치의 충돌 내용을 삭제합니다. 🎜

4.2.2 theirs🎜🎜는 우리와 정확히 반대입니다.
해당 매개변수와 우리 매개변수는 모두 바이너리 파일 충돌을 병합하는 데 적합합니다. 🎜

4.2.2 인내🎜🎜이 매개변수를 사용하면 git merge-recursive는 중요하지 않은 줄(예: 함수의 괄호)이 누락되는 것을 방지하기 위해 추가 시간을 소비합니다. 현재 브랜치와 다른 브랜치의 버전 브랜치 간 간격이 매우 큰 경우 이 병합 방법을 사용하는 것이 좋습니다. 🎜

4.2.3diff-algorithm=[patience|minimal|histogram|myers]🎜🎜는 git merge-recursive에 다른 비교 알고리즘을 사용하라고 지시합니다. 🎜

4.2.4 space-change 무시, all-space 무시, ignore-space-at-eol🎜🎜에 따라 공백 충돌을 처리하기 위한 매개변수를 지정합니다. 🎜
  • 상대방 버전이 공백에만 변경 사항을 추가하는 경우 충돌 병합 중에 우리 버전이 사용됩니다.
  • 우리 버전에는 공백이 포함되어 있지만 상대방 버전에는 많은 변경 사항이 포함되어 있으면 상대방 버전이 병합됩니다. 충돌 병합 중에 사용됩니다
  • 일반 처리 사용

4.2.5 이름 바꾸기 없음no-renames

关闭重命名检测。

4.2.6subtree[=<path>]

이름 바꾸기 감지를 끄세요.

4.2.6subtree[=<path>]

이 옵션은 하위 트리 병합 전략의 고급 형태로, 병합 프로세스 중에 두 노드 트리가 어떻게 이동하는지 추측합니다. 차이점은 지정된 경로가 병합 시작 시 제거되므로 하위 트리를 찾을 때 다른 경로가 일치될 수 있다는 것입니다. (하위 트리 병합 전략에 대한 자세한 내용은 아래를 참조하세요.)

4.3octopus

이 병합 방법은 두 개 이상의 분기에 사용되지만 충돌로 인해 수동 병합이 필요한 경우 병합을 거부합니다. 이 병합 방법은 여러 분기를 함께 묶는 데 더 적합하며 다중 분기 병합을 위한 기본 병합 전략이기도 합니다.

4.4ours

이 방법은 원하는 개수의 분기를 병합할 수 있지만 노드 트리의 병합 결과는 항상 현재 분기의 충돌하는 부분입니다. 이 방법은 이전 버전을 교체할 때 매우 효율적일 수 있습니다. 이 방법은 재귀 전략의 ours 매개변수와 다르다는 점에 유의하세요.

4.5subtree

subtree는 재귀 전략의 수정된 버전입니다. 트리 A와 트리 B를 병합할 때 B가 A의 하위 트리인 경우 B는 동일한 노드를 읽는 대신 먼저 A의 트리 구조와 일치하도록 조정합니다.

4.5 요약3방향 병합 전략(기본 재귀 전략 참조)을 사용할 때 현재 브랜치와 다른 브랜치 모두에서 파일(또는 코드 줄)이 변경되었다가 나중에 하나에서 롤백되는 경우 그러면 이 대체 변경 사항이 결과에 반영됩니다

. 이 점은 일부 사람들을 혼란스럽게 할 수 있습니다. 이는 병합 프로세스 중에 git이 두 분기의 모든 노드가 아닌 두 분기의 공통 조상 노드와 HEAD 노드에만 초점을 맞추기 때문입니다. 따라서 병합 알고리즘은 롤백된 부분을

변경되지 않은 부분

으로 간주하여 병합된 결과가 다른 브랜치의 변경된 부분이 됩니다.


5. Git 사용에 대한 개인적인 의견

    나는 항상 Git이 매우 뛰어난 버전 관리 도구라고 믿어왔지만, 회사에서는 Git을 사용하기 어렵다고 생각하는 사람들이 많습니다. 이러한 상황이 발생하는 가장 큰 이유는 이전의 Subversion 사용으로 인한 관성이 새로운 기술을 수용하는 데 영향을 미치는 반면, 많은 사람들은 GUI 클라이언트를 통해서만 Git을 사용하기 때문입니다. 오랫동안 대부분의 사람들은 GUI를 사용하는 것이 시작하는 데 더 편리한 방법이라고 생각했습니다. 실제로 이것은 의문의 여지가 있습니다. 내 개인적인 경험에 따르면 GUI를 사용하면 관성이 생길 수 있고 버튼 몇 개를 클릭하면 작업이 완료되는 경우가 많아 Git 명령을 배우는 것이 시간과 에너지 낭비라고 생각하는 사람들이 많습니다. 그러나 실제로 Git 명령과 아이디어에 대한 명확한 이해 없이 이러한 간단한 버튼을 사용하면 실제로 많은 문제가 발생합니다. 많은 사람들은 버튼을 클릭한 후 무슨 일이 일어날지 모르고 GUI는 너무 똑똑해서 동일한 버튼을 허용하지 않습니다. 클릭 이벤트는 다양한 매개변수를 가진 명령에 해당할 수 있습니다. 결국, 문제가 무엇인지 전혀 모르기 때문에 큰 상처를 받는 것은 불쌍한 이용자들이다.
  1. 전체 텍스트 내용을 바탕으로 Git을 사용할 때 개인이 따르는 몇 가지 규칙을 요약하면 다음과 같습니다. 이른바 합의란 강제되지 않고 자발적인 행위를 말한다. 이러한 규칙을 준수하지 않아도 문제가 발생하지는 않지만, 이러한 규칙을 준수하면 Git 사용 시 어려움이 완화되고 효율성이 향상될 수 있습니다.
  2. 더 많이 제출하고 덜 푸시하세요. 여러 사람이 협업할 때 푸시로 인해 병합 충돌이 발생하는 경우가 많아 효율성에 영향을 미칩니다. 따라서 가능한 한 커밋 명령을 사용하고 병합 사용을 줄이면 시간이 많이 절약됩니다.
  3. Git Flow(Git Flow)를 사용하세요. 자세한 내용은 내 다른 기사를 참조하세요. 성공적인 Git 분기 모델
  4. 브랜치 사용,
  5. 메인 브랜치를 깔끔하게 유지
  6. . 이는 제가 강력히 권장하는 방법입니다. 브랜치에서 제출한 다음 메인 브랜치로 전환하여 업데이트(git pull —rebase)한 다음 브랜치를 병합하고 푸시하세요. 이러한 프로세스는 교차 병합을 방지합니다(여러 공통 조상 노드가 존재하지 않음). 실제로 많은 사람들이 git merge 작업에 압도감을 ​​느끼는 이유는 다양한 이유로 발생하는 교차 병합 문제로 인해 병합 과정에서 일부 코드가 손실되기 때문입니다. 마스터 브랜치를 깨끗하게 유지하면 교차 병합을 피할 수 있습니다.

빨리감기 모드를 비활성화합니다. 코드를 가져올 때 rebase 매개변수를 사용하고(전제는 기본 브랜치를 깨끗하게 유지하는 것입니다), -no-ff 매개변수를 사용하여 병합 시 빨리 감기 모드를 비활성화합니다. 이렇게 하면 노드의 명확성을 보장할 수 있을 뿐만 아니라 방지할 수도 있습니다. 교차 병합이 나타납니다.
추천 학습: "

Git 학습 튜토리얼🎜"🎜🎜

위 내용은 git-merge 상세 분석(정리 및 공유)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제