zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    21.Merge Two Sorted Lists 、23. Merge k Sorted Lists
    34. Find First and Last Position of Element in Sorted Array
    leetcode 20. Valid Parentheses 、32. Longest Valid Parentheses 、301. Remove Invalid Parentheses
    31. Next Permutation
    17. Letter Combinations of a Phone Number
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项
    oc 异常处理
    oc 类型判断
    oc Delegate
    oc 协议
  • 原文地址:https://www.cnblogs.com/aiwz/p/6333270.html
Copyright © 2011-2022 走看看