http://gitforwindows.org/
本处只讲重点,其它一律点击next
在选择安装路径时候,这个看你自己
选择安装组件:
一般最后两个不勾选,因为最后一个选项打钩的话,需要下载windows Terminal配合Git Bash使用。
这里看你自己觉得需不需要在开始菜单栏或者桌面创建Git图标
选择默认编辑器,Git 安装程序里面内置了 10 种编辑器供你挑选,比如 Atom、Notepad、Notepad++、Sublime Text、Visual Studio Code、Vim 等等,默认的是 Vim ,选择 Vim 后可以直接进行到下一步,但是 Vim 是纯命令行,操作有点难度,需要学习。如果选其他编辑器,则还需要去其官网安装后才能进行下一步。
直接点击Vim跳过
决定初始化新项目(仓库)的主干名字:
第一种是默认master,未来也可以修改成其它名字。第二种我们自行决定,默认为main。当然也可以改其它名字。
调整path环境变量
第一种是仅从 Git Bash 使用 Git。这个的意思就是你只能通过 Git 安装后的 Git Bash 来使用 Git ,其他的什么命令提示符啊等第三方软件都不行。
第二种是从命令行以及第三方软件进行 Git。这个就是在第一种基础上进行第三方支持,你将能够从 Git Bash,命令提示符(cmd) 和 Windows PowerShell 以及可以从 Windows 系统环境变量中寻找 Git 的任何第三方软件中使用 Git。推荐使用这个。
第三种是从命令提示符使用 Git 和可选的 Unix 工具。选择这种将覆盖 Windows 工具,如 “ find 和 sort ”。只有在了解其含义后才使用此选项。一句话,适合比较懂的人折腾。
选择SSH执行文件:
解释:
Use bundled OpenSSH
This uses ssh. exe that comes with Git.
使用捆绑的 OpenSSH
这使用的 ssh.exe 是 Git 自带的
Use (Tortoise) Plink
To use PuTTY, specify the path to an existing copy of (Tortoise) Plink.exe
Set ssh. variant for Tortoise Plink
使用 TortoisePlink (注,这是一个软件)
要使用 PuTTY,请指定 TortoisePlink.exe 的现有副本的路径
为 TortoisePlink 设置 ssh.variant
Use external OpenSSH
NEW! This uses an external ssh. exe. Git will not install its own OpenSSH
(and related) binaries but use them as found on the PATH.
使用外部 OpenSSH
新!这使用外部 ssh.exe 文件。
Git 不会安装自己的 OpenSSH(和相关)二进制文件,而是使用在环境变量 PATH 中找到的它们。
选择HTTPS传输后端
这两种选项的区别在于,如果在企业当中,这种代码内容传输需要加密,则走安全通道。因此选择第二种。如果是普通个人用户,选择前者即可。
配置行尾符号转换:
这三种选择分别是:
签出 Windows 样式,提交 Unix 样式的行结尾。
按原样签出,提交Unix样式的行结尾。
按原样签出,按原样提交。
这里需要注意
GitHub 中公开的代码大部分都是以 Mac 或 Linux 中的 LF(Line Feed)换行。然而,由于 Windows 中是以 CRLF(Carriage Return+ Line Feed)换行的,所以在非对应的编辑器中将不能正常显示。
Git 可以通过设置自动转换这些换行符。使用 Windows 环境的各位,请选择推荐的 “Checkout Windows-style,commit Unix-style line endings” 选项。换行符在签出时会自动转换为 CRLF,在提交时则会自动转换为 LF .
配置终端模拟器与Git Bash一起使用
选择第一种。虽然对Git没什么大帮助。
选择默认的拉代码方式
翻译:
ODefault(fast-forward or merge)
This is the standard behavior ofgit pull": fast-forward the current branch to
the fetched branch when possible, otherwise create a merge commit.
默认(快进或合并)
这是 “git pull” 的标准行为:在可能的情况下将 当前分支 快进到 获取的分支,否则创建合并提交。
ORebase Rebase the current branch onto the fetched branch. If there are no local
commits to rebase, this is equivalent to a fast-forward.
变基将当前分支变基到获取的分支上。如果没有本地提交要变基,则等同于快进。
Oonly ever fast-forward
Fast-forward to the fetched branch. Fail if that is not possible.
只能快进快进到获取的分支。如果不可能,则失败。
第一种 git pull = git fetch + git merge
第二种 git pull = git fetch + git rebase
第三种 git pull = git fetch
此处一般默认选择第一项。
git pull 只是拉取远程分支并与本地分支合并,而 git fetch 只是拉取远程分支,怎么合并,选择 merge 还是 rebase ,可以再做选择。
凭证选择:
第一个选项是提供登录凭证帮助的,Git 有时需要用户的凭据才能执行操作;例如,可能需要输入用户名和密码才能通过 HTTP 访问远程存储库(GitHub,GItLab 等等)。
启用文件系统缓存就是将批量读取文件系统数据并将其缓存在内存中以进行某些操作,可以显著提升性能。这个选项默认开启。
启用符号链接 ,符号链接是一类特殊的文件, 其包含有一条以绝对路径或者相对路径的形式指向其它文件或者目录的引用,类似于 Windows 的快捷方式,不完全等同 类Unix(如 Linux) 下的 符号链接。因为该功能的支持需要一些条件,所以默认不开启。
在配置完成之后,打开cmd,输入如下代码:
$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"
这是对你的机器给远程的git做一个凭证。
注意git config命令的–global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。
git add [fileName]
git add . //添加所有文件
git commit -m "[message]" //message为提交时候说明信息
git status //查看仓库当前状态
git diff [fileName] //查看具体修改内容、位置
git log [--pretty=oneline]//查看修改历史记录
git reset [--hard] HEAD^ //回退版本到本地仓库上一个版本
此处进行一下说明:
首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交1094adb…(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。
还可以使用版本号回退:
git reset --hard [Hex Version Num]
查找之前输入过的命令
git reflog
利用此找到任意版本号可以进行任意回退。
丢弃工作区的修改(其实这个命令是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。):
git checkout --[fileName]
//备注,不能丢掉fileName选项,否则就是切换分支命令
暂存区的文件,也可以回退到工作区。这个时候是把修改也一起原封不动退回工作区。
git reset [HEAD] [fileName]
当我们用HEAD选项时候,为最新版本的回退。
但是如果push到远程仓库中,也是有办法回退的,后面讲到。
暂存区删除文件:
git rm [fileName]
如果需要用远程仓库,首先需要设置一下传输时的SSH加密,需要进行一定的配置:
ssh-keygen -t rsa -C "[your email]"
一路回车。
之后可以在你的系统用户文件夹里面找到.ssh目录,里面有id_rsa和id_rsa.pub文件。id_rsa是私钥,不能泄露。而id_rsa.pub是公钥,可以放心告诉任何人。
然后登录github或者gitee,点开账户设置相应属性,添加ssh key。
添加后点击确定,一般是要输入密码。
如何创建远程仓库?
在github或者gitee创建一个远程仓库
以gitee为例
千万不要用模板创建!!!
然后在本地项目中,输入如下指令:
git remote add origin [your remote library url]
然后推送(第一次推送必须这么写)
git push -u origin master
由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
从现在起,只要本地作了提交,就可以通过命令:
git push origin master
删除远程库:
//先查看远程信息,确认之后再删除(实际应该叫解绑)
git remote -v
//然后根据名字删除(实际应该叫解绑)
git remote rm [remote library url]
克隆一个本地库
git clone [your remote library url]
克隆仓库之后,需要让对方添加你的用户到合作开发组里面,才能关联此远程库并进行推送。否则你就算克隆下来,也推送不了。
git的每次提交都被串成时间线,而HEAD为指针,指向分支。而分支又是一个指针,指向提交点。
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
当前工作区文件没有任何变化,但是指针多出来了dev。且HEAD指向dev。
此时新提交一次,就是移动dev指针了。而master指针不变,于是就变成下面所示:
假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
所以Git合并分支也很快!就改改指针,工作区内容也不变!
合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:
分支相关命令:
git checkout -b [branchName] //创建并切换
//相当于如下
git branch [branchName]
git checkout [branchName]
git branch //查看当前分支命令
git branch命令会列出所有分支,当前分支前面会标一个*号。
合并分支
git merge [branchName]
不过checkout容易搞混,最好用switch
git switch -c [branchName] //切换并创建
//或
git switch [branchName]
分支的冲突问题
如图所示,这分别为第三个提交为基础,生长出来的不同分支的提交。这种情况下,如果改动了相同文件,再进行合并,那就会产生冲突。
git status
可以查看具体是什么冲突
此时需要手动进行修改,然后对其进行add、commit提交,变成如图所示:
git log
可查看当前分支合并情况
git log --graph --pretty=oneline --abbrev-commit
一般git采用fast forward方式。上面如果直接删除feature1分支会丢掉分支信息。如果强制禁用fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
例如如下情况:
切换dev分支,然后修改test.txt文件。并提交一个新的commit。
再切换回master,然后合并dev分支。
git merge --no-ff -m "[your merge information]" dev
如图所示效果
相当于直接在dev上面再进行一次提交。然后合并。
提点建议
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
当然,最好在工作的时候,团队分工修改不同文件。千万不要去乱动不属于你的工作范围的文件或者代码。否则合并时候会产生冲突。
Bug分支
在开发过程中,手头上事情还没干完,但是要去临时修bug,解决办法如下:
1.工作现场存储
git stash
2.从master拉分支
git checkout master
git checkout -b issue-101
3.修复bug,提交
git add .
git commit -m "xxx"
4.切换master分支,然后合并,最后删除issue-101分支
git switch master
git merge --no-ff -m "xxxx" issue-101
5.回到dev分支继续干活
git switch dev
git status
此时发现工作区干净,查看工作区现场
git stash list
恢复
git stash pop
//或
git stash apply
git stash drop
恢复指定的stash,在apply后面添加指定的现场号即可。
到这里,dev上的bug仍然没有被修复,于是我们需要复制修bug那个提交到dev分支上来。这里使用git
的cherry-pick
命令
首先需要找到提交的提交代号,复制,切换回dev分支,然后输入如下命令
git cherry-pick [code]
这时候系统自动给dev分支进行了一次提交,不用我们手动重复一遍。
Feature分支
添加新功能的时候,有一些实验性代码,不能把主分支搞乱,需要实验之后提交。因此,建立一个feature分支,在上面开发完成之后合并,删除该分支。
此时如果不需要这个分支了,就用强制删除
git branch -D [branchName]
推送时指定分支
git push origin [branchName]
多人协作问题
先普及一个命令:
这是从远程创建dev分支。因为在clone的时候,只能看到本地的master分支。
git checkout -b dev origin/dev
当多人写作时候,将各自不同修改推送到远程dev分支的时候,如果两者修改了同一个文件,并且提交的时候,就会产生冲突。
此时,按照git提示,运行git pull
命令。然后本地合并解决冲突再推送。但是直接pull会导致失败。因此需要:
git branch --set-upstream-to=origin/dev dev
然后再运行git pull
到这,git pull
是成功的,但是合并会有冲突,需要手动解决。解决办法见前面分支管理中的解决冲突。
解决完成,再提交。再拉下来,然后进行自己的工作。
多人协作问题总结:
1.首先,可以试图用git push origin [branch-name]
推送自己的修改;
2.如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
3.如果合并有冲突,则解决冲突,并在本地提交;
4.没有冲突或者解决掉冲突后,再用git push origin [branch-name]
推送就能成功!
如果git pull
提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to [branch-name] origin/[branch-name]
。
git rebase:
这个操作称之为变基操作。
看例子:
此时如果需要合并到master分支,该怎么做?
那就是:
git checkout feature
git rebase master
//等价于
git rebase master feature
feature:待变基分支、当前分支
master:基分支、目标分支
结合例子解释:当在feature分支上执行git rebase master时,git会从master和featuer的共同祖先B开始提取feature分支上的修改,也就是C和D两个提交,先提取到。然后将feature分支指向master分支的最新提交上,也就是M。最后把提取的C和D接到M后面,但这个过程是删除原来的C和D,生成新的C’和D’,他们的提交内容一样,但commit id不同。feature自然最后也是指向D’。
通俗解释(重要!!):rebase,变基,可以直接理解为改变基底。feature分支是基于master分支的B拉出来的分支,feature的基底是B。而master在B之后有新的提交,就相当于此时要用master上新的提交来作为feature分支的新基底。实际操作为把B之后feature的提交存下来,然后删掉原来这些提交,再找到master的最新提交位置,把存下来的提交再接上去(新节点新commit id),如此feature分支的基底就相当于变成了M而不是原来的B了。(注意,如果master上在B以后没有新提交,那么就还是用原来的B作为基,rebase操作相当于无效,此时和git merge就基本没区别了,差异只在于git merge会多一条记录Merge操作的提交记录)
但是大部分公司一般禁用rebase,因为这样就很难查到之前的具体提交记录了。此处要注意!!!
1.先切换到要打标签的分支上
2.敲命令
git tag [name]
即可打上标签
默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?
方法是找到历史提交的commit id,然后打上就可以了
注意,标签不是按时间顺序列出,而是按字母排序的。可以用git show [tagname]
查看标签信息
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字
删除标签
git tag -d [tagName]
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
标签推送到远程:
git push origin [tagname]
git push origin --tags//一次推送所有
如果不幸推送到远程,先要从本地删除,再删除远程
git tag -d [tagName]
git push origin :refs/tags/[tagName]
前提:需要一台Linux服务器。这样就能不公开源码,然后也能团队协作更高效了。
安装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
Git就会创建一个裸仓库,裸仓库没有工作区,因为服务器上的Git仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的Git仓库通常都以.git结尾。然后,把owner改为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用户可以正常通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每次一登录就自动退出。
克隆远程仓库
现在,可以通过git clone命令克隆远程仓库了
管理公钥
如果团队很小,把每个人的公钥收集起来放到服务器的/home/git/.ssh/authorized_keys文件里就是可行的。如果团队有几百号人,就没法这么玩了,这时,可以用Gitosis来管理公钥。
这里我们不介绍怎么玩Gitosis了,几百号人的团队基本都在500强了,相信找个高水平的Linux管理员问题不大。
管理权限
有很多不但视源代码如生命,而且视员工为窃贼的公司,会在版本控制系统里设置一套完善的权限控制,每个人是否有读写权限会精确到每个分支甚至每个目录下。因为Git是为Linux源代码托管而开发的,所以Git也继承了开源社区的精神,不支持权限控制。不过,因为Git支持钩子(hook),所以,可以在服务器端编写一系列脚本来控制提交等操作,达到权限控制的目的。Gitolite就是这个工具。
官网下载地址:https://www.sourcetreeapp.com/
提交代码
我们双击learngit这个本地库,SourceTree会打开另一个窗口,展示这个Git库的当前所有分支以及文件状态。选择左侧面板的“WORKSPACE”-“File status”,右侧会列出当前已修改的文件(Unstaged files)
选中某个文件,该文件就自动添加到“Staged files”,实际上是执行了git add README.md命令
然后,我们在下方输入Commit描述,点击“Commit”,就完成了一个本地提交
分支操作
在左侧面板的“BRANCHES”下,列出了当前本地库的所有分支。当前分支会加粗并用○标记。要切换分支,我们只需要选择该分支,例如master,然后点击右键,在弹出菜单中选择“Checkout master”,实际上是执行命令git checkout master
要合并分支,同样选择待合并分支,例如dev,然后点击右键,在弹出菜单中选择“Merge dev into master”,实际上是执行命令git merge dev
推送至远程仓库
在SourceTree的工具栏上,分别有Pull和Push,分别对应命令git pull和git push,只需注意本地和远程分支的名称要对应起来,使用时十分简单。
注意到使用SourceTree时,我们只是省下了敲命令的麻烦,SourceTree本身还是通过Git命令来执行任何操作。如果操作失败,SourceTree会自动显示执行的Git命令以及错误信息,我们可以通过Git返回的错误信息知道出错的原因: