Introduction
Git 的三种状态
Git 有三种状态,你的文件可能处于其中之一:已提交(committed)、已修改(modified)和已暂存(staged)。
已提交:表示数据已经安全的保存在本地数据库中。
已修改:表示修改了文件,但还没保存到数据库中。
已暂存:表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
由此引入 Git 项目的三个工作区域的概念:Git 仓库、工作目录以及暂存区域。
Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。 这是 Git 中最重要的部分,从其它计算机克隆仓库时,拷贝的就是这里的数据。
工作目录是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。
暂存区域是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。 有时候也被称作`‘索引’’,不过一般说法还是叫暂存区域。
基本的 Git 工作流程如下:
1 在工作目录中修改文件。
2 暂存文件,将文件的快照放入暂存区域。
3 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录
记录每次更新到仓库
工作目录中除已跟踪文件以外的所有其它文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有放入暂存区。 初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态。
编辑过某些文件之后,由于自上次提交后你对它们做了修改,Git 将它们标记为已修改文件。 我们逐步将这些修改过的文件放入暂存区,然后提交所有暂存了的修改,如此反复。所以使用 Git 时文件的生命周期如下:
Github 的使用
本地SSH Keys的设置
我们需要通过SSH来让本地编辑的内容托管到Github,所以要对先SSH进行设置。
首先检查电脑上现有的SSH Keys,在Terminal输入
1 | $ cd ~/.ssh |
输入 ls
查看是否有ssh keys。
1 | $ ls |
如果只显示一个 known_hosts
,说明没有ssh keys,可以跳过这一步,否则需要备份和移除原来的SSH Keys
1 | (显示 id_rsa id_rsa.pub known_hosts) |
输入以下代码形成新的SSH Key文件,我们只需要默认设置就好,所以当需要输入文件名的时候,回车就好。
1 | $ ssh-keygen -t rsa -C “your-email” |
上面代码中的 “your-email” 就是你在学习Git时,你自己设置的Git用户名时给出的email地址 ( 我的话,使用的是注册github的email )。
然后系统会要你输入加密串(Passphrase):
1 | Enter passphrase (empty for no passphrase):<输入加密串> |
最后看到SSH Key success,就成功设置SSH Key了。
添加SSH Key到GitHub
在本机设置SSH Key之后,需要添加到 GitHub 上,以完成SSH链接的设置。输入下面代码打开SSH文件夹
1 | $ open ~/.ssh |
用文本编辑工具打开 id_rsa.pub 文件。
登录Github,点击右侧自己的头像,选择 “setting” 。选择右侧的 “SSH and GPG Keys” 项,把 id_rsa.pub 文件中的内容复制到如下位置,然后点击 Add Key 按钮即可。
输入下面的命令,看看设置是否成功,`git@github.com` 的部分不要修改:
1 | $ ssh -T git@github.com |
如果是下面的反应:
1 | The authenticity of host 'github.com (207.97.227.239)' can't be established. |
不要紧张,输入yes就好,然后会看到:
1 | Hi <em>username</em>! You've successfully authenticated, but GitHub does not provide shell access. |
设置你的账号信息
现在你已经可以通过SSH链接到GitHub了,还有一些个人信息需要完善的。
Git会根据用户的名字和邮箱来记录提交。GitHub也是用这些信息来做权限的处理,输入下面的代码进行个人信息的设置,把名称和邮箱替换成你自己的,名字必须是你的真名,而不是GitHub的昵称。
1 | $ git config --global user.name "你的名字" |
好了,你已经可以成功连接GitHub了。
新建仓库
在自己的账号下,新建一个repository(仓库)。创建成功后,可根据一下界面操作。
创建版本库
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来, 每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以”还原”。具体步骤已经完整在上图中展示,下面具体说明。
第一步:首先,选择一个合适的地方,创建一个空目录:
1 | $ mkdir yourRepo |
第二步:通过git init命令把这个目录变成Git可以管理的仓库
1 | $ git init |
在./yourRepo
目录下 新建一个README.txt文件,内容为”hello github”
第三步:用命令git add告诉Git,把文件添加到仓库:
$ git add README.txt
第四步:用命令git commit 把文件提交到仓库:
$ git commit -m "hello github"
第五步:输入远程地址
$ git remote add origin git@github.com:yourName/yourRepo.git
或者
$ git remote add origin https://github.com/yourName/yourRepo.git
如果显示 fatal: remote origin already exists
,使用如下命令:
1 | $ git remote rm origin |
第六步:上传到github
如果该仓库是第一次进行push,输入
$ git push -u origin master
如果已经传输过,此处只是更新,只需输入:
$ git push
提交成功后就可以进入github查看自己的项目了。
git push
命令会将本地仓库推送到远程服务器。git pull
命令则相反。
注:首次提交,先git pull
下,修改完代码后,使用git status
可以查看文件的差别。
忽略文件
一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。 通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式。 来看一个实际的例子:
1 | $ cat .gitignore |
第一行告诉 Git 忽略所有以 .o
或 .a
结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的。 第二行告诉 Git 忽略所有以波浪符(~)结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存副本。 此外,你可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等。 要养成一开始就设置好 .gitignore
文件的习惯,以免将来误提交这类无用的文件。
文件 .gitignore
的格式规范如下:
所有空行或者以
#
开头的行都会被 Git 忽略。可以使用标准的 glob 模式匹配。
匹配模式可以以(/)开头防止递归。
匹配模式可以以(/)结尾指定目录。
要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。 星号(*
)匹配零个或多个任意字符;[abc]
匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?
)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9]
表示匹配所有 0 到 9 的数字)。 使用两个星号(*
) 表示匹配任意中间目录,比如a/**/z
可以匹配 a/z
, a/b/z
或 a/b/c/z
等。
我们再看一个 .gitignore
文件的例子:
1 | # no .a files |
Tip: GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore
文件列表,你可以在 https://github.com/github/gitignore 找到它.
某些push错误的情况
错误1: 新建仓库push出错
有时候对新建的仓库进行push操作,会出现上传失败的情况。
通常出现这种情况的原因,是新建的仓库往往会有一个文件Readme.md文件,而本地仓库中没有这个文件,也就是说本地仓库与服务器端仓库没有实现同步。所以将这个Readme.md文件pull到本地,然后再commit提交,应该就没有问题了。
1 | $ git pull origin master //该指令必须先执行,否则到push的时候会报错,因为在github端已经有一个文件了:README.md,会提示远程仓库和本地仓库有不一致的地方 |
错误2: 本地仓库与远程仓库不一致
在 push 操作的时候遇到下述错误:
1 | error: 无法推送一些引用到 'git@github.com:upcAutoLang/BackgroundSplit-OpenCV.git' |
出现该情况的原因可能是之前在上传时创建的.git文件被删除或者修改,也可能是其他人在 Github 上提交过代码。
解决方案:
1 强行上传:
$ git push -u origin master
2 尽量先同步 Github 上的代码到本地,在上面更改之后再上传。
$ git pull origin master
$ git push -u origin master
必须保证每个文件夹下不能再有除了刚才生成的.git文件夹之外的.git,否则上传后那个文件夹将会是空文件夹,因为.git文件夹是包含连接信息的。和别的会有冲突。
错误3: 上传文件太大
出现错误:this exceeds Github’s file size limit of 100MB
千万不要用这种办法,会把本地的文件删除!!!太坑了
1 | $ git filter-branch --force --index-filter"git rm --cached --ignore-unmatch 文件名及详细路径" --prune-empty--tag-name-filter cat -- --all |
解决办法参考下文git reflog
常用Git命令
Git add, Git commit 添加错文件 撤销
Git add 添加多余文件
git add
如果添加了错误的文件的话
撤销操作
1 | git status 先看一下add 中的文件 |
Git commit 错误
如果不小心 弄错了 git add
后 , 又 git commit
了。
先使用
1 | git log 查看节点 |
然后
1 | git reset commit_id |
PS:还没有 push 也就是 repo upload
的时候
1 | git reset commit_id (回退到上一个 提交的节点 代码还是原来你修改的) |
commit后最佳撤销办法git reflog
首先使用 git reflog
命令查看操作记录:
1 | $ git reflog |
看到 amend 操作之前的最后一个操作就是 HEAD@{1}
.
现在可以用 git reset
将当前分支的 HEAD 指向 HEAD@{1}
, 即可达到撤销 amend 的目的:
1 | $ git reset --soft HEAD@{1} |
随即使用 git status
查看状态, 发现 amend 的内容已经被撤销 (到工作区) 了.
如果想撤销到暂存区, 就用 git reset --soft HEAD@{1}
.
如果想干掉这个修改, 就用 git reset --hard HEAD@{1}
.
这和 git reset
操作 commit 的情形是一样的.
如果一个 commit 被 amend 了多次, 也可以用这种方法撤销到任意一次 amend 处:
1 | $ git reflog |
可以看出, 不止是 amend 操作, 其他操作也可以用这种方法进行撤销.
Push 之后发现错误
如果要是提交了以后,可以使用 git revert
还原已经提交的修改
此次操作之前和之后的commit和history都会保留,并且把这次撤销作为一次最新的提交
最好不要用这种办法,会把本地的文件删除!!!虽然可以再revert回来
1 | git revert HEAD 撤销前一次 commit |
查看、添加、提交、删除、找回,重置修改文件
1 | git help <command> # 显示command的help |
查看文件diff
1 | git diff <file> # 比较当前文件和暂存区文件差异 git diff |
查看提交记录
1 | git log git log <file> # 查看该文件每次提交记录 |
Mac上可以使用tig代替diff和log,brew install tig
Git 本地分支管理
查看、切换、创建和删除分支
1 | git br -r # 查看远程分支 |
分支合并和rebase
1 | git merge <branch> # 将branch分支合并到当前分支 |
Git补丁管理(方便在多台机器上开发同步时用)
1 | git diff > ../sync.patch # 生成补丁 |
Git暂存管理
1 | git stash # 暂存 |
Git远程分支管理
1 | git pull # 抓取远程仓库所有分支更新并合并到本地 |
Git远程仓库管理
1 | git remote -v # 查看远程服务器地址和仓库名称 |
创建远程仓库
1 | git clone --bare robbin_site robbin_site.git # 用带版本的项目创建纯版本仓库 |
也可以命令设置跟踪远程库和本地库
1 | git branch --set-upstream master origin/master |
Git remote
要 参与任何一个 Git 项目的协作,必须要了解该如何管理远程仓库.远程仓库是指托管在网络上的项目仓库,可能会有好多个,其中有些你只能读,另外有些可以写.同他人协作开发某 个项目时,需要管理这些远程仓库,以便推送或拉取数据,分享各自的工作进展.管理远程仓库的工作,包括添加远程库,移除废弃的远程库,管理各式远程库分 支,定义是否跟踪这些分支,等等.本节我们将详细讨论远程库的管理和使用.
查看当前的远程库
要查看当前配置有哪些远程仓库,可以用 git remote 命令,它会列出每个远程库的简短名字.在克隆完某个项目后,至少可以看到一个名为 origin 的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库:
$ git clone git://github.com/schacon/ticgit.git
Initialized empty Git repository in /private/tmp/ticgit/.git/
remote: Counting objects: 595, done.
remote: Compressing objects: 100% (269/269), done.
remote: Total 595 (delta 255), reused 589 (delta 253)
Receiving objects: 100% (595/595), 73.31 KiB | 1 KiB/s, done.
Resolving deltas: 100% (255/255), done.
$ cd ticgit
(1)git remote 不带参数,列出已经存在的远程分支
$ git remote
origin
(2)git remote -v | –verbose 列出详细信息,在每一个名字后面列出其远程url
此时, -v 选项(译注:此为 –verbose 的简写,取首字母),显示对应的克隆地址:
$ git remote -v
origin git://github.com/schacon/ticgit.git如果有多个远程仓库,此命令将全部列出.比如在我的 Grit 项目中,可以看到:
$ cd grit
$ git remote -v
bakkdoor git://github.com/bakkdoor/grit.git
cho45 git://github.com/cho45/grit.git
defunkt git://github.com/defunkt/grit.git
koke git://github.com/koke/grit.git
origin 这样一来,我就可以非常轻松地从这些用户的仓库中,拉取他们的提交到本地.请注意,上面列出的地址只有 origin 用的是 SSH URL 链接,所以也只有这个仓库我能推送数据上去(我们会在第四章解释原因).
添加远程仓库
要添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用,运行 git remote add [shortname] [url]:
$ git remote
origin
$ git remote add pb git://github.com/paulboone/ticgit.git
$ git remote -v
origin git://github.com/schacon/ticgit.git
pb git://github.com/paulboone/ticgit.git现在可以用字串 pb 指代对应的仓库地址了.比如说,要抓取所有 Paul 有的,但本地仓库没有的信息,可以运行 git fetch pb:
$ git fetch pb
remote: Counting objects: 58, done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 44 (delta 24), reused 1 (delta 0)
Unpacking objects: 100% (44/44), done.
From git://github.com/paulboone/ticgit
* [new branch] master -> pb/master
* [new branch] ticgit -> pb/ticgit
现在,Paul 的主干分支(master)已经完全可以在本地访问了,对应的名字是 pb/master,你可以将它合并到自己的某个分支,或者切换到这个分支,看看有些什么有趣的更
Reference
以上内容分别转载自
[2] GitHub入门教程