Git

Table of Contents

Git的help信息非常好,很多可以直接help来了解

给Git输出信息增加颜色

编辑/etc/gitconfig 比如要对git status设置颜色,可以:

[color]
    ui = auto
[color "branch"]
    current = yellow reverse
    local = yellow
    remote = green
[color "diff"]
    meta = yellow bold
    frag = magenta bold
    old = red bold
    new = green bold
[color "status"]
    added = yellow
    changed = green
    untracked = cyan

参考:

关于Git的分支

参考的 何谓分支

因为Git是保存的快照,Git仓库有以下几个基本对象

Git的分支,其本质是一个指向commit对象的可变指针,Git使用master作为分支的默认名字

HEAD指针指向当前的分支指针

使用git branch是查看当前的分支列表

使用git branch branch_name新建分支,然后可以使用git checkout branch_name切换分支

最后可以用git merge branch_name来合并分支

如果遇到冲突,需要到冲突的文件下根据提示编辑后再commit

远程分支

参考的 远程分支

从远程Git repo克隆,Git会自动将此remote repo命名为origin,并下载其中所有的数据,建立一个指向它的master分支的指针,在本地命名为origin/master

但无法在本地更改其数据。接着,Git建立一个属于自己的本地master分支,始于originmaster分支相同的位置,这样可以就此开始工作

touch README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin git@github.com:tankywoo/test.git
git push -u origin master

这里origin是remote repo name,branch name 是master

关于fetch和pull区别

What is git fetch? and what is the difference to git pull?

git fetch是update from remote repo,但是不合并

git pull是fetch and merge

Git标签

2.6 Git 基础 - 打标签

Git 全局配置

全局忽略文件

使用vimdiff

默认的diff应该是使用diff命令, 这个命令也非常有必要掌握.

但是, 更直观的, 可以选择vimdiff.

# 配置Git使用vimdiff来做差异比较
git config --global diff.tool vimdiff
# 在merge时使用
git config --global merge.tool vimdiff
# 因为在使用vimdiff时, vim会有如下提示:
# Viewing: 'tkwiki/tool/git.wiki'
# Launch 'vimdiff' [Y/n]: y
# 可以取消这个提示
git config --global difftool.prompt false

然后就可以

git difftool tkwiki/tool/git.wiki

来查看修改的地方, 效果图:

git vimdiff

参考:

查看提交log

git log 会查看当前git repo里所有的提交历史

git log filename 会查看这个文件的所有提交历史

git log -p -2 [filename] 会把最近的2次提交变更展开

git log --pretty=oneline [filename] 这个太牛逼了, 只显示id和提交说明.

git log --pretty=format:"xxxx" 这个更牛逼, 自定义查看log的输出格式

参考:

文件中文名问题

最近遇到同步文件下来, 中文文件名全部是unicode, 解决这个问题加配置:

git config --global core.quotepath false

Git mv 日志问题

git mv (rename) 文件后, 直接 git log 只能看到这个文件被 rename 后的日志, 想要看到完整的日志, 要用 git log --follow xxx

参考:

指定路径pull

以前都是 cd 到仓库当前目录然后 pull. 因为想到 svn up 可以直接指定路径, 这种基本功能 git 肯定会有的, 但是直接指定路径不行.

搜了下, StackOverflow 上的 回答1回答2 非常给力.

Git 的参数 --git-dir 可以指定 Git 的路径, 即使用这个 .git 的配置等来更新 repo. 但是这个会以 pwd 为要更新的 repo 路径. 所以还需要 --work-tree 来指定要更新的 repo 的路径, 而不需要 cd 过去.

git --git-dir=/path/to/git-repo/.git --work-tree=/path/to/git-repo/ pull

查看指定目录下的 status

git status [path]

比如当前目录下的 status:

git status .

git status - is there a way to show changes only in a specific directory?

选择一部分修改提交

使用 git add -p filename

具体见:

只从 git repo 中移除文件, 但不删除实际文件

git rm --cached file

默认使用 git rm 会把文件也一并删除掉.

修改最后一次提交

使用:

git commit --amend

如果当前 stage区 没有东西, 则相当于可以修改 commit comment.

如果 stage区 有新的文件, 比如有个文件staged后忘了和上次的提交一次commit, 则可以撤销并重新提交.

修改commit的author

如果是staged的文件,提交时直接指定 --author 就可以了:

git commit -m "xxx" --author="Tanky Woo <noreply@tankywoo.com>"

修改最后一次提交的author,可以配合 --amend:

git commit --amend --author="Tanky Woo <noreply@tankywoo.com>"

如果user config配置修改了,可以直接--reset-author:

git commit --amend --reset-author

修改指定commit的author:

* 2f1e828 - (HEAD, origin/test, origin/master, test, master) update test-git-submodule (2 days ago) <Tanky Woo>
* 3243b09 - first commit with submodule (2 days ago) <Tanky Woo>
* 5956ab0 - why conflict and merge? (3 weeks ago) <Tanky Woo>

现在想修改 3243b09 的 author name,需要从它之前的一个commit开始rebase:

TankyWoo@Mac::test-git/ (master) » git rebase -i 5956ab0

Git 会使用设置的编辑器打开如下:

pick 3243b09 first commit with submodule
pick 2f1e828 update test-git-submodule

# Rebase 5956ab0..2f1e828 onto 5956ab0
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

根据提示,把需要修改的一行用edit替换pick:

edit 3243b09 first commit with submodule
pick 2f1e828 update test-git-submodule

