常见的 Git 协作流程
1. 克隆仓库 (Clone Repository)
每个开发者在开始工作时,都需要将远程仓库的代码克隆到本地:
bash
git clone <repository-url>
这样,开发者就会获得一个完整的代码库副本,并能开始在自己的本地环境中进行开发。
2. 创建和切换分支 (Branching)
在 Git 中,分支是独立开发的基本单位。每个开发者通常会创建一个新的分支来开发新的功能或者修复问题。常见的分支策略包括:
main
或master
:主分支,保持稳定的代码版本。develop
:开发分支,所有的功能开发合并到这里,通常用于集成和测试。- 功能分支:每个开发者针对一个功能、bug 修复或者任务创建一个新的分支,例如
feature/login
或bugfix/authentication-error
。
创建并切换到新分支:
bash
git checkout -b <branch-name>
3. 开发和提交 (Develop and Commit)
在分支上进行开发后,开发者需要定期提交更改:
bash
git add .
git commit -m "Description of changes"
提交时,应该写清晰的提交信息,描述所做的更改。
4. 拉取最新远程更改 (Pull Latest Changes)
在提交之前,开发者应该确保自己的分支是基于最新的远程分支。这意味着在提交之前,应该先拉取最新的更改:
bash
git pull origin <branch-name>
这会将远程分支的更改合并到本地分支,确保不会有冲突。若有冲突,开发者需要手动解决冲突。
git pull origin branch
是git fetch和git merge的组合命令
1.git fetch origin branch
2.git merge origin branch
5. 推送代码到远程仓库 (Push Changes)
完成本地开发并提交后,开发者需要将自己的更改推送到远程仓库:
bash
git push origin <branch-name>
推送前,开发者也应该检查是否有其他人已经推送了新的提交,特别是在多人协作时。
6. 发起合并请求 (Pull Request / Merge Request)
一旦开发者完成了某个功能,通常会发起一个合并请求(PR/MR),将自己的分支合并到主分支(main
或 develop
)。PR 会在 GitHub、GitLab、Bitbucket 等平台上创建,团队成员可以进行代码审查(code review)和讨论。
在合并请求的过程中,开发者通常会解决任何发现的问题,进行必要的修改,直到代码被审查通过并合并。
7. 合并代码 (Merge or Rebase)
合并请求通过后,代码可以合并到目标分支中。合并的方式可以是 merge
或 rebase
:
- Merge:将功能分支合并到目标分支。保留了完整的历史记录。
- Rebase:将功能分支的提交“移到”目标分支的最新提交之后,通常可以让历史更简洁。
合并或变基操作后,开发者应该删除功能分支。
8. 更新本地代码库 (Sync Local Repository)
在完成工作后,开发者需要更新本地仓库,确保本地分支和远程分支同步:
bash
git checkout main
git pull origin main
这可以保持本地仓库的最新状态。
常见问题与解决方案
1. 合并冲突 (Merge Conflict)
在多人协作时,常会遇到合并冲突。合并冲突发生在两个或更多的开发者对同一文件的相同部分进行了不同的更改。
- 解决方法:
- Git 会标记冲突区域。开发者需要手动编辑文件,决定保留哪一部分的更改。
- 使用
git add
标记冲突已解决。 - 然后执行
git commit
提交解决冲突后的结果。
如果是 rebase
时出现冲突,解决后继续 git rebase --continue
。
2. 代码未同步,推送被拒绝 (Push Rejected Due to Non-Fast-Forward)
当开发者在推送时收到 non-fast-forward
错误,这意味着远程仓库的分支比本地分支要更新(其他人已经推送了新的提交)。
- 解决方法:
- 首先拉取远程分支的最新更改:
git pull origin <branch-name>
。 - 如果有冲突,解决冲突后进行提交。
- 然后再推送本地更改。
- 首先拉取远程分支的最新更改:
另外,如果使用 git pull
的时候出现复杂的合并冲突,可以使用 git pull --rebase
来避免创建额外的合并提交。
3. 推送历史被重写 (Force Push Issues)
使用 git push --force
强制推送历史时,可能会覆盖其他开发者的工作。如果不小心使用 --force
,可能会导致团队成员的提交丢失。
- 解决方法:
- 使用
git push --force-with-lease
代替--force
,它会确保在推送之前检查远程仓库是否有其他人推送了新的更改,避免覆盖他人的提交。 - 严格遵循团队的工作流程,确保不会频繁地重写公共历史。
- 使用
4. 未提交的更改丢失
如果开发者在切换分支之前没有提交工作,Git 会拒绝切换分支,并提醒有未提交的更改。
- 解决方法:
- 使用
git stash
将未提交的更改暂存起来:
bash git stash
- 切换分支后,再恢复暂存的更改:
bash git stash pop
- 使用
5. 频繁需要拉取更新 (Frequent Pulls)
在团队合作中,为了避免与其他开发者的提交产生冲突,频繁拉取远程分支是一个良好的习惯。
- 解决方法:
- 定期使用
git pull
来获取远程仓库的更新。 - 在开发之前先拉取并同步,避免因长时间未同步而出现较大的合并冲突。
- 定期使用
从远程仓库拉取一条分支并创建一个新的本地分支
操作步骤:
- 拉取远程仓库的更新:
在创建新分支之前,最好先确保你的本地仓库与远程仓库保持同步。可以使用git fetch
命令来从远程仓库拉取更新,获取所有的远程分支信息。
bash
git fetch origin
这条命令会拉取远程仓库的所有更新,但并不会自动合并到你的本地分支。
- 从远程分支创建本地分支:
使用git checkout -b
命令从远程分支创建一个新的本地分支,并切换到该分支。例如,如果你想从远程仓库的origin/develop
分支创建一个新的本地分支feature/new-ui
:
bash
git checkout -b feature/new-ui origin/develop
解释:
- origin/develop
:远程仓库的 develop
分支。
- feature/new-ui
:你想创建的新的本地分支名。
这条命令的作用是:
- 从远程 origin
上的 develop
分支创建一个新的本地分支 feature/new-ui
。
- 自动切换到 feature/new-ui
分支。
- 检查本地分支:
使用git branch
命令查看当前的本地分支,确认切换是否成功。
bash
git branch
你应该看到类似以下的输出:
bash
* feature/new-ui
develop
- 推送新分支到远程仓库(如果需要):
如果你在本地创建了新分支并且已经进行了一些提交,且希望将这个新分支推送到远程仓库,可以使用以下命令:
bash
git push -u origin feature/new-ui
解释:
- -u
选项会将 feature/new-ui
分支与远程 origin/feature/new-ui
分支进行关联,方便以后推送和拉取。
- origin
是远程仓库的名称(默认是 origin
)。
- feature/new-ui
是你要推送的本地分支。
总结:
- 使用
git fetch
从远程仓库获取更新。 - 使用
git checkout -b <新分支名> origin/<远程分支>
从远程分支创建一个新的本地分支并切换到该分支。 - 如果需要,将新分支推送到远程仓库,使用
git push -u origin <新分支名>
。
这样你就成功地从远程仓库拉取并创建了一个新的本地分支。
git push有问题
线上仓库:a->d;本地仓库:a->c,失败:因为本地比线上落后一个分支
解决:git pull 可能会产生代码冲突,是否发生冲突取决于d修改和你做的c修改是否改在了同一文件的同一区域
mr时出现冲突
1.更新代码
$ git pull origin branch
2.在本地将 main 合并到 develop,处理冲突后推送到远程的 develop,在 GitLab 中手动点击 Merge
# 本地切到develop分支
$ git checkout develop
# 将main合并到develop(--no-ff 禁止快进式合并)
$ git merge --no-ff main
# 处理冲突文件(IDE中完成)
# 查看变动的文件
$ git status
# 保存并提交
$ git add .
$ git commit -m "解决了冲突"
# 推送到远程
$ git push origin develop
解决完冲突推送到远程的 develop 分支后,回到 GitLab 的 Merge Request 中会发现原来不能点的 Merge 按钮变绿了,手动点击 Merge 按钮整个合并过程就结束了。
删除远程分支
git push origin --delete <branch-name>