• Git版本控制 — 日常使用(二)


    本地使用

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

    (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/

  • 相关阅读:
    mysql8.0.20安装
    MySQL EXPLAIN结果集分析
    初次安装aliSql
    升级vim到8.0
    REPL环境对语言的帮助
    Python环境搭建及pip的使用
    mysql数据库分库分表(Sharding)
    Git的使用
    Promise的初步认识
    对引用的文件起别名
  • 原文地址:https://www.cnblogs.com/aiwz/p/6333270.html
Copyright © 2020-2023  润新知