保存关闭后会提示:

Stopped at 3243b09... first commit with submodule
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

我设置的PS1的括号里是分支名,可以看到现在的分支是这个要修改的commit id:

TankyWoo@Mac::test-git/ (3243b09*) » git commit --amend --author="Tanky <noreply@tankywoo.com>"

修改完后会进入下一个commit id分支,直接--continue,因为604c35c这个commit设置的是pick,所以不会做改动:

TankyWoo@Mac::test-git/ (604c35c*) » git rebase --continue
Successfully rebased and updated refs/heads/master.

再查看日志:

* 16c4757 - (HEAD, master) update test-git-submodule (2 seconds ago) <Tanky Woo>
* b9fbd8a - first commit with submodule (15 seconds ago) <Tanky>
* 5956ab0 - why conflict and merge? (3 weeks ago) <Tanky Woo>

SO上的回答:

For example, if your commit history is A-B-C-D-E-F with F as HEAD, and you want to change the author of C and D, then you would...

  1. Specify git rebase -i B
  2. change the lines for both C and D to edit
  3. Once the rebase started, it would first pause at C
  4. You would git commit --amend --author="Author Name <email@address.com>"
  5. Then git rebase --continue
  6. It would pause again at D
  7. Then you would git commit --amend --author="Author Name <email@address.com>" again
  8. git rebase --continue
  9. The rebase would complete.

如果要修改指定用户全部commit的author:

git filter-branch -f --env-filter '
an="$GIT_AUTHOR_NAME"
am="$GIT_AUTHOR_EMAIL"
cn="$GIT_COMMITTER_NAME"
cm="$GIT_COMMITTER_EMAIL"

if [ "$GIT_COMMITTER_EMAIL" = "<OLD EMAIL>" ] ; then
    cn="<NEW NAME>"
    cm="<NEW EMAIL>"
    export GIT_COMMITTER_NAME="$cn"
    export GIT_COMMITTER_EMAIL="$cm"
fi
if [ "$GIT_AUTHOR_EMAIL" = "<OLD EMAIL>" ] ; then
    an="<NEW NAME>"
    am="<NEW EMAIL>"
    export GIT_AUTHOR_NAME="$an"
    export GIT_AUTHOR_EMAIL="$am"
fi
'

这个在github官方help里也有脚本。

StackOverflow上有两篇讨论非常好:

Git diff 技巧

(待整理)

git diff tag                    比较tagHEAD之间的不同。
git diff tag file               比较一个文件在两者之间的不同。
git diff tag1..tag2             比较两个tag之间的不同。
git diff SHA11..SHA12           比较两个提交之间的不同。
git diff tag1 tag2 file or
git diff tag1:file tag2:file    比较一个文件在两个tag之间的不同。

ORIG_HEAD 用于指向前一个操作状态,因此在git pull之后如果想得到pull的 内容就可以:

git diff ORIG_HEAD

git diff --stat                 用于生成统计信息。
git diff --stat ORIG_HEAD

HEAD vs ORIG_HEAD

关于 HEADORIG_HEAD 的区别,来至StackOverflow的回答:

HEAD is (direct or indirect, i.e. symbolic) reference to the current commit. It is a commit that you have checked in the working directory (unless you made some changes, or equivalent), and it is a commit on top of which "git commit" would make a new one. Usually HEAD is symbolic reference to some other named branch; this branch is currently checked out branch, or current branch. HEAD can also point directly to a commit; this state is called "detached HEAD", and can be understood as being on unnamed, anonymous branch.

ORIG_HEAD is previous state of HEAD, set by commands that have possibly dangerous behavior, to be easy to revert them. It is less useful now that Git has reflog: HEAD@{1} is roughly equivalent to ORIG_HEAD (HEAD@{1} is always last value of HEAD, ORIG_HEAD is last value of HEAD before dangerous operation).

For more information read git(1) manpage, Git User's Manual, the Git Community Book and Git Glossary

其它的一些讲解:

git revert/reset/checkout 区别

讲得挺好的一篇 Undoing Git Changes,关于git checkout, git revert,git reset, git clean 的对比。

统计每个提交者的提交次数

git shortlog --numbered --summary

git reflog

TODO

git cherry-pick

TODO

Git Commit Message 基本准则

一些基本的准则:

可以看看Git源码的提交log : https://git.kernel.org/cgit/git/git.git/log/

一些不错的文章:

git add 只添加 tracked 的文件

git add 有一个 -u 选项,会只添加tracked的文件,比如在项目根目录下,可以添加所有修改过的已经tracked的文件:

git add -u .

如果单纯的git add . 会把untracked的文件也加进去

删除untracked files

git clean -f

But beware... there's no going back. Use -n or --dry-run to preview the damage you'll do.

If you want to also remove directories, run git clean -f -d

If you just want to remove ignored files, run git clean -f -X

If you want to remove ignored as well as non-ignored files, run git clean -f -x

Note the case difference on the X for the two latter commands.

If clean.requireForce is set to "true" (the default) in your configuration, then unless you specify -f nothing will actually happen, with a recent enough version of git.

See the git-clean docs for more information.

from

同一个文件选择部分提交

You can do git add -p filename, and it'll ask you what you want to stage. You can then:

If the file is not in the repository yet, do first git add -N filename. Afterwards you can go on with git add -p filename.

Source

Git资料


title: Git
date: 2013-11-08 00:02
author:
site: 帐号、业务安全|岂安