Git远程操作与冲突解决全解析
1. 远程仓库同步与拉取操作
在Git中,当我们从远程仓库获取更新后,需要同步本地分支。通过合并操作,我们可以让本地仓库、本地分支以及工作目录中的文件都拥有来自远程的最新更新。例如,在一次合并前后的本地仓库状态变化如下:
origin/master
master
master
master
master
Working Directory
Local Repository
032f120
C1
(master:ecf2390)
883bf34
C2
bed5211
C3
253231d
C4
ecf2390
S5
origin/master
ecf2390
S5
Remote Repository
032f120
C1
883bf34
C2
bed5211
C3
253231d
C4
ecf2390
S5
Working Directory
Local Repository
032f120
C1
(master:253231d)
883bf34
C2
bed5211
C3
253231d
C4
Remote Repository
032f120
C1
883bf34
C2
bed5211
C3
253231d
C4
ecf2390
S5
可以看到,合并后 master 分支快速推进到与远程跟踪分支相同的提交。
而 git pull 命令本质上是 fetch 和 merge 的组合。其语法为:
git pull [options] [<repository> [<refspec>...]]
下面是一些常用的 pull 命令选项:
- 与合并相关的选项
- no-commit :执行合并但不提交结果,便于在提交前检查合并结果。
- no-edit :告诉Git在提交前不调用编辑器,直接接受自动生成的提交消息。
- rebase :有多个可能的设置
- =true :获取更新后,将当前分支变基到上游分支之上。
- =false :将当前分支合并到上游分支。
- =preserve :使用 --preserve-merges 选项进行变基,强制Git在变基过程中保留作为历史一部分的合并提交。
- =interactive :启动变基的交互模式。
- strategy :指定合并策略(简称 -s ),可多次指定,指示Git尝试使用每个策略的顺序。
- strategy-option :为所选的合并策略提供特定选项(简称 -X )。
- 与获取相关的选项
- depth :类似于克隆时的 depth 选项,进行浅拉取,将历史截断到指定的提交数量。例如 --depth=1 只拉取最新的一次提交。
- force :当尝试从远程仓库的分支拉取到本地仓库的分支,且Git无法进行快速合并时,默认会拒绝更新。但可以使用 --force (-f) 选项强制更新。不过,使用前需了解后果并确保自己确实需要这样做。示例如下:
$ git pull origin features:docs
From https://github.com/brentlaster/calc2
! [rejected] features -> docs (non-fast-forward)
$ git pull -f origin features:docs
From https://github.com/brentlaster/calc2
+ abaf124...b372aa6 features -> docs (forced update)
也可以在分支前加 + 号来强制更新:
$ git pull origin +features:docs
From https://github.com/brentlaster/calc2
+ abaf124...b372aa6 features -> docs (forced update)
2. 设置GitHub账户与克隆仓库
为了更好地实践远程操作,我们可以设置一个GitHub账户并克隆仓库。具体步骤如下:
1. 访问 https://github.com 。
2. 填写用户名、邮箱地址和创建密码字段。
3. 点击“Sign up for GitHub”按钮。
4. 接受下一页的默认设置,然后点击“Continue”按钮。
5. (可选)填写下一页的兴趣部分,或点击“skip this step”链接。
6. 按照说明验证邮箱地址,然后点击“Start a project”按钮。
7. 访问 https://github.com/professional-git/calc2 项目。
8. 点击右上角的“Fork”按钮,将仓库复刻到自己的用户ID下(URL会变为 https://github.com/<github userid>/calc2 )。
9. 在本地机器上打开一个可以运行Git的终端会话,并切换到主目录(或至少离开任何包含Git仓库的目录):
$ cd ~
- 在
calc2项目网页的右侧,点击“Clone or download”按钮,弹出的窗口中会显示使用HTTPS协议克隆项目的URL路径。点击该URL右侧的剪贴板图标,将路径复制到剪贴板。 - 切换回终端会话,输入
git clone并粘贴剪贴板中的路径,然后按回车键:
$ git clone https://github.com/<your github user id>/calc2.git
之后会看到远程的一些消息,项目将被克隆到 calc2 目录中。
12. 创建另一个克隆副本,模拟另一个人在同一仓库中工作。使用不同的目标目录名执行克隆命令:
$ git clone https://github.com/<your github user id>/calc2.git calc_other
- 可以浏览
calc2和calc_other目录。每个目录可能只包含一个文件,但查看隐藏文件可以看到从远程克隆下来的.git仓库。还可以运行以下命令查看每个克隆仓库中的分支列表和最新更改信息(需先切换到相应的仓库目录):
$ git branch -r
$ git branch -av
- 为了能够拉取原始GitHub仓库的更新,需要在每个目录(
calc2和calc_other)中添加另一个远程仓库:
$ git remote add upstream https://github.com/professional-git/calc2.git
- 运行以下命令查看每个仓库中的远程仓库列表:
$ git remote -v
下面是创建GitHub仓库并克隆的流程图:
graph LR
A[访问https://github.com] --> B[填写注册信息]
B --> C[点击Sign up for GitHub]
C --> D[接受默认设置并点击Continue]
D --> E{是否填写兴趣部分}
E -- 是 --> F[填写兴趣部分]
E -- 否 --> G[点击skip this step]
F --> H[验证邮箱地址并点击Start a project]
G --> H
H --> I[访问https://github.com/professional-git/calc2]
I --> J[点击Fork按钮]
J --> K[打开终端并切换到主目录]
K --> L[复制克隆URL到剪贴板]
L --> M[在终端执行git clone命令]
M --> N[创建另一个克隆副本]
N --> O[浏览目录并运行分支相关命令]
O --> P[添加远程仓库]
P --> Q[查看远程仓库列表]
3. Git中的冲突与合并解决工作流
在多人协作使用Git时,冲突与合并解决是常见的问题。下面详细介绍相关工作流程。
3.1 远程仓库如何处理冲突
远程仓库期望从本地推送的内容已经包含了目标分支的所有当前内容,以便进行快速合并,即不需要在远程进行实际的合并操作。但当多人在同一仓库工作时,可能会出现无法快速合并的情况。例如,当其他人已经将更新推送到远程仓库,而你尚未拉取并合并这些更新到自己的待推送更改中时,Git就无法进行快速合并,此时远程仓库会标记冲突并拒绝你的推送,要求你在本地环境解决冲突后再尝试推送。
常见的拒绝推送错误信息如下:
$ git push
To C:/Program Files/Git/./calc2.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'C:/Program Files/Git/./calc2.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
3.2 冲突范围
与其他源管理系统通常以文件为粒度记录更改不同,Git以提交(或快照)为单位记录整个文件树和目录的更改。因此,只要在你开始更改后,其他人在提交范围内对任何文件进行了更改,当你尝试将更改推送到远程仓库时,就会出现合并冲突,即使你和其他人更改的是完全不同的文件或目录。
以下是一个示例,假设两个用户克隆了同一个远程仓库:
User 1
Remote Repository
Clone
Server
Local Repository
Staging Area
Working Directory
User 2
Local Repository
Staging Area
Working Directory
A2
B1
A2
B1
C2
A2
B1
C2
A2
B1
C2
A2
B1
C2
Clone
C2
用户1修改了文件 A2 和 C2 ,并将更改推送到远程仓库:
User 1
Remote Repository
Push
Server
Local Repository
Staging Area
Working Directory
User 2
Local Repository
Staging Area
Working Directory
A2
B1
A2
B1
C2
A2
B1
C2
A2
B1
C2
A2
B1
C2
C2
而用户2只修改了文件 B1 ,当用户2尝试推送更改时,Git会拒绝推送:
$ git push
To C:/Program Files/Git/./calc2.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'C:/Program Files/Git/./calc2.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
3.3 解决冲突
当遇到冲突时,可以通过获取最新更改并在本地进行合并来解决。可以使用 fetch 和 merge 操作,也可以直接使用 pull 操作。
需要注意的是,虽然可以使用 --force (-f) 选项或在推送分支前加 + 号来强制进行非快速合并,但这种方法不推荐使用,因为可能会导致其他更改被覆盖。而且,要允许这种操作,Git配置中的 receive.denyNonFastForwards 值必须设置为 false ,通常建议将其设置为 true 以防止非快速推送。
下面通过一个具体示例说明解决冲突的过程。假设有两个用户对一个应用程序的说明文件进行更改:
用户1的操作:
$ echo "Chapter 1" >> instructions.txt
$ git commit -am "Add chapter 1 heading"
[master 6d30ad0] Add chapter 1 heading
1 file changed, 1 insertion(+)
$ echo "Welcome" >> instructions.txt
$ git commit -am "Add chapter 1 title"
[master ae619aa] Add chapter 1 title
1 file changed, 1 insertion(+)
$ git push
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 546 bytes | 0 bytes/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To C:/Program Files/Git/./calc2.git
b7f554d..ae619aa master -> master
用户2的操作:
$ echo "Chapter 2" >> instructions.txt
$ git commit -am "Add chapter 2 heading"
[master 5446cab] Add chapter 2 heading
1 file changed, 1 insertion(+)
$ echo "Next steps" >> instructions.txt
$ git commit -am "Add chapter 2 title"
[master c6495d9] Add chapter 2 title
1 file changed, 1 insertion(+)
$ git push
To C:/Program Files/Git/./calc2.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'C:/Program Files/Git/./calc2.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
用户2被拒绝推送后,可以选择使用默认的 git pull 合并行为或 git pull --rebase 选项进行变基。
- 仅使用
pull
$ git pull
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From C:/Program Files/Git/./calc2
b7f554d..ae619aa master -> origin/master
Auto-merging instructions.txt
CONFLICT (content): Merge conflict in instructions.txt
Automatic merge failed; fix conflicts and then commit the result.
解决冲突后:
$ cat instructions.txt
User Instructions
Chapter 1
Welcome
Chapter 2
Next steps
$ git add .
$ git commit -am "Merged chapter 2 content"
[master 934258f] Added chapter 2 content
- 使用
pull --rebase
$ git pull --rebase
From C:/Program Files/Git/./calc2
+ 934258f...ae619aa master -> origin/master (forced update)
First, rewinding head to replay your work on top of it...
Applying: Add chapter 2 heading
Using index info to reconstruct a base tree...
M instructions.txt
Falling back to patching base and 3-way merge...
Auto-merging instructions.txt
CONFLICT (content): Merge conflict in instructions.txt
error: Failed to merge in the changes.
Patch failed at 0001 Add chapter 2 heading
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
解决冲突后继续变基:
$ git add .
$ git rebase --continue
Applying: Add chapter 2 heading
Applying: Add chapter 2 title
Using index info to reconstruct a base tree...
M instructions.txt
Falling back to patching base and 3-way merge...
Auto-merging instructions.txt
CONFLICT (content): Merge conflict in instructions.txt
error: Failed to merge in the changes.
Patch failed at 0002 Add chapter 2 title
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
再次解决冲突并完成变基:
$ git add .
$ git rebase --continue
Applying: Add chapter 2 title
完成合并或变基后,本地环境中的更改已经包含了远程仓库的最新更新,此时可以再次尝试将更改推送到远程仓库:
User 1
Remote Repository
Push
Server
Local Repository
Staging Area
Working Directory
User 2
Local Repository
Staging Area
Working Directory
A2
B1
C2
A2
B1
C2
A2
B1
C2
A2
B1
C2
A2
B1
C2
下面是冲突解决流程的表格总结:
|步骤|仅使用 pull |使用 pull --rebase |
| ---- | ---- | ---- |
|1|执行 git pull ,出现合并冲突|执行 git pull --rebase ,出现合并冲突|
|2|手动解决冲突|手动解决冲突|
|3| git add . 并 git commit | git add . 并 git rebase --continue ,可能多次解决冲突|
|4|再次推送更改|再次推送更改|
冲突解决流程的mermaid流程图如下:
graph LR
A[推送更改被拒绝] --> B{选择解决方式}
B -- 仅使用pull --> C[git pull]
B -- 使用pull --rebase --> D[git pull --rebase]
C --> E[出现合并冲突]
D --> F[出现合并冲突]
E --> G[手动解决冲突]
F --> H[手动解决冲突]
G --> I[git add . 并git commit]
H --> J[git add . 并git rebase --continue]
J --> K{是否还有冲突}
K -- 是 --> H
K -- 否 --> L[再次推送更改]
I --> L
综上所述,在多人协作使用Git时,了解远程操作、冲突范围和解决方法是非常重要的。通过合理使用 pull 命令的选项,可以更高效地处理冲突,保持代码库的一致性。
超级会员免费看
76

被折叠的 条评论
为什么被折叠?



