本地使用

以下是我的一些日常操作。

(1) 创建版本库

# cd /proj

# git init

Initialized empty Git repository in /proj/.git/

(2) 查看状态

# git status

staged:文件被暂存了

modified, unstaged:文件被修改了但是没有被暂存

untracked:文件没有被跟踪

(3) 初次提交

# git add * //首先提交到index

# git commit -m "initial import" //再提交到本地仓库

和svn的一步到位不同,git是分成两步的。

(4) 显示提交内容

# git show 9b1796 //查看提交的具体内容

# git show -s 9b1796 //显示提交的概要

# git show 9b1796 --shortstat // 显示提交的改动量

# git ls-tree 9b1796 //查看commit指向的tree包含的tree和blob

# git cat-file -p 9b1796 //查看提交的基本信息

(5) 清除暂存区

如果你后悔了,可以清除index中的内容。

# git reset HEAD <file>

注意,这个时候暂存区的内容被清除了,但工作目录内容不变。

(6) 建立一个裸仓库

裸仓库(bare repository)相当于SVN的服务器。

proj是我们自己的本地仓库,现在要建立一个可供远程访问的裸仓库proj.git。

# git clone --bare proj proj.git

裸仓库proj.git里面只有git目录包含的文件,没有工作目录。

(7) 克隆一个仓库

可以把公共Git仓库复制一份到本地使用,使用ssh来clone一个仓库。

# git clone user@IP:/path/proj.git proj

当然git也支持其它协议,比如http和git。

(8) 查看日志

日志是版本控制中非常重要的一部分,它描述了你的所有操作。

# git log // 显示提交日志

# git log -p // 显示日志,并显示提交内容

# git log file // 只显示有修改file的commit

# git log --stat // 显示统计信息

# git log --graph // 用ASCII字符画图显示提交历史线,这个功能很不错

(9) 比较变更

我们经常要查看对工作目录的内容作了哪些修改,以确定这些修改是否合理。

# git diff --cached // 查看将要提交的内容,这时候的比较的是:暂存区 vs HEAD

# git diff // 当前你所做的,但是没有提交到暂存区的修改,也就是这时候比较:前工作目录 vs HEAD

# git diff file // 比较单个文件

# git diff commit1:path/file commit2:path/file // 比较不同提交中的同一个文件

# git diff --stat // 查看统计信息

(10) 一步提交

如果你嫌提交分两步走太麻烦,可以跳过提交到暂存区的步骤git add,直接提交到本地仓库。

# git commit -am "log"

自动把所有内容被修改的文件(不包括新创建的未跟踪文件)都添加到暂存区中,并且同时把它们提交。

(11) 注释技巧

commit注释最好以一行短句作为开头,来简要描述一下这次commit所做的修改(最好不要超过50个字符)。

然后空一行,再把详细注释写清楚。这样可以很方便的用工具把commit注释变成email通知,第一行作为标题,

剩下的部分就作为email的正文。

(12) 提交到暂存区

git add 不但用来添加不在版本控制中的文件,也用于添加已在版本控制中但是刚修改过的文件,在这两种情况下,

git都会获得当前文件的快照并且把内容暂存(stage)到暂存区(index)中,为下一次commit做好准备。

(13) 分支的创建和删除

项目一般不会只有一个主分支,通常情况下还会有其它分支。

# git branch // 得到当前仓库中存在的所有分支列表,星号表示当前所在分支

# git branch new // 创建new分支

# git checkout new // 切换到new分支上

# git checkout -b new // 创建new分支并切换到new分支上

# git branch -d new // 删除已被合并的new分支

# git branch -D new // 强制删除分支new

(14) 合并分支

分支一般用于开发新feature,当开发完成后就要合并到主分支了。

# git diff new master // 从new到master所做的变化

# git diff master new // 从master到new所做的变化

# git diff new // 等价于git diff new master

# git merge new // 实际上是把git diff master new添加到master中

合并分支的提交会带有merge信息(指明合并了哪两个分支),SVN上则无此功能!

(15) 解决冲突

多人开发的项目,提交时很肯能发现有冲突。

git status显示unmerged paths。

这是一个冲突文件示例:

1 <<<<<<< HEAD
  2 This is file in master
  3 =======
  4 This is a test file for branch.
  5 >>>>>>> test

编辑冲突文件来解决冲突,比如我们保留test的修改。

然后再重新:

# git add file

# git commit -m "merge master and test"

(16) 回到最新提交

签出master分支时,工作目录是master分支的最新提交。

# git checkout master

(17) 匿名分支

可以使用匿名分支回到过去的某个提交中,进行修改,最后把修改合并到主分支中。

