本文记录一些学到的Git相关的基础操作
Git 相关的一些基本概念

图片来源:廖雪峰的官方网站
工作区:电脑中能看到的目录,这里git-learning文件夹就是一个工作区
stage:暂存区
.git:这个不算工作区,而是Git的版本库
Git的配置
查看Git相关的用户名和邮箱
git config user.name
git config user.email
修改用户名和邮箱(或初始化时配置用户名和邮箱)
git config --global user.name "CZ" // 也可以不加双引号
git config --global user.email "1229383755@qq.com"
创建第一个Git仓库
git init
该方法执行后会在当前目录下创建一个隐藏的.git目录(Git的版本库),用来跟踪版本信息

mkdir git-learning
cd git-learning
// 该方法执行后会在git-learning目录下创建一个隐藏的.git目录(Git的版本库),用来跟踪版本信息
git init
// 在git-learning目录下新建一个文件,模拟在项目中添加了内容
touch helloGit.txt
git status
此时,helloGit.txt
保存在工作区,Git还没有登记这个文件。可以通过命令git status
查看文件的状态

git add
执行git add helloGit.txt
,将当前文件的当前状态添加到stage区,相当于给该文件添加了快照。
此时执行git status
,会显示Changes to be committed
,说明文件已经在stage区。

git commit
git commit
提交更改,实际上就是把stage区的内容提交到当前分支
使用git commit
或者git commit -m "提交相关的一些说明"
,此处我执行的命令是git commit -m "Add txt secondly"
git log
此时执行git log
可以看到之前的两次提交结果。每次提交都会生成对应的Hash value,head表示分支的当前位置,head->master表示我们在当前的master分支上。

如何修改已经完成的提交
情景描述:小i刚进行了一次
commit
,突然发现有一段代码写错了。如何处理这种情况?
使用git log
查看提交记录如下图

在最新的一次提交中发现代码有一处拼写(Git写成iGt)错误:

此时,如果已经将错误的代码push
线上的代码仓库,则只能将错误代码修正后重新add
和commit
。
如果只是在本地使用和管理代码,可以使用以下几种方案:
git reset --soft
通过git log
命令找到“change the content”的上一次提交,然后复制一下这个ID(hash value)。回到终端,执行git reset --soft 186e17b265a6b9c1d2bf35d6de24373f18441149
执行完这句命令后,git库会更新到指定的这次提交,并且不会改变你工作区中的内容,同时将更新之前的内容copy到stage区。使用git log
和git status
命令查看如下图:


打开源文件,修改错误的地方。此时,工作区和stage区内容不一致。使用git status
查看:

接下来执行git add .
(该命令表示将所有修改过的文件提交到stage区)和git commit -m "change the content"
。
到此,错误的提交就已经被修改过来了。
可以使用git log
查看。
git reset --hard
使用git reset --hard
前工作区的内容为“hello iGt!!“。如下图:

此时执行git reset --hard 186e17b265a6b9c1d2bf35d6de24373f18441149
后,git库将会更新到你指定的ID,同时工作区(即本地代码)也会被同步更新到上提交的内容(被修改为"hello Git!")。见下图:

所以要慎用hard
-
git commit --amend
直接将更正后的内容恢复到之前的提交中。
打开文件编辑,更正之前的错误并保存,然后执行git commit --amend
。之后会弹出最近一次提交的日志,可以根据需要决定是否需要修改提交日志的内容(一般是不需要修改,直接:wq保存退出)。
在项目中使用分支
为什么要使用分支?
情景描述:
小i的开发团队只有一个分支-master。此时,他正基于master分支进行post
API的开发,post
正写到一半,突然有人反馈说request
API无法访问,需要立即修复。如下图。错误原因是因为request
被误写成requets
。此时如果直接修改为request
,并执行add
和commit
操作,那么便会将未开发完成的post
API提交上去,显然我们不该这么做。此时,该怎么办?

使用分支来解Bug和开发需求
git checkout -- <file>
基于上述情况,我们只能撤销掉master分支上在最后一次提交之后的所有修改。
执行git checkout -- vapor/ViewController.m
。执行后的结果如下图:

git branch
用于创建一个新的分支。分支的名称要反应分支的用途,一般开发功能叫做feature-<功能名>
,修复Bugbug-<ID>
,如果是issueissue-<ID>
我们此时开发post
API,应进行如下操作:
// 创建分支
git branch feature-post
// 切换分支到feature-about
git checkout feature-about
或者直接执行git checkout -b feature-about


此时,如果接到紧急修复requst
API的Bug,先将feature-post
分支上的代码commit,创建一个修复Bug的分支(当然这里可以直接切换到主分支直接进行修改并commit)。切换后代码变化见下图:

