目录

git

快速入门

克隆仓库

git clone http://git.oschina.net/yiibai/git-start.git

//如果想在克隆远程仓库的时候,自定义本地仓库的名字,可以使用如下命令:
git clone http://git.oschina.net/yiibai/git-start.git mygit-start

在现有目录中初始化仓库

如果不克隆现有的仓库,而是打算使用 Git 来对现有的项目进行管理。假设有一个项目的目录是:D:\worksp\git_sample,只需要进入该项目的目录并输入:

git init

更新提交到仓库

工作目录下的每一个文件都不外乎这两种状态:已跟踪或未跟踪。 已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后,它们的状态可能处于未修改,已修改或已放入暂存区。 工作目录中除已跟踪文件以外的所有其它文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有放入暂存区。 初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态

./pic5.png

检查当前文件状态

git status

git status -s 命令或 git status –short 命令,将得到一种更为紧凑的格式输出。

跟踪新文件

git add mytext.txt
git add .

忽略文件

文件 .gitignore 的格式规范如下:

  • 所有空行或者以 # 开头的行都会被 Git 忽略。
  • 可以使用标准的 glob 模式匹配。
  • 匹配模式可以以(/)开头防止递归。
  • 匹配模式可以以(/)结尾指定目录。
  • 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反

所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。 星号()匹配零个或多个任意字符;[abc]匹配任何一个列在方括号中的字符(这个例子要么匹配一个字符 a,要么匹配一个字符 b,要么匹配一个字符 c);问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。 使用两个星号() 表示匹配任意中间目录,比如a/**/z 可以匹配 a/z, a/b/z 或 a/b/c/z等。

查看修改内容

git diff

提交

把暂存区的内容提交前先确定文件是否都添加到暂存区内了

Git commit -m "提交信息"

Git commit -a 参数可以把变化的文件先添加到暂存区并提交,换句话说Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add,新增的为追踪的不行。

移除文件

git rm会删除本地文件,推送后也会把仓库里的删除。 如果文件已经添加到缓存区了,那么git rm命令是删除不了的 可以使用下面两个命令:

git rm -f 文件名 // 缓存区和工作目录的都会删除
git rm --cached 文件名 // 只删除缓存区,工作目录的保留

查看提交历史

git log 会按提交时间列出所有的更新,最近的更新排在最上面。

Git log -p // 用来显示每次提交的内容差异

另外一个常用的选项是 –pretty。 这个选项可以指定使用不同于默认格式的方式展示提交历史。 这个选项有一些内建的子选项供你使用。 比如用 oneline 将每个提交放在一行显示,查看的提交数很大时非常有用。 另外还有 short,full 和 fuller 可以用,展示的信息或多或少有些不同

git log --pretty=oneline

远程仓库

可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读写。 与他人协作涉及管理远程仓库以及根据需要推送或拉取数据。

查看远程仓库

git remote 命令。 它会列出你指定的每一个远程服务器的简写。 如果已经克隆了自己的仓库,那么至少应该能看到 origin - 这是 Git 给你克隆的仓库服务器的默认名字。 也可以指定选项 -v,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。

添加远程仓库

运行 git remote add 添加一个新的远程 Git 仓库,同时指定一个可以轻松引用的简写

从远程仓库中抓取与拉取

就如刚才所见,从远程仓库中获得数据,可以执行:

git fetch [remote-name]

这个命令会访问远程仓库,从中拉取所有还没有的数据。执行完成后,将会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。 必须注意 git fetch 命令会将数据拉取到本地仓库 - 它并不会自动合并或修改当前的工作

如果你有一个分支设置为跟踪一个远程分支,可以使用 git pull 命令来自动的抓取然后合并远程分支到当前分支。 这对你来说可能是一个更简单或更舒服的工作流程;默认情况下,git clone 命令会自动设置本地 master 分支跟踪克隆的远程仓库的 master。

推送到远程仓库

git push [remote-name] [branch-name]。 当你想要将 master 分支推送到 origin 服务器时(再次说明,克隆时通常会自动帮你设置好那两个名字)

git push origin master

只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。 当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。 你必须先将他们的工作拉取下来并将其合并进你的工作后才能推送。

查看远程仓库

如果想要查看某一个远程仓库的更多信息,可以使用 git remote show [remote-name] 命令

git remote show origin
* remote origin
  Fetch URL: http://git.oschina.net/yiibai/git-start.git
  Push  URL: http://git.oschina.net/yiibai/git-start.git
  HEAD branch: master
  Remote branch:
    master tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (fast-forwardable)

它同样会列出远程仓库的 URL 与跟踪分支的信息。 这些信息非常有用,它告诉你正处于 master 分支,并且如果运行 git pull,就会抓取所有的远程引用,然后将远程 master 分支合并到本地 master 分支。 它也会列出拉取到的所有远程引用。 它也同样地列出了哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除了,还有当你执行 git pull 时哪些分支会自动合并。

远程仓库的移除与重命名

如果想要重命名引用的名字可以运行 git remote rename 去修改一个远程仓库的简写名。 例如,想要将 gs 重命名为 newgs,可以用 git remote rename 这样做:

git remote rename gs newgs

值得注意的是这同样也会修改你的远程分支名字。 那些过去引用 gs/master 的现在会引用 newgs/master。

删除远程库: git remote rm newgs

命令详解

git add

git add 命令。 这是个多功能命令:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。 将这个命令理解为“添加内容到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。

查看更改记录

git log //查看更改记录
git show 版本号 // 查看某次提交详细信息

git rm

删除了文件,也属于文件变化,可以使用:

git add 文件 //或者git rm 文件
git commit

来提交变化。 如果想撤销删除,可以参考上面的撤销工作区、暂存区内容。

git rm –cached newfile_name 就可以将这个文件从暂存区移除掉,但是在工作区里没有消失,如果不加 –cached 参数,就会从工作区和版本库暂存区同时删除,相当于执行了 rm newfile_name 和 git add new_file 两条命令。

git pull

执行git pull命令以将其本地存储库与远程存储库同步。

拉取远程代码时别人已经提的可能会与你的冲突 打开冲突文件,eg:

a = 10

b = 20
<<<<<<< HEAD
c = a + b
print("The value of c is  ", c)

def mul(a, b):
    return (a * b)
=======

def sum(a, b):
    return (a+b)

c = sum(a, b)
print("The value of c is  ", c)
>>>>>>> 01c54624879782e4657dd6c166ce8818f19e8251

并发现其它开发人员的提交的详细信息,提交ID为:01c54624879782e4657dd6c166ce8818f19e8251

解决完冲突,把冲突文件重新add 一次,再重新push一次,

暂存stash

代码写到一半需要切换分支,但是写到一半提交上去又不合适,可以先把改变暂存起来,等后面再还原。暂存起来的分支可以在其他分支还原。

git stash // 把当前分支的改变暂存
git stash list // 命令来查看已存在更改的列表。
git stash pop // 命令即可从堆栈中删除更改并将其放置在当前工作目录中
git stash show [<stash>] // 查看某次暂存内容
git stash drop [-q|--quiet] [<stash>] // 删除暂存
git stash apply [-q|--quiet] [<stash>] // 还原暂存
git stash clear 
git stash save [<message>] // 带信息的暂存

checkout

Git checkout用于切换分支或恢复文件。

Git checkout -b dev origin/dev 生成一个新的dev分支,远程分支对应origin/dev
Git branch -D 分支名 删除本地分支(不管有没有合并)
Git checkout 文件 // 恢复工作区修改
Git checkout head 文件 // 恢复已经提交到暂存区的修改,工作区也不会保留修改

git commit

–amend 修改当前最新的提交,可以修改提交信息、文件。注意,只能改当前最新的那次,如果想改以前的,那就麻烦一点,需要先回到那个版本才行。 eg: Git commit –amend -m “这才是正确的,刚才那次是错误的”

Git commit -a -m "xx" // 添加到暂存区并提交文件

标准的git commit分为3个部分,header、body、footer,后两个一般不用。 heder结构为 type(scope):subject

Type一般有几种类型:

  • feat:新功能
  • fix:修复bug
  • style:格式
  • refactor:代码重构
  • chore:项目构建

比如fix(pay):修复了xxbug

git merge

Git merge dev // 从dev合并到当前分支

合并后可能会有冲突,如果想放弃合并回到刚才,使用git merger –abort命令。

git tag

使用git tag命令来标记当前HEAD指针。在创建标签时需要提供-a选项的标签名称,并提供带-m选项的标签消息。

Git tag -a 'v1.0.0' -m "v1.0.0 tag"

如果要标记特定提交,则使用相应的COMMIT ID而不是HEAD指针。使用以下命令将标签推送到远程存储库。

Git tag -a 'v1.0.0' -m "v1.0.0 tag" 1852b48f8d1d86bce1694f99039833e3eaa55bc9
Git push origin tag v1.0.0 // 推送tag至远程
Git show v1.0.0 // 查看tag详细信息
Git tag -d v1.0.0 // 删除标签

git config

git的配置分为全局和各仓库的单独配置。 查看配置 git config –list 如果当前目录是git仓库就能看到该仓库的单独配置。 git config –global user.name配置全局用户名 git config –global user.email配置全局邮箱

git config –local user.name在仓库地址路径配置该仓库的特定用户名,如果不指定–local默认也是该效果,配置邮箱等信息同理。

