持续记录使用Git开发过程中常用命令/常见问题等等..
一般来说,日常使用只要记住下图6个命令,就可以了。但是熟练使用,恐怕要记住60~100个命令。
- Workspace:工作区
- Index / Stage:暂存区
- Repository:仓库区(或本地仓库)
- Remote:远程仓库
Git常用命令清单
新建代码库
1 | # 在当前目录新建一个Git代码库 |
配置
Git的设置文件为 .gitconfig
,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)
1 | # 显示当前的Git配置 |
增加/删除文件
1 | # 添加指定文件到暂存区 |
代码提交
1 | # 提交暂存区到仓库区 |
分支
1 | # 列出所有本地分支 |
标签
1 | # 列出所有tag |
查看信息
1 | # 显示有变更的文件 |
远程同步
1 | # 下载远程仓库的所有变动 |
撤销
1 | # 恢复暂存区的指定文件到工作区 |
其他
1 | # 生成一个可供发布的压缩包 |
Git 设置
邮箱和密码
1 | git config --global user.email "code0809@163.com" |
需要注意的是,如果以前全局配置后,再次执行该操作会覆盖原用户名。
如果配置了全局账号,多个 Git 账号的情况下执行 remote、pull、push 的时候会出现问题,因为要 pull 的时候识别的是邮箱,多个 git 账号,必然对应多个邮箱,那自然就不能使用 global 的 user.email 了。
这时候可以为每个 repo 设置自己的 user.email。
1 | # 取消 global |
SSH key
1 | ssh-keygen -t rsa -C "code0809@163.com" |
一直回车,成功的话会在 ~/ 下生成 .ssh 文件夹,进去,打开 id_rsa.pub,复制里面的 key,然后进入 GitHub 的 Account Settings,选择 SSH Keys -> Add SSH Key,粘贴在你电脑上生成的 key。(title 随便填)
验证是否成功:
1 | $ ssh -T git@github.com |
配置多个 Git 远程仓库的 SSH-Key
我机器上的 Git 会在 GitHub、GitCafe、Coding.NET 、以及树莓派上的私有 Git 仓库之间来回切换,所以如果不配置 SSH-Key 光输入密码就得浪费不少时间。
在默认情况下,ssh 总是使用 id_rsa 密钥文件进行链接,即是第一次执行 ssh-keygen 后默认生成的,这样对于多个账号的认证肯定是不行的。
因此,要实现多帐号下的 SSH Key 的切换需要在客户端做一些配置:
1 | cd ~/.ssh # 必须进入这个路径否则生成的密钥路径容易遗忘 |
然后复制 ~/.ssh/ 下面的相应的公钥到你的 Git 远程仓库服务器上即可,这个步骤和 GitHub 上的操作是一样的。
然后在 ~/.ssh/ 下面创建一个 config 文件,填入你刚刚配置的 SSH 密钥信息,内容应类似于如下:
1 | Host github.com |
然后可以测试一下是否配置 OK:
1 | ssh -T git@github.com |
如果没有提示错误就说明 SSH 配置好了。
然后克隆 SSH 协议的 Git 仓库即可,此后便不用每次输入用户名密码了,比如:
1 | git clone git@gitcafe.com:SoulMate94/soulmate94.git |
然后还可以为不同远程 Git 仓库起不同的别名,就算是为同一内容的不同 Git 仓库提交代码,也可以通过别名来区分,比如:
1 | git remote add gitcafe git@gitcafe.com:SoulMate94/soulmate94.git |
这样修改了同一个仓库后就算已经 push 到了一个远程仓库地址,也可以继续 push 到另一个的同一分支或不同分支,其区别就是别名:
1 | git push gitcafe master |
注意
只有克隆 SSH
协议的 Git
仓库才能使 SSH
密钥机制生效,如果克隆的是 HTTPS
协议的则每次依然需要输入用户名和密码。
GIT 分支操作
添加远程仓库地址和推送到远程仓库
1 | git remote add origin git@github.com:SoulMate94/blog.git |
origin
是为远程仓库地址起的别名。-u
只在第一次推送时使用,作用是把本地的 master 分支和远程的 master 分支关联起来,之后的推送不再需要这个参数。
为远程仓库起别名
1 | 移除现有分支别名 |
创建分支
如果 clone 了一个空仓库,那么在执行 git branch master 的时候会报错:
这时候只需添加一些文件 commit 就行了, 比如:
1 | git add README.md |
切换分支
1 | git checkout --orphan gh-pages |
查看分支
1 | git branch -a # 查看远程分支 |
删除分支
1 | git branch -d branch_name # 删除本地分支 |
重命名本地分支
1 | git branch -m devel develop |
Git 移除已经 add 的文件
1 | git reset --hard 需要回退的那次 commit 的哈希值 |
每次 commit 的哈希值可以通过 git log 命令查看
上述命令执行成功之后,会彻底返回到回退到的版本状态,新发生的变更将会丢失。 对于部分发生了变更,但是变更部分的文件夹存在未提交的文件可能导致目录非空而删除失败,此时需要自行处置
完成之后,使用 –force
或 -f
参数强制 push
:
1 | git push origin HEAD --force |
查看远程 Git 仓库
1 | git remote -v |
FAQ
为什么删不了 master 分支?
需要先更改默认分支为非 master 分支。再执行删除操作:
1 | 删除本地分支 |
将 .gitignore.txt 修改为 .gitignore 时提示 “必须键入文件名” 怎么办?
1 | rename .gitignore.txt .gitignore |
Git忽略规则及 .gitignore 规则不生效的解决办法
已知在 git 中如果想忽略掉某个文件,不让这个文件提交到版本库中,可以使用修改根目录中 .gitignore 文件的方法(如无,则需自己手工建立此文件)。
这个文件每一行保存了一个匹配的规则例如:
1 | # 此为注释 – 将被 Git 忽略 |
规则很简单,不做过多解释,但是有时候在项目开发过程中,突然心血来潮想把某些目录或文件加入忽略规则,按照上述方法定义后发现并未生效,原因是 .gitignore只能忽略那些原来没有被track的文件,如果某些文件已经被纳入了版本管理中,则修改 .gitignore
是无效的。那么解决方法就是先把本地缓存删除(改变成未track状态),然后再提交:
1 | git rm -r --cached . |
如果 cache 暂存区的内容和 HEAD 不一致,请使用: git rm rf --cache .
强制删除
Git 停止追踪文件权限
1 | git config core.filemode false |
.gitkeep
有什么用 ?
“.gitkeep” isn’t documented, because it’s not a feature of Git.
Git cannot add a completely empty directory. People who want to track empty directories in Git have created the convention of putting files called “.gitkeep” in these directories. The file could be called anything; Git assigns no special significance to this name.
There is a competing convention of adding a “.gitignore” file to the empty directories to get them tracked, but some people see this as confusing since the goal is to keep the empty directories, not ignore them; “.gitignore” is also used to list files that should be ignored by Git when looking for untracked files.
or you can use like this to except for this one: !.gitignore
.
git fetch repo 和 git fetch repo branch 的区别 ?
git fetch
, 理解 fetch
的含义, 是远程协作的关键,而理解 fetch 的关键, 是理解 FETCH_HEAD。
FETCH_HEAD 指的是: 某个 branch 在服务器上的最新状态。
每一个执行过 fetch 操作的项目,都会存在一个 FETCH_HEAD 列表,这个列表保存在 .git/FETCH_HEAD
文件中, 其中每一行对应于远程服务器的一个分支。
当前分支指向的 FETCH_HEAD, 就是这个文件第一行对应的那个分支。
一般来说, 存在两种情况:
- 如果没有显式的指定远程分支, 则远程分支的 master 将作为默认的 FETCH_HEAD。
- .如果指定了远程分支, 就将这个远程分支作为 FETCH_HEAD。
常见的 git fetch
使用方式包含以下四种:
git fetch
这一步其实是执行了两个关键操作:
1.创建并更新所有远程分支的本地远程分支。
2.设定当前分支的 FETCH_HEAD 为远程服务器的 master 分支 (上面说的第一种情况)。
需要注意的是,和 push 不同, fetch 会自动获取远程 新加入的分支。
git fetch origin
同上, 只不过手动指定了 remote。
- git fetch origin branch1
设定当前分支的 FETCH_HEAD 为远程服务器的 branch1 分支。
注意: 在这种情况下, 不会在本地创建本地远程分支, 这是因为:
这个操作是 git pull origin branch1 的第一步, 而对应的 pull 操作,并不会在本地创建新的 branch。
一个附加效果是:这个命令可以用来测试远程主机的远程分支 branch1 是否存在, 如果存在, 返回0, 如果不存在, 返回128, 抛出一个异常。
- git fetch origin branch1:branch2
只要明白了上面的含义, 这个就很简单了:
1.首先执行上面的 fetch 操作
2.使用远程 branch1 分支在本地创建 branch2 (但不会切换到该分支),如果本地不存在branch2分支, 则会自动创建一个新的 branch2 分支。
如果本地存在 branch2 分支, 并且是 fast forward,则自动合并两个分支, 否则, 会阻止以上操作.
- git fetch origin :branch2
等价于: git fetch origin master:branch2。
- git pull
只要理解了 git fetch, git pull就太简单了。
git pull 等价于以下两步:
1.经命令中的pull换成fetch, 执行之。
2.git merge FETCH_HEAD
唯一需要提及的一点是:
我认为 pull 操作, 不应该涉及三方合并 或 衍合 操作。
换个说法: pull 应该总是 fast forward 的. 为了达到这样一个效果, 在真正 push 操作之前, 我倾向于使用衍合, 在本地对代码执行合并操作。
关于 git 不区分文件名大小写的处理
处理办法:
windows 下在 git 中修改文件的大小写
1 | git mv --force myfile MyFile |
然后 commit 就好了。当然也可以配置一下 git:
1 | Add ignorecase = false to [core] in .git/config; |
其他
- 创建版本号为 1 的 master 分支
1 | git push sina master:1 |
- 删除 master 分支上版本号为 1 的 代码
1 | git push sina :1 |
有空格则为删除版本,无空格则为新建版本。
1 | git push origin :branch |
表示将一个内容为空的同名分支推送到远程的分支,说白了, 即删除远程主机的 branch 分支, 但是这并不会消除之前的 comment 内容, 而且你一旦提交了一些大的文件(例如: 图片之类的), 通过这个操作, 是不会将这些文件占用的空间消除的. 如果要真正的删除一个文件, 除了删除整个项目, Github网站也有提供办法。