# git checkout 1b8754 // 切换到某一个commit

这时候git branch会显示 *(no branch),切换到匿名分支。

在匿名分支上所做的修改,master或其它分支是看不到的。

所以我们需要为匿名分支命名:

# git branch develop

# git checkout develop

或者直接

# git checkout -b develop

这样匿名分支就成为develop分支。

然后我们切换回master分支,并合并develop中的修改:

# git checkout master

# git diff master develop

# git merge develop

好了,现在master分支就包含develop分支上的修改。

最后可以删除develop分支:

# git branch -d develop

(18) 重命名和删除

# git mv file new // 重命名文件

# git rm -f file // 删除文件

# git branch -m oldbranch newbranch // 重命名分支

(19) 抹除提交

如果你想要放弃某个提交之后的所有修改,可以用git reset。

# git reset --hard 1b8754

加载此commit并抹除此提交之后的所有提交。

(20) 显示当前分支和提交

# git branch -v // 显示当前分支、当前提交

(21) 修改之前提交

可以修改以前的提交,并且修改后在以后的版本中也有效,Git世界里是有后悔药的。

# git rebase 7daa17^ --interactive // 退回到要修改的7daa17的前一个提交

执行后,git会调用vi显示7daa17到最新提交的记录,把我们要修改的7daa17的pick改成edit。

进行修改后:

# git add <file>

# git commit --amend // 修改这个commit

# git rebase --continue // 提交修改后的commit并且返回到原来的head处

取消修改操作:

# git rebase --abort

(22) 忽略文件

编辑.gitignore,可以指定要忽略哪些目录和文件,这些文件就对Git隐形了。

比如指定忽略proj下的patches目录:

/patches

(23) 标签

git中有两种主要的标签:轻量级标签(lightweight)和带注释的标签(annotated)。

轻量级标签是针对某个特定提交的指针,带注释的标签是git仓库中的对象,包含更多信息。

轻量级标签:

# git tag v1.0 // 把最新commit做成v1.0标签

带注释的标签:

# git tag -a v1.0 -m "describe what is v1.0" // 也可以不指定-m,直接用vi编辑

显示标签列表:

# git tag -l

删除标签:

# git tag -d v1.0

显示某个标签的内容:

# git show v1.0

(24) 查看包含某个commit的最早版本

查看包含某个提交的最早版本。

# git describe --contains <commit id>

(25) 放弃工作目录中的修改

修改了工作目录中的文件,还没提交到暂存区时,想把工作目录文件复原。

# git checkout -- <file>

(26) 获取分支中的某个文件

你在一个分支中工作,但是像获取另一个分支中的某个文件。

# git checkout <branch> -- <file>

(27) 把一个分支的所有更新应用到另一个分支

假如有两个分支A和B,它们在提交m处分叉了。

现在B更新到了n,要把B分支从m到n的提交也应用到A,这就是使用场景。

# git rebase master branch

相当于:

# git checkout branch

# git rebase master

这样一来,branch就包含了master的后续更新了。

(28) 把某个分支的一个提交应用到另一个分支上

git rebase可以应用其它分支的所有后续提交,但如果我们只想要其中的某一个提交呢?

git cherry-pick可用于把某个分支的一个commit应用到另一个分支。

假设master分支上有个commit,现在想把它应用到branch分支。

git checkout branch

git cherry-pick <commit id>

(29) 获取远程分支

# git branch -r // 查看都有哪些远程分支

# git checkout -b local_name origin/remote_name // 把远程分支映射为本地分支

(30) 生成Git格式的Patch

# git format-patch -o patches -1 c7fafc0ec // Patch只包含一个commit

从commit1开始(不包含),到commit2(包含),每个commit生成一个patch,放在patches目录下:

# git format-patch -o patches <commit1>..<commit2>

(31) 合并多个提交为一个

把最后3个提交合并为一个,并修改日志,还是用git rebase。

# git rebase -i HEAD~3

执行以上命令后,自动生成一个文件,包含三个commit的条目:

把第一个commit前的pick,改为reword。这个是最早提交的,reword表示要修改日志。

把第二个、第三个commit前的pick,改为squash,表示要把提交融合掉。

保存退出后,自动生成一个文件,可以修改下最终的日志。

合并成功。

(32) 修改最后一次提交的日志

# git commit --amend

(33) 撤销之前的提交

如果发现最后一个提交有错误,想撤销提交,但是不想放弃修改,可以使用git reset。

# git reset HEAD^

这样一来,上次提交就又回到了暂存区了。可以进行修改,然后重新提交。

如果使用git reset --hard HEAD^,则会直接放弃最后一个commit,而不把修改放回暂存区。

