Git指南
这里所列举的通用配置无论是在Windows还是Linux,都要用到。
一定一定要设置好nginx或者apache的权限,保护好.git目录,防止被黑客获取到,因为这个目录下的文件包含了所有的文件内容,例如:
1
2
3
4
5
6import zlib
import requests
url = "https://domain/.git/objects/9d/6d1ae673f15900b8efd9ad875364b3a651cc0e"
re = requests.get(url)
content = zlib.decompress(re.content) # 这就是文件内容
安装与配置
安装Git软件
Windows平台:Git for Windows(在安装的时候注意那些选项的设置)
Linux平台:sudo apt-get install git
基础配置
打开终端,在windows平台就用上一步安装上的git bash
1 | 全局配置,这里的用户名和邮箱填写你自己的帐号,可以是github上的帐号信息 |
Git相关文件
.gitkeep: 这个文件当前所在的空目录可以加入到版本控制里面去
Github的使用
打开公钥文件,然后复制其中的内容到Github上的setting->SSH keys->Add SSH key,如下
点击Add Key后会要求输入github密码,因为这是特别敏感的操作
然后进行新建仓库,无论是github还是其他托管网站都可以新建远程库,新建完成后都会提示你下一步该怎么做
按照上图给出 操作指南,有三种方法分别是
- 在本地建立一个新库,并新建一个README.md到远程库
- 直接将本地库的代码推送到远程库,不过在本地需要将文件夹编程一个库
- 从别的库导入代码到该库
具体的命令在途中均有给出
常用操作
日志/历史/版本
1 | GIT_CURL_VERBOSE=1 GIT_TRACE=1 git ... # 相当于debug,能看到git命令执行期间的状态 |
代码更改
1 | git blame filename # 查看某文件的改动历史 |
分支操作
分支命名规范:
- 功能(feature)分支:
feature-*
- 预发布(release)分支:
release-版本号
- 修补bug(fixbug)分支:
fixbug-*
1 | git clone ... branchName # 直接拉取指定分支的代码 |
变基(rebase)
- 简单地说就是将多个
commit
合并为一个commit
,以使提交历史变得干净整洁。 - 最好不要修改已经
push
过的提交进行修改,如果一定要修改,需要使用git push -f origin 分支名
进行推送以覆盖历史提交,对于还没合并进主分支的提交,其实也还可以,但是一定要慎重。 - 需要注意的是变基后提交的
hash
会改变 - 可以使用
git filter-branch --treefilter 'rm -f password.txt' HEAD
命令对整个版本历史中的每次提交进行修改,可以以此来删除误提交的敏感信息 git rebase --abort
可以终止rebase
例如,我在本地新建了一个文件,并且先后对文件进行了三次修改操作,但是我想将更新操作合并。通过git log --oneline
查看本地的提交历史如下:
1 | 4721d5f update readme file |
为了防止合并多次或者多个冲突,在rebase
之前最好先git fetch origin master
将远程分支的提交log拉取下来。
接下来,我就使用rebase
命令编辑提交历史: git rebase -i [startpoint] [endpoint]
,其中-i
参数表示交互式界面,后面两个参数表示指定一个编辑区间,如果不提供,那么startpoint
默认为当前已经提交到远程仓库的最后一次提交,endpoint
为当前为提交到远程仓库的最后一次提交,是一个左开右闭区间。我这里直接执行git rebase -i 7c040d1
(一般情况下只需要git rebase origin/master
即可)表示只合并最后三个提交。会弹出下面这个交互式页面:
1 | pick 31cf944 update readme file |
其中开头几行为几次提交的信息,下面的则是操作说明。我现在直接将上面的提交信息修改为
1 | pick 31cf944 update readme file |
然后:wq
保存即可。现在查看提交历史就变成了这样
1 | 2783433 update readme file |
标签
1 | git tag # 查看当前所有的标签 |
其他功能
1 | 统计代码行数 |
钩子/hook
- 不仅仅
Github
有webhook
钩子,git
本身也是有钩子的 - 所有的
git hooks
都在.git/hooks
目录下,并且所有钩子类型都在该文件有提供示例脚本文件,可以直接根据脚本文件进行修改,例如,可以这样设置钩子 - 常常可以在这里做代码检查
- 常用钩子包括:
pre-commit
提交前、prepare-commit-msg
准备提交信息、commit-msg
提交日志、post-commit
提交后,post-checkout
切换后、pre-rebase
Rebase前 git commit --no-verify
: 忽略hook
禁止本地提交到master/develop分支
1 | .git/hooks/pre-commit |
禁止提交包含非ASCII的文件
1 | .git/hooks/pre-commit |
贡献PR(Fork别人的项目)
如果希望给开源项目贡献代码或者直接修复bug,那么就需要涉及到fork了并提交了。步骤如下:
fork别人的仓库到自己这里: 直接在github里面点击fork,即可在自己的代码仓库里面创建一个一模一样的仓库。
从自己的代码仓库clone下来,并开发。
开发完成后,commit到自己的代码仓库
在自己的项目创建Pull Request,指向到原开源项目中去。
记得添加commit说明。
多人协作
参考文章:廖雪峰的官方网站
前提:已经在Github上创建了库并创建了一个新的分支,假设新分支名为dev,那么开发步骤如下:
抓取远程分支到本地
1
2
3
4
5git clone git@github.com:haoflynet/test.git
git branch # 查看当前分支
git checkout -b dev origin/dev # 将本地的dev分支对应远程的origin/dev分支并切换到该分支
git clone -b mybranch --single-branch git://sub.domain.com/repo.git # 直接拉取指定分支到本地在该分支下进行开发
修改完成后推送到远程dev分支
1
2
3git add .
git commit -m "some modification"
git push origin dev修改并合并到master分支
1
2
3git checkout master # 首先切换到本地的master分支
git merge --no-ff # 将本地的dev分支与本地的master分支合并
git pull # 获取远程索引这一步可能这一步可能会冲突,原因当然是其他人在你之前对远程的master分支进行了修改并提交上去
如果没有错,就直接推送git push origin master
TroubleShooting
git checkout -b dev origin/dev出现错误fatal: cannot update paths and switch to branch ‘origin/dev’
原因是未在远程创建dev分支,或者未在本地更新分支信息git remote add origin git@gitb.com:haoflynet/test,出现错误fatal: remote origin already exists
原因是克隆别人的库下来修改后push到自己的库可能会出现这种错误,要先执行git remote rm origin.gitignore无效,该忽略的依然没有被忽略
1
2
3
4
5
6
7
8
9git rm -r --cached . # 这条命令处理不了文件夹,如果是文件夹,需要把最后的点修改为文件夹的路径
git add .
git commit -m "fixed untracked files"
如果只想删除指定的文件或者目录,就这样做
git rm -r --cached node_modules
rm -rf node_modules
git add .
git commit -m "fixed untracked files"这样会删除github上面已经提交了的但是现在忽略了的文件,如果要在github上面保留一份,那么执行
git add -f filename
There was a problem with the editor ‘vi’
vi编辑器的问题吧,直接换成vimgit config --global core.editor $(which vim)
更改文件名后,远程居然没有过更新
git默认对文件名的大小写不敏感,需要在仓库执行git config core.ignorecase false
让它对大小写敏感413 request entity too large
发生这个问题是因为采用的是https而不是ssh方式来push仓库,而https传输数据的大小一般是由服务器,即nginx来控制的,太大了是传不上去的,这时候只需要更改为ssh方式即可。
修改提交作者和邮箱: git可以通过
git filter-branch
修改已经提交了的commit的作者和邮箱。- 如果仅仅想修改最近一次的,可以直接
git commit --amend --author="haoflynet <haoflynet@gmail.com>"
- 如果像修改最近几次的,可以使用
git base -i HEAD~5
(其中5表示最近的5次),然后将要更改的提交的pick
修改e
,保存后,执行git commit --amend --author="haoflynet <haoflynet@gmail.com>"
,然后一个后就执行git rebase --continue
,如果还有需要继续执行git commit --...
这条命令,最后知道continue
命令返回Successfully rebased and updated...
为止,就可以git push -f
了 - 如果像修改所有历史的,这里有一个来自若有所思-胡磊的批量修改的脚本,完成后可以check一下,然后
git push -f
即可,亲测可用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25!/bin/sh
git filter-branch --env-filter '
an="$GIT_AUTHOR_NAME"
am="$GIT_AUTHOR_EMAIL"
cn="$GIT_COMMITTER_NAME"
cm="$GIT_COMMITTER_EMAIL"
if [ "$GIT_COMMITTER_EMAIL" = "[Your Old Email]" ]
then
cn="[Your New Author Name]"
cm="[Your New Email]"
fi
if [ "$GIT_AUTHOR_EMAIL" = "[Your Old Email]" ]
then
an="[Your New Author Name]"
am="[Your New Email]"
fi
export GIT_AUTHOR_NAME="$an"
export GIT_AUTHOR_EMAIL="$am"
export GIT_COMMITTER_NAME="$cn"
export GIT_COMMITTER_EMAIL="$cm"
'- 如果仅仅想修改最近一次的,可以直接
error: you need to resolve your current index first: 通常是因为合并冲突所致,可以简单地使用
git reset --merge
进行恢复在目录外面执行git参数,不进入目录提交git:
1
git --git-dir=~/foo/.git --work-tree=~/foo push
误删分支及恢复方法: 项目很久以后才发现以前某个被删除的分支还没合并到主分支,看不到修改了哪些地方了。
- 先用
git log -g
找到之前在该分支上面的commit
记录(所以必须要有经常commit
的习惯,可以不push
但是要commit
) - 从该commit处新建分支
git branch 新分支名 commit的hash值
- 切换到新分支
git checkout 新分支名
- 先用
两个人用同一个账号登录同一台服务器居然有一个人有git权限,另一个却没有: 这是因为虽然是同一个用户登录的服务器,但是所带的key确实不一样的,可以使用
ssh-add -l
查看你登录的ssh key
,看是否有权限。warning: refname ‘remotes/origin/dev’ is ambiguous. fatal: 歧义的对象名: ‘remotes/origin/dev’: 原因是错误的新建了一个和远程分支同名的分支,在新建分支的时候一定要
-b
让本地分支与远程分支相对应,遇到这种情况,只需要先删除本地分支即可git branch -d 分支名
提交时出现
fatal: Unable to create '.git/index.lock': File exists.
: 原因是检测到有其他的Git在同时操作该本地仓库,如果确认没有其他的,那么直接删除它即可rm -rf .git/index.lock
The project you were looking for could not be found: 切换用户试试
git revert后如何将分支再次合并进去: 有时候我们在发现合并错分支后执行了
git revert
进行分支回滚,但是之后再次上线时发现应该合并的代码合并不了了。例如有三个分支prod、master和dev,在dev分支上修改了代码,分别合并到了prod和master,但是prod执行了git revert进行了回滚,之后再想把master合并到prod发现该次的修改消失了,这时候可以再prod上执行git revert,但是revert后的分支合并到mster,而不是prod,这样master之后就能将这次的提交重新合并到prod了github后台添加ssh key但是错误提示: Key is already in use: 原因是github限制一个key只能在一个账户里面设置,该key已经在其它用户的账户设置里面了,可以用命令
ssh -T -ai ~/.ssh/id_rsa git@github.com
查看到底是谁已经在使用该key了,返回值类似这样:1
Hi haoflynet! You've successfully authenticated, but GitHub does not provide shell acess.
其中,Hi后面的即是占用该key的用户名,如果响应类似于 “username/repo”,则表示密钥已作为部署密钥附加到仓库。
系统中存在多个key,给git指定使用哪一个key:
解决方法一,最简单的方法,在
~/.ssh/config
中添加这样的配置:1
2
3
4
5
6
7
8注意如果有定义Host *,不要在Host *区块下定义IdentityFile ~/.ssh/xxx
host my-repo
HostName github.com
IdentifyFile /Users/hao/.ssh/id_rsa_mygit # 这里最好用权路径
User git
IdentitiesOnly yes # 这一句一定要加,网上很多教程没有加这个
git remote set-url origin my-repo:haoflynet/app.git # 无论是在终端还是sourcetree都适用解决方法二,每次执行命令都使用
GIT_SSH_COMMAND
,例如:1
GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_mygit" git pull
Unable to append to .git/: 可能是因为当前目录存在当前用户无权访问的文件或文件夹,可以使用
ls -al
查看文件夹权限,然后使用chown
改变目录所属用户git rebase后在另外一端进行pull操作每次都会弹出编辑框: 这是因为远端的仓库超前了几个commit,但是那几个commit已经不存在了,需要进行
git reset --hard ID
将分支切换到当前最新的head如果想用账号密码访问,但是git pull的时候提示
Repository not found / does not exist
: 可以将账号密码放到命令里面试试:git clone https://账户:密码@项目地址.git
仓库可以pull,但是push的时候提示
Repository not found
: 原因可能是仓库所有者设置了不同的读写权限,可以去github上面看看能不能在线编辑文件,如果在线都不能那么应该就真的只有读权限了搜索查找Git中被删除的文件
1
2git log --all --full-history -- **/filename.* # 模糊查找
git checkout <SHA>^ -- <path-to-fil> # checkout下来强制push(git push -f)报错: remote: error: denying non-fast-forward:这是因为远端没有开启
force push
权限,这时候只能去仓库托管方修改权限了,github应该是默认开启的,但是assembla没有使用sourcetree等工具的时候Can’t find node in PATH, trying to find a node binary on your system:
1
2
3
4
5vim ~/.huskyrc,这个文件就是用于加载这些环境变量的,注意这是home目录不是项目目录
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
export PATH="/Users/haofly/.nvm/versions/node/v15.3.0/bin:$PATH" # 上面的配置还是不行那直接加到PATH吧Large files detected, … recommended maximum file size of 50 MB: github不允许超过50M的文件上传,只能存储在其他地方,但是已经
commit
倒本地的需要移出来,git rm --cached 文件名 && git commit --amend -CHEAD
修改sourcetree保存的仓库密码: 需要在macos的keychain中进行删除
The unauthenticated git protocol on port 9418 is no longer supported: 将
git://github.com/xxx
修改为https://github.com/xxx
Permission denied (publickey).fatal: Could not read from remote repository.Please make sure you have the correct access rights and the repository exists. 权限问题,首先检查帐号是否真的有权限,然后可以用
GIT_SSH_COMMAND=‘ssh -v’ git clone
命令看下到底用的是哪个key