这是一次在分支切换时丢失工作区内容的惨痛经历。
刚开始直接就在分支pre上进行开发工作,然后需要切换到dev分支上进行开发
git checkout dev
此时pre上工作区的内容因为和dev没有冲突,所以工作区的内容完整保留到dev中。
然后想把dev上的工作区内容删除掉(注意这是错误理解,事实上git工作区和暂存区并不分支),因此用版本回退命令git reset head --hard,意图清除dev上(注意,错误理解!)工作区和暂存区新的代码
git reset head --hard //这是把自己往死里逼啊
然而当再切回到pre上时,发现工作区和暂存区的新代码也消失了。
既然发现git的路走弯了,那么跪着也要把它掰回来 :) 。因此事后对git的原理和常见操作进行了一次完整的梳理。
这里先不讲工作区代码丢失惨案的解决方案,请大家自行思考原因和解决方案。文章最后我会揭晓答案。
git分三个区,工作区(working tree),暂存区(indexing),版本库(repository)。
与svn不同,svn开辟一个分支会拷贝代码,而git仅仅是增加一个指针而已,轻体瘦身。
HEAD的概念:指向当前分支最新的commit点。
//.git目录中的内容
GccJ:.git zhangwenhao$ ls -la
total 24
drwxr-xr-x 10 zhangwenhao wheel 320 Nov 5 14:56 .
drwxr-xr-x 6 zhangwenhao wheel 192 Nov 5 14:55 ..
-rw-r--r-- 1 zhangwenhao wheel 23 Nov 5 14:55 HEAD
drwxr-xr-x 2 zhangwenhao wheel 64 Nov 5 14:55 branches
-rw-r--r-- 1 zhangwenhao wheel 164 Nov 5 14:56 config
-rw-r--r-- 1 zhangwenhao wheel 73 Nov 5 14:55 description
drwxr-xr-x 13 zhangwenhao wheel 416 Nov 5 14:55 hooks
drwxr-xr-x 3 zhangwenhao wheel 96 Nov 5 14:55 info
drwxr-xr-x 4 zhangwenhao wheel 128 Nov 5 14:55 objects
drwxr-xr-x 4 zhangwenhao wheel 128 Nov 5 14:55 refs
//拷贝远程服务端仓库
//首先进入你的项目想要在的目录中,运行如下命令
git clone https://github.com/git-share-study/git-share-study.git
//拷贝别人客户端仓库
//首先进入你的项目想要在的目录中,运行如下命令
git clone [email protected]:/myCode/IdeaProjects/git-share-study
//设置git用户名,用于git登陆
git config --global user.name "zhangwenhao"
//设置git邮箱账号,用于git登陆
git config --global user.email "[email protected]"
//设置快捷键co替代checkout
git config --global alias.co "checkout"
//设置快捷键cm替代commit -m
git config --global alias.cm "commit -m"
//查看配置内容
git config --global -l
//结果
user.name=zhangwenhao
[email protected]
alias.co=checkout
alias.cm=commit -m
//添加远程仓库地址源,并起别名rr
git remote add rr https://github.com/git-share-study/git-share-study.git
//查看远程仓库地址
git remote -v
//结果
rr https://github.com/git-share-study/git-share-study.git (fetch)
rr https://github.com/git-share-study/git-share-study.git (push)
//删除远程仓库地址
git remote remove rr
//将暂存区的haha文件覆盖工作区的haha文件
git checkout haha
或者
git restore haha
//将版本库的head指向版本的内容覆盖暂存区内容
git reset head
//将版本库最新版的haha文件覆盖暂存区的haha文件
git restore --staged haha
git reset head --hard
从版本库拉取最新提交点,并覆盖暂存区和工作区。hard的作用,就是一同覆盖暂存区和工作区,不用hard,那么只会覆盖暂存区。
git rm [file]
git rm是从暂存区和工作区中删除文件!
rm命令仅仅删除工作区的文件!
git rm --cached 那么就仅仅删除工作区的内容!
可以通过上述的checkout或restore命令进行内容恢复!如果要删除文件夹,那么需要加入-r参数,表示递归删除。
git help
查看基本常用命令行!
git stash
将工作区的内容存放起来,在需要的时候取出!
开发者进行了代码的更新,只要最终没有commit到版本库的内容都可以stash起来。
//添加到stash库中,save后是备注信息
git stash save "firt time"或git stash
//查看stash库列表
git stash list
//结果
stash@{0}: On master: firt time
//切换到其他分支(也可以不切换)
git checkout dev
//在需要的任何时间,任何分支,操作如下指令,即可加入到工作区中(如有冲突,解决即可)
git stash apply stash@{0}
//删除某个stash内容
git stash drop stash@{0}
//清空所有stash内容
git stash clear
//git log 结果
commit ff780e5b16c795840a602f1bdf05f261c473b48a (HEAD -> dev, master)
Author: zhangwenhao
Date: Tue Nov 5 17:19:21 2019 +0800
ignore
commit 6ca340ba642285757028dbfe3ce004346b1481d5
Author: zhangwenhao
Date: Tue Nov 5 16:34:41 2019 +0800
skd
commit 491db9dbf995d8feeb5dd552ef9fdae141058f1f
Author: zhangwenhao
Date: Tue Nov 5 16:33:33 2019 +0800
rm
//git reflog的结果
ff780e5 (HEAD -> dev, master) HEAD@{0}: reset: moving to ff780e5
ff780e5 (HEAD -> dev, master) HEAD@{1}: reset: moving to ff780e5
491db9d HEAD@{2}: reset: moving to head~2
ff780e5 (HEAD -> dev, master) HEAD@{3}: reset: moving to ff780e5
491db9d HEAD@{4}: reset: moving to head^^
ff780e5 (HEAD -> dev, master) HEAD@{5}: checkout: moving from master to dev
ff780e5 (HEAD -> dev, master) HEAD@{6}: reset: moving to HEAD
ff780e5 (HEAD -> dev, master) HEAD@{7}: reset: moving to head
ff780e5 (HEAD -> dev, master) HEAD@{8}: commit: ignore
commit bb7fa1fd4421789de155e525257a500941f3b815 (HEAD -> dev)
Author: zhangwenhao
Date: Thu Nov 7 18:29:43 2019 +0800
2
commit 500b0832b66499b825ee1dff8dbd31de5ddf97a2
Author: zhangwenhao
Date: Thu Nov 7 18:29:29 2019 +0800
1
commit 8dc44dd1f9b15fab14e2c0ba478612609f9d6042
Author: zhangwenhao
Date: Thu Nov 7 18:22:34 2019 +0800
我们需要将最近的两次提交点合并,所以应该选择8dc44dd1f9b15fab14e2c0ba478612609f9d6042作为其新的基础点,因此调用
git rebase -i 8dc44dd1f9b15fab14e2c0ba478612609f9d6042
弹出配置框,并配置squash id1和pick id2,表示将id1和id2的提交点进行合并
pick 500b083
squash bb7fa1f
# Rebase 8dc44dd..bb7fa1f onto 8dc44dd (2 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
保存后会跳出填写combination的提交信息,填写后再次保存,然后查看提交记录:
commit 18e88fce095f5464e388b907e6466c1377738b7b (HEAD -> dev)
Author: zhangwenhao
Date: Thu Nov 7 18:29:29 2019 +0800
this ia a combination
1
2
commit 8dc44dd1f9b15fab14e2c0ba478612609f9d6042
Author: zhangwenhao
Date: Thu Nov 7 18:22:34 2019 +0800
即发现多个提交点合并成了一个提交点。
//创建名为origin的远程仓库源
git remote add origin https://github.com/git-share-study/git-share-study.git
//将origin的数据源名称改为ddd
git remote rename origin ddd
//删除名称为ddd的数据源
git remote remove ddd
//查看数据源情况
git remote -vv
//结果
origin https://github.com/git-share-study/git-share-study.git (fetch)
origin https://github.com/git-share-study/git-share-study.git (push)
git branch --set-upstream-to=origin/dev
设置本地分支默认操作对应的远程仓库分支(前提必须要先track到远程仓库),可以用git branch --unset-upstream 来解除默认操作。当设置完毕后,上述两个命令只需简单输入git push 或git pull操作即可默认从本地推送到设置的远程分支上,从而不用指定远程仓库信息。
git branch -r --list
查看远程已经追踪的分支(注意是追踪的分支,即和本地有关联的分支,通过git pull,git push,git fetch建立和远程仓库的追踪关系)
git branch -r -d origin/pre
删除远程分支追踪关系
git fetch
将远程仓库的内容拉到本地,并放入一个临时的名称为FETCH_HEAD分支上。此时本地和远程建立了track关系。
git pull
从远程仓库拉取到本地仓库,并merge到该分支,覆盖版本库,暂存区,工作区。此时本地和远程建立了track关系。等同于下面两步骤。
git fetch
然后
git merge FETCH_HEAD
git pull origin master 从master拉取到本地当前分支
git pull origin master:pre 从master拉取到本地pre分支
如果在pull的时候出现refusing to merge unrelated histories报错,那么加上--allow-unrelated-histories参数即可。
git push
将本地版本库内容推送到远程仓库。此时本地和远程建立了track关系。
git push origin master 从本地当前分支推送到远程master分支
git push origin master:pre 从本地master分支推送到远程pre分支
如果第一次将本地仓库推送到远端空仓库(因为是空仓库,所以无法通过git fetch,git pull建立track关系),那么要加一个-u来建立track关系(等同于--set-upstream),git push -u origin master。
git push origin --delete pre
删除远程分支
标签管理就是记录一些重要关键点的commitId,比如在发布版本的时候,进行一个tag记录,可以更方便更清晰的管理代码版本。
//创建一个简单的标签
git tag v1.0
//创建一个带备注的标签
git tag -a -m 'firt release 2019/10/10' v1.1
//精确查询
git tag -l 'v1.0'
//*即为通配符,代表以1结尾的tag名
git tag -l '*1'
//*即为通配符,代表包含1的tag名
git tag -l '*1*'
//结果
v1.0
v1.1
//展示标签v2.0
git show v2.0
//结果
tag v2.0
Tagger: zhangwenhao
Date: Thu Nov 7 16:17:31 2019 +0800
second tag
commit 69d644839fc17e18d40d21d4a14005e0083b1024 (HEAD -> master, tag: v2.0, origin/master)
Author: zhangwenhao
Date: Tue Nov 5 18:41:33 2019 +0800
ha
diff --git a/haha b/haha
index c82fdc3..38e28f7 100644
--- a/haha
+++ b/haha
@@ -1 +1,2 @@
-skdfj
项目组的其他人再次git pull远程仓库的同时,会拉取远程仓库中本地所没有的标签。就可以同步标签信息了。
场景:.gitignore忘记过滤了.idea文件,并且上传到了远程仓库,如何删除远程仓库里的.idea,并且将该文件重新加入ignore文件。
需要明白,.idea文件已经加入的本地版本库和暂存区,而.gitignore仅仅对尚未加入暂存区和本地版本库的内容起作用,因此,首先要做的是删除本地暂存区,版本库的内容,然后删除远程仓库的内容,再添加到过滤文件中:
//删除暂存区的内容(工作区需要保留)
git rm -r --cached .idea
//删除本地版本库中的内容,cm在前面设置的alias,相当于commit -m
git cm "del"
//删除远程仓库中的内容(已经用git push --set-upstream origin dev设置过默认源,因此可以用git push这种简便操作)
git push
//在.gitingnore文件中加入如下规则
.idea
场景:本地版本回退,然后修改提交,此时git push操作会rejected。
此时需要删除远程仓库的分支,然后重新push上去分支即可。(其他人的客户端如果想要上传,必须先pull,解决冲突后,才能push)
//先删除远程分支
git push origin dev -d
//再推送回退版本后并修改的版本库
git push
刚开始提到的问题,工作区的内容丢失该如何应对呢?
第1种方法:可以用本地历史找回文件的记录点,但是其保存点是随机的,有可能漏掉关键代码。因此不推荐。
第2种方法:先commit保存下来,再去另一个分支开发,不推荐,因为每一个保存点都应当是一个完整的功能点,都应该是完整开发并测试后的功能点,便于以后查看、回退、开新分支等操作,不能将版本库当作一个保存文件的地方。
第3种方法:用git stash 保存下来,然后切换到别的分支去开发,当需要继续回来开发时,再用git stash apply stash{index}重新提取到工作区内。(完整操作看第3章中的git stash介绍)这种方法是最可取的。