一、Git 简介
Git 是一个分布式版本控制系统,每一台安装了 Git 的电脑都能拥有某个项目每个版本的每个文件,所以每台安装了 Git 的电脑都能拥有备份。
二、一些概念
本地仓库:文件夹 .git
里用于存放项目每个版本的内容的仓库。
工作区:项目文件所在的根目录。
暂存区:文件夹 .git
里面的一个专门用于存放被修改过的文件并可一次性提交到本地仓库的“缓冲区”。
三、对本地仓库的操作
(一) 基本操作
git init
:将当前目录下的所有文件或文件夹设置为 Git 的管理对象。
git add <filename>/--all
:添加修改的文件到文件夹 .git
里面的暂存区。
git commit -m "<message>"
:将暂存区里修改的文件一次性提交到文件夹 .git
里面的本地仓库,提交后暂存区将被清空。
(二) 查看 Git 工作情况
git status
:查看工作区文件的增删改情况,工作区哪些文件还没提交到暂存区,暂存区都有哪些文件或暂存区的文件是否已提交到本地仓库。
-
若显示结果含有“nothing to commit, working tree clean”字眼,则说明工作区的修改已全部提交到暂存区。
-
若显示结果含有“Changes not staged for commit”字眼,则说明工作区存在还没提交到暂存区的修改。
-
若显示结果含有“Changes to be committed”字眼,则说明工作区存在一些已经提交到暂存区的修改。
-
若同一个文件同时出现在“Changes not staged for commit”部分和“Changes to be committed”部分,则说明该文件提交到暂存区后又被修改了。
git diff (<filename>)
:查看工作区的文件与暂存区的文件相比发生了哪些内容上的变动。
git log (--pretty=oneline)
:查看本地仓库都有哪几个版本,以及它们的作者和提交日期。
git reflog
:查看本地仓库所有分支的操作记录。commit、checkout、rebase、pull 四种操作都会被记录在 reflog 里面。
(三) 恢复工作区
git reset --hard <id>
:在本地仓库的所有版本里选择一个编号为 id
的版本导入工作区。<id>
部分可用 HEAD~<N>
或 HEAD
后面紧跟着 N 个异或符号 ^
代替,表示当前版本往前数第 N 个版本。
git checkout -- <filename>
:在修改尚未被提交到暂存区时,撤销工作区指定文件的修改,等同于手动增删改将工作区恢复原状。
git reset HEAD <filename>
:在已提交修改文件到暂存区的情况下,清除暂存区中该文件的内容,返回到工作区文件已修改但还没提交到暂存区的状态。
所以恢复工作区的某个文件有三种情况:
一是被修改的文件尚未提交到暂存区,可手动对文件进行增删改或直接运行命令 git checkout -- <filename>
。
二是被修改的文件已提交到暂存区但还没提交到本地仓库,可运行命令 git reset HEAD <filename>
清除暂存区中该文件的内容,然后执行情况一对应的操作。
三是被修改的文件已提交到本地仓库但还没推送到远程仓库,可直接回退到前一个版本。(目前没有发现一种能先删除当前版本、将暂存区恢复到最近一次 commit
操作前的状态的方法)
(四) 删除文件
git rm <filename>
:删除工作区中的某个文件。
git rm -f <filename>
:删除工作区中的某个文件暂存区若有该文件的话也会被删除。
(五) 分支管理
在 Git 中,分支就是一个指向某个版本的指针,而 HEAD
是一个指向分支指针的指针。
1. git checkout
git checkout -b <新分支名>
:创建新分支并切换到新分支,相当于先执行命令 git branch <新分支名>
后执行命令 git checkout <新分支名>
。(创建一个新指针并将其指向 master
指针所指向的版本,并且让 HEAD
指针指向该新指针)
git checkout <分支名>
:切换到特定分支。(将 HEAD
指向指定的分支指针)
2. git branch
git branch <新分支名>
:创建一个新分支。
git branch
:查看当前分支。
git branch -d <分支名>
:删除已经合并到其他分支的指定分支。(销毁特定指针,而不是销毁某个版本)
git branch -D <分支名>
:强行删除尚未合并到其他分支的指定分支。
git branch -r
:查看远程仓库分支。
git branch -a
:查看本地和远程仓库所有分支。
3. git merge
git merge <分支名>
:将指定分支合并到当前分支。(找到特定指针指向的版本,然后将 HEAD
指向的指针直指该版本)
git merge --no-ff -m "<版本信息>" <分支名>
:将指定分支与当前分支合并为一个新版本并提交,不抹除原有提交版本。
4. git rebase
git rebase <分支名>
:以指定分支最新一个版本为起点,将当前分支拼接在其后面。
5. git stash
git stash
:保留工作现场。
git stash pop
:恢复工作现场。
四、对远程仓库的操作
(一) 远程仓库记号管理——git remote
git remote add <自定义远程仓库记号> <URL>
:添加一个自定义记号,该记号代表指定的远程仓库的 URL。
git remote rm <远程仓库记号>
:删除指定远程仓库的记号。
git remote
:查看该项目下所有自定义的远程仓库记号。
git remote -v/--verbose
:查看远程仓库的地址及记号。
git remote show <远程仓库记号>
:显示指定远程仓库的信息。
git remote rename <远程仓库原有记号> <远程仓库新记号>
:更改指定远程仓库的记号。
(二) 将远程仓库拷贝到本地——git clone
git clone <远程仓库的 URL> <本地目录>
:将指定的远程仓库拷贝到本地指定目录下。
git clone <远程仓库的 URL>
:将指定的远程仓库拷贝到本地当前目录下。
(三) 抓取远程仓库更新部分到本地——git fetch
git fetch <远程仓库记号> <远程仓库分支名>
:将指定远程仓库指定分支的更新部分拷贝到本地仓库中。
git fetch <远程仓库记号>
:将指定远程仓库所有分支的更新部分拷贝到本地仓库中。
使用该命令后,可用诸如 origin/master 的记号表示远程仓库的分支。
用该命令抓取了记号 origin 的远程仓库的 master 分支到本地之后,则可用命令 git checkout origin/master
切换到远程分支进行查看,查看完可执行命令 git checkout master
返回本地的 master 分支。
(四) 抓取远程仓库更新部分到本地并合并——git pull
git pull <远程仓库记号> <远程仓库分支名>:<本地仓库分支名>
:取回远程仓库指定分支的更新,与本地仓库的指定分支合并。如果指定的本地分支是当前分支,则可省略“:<本地仓库分支名>”部分,直接输入“git pull <远程仓库记号> <远程仓库分支名>
”。
使用该命令后,可用诸如 origin/master 的记号表示远程仓库的分支。
该命令等同于先执行命令“git fetch
”,后执行命令“git merge
”。
执行完 git pull
操作后,本地仓库一个分支 B 会和远程仓库被抓取过来的分支 A 建立跟踪关系。若在分支 B 下执行合并操作,则分支 A 仍保持不变,不会和分支 B 同步;若在分支 B 下执行 commit 操作,则分支 A 会自动和分支 B 同步。
(五) 将本地仓库推送到远程仓库——git push
git push <远程仓库记号> <本地仓库分支名>:<远程仓库分支名>:将本地仓库的指定分支推送到远程仓库的指定分支。
git push <远程仓库记号> <本地仓库分支名>:将本地仓库的指定分支推送到远程仓库的同名分支,远程仓库若存在该同名分支则直接推送,若不存在则先创建同名分支再推送。
git push <远程仓库记号> :<远程仓库分支名>:删除远程仓库指定分支。
若本地仓库中有诸如 origin/master 的远程仓库分支记号,则执行完该操作后,所有远程仓库分支记号都会和远程仓库进行同步。
五、易混淆点总结
(一) git reset 与 git checkout
git reset
总结:
-
git reset -- hard <版本号>
:将工作区恢复到特定版本 -
git reset <版本号> <文件名>
:将工作区的特定文件恢复到特定版本下的对应文件,但不能用于恢复被删除的文件。该恢复只会影响暂存区,不会影响工作区。
git checkout
总结:
-
git checkout -- <文件名>
:若某个文件的修改尚未提交到暂存区,则用上一版本的该文件作为备份恢复,可用于恢复被删除的文件。 -
git checkout <版本号> <文件名>
:用特定版本的特定文件作为备份恢复,该恢复既会影响工作区也会影响暂存区。 -
git checkout <分支名>
:跳转到特定分支的最新版本,工作区会被更改为该该分支最新版本的内容。
(二) 两种合并操作 git merge 和 git rebase
- 两种合并操作所得到的最终版本是一样的,只是
git merge
会导致提交历史链出现环状,而一次git rebase
操作会减少提交历史链中的一个环状,保持提交历史的整洁。 - 两种操作的命令格式中在语义上的有所区别,
git merge <分支 A>
是把 A 合并到当前分支上,git rebase <分支 A>
是把当前分支插入到分支 A 前面。