1.选择一个合适的位置创建一个空文件
$ mkdir learngit $ cd learngit $ pwd /home/wanzhizheng/learngit2.通过git init命令把这个目录变成Git可以管理的仓库:
$ git init Initialized empty Git repository in /Users/michael/learngit/.git/3.把文件添加到版本库 新建一个 readme.txt 文件(vim去编辑并保存为readme.txt文件,内容自定义) (1)用命令git add告诉Git,把文件添加到仓库
$ git add readme.txt执行上面的命令,没有任何显示,表示操作成功 (2)用命令git commmit 告诉Git,将文件提交到仓库
$ git commit -m "wrote a readme file" [master (root-commit) 0e6a8ed] wrote a readme file 1 file changed, 2 insertions(+) create mode 100644 readme.txt简单解释一下git commit命令,-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。 git commit命令执行成功后会告诉你,1 file changed:1个文件被改动(我们新添加的readme.txt文件);2 insertions:插入了两行内容(readme.txt有两行内容)。
(1)git log命令显示从最近到最远的提交日志
$ git log commit 18252ee3335f7b0d38d6f03b229d871f0bc7a2f5 Author: 万志峥 <wanzhizheng@meizu.com> Date: Thu Jul 18 14:08:45 2019 +0800 append GPL 2 commit ff1efa4abfd9a3f46331e64db7aacdc71877bfab Author: 万志峥 <wanzhizheng@meizu.com> Date: Thu Jul 18 13:59:34 2019 +0800 append GPL commit 0e6a8ed98d757d0f21089703c9ee70f98a241985 Author: 万志峥 <wanzhizheng@meizu.com> Date: Thu Jul 18 11:00:10 2019 +0800 wrote a readme file显示三次提交情况
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:
$ git log --pretty=oneline 18252ee3335f7b0d38d6f03b229d871f0bc7a2f5 append GPL 2 ff1efa4abfd9a3f46331e64db7aacdc71877bfab append GPL 0e6a8ed98d757d0f21089703c9ee70f98a241985 wrote a readme file其中18252ee3335f7b0d38d6f03b229d871f0bc7a2f5等 是commit的id
(2)版本更换(向后/向前) 在Git中,用HEAD表示当前版本,也就是最新的提交18252ee… 上一个版本HEAD^,上上个版本HEAD^^,往上n个版本HEAD~n 用命令$ git reset 例:(假设共有三个版本,现在处于ver3.0)
$ git reset --hard HEAD^ //返回上一个版本(ver 2.0)此时已回到第二个版本,可以继续到上一个版本(ver1.0) 若此时我想回到第三个版本,就只能用commit 的 id(前提是要记住那一长串id)
$ git reset --hard 18252ee //(ver 3.0) 只需要输入一定前缀,不要太少,不然会匹配到多个commit若忘记了id也不要紧,Git提供了一个命令$ git reflog用来记录你的每一次命令
$ git reflog 18252ee HEAD@{0}: commit: append GPL 2 //得知第三个版本的id为 18252ee... ff1efa4 HEAD@{1}: commit: append GPL 0e6a8ed HEAD@{2}: commit (initial): wrote a readme file //可以看到每次命令的记录就是电脑里面看到的目录,即learngit这个文件夹
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。 Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。 前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
git status可以查看当前工作区所做的一些改变 若对工作区文件修改或添加文件后没有add,commit就会显示出当前是修改未提交的状态 若add,commit后就会显示工作区是干净的,clean
Git跟踪并管理的是修改,而非文件 第一次修改 -> git add -> 第二次修改 -> git commit最后提交到版本库的只是第一次修改 如果这个时候查看status就可以看到的确有未提交的修改 可以用git diff HEAD -- readme.txt查看工作区和版本库里面最新版本的区别: a指的是版本库的,b指的是工作区的
命令git checkout -- readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
(1)一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
(2)一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。 总之,就是让这个文件回到最近一次git commit或git add时的状态。
附: Git可以用命令git reset HEAD <file>可以把暂存区的修改撤销掉(unstage),重新放回工作区 git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD <file>,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库
一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删了:
rm test.txt这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了: 现在有两个选择: (一)确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit: (二)删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:
git checkout -- test.txtgit checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
(1)首先在Github上创建远程库learngit (2)git remote add origin https://github.com/WanZhiZheng/learngit.git关联一个远程库 (3)git push -u origin master把本地库的所有内容推送到远程库上 由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。 以后就可以通过命令
git push origin master把本地master分支的最新修改推送至github
小结 要关联一个远程库,使用命令git remote add origin git@server-name:path/repo-name.git
关联后,使用命令git push -u origin master第一次推送master分支的所有内容;
此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;
创建一个远程库,或已有远程库gitskills 现在,远程库已经准备好了,下一步是用命令git clone克隆一个本地库: ssh密钥 git clone git@github.com:WanZhiZheng/gitskills.git (较快)
https协议git clone https://github.com/WanZhiZheng/gitskills.git
到现在为止若没有创建其他分支,则处于默认分支master。之前所说的HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。 创建分支
$ git checkout -b dev Switched to a new branch 'dev'git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
$ git branch dev $ git checkout dev Switched to branch 'dev'用git branch命令会列出所有分支,当前分支前面会标一个*号
$ git branch * dev master修改readme.txt然后正常提交提交:
//修改readme.txt后 $ git add readme.txt $ git commit -m "branch test" [dev b17d20e] branch test 1 file changed, 1 insertion(+)现在,dev分支的工作完成,我们就可以切换回master分支:
$ git checkout master Switched to branch 'master'切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变 现在,我们把dev分支的工作成果合并到master分支上:
$ git merge dev Updating d46f35e..b17d20e Fast-forward readme.txt | 1 + 1 file changed, 1 insertion(+)git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。此时图示如下 合并后可一删除dev分支
$ git branch -d dev Deleted branch dev (was b17d20e)删除后,查看branch,就只剩下master分支了:
$ git branch * masterGit鼓励大量使用分支:
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
创建+切换分支:git checkout -b <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
这种情况是: 假设从当前master新建一个feature1分支,然后commit的修改 回到master分支并没有马上合并,而是修改了master的内容提交后才将feature1合并到master,中间feature1可能也修改了该文件 merge不成功,需要手动修改发送冲突的文件 git status可以告知哪个文件(readme.txt)发送冲突,然后再手动修改 查看内容可得 Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容 手动修改后再commit,git log --graph 查看提交图
可以看到之前merge合并的时候会用Fast forward模式,这种直接将master分支指针移到dev上。 如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。 即--no-ff方式的git merge
合并分支时,加上–no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
git stash可以把当前工作现场“储藏”起来,然后去创建分支修改bug,等debug完成以后恢复现场后继续工作(把当前工作现场入棧),
git stash list是用来观察已入棧的一些内容 恢复: (1)用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除; (2)另一种方式是用git stash pop,恢复的同时把stash内容也删了 这两种方式都是操作棧顶的那个stash
你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:
$ git stash apply stash@{0}修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。
软件开发中,总有无穷无尽的新的功能要不断添加进来。
添加一个新功能时,你肯定不希望因为一些实验性质的代码,把主分支搞乱了,所以,每添加一个新功能,最好新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
现在,你终于接到了一个新任务:开发代号为Vulcan的新功能,该功能计划用于下一代星际飞船。
其操作和bug分支过程类似 1.从dev新建分支
$ git checkout -b feature-vulcan Switched to a new branch 'feature-vulcan'2.开发完毕 --> add --> commmit
$ git add vulcan.py $ git status On branch feature-vulcan Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: vulcan.py $ git commit -m "add feature vulcan" [feature-vulcan 287773e] add feature vulcan 1 file changed, 2 insertions(+) create mode 100644 vulcan.py3.切回dev,准备合并
$ git checkout dev如果顺利则和bug分支类似,合并成功,然后删除该新建分支
但是 如果此时上级命令取消该功能,就必须对commit后的分支进行删除操作
$ git branch -d feature-vulcan error: The branch 'feature-vulcan' is not fully merged. If you are sure you want to delete it, run 'git branch -D feature-vulcan'.销毁失败。Git友情提醒,feature-vulcan分支还没有被合并,如果删除,将丢失掉修改,如果要强行删除,需要使用大写的-D参数。 现在我们强行删除:
$ git branch -D feature-vulcan Deleted branch feature-vulcan (was 287773e).查看远程库的信息:git remote 显示远程库更详细信息: git remote -v
但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
master分支是主分支,因此要时刻与远程同步;dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。假设团队里面另外一个人在其电脑中在dev分支已经推送了他的修改,而碰巧我也对同样的文件作了修改,并试图push
$ cat env.txt env $ git add env.txt $ git commit -m "add new env" [dev 7bd91f1] add new env 1 file changed, 1 insertion(+) create mode 100644 env.txt $ git push origin dev To github.com:michaelliao/learngit.git ! [rejected] dev -> dev (non-fast-forward) error: failed to push some refs to 'git@github.com:michaelliao/learngit.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.push失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突。
解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送:
$ git pull There is no tracking information for the current branch. Please specify which branch you want to merge with. See git-pull(1) for details. git pull <remote> <branch> If you wish to set tracking information for this branch you can do so with: git branch --set-upstream-to=origin/<branch> devgit pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接:
$ git branch --set-upstream-to=origin/dev dev Branch 'dev' set up to track remote branch 'dev' from 'origin'.再pull:
$ git pull Auto-merging env.txt CONFLICT (add/add): Merge conflict in env.txt Automatic merge failed; fix conflicts and then commit the result.提示发生冲突,在本地解决冲突然后再推送上去。
因此,多人协作的工作模式通常是这样:
首先,可以试图用git push origin 推送自己的修改;
如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin 推送就能成功! 如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
Rebase主要有两种主要应用。一是合并多次提交记录,二是分支合并
(1)合并多次提交记录 此时已有多次提交记录而完成一个功能显而觉得繁琐,需要合并第3-6此的commit
$ git rebase -i HEAD~4或
$ git rebase -i 46b1a5b76ff546bfec797f6fb5106d89d1796137 //写前面几个也可以 //这里是用commit-id ,即操作该id到最近的commit通过$ git config core.editor vim 来设置默认编辑器(不会用nano编辑器的就调这个吧) 按照命令提示,将4-6合并到3, 然后按左上角ESC,:wq保存,自动跳到以下画面 第一行显示了这是一个4个提交的组合,说明合并成功,然后按左上角ESC,:wq保存。 git log 打印一下提交记录 提交合并成功! (2)分支合并 1.我们先从 master 分支切出一个 dev 分支,进行开发:
git:(master) git checkout -b feature12.这时候,你的同事完成了一次 hotfix ,并合并入了 master 分支,此时 master 已经领先于你的 feature1 分支了: 3.恰巧,我们想要同步 master 分支的改动,首先想到了 merge ,执行: git log 查看 就会在记录里发现一些 merge 的信息,但是我们觉得这样污染了 commit 记录,想要保持一份干净的 commit ,怎么办呢?这时候, git rebase 就派上用场了。
4.让我们来试试 git rebase ,先回退到同事 hotfix 后合并 master 的步骤: 5.使用 rebase 后来看看结果:
git:(feature1) git rebase master (注意这个时候在feature1分支上,意思是当前分支变基到master)这里补充一点: rebase 做了什么操作呢?
首先, git 会把 feature1 分支里面的每个 commit 取消掉;
其次,把上面的操作临时保存成 patch 文件,存在 .git/rebase 目录下;
然后,把 feature1 分支更新到最新的 master 分支;
最后,把上面保存的 patch 文件应用到 feature1 分支上; 从 commit 记录我们可以看出来, feature1 分支是基于 hotfix 合并后的 master ,自然而然的成为了最领先的分支,而且没有 merge 的 commit 记录,是不是感觉很舒服了。
6.在 rebase 的过程中,也许会出现冲突 conflict 。在这种情况, git 会停止 rebase 并会让你去解决冲突(vi 指定文件去修改)。在解决完冲突后,用 git add 命令去更新这些内容。 注意,你无需执行 git-commit,只要执行 continue
git rebase --continue7.在任何时候,我们都可以用 --abort 参数来终止 rebase 的行动,并且分支会回到 rebase 开始前的状态。
git rebase —abortgit log查看结果,与上图一致
1.在工作区新建.gitignore文件
$ touch .gitignore配置文件示例
# 忽略 .a 文件 *.a # 但否定忽略 lib.a, 尽管已经在前面忽略了 .a 文件 !lib.a # 仅在当前目录下忽略 TODO 文件, 但不包括子目录下的 subdir/TODO /TODO # 忽略 build/ 文件夹下的所有文件 build/ # 忽略 doc/notes.txt, 不包括 doc/server/arch.txt doc/*.txt # 忽略所有的 .pdf 文件 在 doc/ directory 下的 doc/**/*.pdf当我向.gitignore中添加了配置时 git status 查看 在hhh/hhh2/.c文件没有添加到.gitignore中,所以会被检测到,我这里再次把该文件放入.gitignore中 git status 查看一下 发现的确都被ignore了
参考博客 http://jartto.wang/2018/12/11/git-rebase/ https://www.liaoxuefeng.com/wiki/896043488029600