如果不对各仓库配置自己的邮箱,可能会造成邮箱不必要的暴露。

git各区

git本地仓库

各区之间数据状态转换流程

./pic5.png

工作区和暂存区

我们先来理解下Git 工作区、暂存区和版本库概念

  • 工作区:就是你在电脑里能看到的目录,工作区就是项目所在的目录

  • 暂存区:英文叫stage, 或index。一般存放在"git目录"下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。文件修改后,用add命令放到暂存区,然后在通过commit命令放到分支上。每次的修改只有先add到暂存区才能被提交。

  • 版本库:工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

总结起来一个文件的状态通常可以分为:

不受版本控制的 untracked 状态 受版本控制并且已修改的 modified 状态 受版本控制已修改并提交到暂存区的 staged 状态 从暂存区已经提交到本地仓库的 committed 状态 提交到本地仓库未修改或者从远程仓库克隆下来的 unmodified 状态

Git回退命令

git checkout

这个命令又出现了,上次是总结 git branch 分支操作的时候,git checkout 可以用来新建或者切换分支,这次总结回退版本的命令,git checkout 也可以用来回退文件版本,很神奇吧。

其实这个命令的作用就是它单词的本义——检出,他的常用操作也取自这个意思,比如 git checkout branch_name 切换分支操作,实际上就是把指定分支在仓库中对应的所有文件检出来覆盖当前工作区,最终表现就是切换了分支。

而针对于文件的检出可以使用 git checkout – file_name,当不指定 commit id 就是将暂存区的内容恢复到工作区,也就可以达到回退本地修改的作用。

不过,这个身兼数职的 git checkout 命令现在可以轻松一些了,从 Git 2.23 版本开始引入了两个新的命令: git switch 用来切换分支,git restore用来还原工作区的文件

git restore

这个命令是 Git 2.23 版本之后新加的,用来分担之前 git checkout 命令的功能, git restore –staged 从暂存区撤销,回到工作区,就是git add 的逆操作。 git restore 从工作区撤销,就是放弃更改

git reset

reset 重新设置的意思,其实就是用来设置分支的头部指向,当进行了一系列的提交之后,忽然发现最近的几次提交有问题,想从提交记录中删除,这是就会用到 git reset 命令,这个命令后面跟 commit id,表示当前分支回退到这个 commit id 对应的状态,之后的日志记录被删除,工作区中的文件状态根据参数的不同会恢复到不同的状态。

–soft: 被回退的那些版本的修改会被放在暂存区,可以再次提交。

–mixed: 默认选项,被回退的那些版本的修改会放在工作目录,可以先加到暂存区,然后再提交。

–hard: 被回退的那些版本的修改会直接舍弃,好像它们没有来过一样。

这样来看,git reset 命令好像是用来回退版本的,但是如果使用 git rest HEAD file_name 命令就可以将一个文件回退到 HEAD 指向版本所对应的状态,其实就是当前版本库中的状态,也就相当于还原了本地的修改。

git每次commit都是一个快照,方便以后查找或恢复。 在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。

git reset –hard HEAD^ 这样就回到了上个快照,在查看git log发现刚提交的那条记录不在了。当然如果你还能记住刚才那个最新的快照id还是可以回去的。

如果记不住了就再也回不去了吗? 当然不是,Git提供了一个命令git reflog用来记录你的每一次命令。 然后 git reset –hard 快照id 就可以再回来啦。

git revert 也可以回退一个已经提交到仓库的版本 git revert 版本号 即可。会生成一个提交记录,提交记录明确记录着revert 的是哪个版本,原来的版本记录都是在的。如果对revert再revert一次,那就等于负负得正,回到原来的版本中。 注意,revert针对最后一次的commit比较方便,如果想revert上上一次或更前面的,就会冲突。

如果修改已经push到远程了,需要本地回退后,在push一次

merge和rebase

git rebase和git merge区别: git rebase后变成了一个线,且不会生成新的合并节点。 git merge后两个分支记录依然各自存在,会生成新的合并节点。 git merge冲突后需要手动add并commit,git rebase自动生成一次提交。

当完成一个特性的开发并将其合并到 master 分支时,我们有两种方式:git merge 和 git rebase。 看merge图解:

./pic1.png

./pic2.png

rebase图解:

./pic3.png

./pic4.png

我们可以看到,merge后会产生一个多余的commit,但是每个提交记录先后顺序不变。

rebase没有生产新的commit,把两个分支合成一个线性的记录,可读性更强,但是提交记录的先后顺序变了。

总结:

当需要保留详细的合并信息的时候建议使用git merge,特别是需要将分支合并进入master分支时;当发现自己修改某个功能时,频繁进行了git commit提交时,发现其实过多的提交信息没有必要时,可以尝试git rebase。