feature-post
分支上写的代码不见了。就应该如此。基于bug
分支,我们直接修改request。修改完毕后,切换到主分支。
git merge
执行merge操作。此时一定要确保在主分支上。
// --no-ff参数,在历史记录中明确记录下本次分支合并。
git merge --no-ff bug-request
git merge bug-request
效果见下图:

git branch -d <分支名>
此时Bug已经修复,可以删除bug-request
分支。
git branch -d bug-request
然后可以切换到feature-post
分支进行开发,完成后切换到主分支进行merge。(merge后不需要执行add和commit)。
使用Git别名
git config --global alias.<别名> <原名称>
git config --global alias.s status

vi ~/.gitconfig
查看git的配置

使用stash缓存代码修改
当你在某个分支上进行开发时,如果要紧急切换回master修复BUG,则可以先在当前分支上提交,之后切换分支,修复BUG并提交,然后,切换回功能分支继续开发。当然,这只是一个理想的情况,现实中,有很多时候,我们的代码还不具备提交条件,面对这种情况,该怎么办呢?
先介绍一种较为麻烦的方法:
将当前feature分支先commit并备注"WIP"(work in process),切换到主分支修改完Bug后,切回feature分支,同时查看git log,reset到最后一次提交的上一次提交。
第二种实用git stash
git stash
先在当前feature分支执行
git stash
git stash apply stash@{0}
然后切换到主分支进行操作,完成后切换到feature分支,执行如下操作:
git stash apply stash@{0}
此时,之前的内容被恢复过来。可以接着进行开发。
git stash drop stash@{0}
手工清除“缓存记录”。
把stash推到新分支上
feature分支的代码stash后,切换回主分支,此时由于不小心将feature分支删除了。此时该怎么办?
git stash list
在主分支中执行
// 查看缓存记录
git stash list
// 把缓存的内容先恢复到master分支上
git stash pop
// 然后重新执行git stash,这时,就是对master分支上的“缓存”了
git stash
// 用缓存的内容创建并切换到feature-post分支
git stash branch feature-post
目前的这些总结是Git中非常基础的一部分,但对我来说,在目前的工作中已经够用了,待到日后有时间或者工作需要更进阶的使用,我再去学习总结。文中有错误的地方,欢迎指正,共同学习。
参考文章:
Git
通过GitHub分享代码

如果要把本地的项目直接推送到GitHub,就不要选中Initialize this repository with a README
选项,否则GitHub就会直接创建一个空项目。
点击Create repository
:

第一个适用于新创建的项目:
前四行代码是为了创建并commitREADME.md
文件。第五行代码是为了将GitHub分配给我们的项目地址添加到项目的一个远程来源,并把这个来源命名为origin。最后一行代码是将本地项目推送到远程来源。-u
表示upstream
。
在GitHub创建和处理PR
如果我们想给别人的开源项目贡献代码,需要进行Pull Request。

第一:在你想要贡献代码的项目主页,点击右上角的Fork
,这时会在你的GitHub上Clone一个副本。如下图所示:

第二:此时我们点击右上角的Clone,复制一下项目地址,将其Clone到本地chuchu2文件夹下。操作如下:

第三:然后cd到chuchu2文件夹后,执行如下命令(1. 清空保存的认证信息 2.配置Git用户名和邮箱3.编辑文件并commit4.)


第四:回到项目首页,点击new pull request按钮

第五:点击左上角Create pull request按钮

第六:点击Create pull request

Rebase Code
merge后的:
红色是master分支,绿色是feature分支,星号表示在某个分支上的具体操作(左侧的星号表示在master分支的操作)。

但有时,我们创建分支仅仅是为了不影响master,并没有必要在master的提交记录上看到这个创建分支的过程,因为分支的创建有可能会很频繁。这时,我们就可以使用git rebase命令。
通过rebase简化提交记录
切换到feature分支,commit后,执行git rebase master
。然后切回到master分支,执行git merge feature
。此时feature的提交记录就合并到master分支上了。如下图:

记录最近比较常用到的操作
基于远程分支创建分支
git checkout -b <要创建的分支名> <远程库名>/<远程分支名>
eg:
git checkout -b feature_a origin/dev
查看远程分支
git branch -r
// 查看本地分支加远程分支
git branch -va
pull远程分支
git pull <远程库名> <分支名>
eg:
git pull origin dev
fetch远程分支
git fetch <远程库名> <分支名>
eg:
git fetch origin dev
基于本地分支创建远程分支
git push origin <本地分支名>:<新创建的远程分支名>
查看当前的本地分支与远程分支的关联关系
git branch -vv
关联本地分支与远程分支
git branch --set-upstream-to=[远程分支名]
eg:
git branch --set-upstream-to=origin/feature_scanner
为本次提交打tag
git tag <标签名>
git push --tags
eg:
git tag v1.3.2
git push --tags
将之前连续的几次commit合并为一次commit
此操作的前提是这几次commit操作均没有push到远端。

