文章目录
说明
- 本文为工作中git使用总结
- 本文没有商业目的
gerrit
merge the Gerrit branch to another Gerrit branch
To the best of my knowledge, you have 2 options currently
-
Force push to
refs/heads
. It is just a fast-forward, so in theory everything has already been reviewed and verified. There is no point in doing so again, so just skip that process and push torefs/heads
rather thanrefs/for
. -
Go ahead and create a merge commit. Use
git merge --no-ff
- this will create a merge commit even though it isn’t necessary in your fast-forward situation. Then the merge commit can be uploaded, reviewed, verified, and merged like normal.
git add
git add -h
git add -u # -u, --update update tracked files
git am
git am (--continue | --skip | --abort) PATCH_NAME //打补丁
git apply --reject PATCH_NAME //强制应用补丁
git add FILE_NAME //添加到缓冲区
git cat-file
git cat-file: show info and contents of objects file.
-
blob 对应仓库里的普通文件,当将一份文件 add 到仓库里时,git 将会产生一个 blob 对象存于 objects 目录下。
-
tree 对应仓库里的一个目录,当做一次 commit 时,git 将会为新增的目录产生 tree 对象存于 objects 目录下。
-
commit 大致可以视为工作目录的快照。commit 时创建工作目录的快照 git 做了三件事:
- commit 对象的哈希
- 如果这个文件没有改变,git 仅仅只把压缩文件的名字哈希值放入工作目录快照。如果文件发生了变化,git 会压缩它,然后把压缩后的文件存入 object 目录,再把压缩文件的名字哈希值放入工作目录快照。
- 工作目录快照的哈希
注意:如果文件的哈希值是“89faaee…”,git 会把这个文件存在 object 目录的 “89” 目录下,然后命名这个文件为 “faaee…”。
git checkout-index
Will copy all files listed from the index to the working directory (not overwriting existing files).
-
When creating files, prepend <string> (usually a directory including a trailing
/
)
--prefix=<string>
Export tree of tag v1.6.0 to specific directory
git read-tree v1.6.0 | git checkout-index -a --prefix=/home/nocent/work/git/tf1.6.0/
git config
$ git config --global user.name "YOUR NAME"
$ git config --global user.email "YOUR EMAIL ADDRESS"
git diff
$ git diff HEAD
这条命令显示的内容会在执行“git commit -a”命令是被提交,这里-a参数 自动将所有修改或删除的文件添加到index区,但对那些没有添加到git库的新创建的文件没有影响,也就是显示不出区别。
$ git diff --cached
上面的命令会显示你当前的索引和上次提交间的差异;这些内容在不带"-a"参数运行 "git commit"命令时就会被提交。
$ git diff test
这会显示你当前工作目录与另外一个叫’test’分支的差别。你也可以加上路径限定符,来只 比较某一个文件或目录。
$ git diff HEAD -- ./lib
上面这条命令会显示你当前工作目录下的lib目录与上次提交之间的差别(或者更准确的 说是在当前分支)。
如果不是查看每个文件的详细差别,而是统计一下有哪些文件被改动,有多少行被改 动,就可以使用 --stat
参数。
$ git diff --stat
No newline at end of file
When doing a git diff it says No newline at end of file
. What’s the significance of the message and what’s it trying to tell us?
It indicates that you do not have a newline (usually '\n'
, aka CR
or CRLF
) at the end of file.
That is, simply speaking, the last byte (or bytes if you’re on Windows) in the file is not a newline.
The message is displayed because otherwise there is no way to tell the difference between a file where there is a newline at the end and one where is not. Diff has to output a newline anyway, or the result would be harder to read or process automatically.
Note that it is a good style to always put the newline as a last character if it is allowed by the file format. Furthermore, for example, for C and C++ header files it is required by the language standard.
比较两次提交的同一个文件的差异
git diff commit-id-old commit-id-new -- filename
git format-patch
基于上几次内容打包
git format-patch HEAD^
有几个^
就会打几个patch,从最近一次打起git format-patch HEAD^^
最近的二个patch内容
以下代码作用同上
git format-patch -1
git format-patch -2
git format-patch -1 -4
//可以打包版本2,3的patch,但是发现有时候会把最近4个包都打包出来,具体原因未知
note
git format-patch
的补丁,使用git am
命令打patch
一般而言,为了保留git log的记录,我们在做patch的时候会使用git format patch的命令来生成一个patch,在应用patch的时候会选择git am来打上patch.一般的patch会包含N个文件的补丁,假设
有其中一个文件发生了conflict,那么am的过程就会停止,这时候需要我们手动去解决冲突,然后才能继续.
2.用到的命令
git format-patch -N //制作一个补丁,N表示生成几个patch,默认是一笔commit一个patch
git fetch and git pull
git中从远程的分支获取最新的版本到本地有这样2个命令
git fetch
相当于是从远程获取最新版本到本地,不会自动merge
git fetch <远程主机名> <远程分支名>:<local分支名>
- 省略local 分支名 但不省略 远程分支名,则fetch到本地的 FETCH_HEAD 上
- 省略local 分支名 并且省略 远程分支名,获取最新remote版本信息到本地,
获得代码
git checkout -b branch_name FETCH_OUT
下面的命令含义:
git fetch origin master
git log -p master..origin/master
git merge origin/master
- 首先从远程的origin的master主分支下载最新的版本到origin/master分支上
- 然后比较本地的master分支和origin/master分支的差别
- 进行合并
上述过程其实可以用以下更清晰的方式来进行,但对origin/master有不同的影响:
git fetch origin master:tmp 没有更新origin/master
git diff tmp
git merge tmp
从远程获取最新的版本到本地的tmp分支上,之后再进行比较合并到本地 master分支上
git pull
git pull <远程主机名> <远程分支名>
- 省略<远程分支名>,则 pull 到当前分支 remote-tracking 的那个 <远程分支名> 并合并到当前分支上
- 不省略<远程分支名>,则 pull 到本地的 FETCH_HEAD 上,并合并到当前分支
git pull 命令执行两个操作:
- 从远程分支(remote branch)抓取修改的内容
- 把它合并进当前的分支
相当于是从远程获取最新版本并merge到本地当前分支
git pull origin master
Example:
Update the remote-tracking branches for the repository you cloned from, then merge one of them into your current branch:
$ git pull, git pull origin
Normally the branch merged in is the HEAD of the remote repository, but the choice is determined by the branch..remote and branch..merge options; see git-config(1) for details.
Merge into the current branch the remote branch next:
$ git pull origin next
This leaves a copy of next temporarily in FETCH_HEAD, but does not update any remote-tracking branches. Using remote-tracking branches, the same can be done by invoking fetch and merge:
$ git fetch origin
$ git merge origin/next
上述命令其实相当于git fetch 和 git merge在实际使用中,git fetch更安全一些,因为在merge前,可以查看更新情况,然后再决定是否合并结束。
git fetch:
Depending on the operation, git will use one of the following refspecs, if you don’t provide one on the command line. is the name of this file in $GIT_DIR/branches and defaults to master.
git fetch uses:
refs/heads/<head>:refs/heads/<branch>
git push uses:
HEAD:refs/heads/<head>
EXAMPLES
Update the remote-tracking branches:
$ git fetch origin
The above command copies all branches from the remote refs/heads/ namespace and stores them to the local refs/remotes/origin/ namespace, unless the branch..fetch option is used to specify a non-default refspec.
Using refspecs explicitly:
$ git fetch origin +pu:pu maint:tmp
This updates (or creates, as necessary) branches pu and tmp in the local repository by fetching from the branches (respectively) pu and maint from the remote repository.
git log
-
–summary
- Output a condensed summary of extended header information such as creations, renames and mode changes.
git push
git push命令用于将本地分支的更新,推送到远程主机。它的格式与git pull命令相仿。
$ git push <远程主机名> <本地分支名>:<远程分支名>
注意,分支git push推送顺序的写法是 <来源地>:<目的地>
-
git push 如果省略远程分支名,则表示将本地分支推送与之存在”追踪关系”的远程分支(通常两者同名),如果该远程分支不存在,则会被新建。
$ git push origin master
上面命令表示,将本地的master分支推送到origin主机的master分支。如果后者不存在,则会被新建。
-
如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支。
$ git push origin :master # 等同于 $ git push origin --delete master
上面命令表示删除origin主机的master分支。
-
将本地所有与远程分支之间存在追踪关系的分支推送到远程对应的分支,则本地分支和远程分支都可以省略。
$ git push origin
上面命令表示,本地所有与远程分支之间存在追踪关系的分支推送到origin主机的对应分支。
-
如果当前分支只有一个追踪分支,那么主机名都可以省略。
$ git push
-
如果当前分支与多个主机存在追踪关系,则可以使用-u选项指定一个默认主机,这样后面就可以不加任何参数使用git push。
$ git push -u origin master
上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。
for gerrit
$ git push remote_name HEAD:refs/for/branch_name
// example: git push origin HEAD:refs/for/master
git tag
-
what is a tag in git
A tag is used to label and mark a specific commit in the history.
It is usually used to mark release points (eg. v1.0, etc.).Although a tag may appear similar to branch, a tag, however, does not change.
It points directly to a specific commit in the history.You will not be able to checkout the tags if it’s not locally in your repository so first, make sure that the tag exists locally by doing:
# --all will fetch all the remotes. # --tags will fetch all tags as well git fetch --all --tags --prune
Then check out the tag with the
tags/
prefix by running:git checkout tags/<tag_name> -b <branch_name>
In the follow sample you have 2 tags
version 1.0 & version 1.1
, you can checkout them out with any of the following:git checkout A ... git checkout version 1.0 ... git checkout tags/version 1.0 ...
All of the above will do the same since tag is only a pointer to a given commit.
-
How to see the list of all tags
# list all tags git tag # list all tags with given pattern ex: v- git tag --list 'v-*'
-
How to create tags
There are 2 ways to create a tag:
# normal tag git tag # annotated tag git tag -a
The difference between the 2 ways is that that the when creating an annotated tag you can add metadata like you have in a git commit:
name, e-mail, date, comment & signature
-
How to delete tags?
Don’t forget to remove the deleted tag from the server with push tags
# delete any given tag git tag -d <tag name>
-
Sharing Tags
By default, the git push command doesn’t transfer tags to remote servers. You will have to explicitly push tags to a shared server after you have created them. This process is just like sharing remote branches.
git push origin <tagname>
git rebase
Assume the following history exists and the current branch is “topic”:
// branch:
A---B---C topic
/
D---E---F---G master
From this point, the result of either of the following commands:
git rebase master
git rebase master topic
would be:
// branch:
A'--B'--C' topic
/
D---E---F---G master
git rebase 的交互模式只需要传入一个参数 -i
即可,同时还需要指定对哪些提交进行处理,如:
git rebase -i HEAD~4
上述命令指定了对当前分支的最近四次提交进行操作。
多个commit合并
合并最新三个提交:
-
从HEAD版本开始往过去数3个版本
git rebase -i HEAD~3
-
指名要合并的commit id 之前的那一个commit id
git rebase -i da49f2b
请注意
da49f2b
这个版本是不参与合并的。- pick 的意思是要会执行这个 commit;
- squash 的意思是这个 commit 会被合并到前一个commit。
git read-tree
Reads the tree information given by into the index, but does not actually update any of the files it “caches”. (see: git-checkout-index(1)). Manual:
man git-read-tree
command:
# read tag v1.6.0 information to index
git read-tree v1.6.0 --index-output index_out
git remote
git remote set-url
usage: git remote [-v | --verbose]
or: git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>
or: git remote rename <old> <new>
or: git remote remove <name>
or: git remote set-head <name> (-a | --auto | -d | --delete |<branch>)
or: git remote [-v | --verbose] show [-n] <name>
or: git remote prune [-n | --dry-run] <name>
or: git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]
or: git remote set-branches [--add] <name> <branch>...
or: git remote set-url [--push] <name> <newurl> [<oldurl>]
or: git remote set-url --add <name> <newurl>
or: git remote set-url --delete <name> <url>
-v, --verbose be verbose; must be placed before a subcommand
git remote show origin
$ git remote show origin
* remote origin
Fetch URL: ssh://xuxin-m@172.19.120.13:29418/ns/cv/ocr
Push URL: ssh://xuxin-m@172.19.120.13:29418/ns/cv/ocr
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 (up to date)
git reset
--hard Matches the working tree and index to that of the tree being
switched to. Any changes to tracked files in the working tree since
<commit> are lost.
--merge
Resets the index to match the tree recorded by the named commit, and
updates the files that are different between the named commit and
the current commit in the working tree.
The git reset --merge
is meant to be a safer version of git reset --hard
, when your changes and somebody else changes are mixed together, trying to carry our changes around.
git rev-parse
gitdir=$(git rev-parse --git-dir); scp -p -P 29418 xuxin-m@172.19.120.13:hooks/commit-msg ${gitdir}/hooks/
proxy
git config --global http.proxy http://username:password@proxy.server.com:port
git config --global https.proxy http://username:password@proxy.server.com:port
issues
How do I push amended commit to the remote Git repository?
> git commit --amend
# Unfortunately the commit can't be pushed back to the repository. It is rejected like this:
> git push origin
To //my.remote.repo.com/stuff.git/
! [rejected] master -> master (non-fast forward)
error: failed to push some refs to '//my.remote.repo.com/stuff.git/'
Here is a tip to recover from the situation after you have pushed out the amended commit with --force
(or +master
).
- Use
git reflog
to find the old commit that you amended (call itold_id
), and we’ll call the new commit you created by amendingnew_id
. - Create a merge between
old_id
andnew_id
, recording the tree ofnew_id
, likegit checkout new_id && git merge -s ours old_id
. - Merge that to your master with
git merge master
. - Update your master with the result with
git push . HEAD:master
. - Push the result out with
git push origin master
.
Then people who were unfortunate enough to have based their work on the commit you obliterated by amending and forcing a push will see the resulting merge will see that you favor new over old. Their later merges will not see the conflicts between old
and new
that resulted from your amending, so they do not have to suffer.
减少.git的大小
下面是具体的操作方法:
-
运行 gc ,生成 pack 文件(后面的 --prune=now 表示对之前的所有提交做修剪,有的时候仅仅 gc 一下.git 文件就会小很多)
$ git gc --prune=now
-
找出最大的三个文件
$ git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -3 1debc758cf31a649c2fc5b0c59ea1b7f01416636 blob 4925660 3655422 14351 c43a8da9476f97e84b52e0b34034f8c2d93b4d90 blob 154188651 152549294 12546842 2272096493d061489349e0a312df00dcd0ec19a2 blob 155414465 153754005 165096136
-
查看那些大文件究竟是谁(c43a8da 是上面大文件的hash码)
$ git rev-list --objects --all | grep c43a8da c43a8da9476f97e84b52e0b34034f8c2d93b4d90 data/bigfile
4.移除对该文件的引用(也就是 data/bigfile)
```
$ git filter-branch --force --index-filter "git rm --cached --ignore-unmatch 'data/bigfile'" --prune-empty --tag-name-filter cat -- --all
```
5.进行 repack
```
$ git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
$ git reflog expire --expire=now --all
$ git gc --prune=now
```
6.查看 pack 的空间使用情况
```
$ git count-objects -v
```