我之前的项目都不太涉及到频繁的开发合作,模块和模块之间泾渭分明,所以这方面的git用法掌握不足,还是很有必要记下一些工作中的常用用法。
工作区、暂存区和仓库
工作区是本地实际编辑的项目文件。暂存区是git准备下次提交的区域,可以在source control中staged changes看到,在git add
后加入,仓库是git存储所有提交历史的地方,在git commit
后加入。
文件状态
我之前没有太注意这些,实际上文件右侧会显示不同的字母表示当前的状态,在source control插件这里可以看得很清楚。
- U: untracked,未跟踪的文件不会上传到远程,作为本地的文件,在切换分支时也不会受到影响,但是在merge和rebase的时候需要清理好,工作区必须是干净的才可以merge。
- M: Modified,当前更改的文件,本次修改的文件。
- D: Deleted,删除的文件。
在branch上开发
场景通常是项目在master上进行更新,当要添加新的feature时,先在master代码的基础上新建一个自己的feature的分支,待开发完毕测试没问题,就可以提交merge request,将自己的分支代码合并到主分支(master)上了。
上述是一个非常理想的情况,实际上可能有各种具体的不同情形。
克隆项目
正常克隆项目是没问题,但是如果这个项目有很多branch,直接克隆后再运行git branch
会看到项目的所有branch名称,我觉得不方便我切换branch,如果只想显示master分支或者某个特定的分支,可以这样克隆:
git clone --single-branch --branch <branch-name><repositroy-url>
更新分支代码
首先开发新的feature时,需要保证你的开发是在最新代码上进行修改的,那么需要做的就是更新代码,不推荐直接使用git pull
,因为这样会拉取远程的所有分支,既占内存又不好用。最简单的方法是使用git pull --single-branch
。
- 只拉取指定的分支代码
git pull --single-branch origin <branch-name>
- 如果已经在某个分支上,要拉取该分支上的新代码
git pull --single-branch
有时候感觉single-branch需要打的英文字符太多了,也可以将pull拆开成
git fetch
和git merge
# 只fetch当前分支 git fetch origin <branch-name> # 然后合并 git merge origin/<branch-name>
merge代码
在独立的分支上开发完feature后,可能发现master上的代码已经更新,这时需要merge只能先rebase。
对于untracked的文件,rebase时会报错,所以必须先对untracked的文件做单独的处理,因为对我而言,untracked的文件我是不想上传远程的,但是同时我也不想删除本地,这种情况加上.gitignore就可以了。
git rebase <commit-id>
rebase时可能会产生conflict,这时根据提示解决conflict,同时也要留意一下automatically merge的文件,因为有可能自动合并的内容并不对,只是简单地全部合并,并不是我们想要的做法。 解决好conflict以后只要继续rebase就可以:
git rebase --continue
rebase中途会打开commit的message可以更改,我建议可以在原有commit信息上加上(rebase)就可以。
rebase结束以后在source control处可以看到更改的信息,如果没问题就可以上传,因为rebase会重写之前的commit,会导致conflict,上传时需要强制上传:
git push origin <分支> --force-with-lease
切换分支
在开发过程中需要切换分支,可以使用git stash
保存在当前分支上的修改后再切换分支:
git stash save -m "<explanation>"
git checkout <branch-name>
stash的内容可以用apply
或者pop
覆盖,我比较推荐apply
,因为不会删除历史:
git stash apply stash@{0}
如果想要删除git stash的历史用drop
就可以,如果想一次性删除所有历史可以用git stash clear
。
更新其他分支上的代码
比如目前有两个分支a和分支b,分支a想要应用分支b的部分更新功能,但是不想全部rebase,可以使用cherry-pick
:
git cherry-pick <commit-id>
如果想要应用多个commit的内容可以使用:
git cherry-pick <start-commit-id>...<end-commit-id>
误传大文件
分为以下3种情况:
还没有commit的情况下
在执行git add
后发现不小心把大文件给添加了,但是还没有commit。这个时候还相对比较简单,可以使用以下命令将暂存区的内容删除:
# 新版本git命令
git restore --staged <file-name>
已经commit还没有上传远程
如果大文件已经被commit到本地仓库,但还没有push到远程,可以使用以下方法:
- 首先查看目前的情况
git log
我们可以把状态退回到commit之前的commit,记下这个commit id。
- 回退到上一个commit
# 工作区会保存更改,暂存区不会 git reset --mixed <commit-id>
已经上传远程,不想再上传
只用将文件加入.gitignore后再上传就可以。如果非常严格,因为只加入.gitignore没有改变commit历史,其他人仍然可以通过历史访问到,仓库大小不会变少,那么需要:
# 使用 git filter-branch 从历史中移除
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch <filename>' \
--prune-empty --tag-name-filter cat -- --all
# 清理和强制推送
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push --force-with-lease origin <branch-name>