git reset还可以用来合并多个commit,来直接作为一个patch:

# git reset HEAD~3 // 撤销最近的3次提交,把修改存到暂存区

然后重新提交,这样一来最近的3次提交,就变为一个commit。


(34) 撤销本地所有修改

git checkout .

远程交互

我们用三台机器的交互操作,来说明Git的分布式管理。

@远程机器A

首先在远程机器A上创建一个裸仓库。

# mkdir proj.git

# cd proj.git

# git init --bare // 建立一个裸仓库

@本地机器B

在本地机器B上存在一个叫做test的本地仓库。

# cd test

定义远程分支的本地缩写:

# git remote add far ssh://user@IP:port/path/proj.git

删除远程分支的本地缩写:

# git remote rm far

然后将test推送到远程机器A的裸仓库proj.git:

# git push far master // 将本地的master分支推送到far的master分支

操作等价于:

# git push far master:master // 从本地master分支推送到far的master分支

或者:

# git push far test:master // 从本地test分支推送到far的master分支

# git push far test:test // 从本地test分支推送到far的test分支

分支操作:

# git branch // 列出本地分支

# git branch -r // 列出远程分支

# git branch -a // 列出所有分支

# git branch new // 创建一个新的本地分支,但不进行切换

# git branch -m | -M oldbranch newbranch // 重命名分支,如果newbranch名字已经存在,需用-M强制重命名

# git branch -d | -D new // 删除new分支,-D表示强制删除尚未合并的分支

# git branch -d -r new // 删除远程new分支

# git branch new <start-point> // 从start-point创建new分支

总而言之,现在把本地机器B的test项目,推送到了远程机器A的proj.git裸仓库中了。

@本地机器C

从远程机器A 的裸仓库克隆proj,修改proj,最后把修改推送到远程机器A的裸仓库中。

# git clone ssh://user@IP:port/path/proj.git proj // 当然也可以用其它协议

这时候我们可以看下.git/config:

[remote "origin"]

url = ssh://user@IP:port/path/proj.git

这里origin代表远程机器A上的裸仓库,以后可以直接使用这个缩写:)

修改master分支,然后推送到远程机器A的裸仓库中:

# git push origin master

@本地机器B

本地机器C进行修改后,本地机器B就要进行更新,以便及时获取这些修改。

git pull命令执行两个操作:

git pull从远程分支抓取修改内容,然后把它合并到当前的分支。git pull类似于svn update。

# git pull far master

如果只想抓取远程分支的修改内容,但不自动合并这些修改呢?

git fetch用于执行git pull的前半部工作,但是不会把抓下来的分支(far/master)合并到当前分支中。

# git fetch far master

查看本地master分支和抓取的远程分支的差异:

# git diff master far/master

或者

git log -p master..far/master

最后手动合并:

# git merge far/master

可能遇到的问题:

bash: git-receive-pack: command not found

git的安装路径不是默认路径。

ln -s /your_path/git-receive-pack /usr/bin/git-receive-pack

git-upload-pack同理。

Git协议公共仓库

我们想建立一个公共裸仓库,以供他人访问。据说用git协议的访问速度是最快的,只需要启动git-daemon。

它的监听端口为9418,它允许含有git-daemon-export-ok的git目录被读,但是默认不允许写(可以配成允许)。

git-daemon

A really simple server for git repositories.

This is ideally suited for read-only updates, i.e., pulling from git repositories.

建立公共裸仓库:

# git clone --bare /path/proj proj.git // proj的默认裸仓库名字为proj.git

# touch proj.git/git-daemon-export-ok // 允许git服务器读取

然后就是配置Git服务器,最后启动Git服务器。

git服务器常用参数:

--port = <port>

重新选定监听端口

--export-all

Allow pulling from all directories that look like GIT repositories.

even if they do not have the git-daemon-export-ok file.

--base-path = <path>

Remap all the path requests as relative to the given path. 指定git公共仓库的默认基路径。

--verbose

Log details about the incoming connections and requested files.

--reuseaddr

Use SO_REUSEADDR when binding the listening socket. This allows the server to

restart without waiting for old connections to timeout.

如果想配置成可以写的(允许push):

git daemon需要加--enable=receive-pack。

allowing anonymous push. It is disabled by default, as there is no authentication in the protocol.

This is soley meant for a closed LAN setting where everybody is friendly.

了解了以上信息,可以启动git服务器了:

(proj.git放在/path目录下)

# git daemon --verbose --reuseaddr --base-path=/path --enable=receive-pack &>> /path/log &

从公共Git仓库获取proj:

# git clone git://IP/proj.git // 默认端口是9418,默认基路径为之前设置的/path

Author

zhangskd @ csdn blog

Reference

[1] Git Community Book.

[2]. http://www.open-open.com/lib/view/open1356608472385.html

[3]. http://eikke.com/importing-a-git-tree-into-a-subversion-repository/

[4]. http://john.albin.net/git/convert-subversion-to-git

[5]. http://smilejay.com/2011/12/git-daemon/

Git版本控制 — 日常使用(二)的更多相关文章

  1. git版本控制工具(二)----本地版本库的常用操作

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  2. Git版本控制工具(三)----远程仓库GitHub的使用

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  3. Git版本控制工具(一)----git的安装及创建版本库

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  4. Git 版本控制工具(学习笔记)

    GIT(分布式) 一.Git 初始版本控制工具 1. 安装Git Ubuntu系统下,打开shell界面,输入: sudo apt-get install git-core  之后回车输入密码,即可完 ...

  5. git版本控制(一)

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  6. 使用Git版本控制工具管理GitHub

      使用Git版本控制工具管理GitHu Git是一个分步式的管理系统:只要上传操作得当,所有的都可以相当于是中央服务器,成员代码共享,A写的代码B也有,一般把一个人当做主机,其他人通过该主机拼装代码 ...

  7. Git版本控制之ubuntu搭建Git服务器

    Git是一个开源的分布式版本控制系统,可以有效.高效的处理从很小到非常大的项目版本管理.使得开发者可以通过克隆(git clone),在本地机器上拷贝一个完整的Git仓库,也可以将代码提交到Git服务 ...

  8. Git学习笔记(二) · 非典型性程序猿

    远程库的使用 前面说到的都是git在本地的操作,那么实际协作开发过程中我们肯定是要有一个远程版本库作为项目的核心版本库,也就是投入生产使用的版本.这里我们以 Github为例.Github是一个开放的 ...

  9. GIT 版本控制常用命令学习汇总

    GIT 版本控制常用命令汇总 git version 查看当前git版本信息 git help 获取全部命令帮助信息 git help <command> 获取指定命令帮助信息 git c ...

随机推荐

  1. ACM Tempter of the Bone

    小狗在古老的迷宫(maze)中发现了一个骨头,这使它非常着迷.然而,当他把它捡起来的时候,迷宫开始摇晃,狗狗可以感觉到地面下沉(sinking).他意识到这块骨头是一个陷阱(trap),他拼命地想摆脱 ...

  2. C# 定积分求周长&面积原理 代码实现

    前言: 前些日子,因为工作原因,接触到了求解曲线周长,真的是搞了很久,学生时代真的很简单,但是如今的我来说,忘记了....很多人跟我应该一样. 所以来巩固加强一下记忆.一开始的时候,求周长嘛,找公式呗 ...

  3. JavaScript的事件、DOM模型、事件流模型以及内置对象详解(三)

    JS中的事件 JS中的事件分类 1.鼠标事件: click/dbclick/mouseover/mouseout 2.HTML事件: onload/onunload/onsubmit/onresize ...

  4. CentOS7: How to resolve curl#56 - "Recv failure: Connection reset by peer"

    Issue: When you execute Yum installation or update, you may encounter following error: Loaded plugin ...

  5. hive表的存储格式; ORC格式的使用

    hive表的源文件存储格式有几类: 1.TEXTFILE 默认格式,建表时不指定默认为这个格式,导入数据时会直接把数据文件拷贝到hdfs上不进行处理.源文件可以直接通过hadoop fs -cat 查 ...

  6. x264源代码简单分析:宏块分析(Analysis)部分-帧内宏块(Intra)

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  7. ListView之侧滑删除

    SwipeMenuListView 是一个为listview添加item侧滑菜单的开源库,项目地址:https://github.com/baoyongzhang/SwipeMenuListView ...

  8. Matlab:如何查找给定目录下的文件

    我们有很多目录,每个目录下都有些有用的文件,比如图像文件,如何自动的扫描这些文件呢? 可以使用dir函数来完成这个任务. 比如假设给定目录 baseDir,它是一个字符串,包含的是某个目录,例如'./ ...

  9. (NO.00005)iOS实现炸弹人游戏(十一):怪物之火精灵

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 从本篇开始我们一次介绍一下游戏中敌人的制作过程.看过第一篇的小 ...

  10. DFS(深度优先)算法编程实践

    DFS定义 DFS(Depth-First-Search)深度优先搜索算法,是搜索算法的一种.是一种在开发爬虫早期使用较多的方法.它的目的是要达到被搜索结构的叶结点 . 特点 每次深度优先搜索的结果必 ...