-
Notifications
You must be signed in to change notification settings - Fork 0
/
git学习
160 lines (125 loc) · 12.9 KB
/
git学习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
在ubuntu上可以使用 sudo apt-get install git来安装;在windows下安装msysgit: http://msysgit.github.io/
安装完后要输入用户信息:
git config --global user.email "[email protected]"
git config --global user.name "rczhang"
cd一个目录,使用git init将该目录变为git仓库(repository),配置信息会保存在隐藏目录.git/下。注:所有的版本控制系统只能跟踪纯文本的变化。
git add file 将文件加入即将提交队列
git commit -m "sth changed" 提交入库,git commit -a -m 'sth',其中-a选项是跳过add步骤,直接从工作区提交到仓库。
git status 查看仓库状态
git diff file 查看对file做了哪些修改
git diff 默认查看工作区与暂存区的区别,git diff --cached 查看暂存区和当前commit的区别。
git log 查看历史commit日志 可以使用git log --pretty=oneline来简化输出,-p可以显示每次提交的差异,-2可以只显示最近2次提交,--stat 仅显示简要的增改行数统计。--pretty可以取很多值,其中--pretty=format可以定制格式,便于编程分析。 git log选项很多,都很有用。
git reset --hard commit_id 版本回退至commit_id所表示commit,commit_id通过git log命令查看
在git中,HEAD指向当前commit,HEAD^指向上一个commit,HEAD^^指向上上一个版本,HEAD~100指向上100个版本。
git reflog 用户操作记录日志。
git add其实就是将修改放到暂存区(stage),git commit将暂存区的内容提交到分支。git管理的是修改而不是文件。
git diff HEAD -- readme.txt命令可以查看工作区和版本库里面最新commit的区别
当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file,其实就是用版本库里的commit替换工作区版本。
当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file将暂存区修改回退到工作区,然后git checkout -- file
git rm file 删除暂存区以及工作区中的file,之后还要commit才真正删除。
git mv README.txt README等价于三条命令:
$ mv README.txt README
$ git rm README.txt
$ git add README
远程仓库github:
注册github帐号
创建sshkey: ssh-keygen -t rsa -C "[email protected]"一路默认下去
在github网站的Account settings中添加sshkey: title随便填,Key中复制主目录下.ssh/id_rsa.pub中的内容。
在github上创建一个repository(比如叫learngit),将本地仓库推送至该repository:
先cd该本地仓库
然后 git remote add origin [email protected]:roykingz/learngit.git (给远程仓库起了个名字origin,通常远程仓库默认使用该名字)。一个本地仓库可以add到多个远程仓库中,但是起的名字不能相同,比如git remote add pb git://github.com/paulboone/ticgit.git
从某个远程仓库获取本地没有的信息:git fetch pb(git fetch只拉取数据,但不自动合并到当前分支)
git pull不仅拉取远程仓库数据,还自动合并到当前分支。
最后git push -u origin master (之后的该仓库推送不再需要-u选项)
git remote 查看远程库,git remote -v查看远程库更详细的信息。
命令:git clone [email protected]:roykingz/gitskills.git可以将github的gitskills库克隆到本地。(该命令是基于ssh的,也可以使用基于http的命令:
git clone https://github.com/michaelliao/gitskills.git,该命令速度慢且后续麻烦~)
git clone本质就是在本地自动创建master分支跟踪远程的master分支。
git push origin master 向远程库推送master分支。只有别人没改动过远程仓库,推送才会成功。
git remote rename pb paul 更改远程仓库名为paul
git remote rm paul 移除远程仓库
git tag <name>为当前分支的最新commit加标签,如果想为之前的commit打标签,须指明commit id: git tag v0.9 commit_id
git show <tagname>查看该标签的信息
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:git tag -a v0.1 -m "version 0.1 released" 3628164
git tag -d v1.0删除标签
git push origin v1.0推送某标签到远程
git push origin --tags一次性推送全部尚未推送到远程的本地标签
要删除远程标签则要先删除本地标签: git tag -d v1.0,再删除远程标签:git push origin :refs/tags/v1.0
每次Git commit,就会创建一个commit object,其中包含一个树指针(指向仓库所在目录),作者及相关信息,0个或多个指向祖先对象(也就是之前的commit object)的指针
Git分支本质上仅仅是个指向 commit object的可变指针
git branch test 创建test分支(并不切换),也就是在当前的commit object上创建了一个指针
创建了分支后,就产生了一个分叉,test和master之后各自的提交各走各路互不影响,
HEAD指针就指向当前工作分支
git checkout test 切换到test分支,该命令做了两件事:改变HEAD指向test分支,将工作目录中的文件替换为test分支里最新的commit
git checkout -b dev 创建并切换到dev分支,相当于两条命令:git branch dev(创建)和git checkout dev(切换)
git branch查看当前分支。
之后的各种提交都是在这个分支上进行的,不影响master分支。
git branch -d dev 删除dev分支
切换回master分支:git checkout master,如果想将dev分支的修改或提交添加到master分支,就需要合并分支:
git merge dev 合并指定分支到当前分支,
若master分支是dev分支的直接上游,那么可以Fast forward,也就是指针直接下移到dev的最新commit上即可,
若合并的两个分支都做过修改且都提交,那么git会对比两个分支各自最新的commit和两个分支的共同祖先commit,也就是三方合并,根据对比结果:
1.若修改的是不同文件或者是相同文件的不同部分,那么git会将所有这些修改合并到一起,然后创建一个新的commit object,然后将HEAD指向该commit;
2.若修改了相同文件的相同部分,那么merge失败,可以使用git status查看失败状态,而且merge失败时,git会在该文件冲突的部分使用标记来显示出来,你需要手动编辑该文件,然后再git add和git commit(其实merge失败后,你也可以不理会冲突,直接add+commit)
分支合并默认是以fast forward模式合并的,即将master直接指向dev分支的最新commit,若之后删除分支,则会丢失该分支的其他commit信息,可以使用--no-ff选项以非fast forward的模式来合并,这样会将dev分支上的完整commit链合并到master分支,这样即使删除dev也不会丢失commit信息。
git branch --merged 查看已合并到当前分支的分支,--no-merged查看未合并到当前分支的分支
如果一个分支尚未被合并,那么删除该分支时会出错,此时可以使用强制删除:git branch -D feature-vulcan
远程分支
git clone时会在本地创建一个master分支,并创建一个origin/master指针,执行远程仓库master的当前commit
其他人向远程仓库的master分支推送后,会导致你本地的origin/master指针与远程的master分支的当前commit不一致,此时可用git fetch origin从远程取到你没有的commit,但不会跟你本地的master分支合并,这相当于fetch之后你有了两条分支:master和origin/master
git pull不仅拉取数据,还会和本地的分支合并。
git push origin dev:dev123 将本地分支dev推送到远程仓库,但分支名改为dev123
若远程仓库使用的是HTTP URL,那么每此push时都会要求输入账号密码,可以使用git config --global credential.helper cache,短时间内不再要求输入账号密码
当别人将他独有的分支(如devx)推送到远程仓库后,下次你再fetch时只会取到该分支的远程指针origin/devx,而不是该分支的副本,也就是说你再本地无法编辑该分支devx。
但是你可以将该远程分支merge到你的本地分支:git merge origin/devx
也可以在origin/devx分支的基础上新建本地分支:git checkout -b devx origin/devx,(也可以取不同的名字)这样本地devx就和远程分支建立的联系,之后的push,pull操作,git会自动判断向远程的哪个分支推送或拉取数据。
git checkout --track origin/devx效果类似上述命令,也是建立本地devx分支并跟踪origin/devx
其实git clone时就自动执行了远程与本地master分支的关联操作。
若想用已有的本地分支来跟踪刚拉下来的远程分支,可以先checkout该分支,然后git branch -u origin/devx
git branch -vv查看远程分支与本地跟踪分支的对应关系
删除远程分支git push origin :devx 该命令的意思就是将空推送到远程devx,也就是删除了,或者使用git push origin --delete devx也可以删除远程分支devx
衍合rebase
除了merge,衍合也可以将一个分支整合到另一个分支
假如有两个分支master和experiment,二者都有各自新的commit(也就是有分叉),要将experiment整合到master上,可以这样:
git checkout experiment
git rebase master
git checkout master
git merge experiment
rebase原理:https://git-scm.com/book/en/v2/Git-Branching-Rebasing
大抵就是:现将当前分支experiment独有的每个新commit跟两分支祖先commit对比,提取出每个diff保存在临时文件,然后依次将这些diffs应用到你想要整合到的master分支的当前commit上,这样就在master生成了几个新的commit,且experiment会指向最新生成的commit
也就是说二者成了一条线上的两个分支,没有了分叉,这时执行merge,只需要fast forward。
rebase和merge达到的最终合并效果是一样的,但使用衍合可以使得commit历史更加清晰。
衍合的风险:永远不要衍合那些已经推送到公共仓库的更新。因为在衍合的时候,实际上抛弃了一些现存的 commit 而创造了一些类似但不同的新 commit。
多人协作的工作模式通常是这样:
首先,可以试图用git push origin branch-name推送自己的修改;
如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream branch-name origin/branch-name。
当dev分支的任务没做完不想提交,但又要去临时处理一个Bug时,可用git stash将工作区存储起来,此时用git status查看,会发现工作区clean
git stash list查看以保存的工作区,git stash apply默认恢复最新加入list的工作现场,也可以为其制定恢复某个现场,如git stash apply stash@{2},然后用
git stash drop从list中删除该现场。也可以用git stash pop一次完成上述两步,但不可以为pop指定某个现场。
在git工作区根目录下创建一个.gitignore文件,并将某些文件的名字或相应的格式写进去,那么commit时会忽略这些文件。在https://github.com/github/gitignore上有各种开发语言对应的.gitignore文件模板。
创建了.gitignore文件后要commit才会生效。
可以为一个字符串配置一个别名,这通常用于命令太长,我们可以配置一个短一点的别名
git config --global alias.st status 为status配置别名st,以后git st 就等效与git status。--global选项表明该别名对本机的所有仓库都生效,如果没有--global选项则仅对当前仓库生效。
如果要取消这些别名设置,需要删除配置文件中[alias]下对应的别名,全局配置文件是主目录下的隐藏文件.gitconfig,仓库的配置文件是.git/config
搭建一个git服务器步骤(假设服务器运行ubuntu系统):
第一步,安装git:
sudo apt-get install git
第二步,创建一个git用户,用来运行git服务:
sudo adduser git
第三步,创建证书登录:
收集所有需要登录的用户的公钥,就是他们自己的id_rsa.pub文件,把所有公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。
第四步,初始化Git仓库:
先选定一个目录作为Git仓库,假定是/srv/sample.git,在/srv目录下输入命令:
sudo git init --bare sample.git
sudo chown -R git:git sample.git
第五步,禁用shell登录:
出于安全考虑,第二步创建的git用户不允许登录shell,这可以通过编辑/etc/passwd文件完成。找到类似下面的一行:
git:x:1001:1001:,,,:/home/git:/bin/bash
改为:
git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell
第六步,克隆远程仓库:
现在,可以通过git clone命令克隆远程仓库了,在各自的电脑上运行:
git clone git@server:/srv/sample.git