如上图所示,我想要将d5d4167
之前的commit合并为一次commit,因此,执行如下操作
git rebase -i d5d4167
然后在新弹出的编辑框中将除第一行的commit message 中的信息开头改为s,然后保存退出。这时会新弹出一个编辑框,可以为合并的这几次commit写一个总结commit message。
将指定的commit的内容复制到当前分支中
比如当前在B分支,但是我想将A分支的某几次commit合并到B分支,则可以如下操作:
git cherry-pick <commit-id>
git cherry-pick <start-commit-id>...<end-commit-id> //(左开,右闭] 即不包括<start-commit-id>
git cherry-pick <start-commit-id>^...<end-commit-id> //[左闭,右闭] 即也包括<start-commit-id>
极客时间Git学习记录
git mv
更改文件名
// 将readme重命名为readme.md
git mv readme readme.md
git commit -m "Change readme to readme.md"
git log
显示当前分支的记录
git log --all
显示所有分支的记录
git log --all --graph
图形化的形式显示所有分支
git log -n2/git log --oneline --all -n2/...
查看最近两次的提交。
git checkout [comit_id]
可以基于某次commit分离头指针,在HEAD detached from comit_id
commit的记录不会被git作为分支记录,如果此时切换回其他分支,那么在分离头指针上的操作有可能被丢弃。除非通过git branch [new-branch-name] [commit-id]
显示为分离头指针创建一个分支。
查看不同的提交或者不同分支上的提交的差异
git diff [commit-id-one] [commit-id-another]
该指令也可以比较不同分支commit-id的差异
也可以使用git diff HEAD HEAD~1
比较当前分支commit和上次commit。
修改最新的commit message
git commit --amend
修改老旧的commit message
git rebase -i [需要调整的commit的parent commit id]
把将要修改的commit前的pick改为reword或者r。
把连续的多个commit整理成一个
git rebase -i [需要调整的commit的parent commit id]
把将要合并的commit前的pick改为squash或者s。
比较HEAD和暂存区所含文件的差异
git diff --cached
比较工作区和暂存区所含文件的差异
// 比较工作区和暂存区所有文件的差异
git diff
// 比较工作区和暂存区指定文件的差异 (--后有空格)
// 可以指定多个文件
git diff -- 文件名(需包含完整路径)
eg:
// 指定单个文件
git diff -- Model/StackModel.m
// 指定多个文件
git diff -- Model/StackModel.m styles/style.css
恢复暂存区所有文件和HEAD一样
git reset HEAD
恢复暂存区指定文件和HEAD一样
git reset HEAD 文件名
git reset HEAD 文件1 文件2 ... 文件n
总结:
reset指令变更暂存区内容-恢复暂存区和HEAD一样
checkout指令变更工作区内容-恢复工作区和暂存区一样
消除最近的几次commit
git reset --hard [commit-id]
该指令会更改head指针,同时更新暂存区和工作区
正确删除文件的方法
git rm [文件名]
该操作会删除本地文件,同时将删除的状态更新到暂存区。
开发中临时加塞了紧急任务
// 该指令会将暂存区和工作区的内容缓存起来,并更新工作区和暂存区的内容与最新的提交保持一致
git stash
// 当紧急任务完成并且提交之后,执行如下指令,会将缓存的内容同步到工作区
git stash pop 或者
git stash apply
指定不需要Git管理的文件
在.git
所在的目录下添加.gitignore
文件。
有如下几点需要注意:
假如要忽略doc文件夹下所有文件,可以在.gitignore
文件中输入doc
。但此时如果.git
所在的目录下有一个名为doc的文件,则也会被git忽略。如果不想将该文件被忽略,只是忽略doc文件夹下的所有文件,则将.gitignore
文件中的doc
改为doc/
即可。
如何将Git仓库备份到本地
- cd 到备份文件夹下,例如backup/
- 在backup目录下执行 git clone --bare file://[待备份路径/.git],例如:git clone file:///Users/cz/desktop/git_learning/.git(--bare表示clone裸仓库,不带工作目录。file://前缀代表采用智能协议。如果不带file://的话说明是采用哑协议,哑协议clone时没有进度显示)。执行完该步骤之后即备份成功,然后在终端中回到待备份目录,/Users/cz/desktop/git_learning/
- git remote add [远端仓库别名] [备份路径/.git],例如 git remote add remoteRepo file:///Users/cz/desktop/git_learning/.git
- git push --set-upstream [远端仓库别名] [当前分支名],例如git push --set-upstream remoteRepo master(假设当前在master分支)
- 以后push时只需执行git push [远端仓库别名]
git remote -v
查看备份仓库
git branch -av
查看本地和远端分支
网友评论