Git
Tags: git
- Configuration
- Commit message best practices
- Use git log
- Git Concepts and Architecture
- Frequent commands
- Undo
- .gitignore
- navigating the commit tree
- Branching
- Merging Branches
- stash
Configuration
git把config info存在三个位置
- System:
/etc/gitconfig
.- To every user of this computer, user can overwrite, but this is default.
- User:
~/.gitconfig
- Project:
my_project/.git/config
编辑命令:
$ git config --system
$ git config --global #user
$ git config #project
$ git config --global user.name "your_name"
$ git config --global user.email "your_email"
$ git config --list #check your config
$ git config user.name #return your name
还可以设定你需要的editor,例如(详细):
$ git config --global core.editor "subl -n -w"
设置颜色
$ git config --global color.ui true
下载auto-completion,重命名之后在bash_profile里加上
# Enable tab completion
if [ -f ~/.git-completion.bash ]; then
source ~/.git-completion.bash
fi
$ git help <command> #查找特定命令帮助
f b 按键可以前进或者后退浏览manual
Commit message best practices
- short single-line summary (less than 50 characters)
- optionally followed by a blank line and a more complete description
- keep each line to less than 72 characters
- write commit messages in present tense, not past tense
- “fix bug” or “fixes bug”, not “fixed bug”
- can add “ticket tracking numbers” from bugs or support requests
- can develop shorthand for your organization
- “[css,js]”
- “bugfix: “
- “#38405 - “
- Be clear and descriptive
Use git log
常见用法
$ git log -n <number> #show number of recent commit
$ git log --since=YYYY-MM-DD #show commits since that date
$ git log --until=YYYY-MM-DD #show commits until that date
$ git log --author="<part of name>"
$ git log --grep="re"
$ git log --oneline #show logs in oneline
$ git log --oneline -3 #show recent 3 logs in oneline
$ git log --since="2 weeks ago" --until="3 days ago"
$ git log --since=2.weeks --until=3.days
$ git log --author=<name>
$ git log --<checksum>..<checksum> #range
$ git log <checksum>.. <file> #certain file since this commit
$ git log -p #log with diff
#log with change for a certain file since a certian period
$ git log -p <checksum>.. <file>
$ git log --stat --summary #statistics
$ git log --format=oneline #full SHA1 with comments
$ git log --format=short
$ git log --format=medium(default)
$ git log --format=full
$ git log --format=fuller
$ git log --format=email
$ git log --format=raw
$ git log --graph (show branches)
$ git log --graph --oneline --all --decorate
Git Concepts and Architecture
Git uses three-tree architecture
- repo
- staging index
- working directory
这个结构的好处是,我们可以修改working directory中的10个文件,可以把5个文件加到staging,作为一个commit。
在pull的时候通常从repo pull到working。
- Git generates a checksum for each change set
- checksum algorithms convert data into a simple number
- same data always equals same checksum
- data integrity is fundamental
- changing data would change checksum
- Git uses SHA-1 has algorithm to create checksums
- 40-character hexadecimal string(0-9, a-f)
Git takes the entire set of changes, runs them through in algorithm, and comes out with a 40 digit number. It attaches a bit of meta information to each snapshots, it has that commit number at the top, it has the parent commit the commit comes before it, the author of the commit, then the commit message.
HEAD
Git maintains a reference variable called HEAD. Its purpose is to reference, or point to, a specific commit in the repo. As we make new commits, the pointer is going to change or move to point to a new commit. HEAD always points to the tip of the current branch in our repo. It has to do with our repo, not our staging index or working directory. It’s about the repo the commits we’ve made by checking them in.
Another way to think of it is the last state of our repo or what was last checked out, the HEAD points to the parent of the next commit or it’s where commit writing is going to take place.
HEAD always points to the tip of the currently checked out branch from the repo. We can look at HEAD in .git
directory.
$ cat .git/HEAD #ref: refs/heads/master
refs/head/master 含有这个branch的last checksum。
$ git log HEAD #返回last commit
Frequent commands
git diff
没add之前,diff比较working和repo。
当add file to staging index后,git diff只返回working directory和repo的diff。要查看stage与repo的diff,需要给参数
$ git diff --staged <file>
$ git diff --color-words <file> #show diff in one-line
git fetch
After fetch, before pull, you can use git log
to view the difference.
git show
After fetch, see remote commit
git show origin/master
git rm / git mv
删除,重命名,都用git rm/mv 可以跳过add,直接进入staging
Undo
在Working directory 恢复文件的上一个版本
$ git checkout -- <file>
这里特别注意checkout后面的两条横线,因为checkout还有checkout branch的功能,所以加横线避免歧义。
取出在staging index的file
# 这里不是指把文件恢复到修改之前,
# 而是把文件从staging转移到working directory
$ git reset HEAD <file>
Amending commits
先把修改add到staging,然后:
$ git commit --amend -m "new msg"
这也可以用来修改最近一次的commit或者仅仅修改message。
Retrieving old versions
做一个新的commit,但是跟前一个commit完全相反。
# 完全撤销该commit的修改,返回msg编辑界面。
# 确认msg之后直接commit。-n可以不自动commit。
git revert [-n] <checksum>
git revert
在做简单的编辑撤销时非常好用,复杂的返回操作,例如有文件移动,重命名等,做一个 mirror image返回就很困难了,git将用merging来解决这些问题。
还有一种办法是在git log找到前一个commit的checksum,然后:
#状态从repo回到checksum状态,working directory并没有变
$ git checkout <checksum> -- <file>
在commit时最好注明是从哪个checksum退回来的。
Undo multiple commits!
Be cautious when use git reset
to move the HEAD pointer. Usually we let git to manage HEAD pointer. There are 3 options to reset.
soft
Soft is going to move the HEAD pointer to the specified commit, and it’s not going to change staging index or working directory at the same time. It’s just going to move the pointer. It’s the safest.
Just a soft reset, move the pointer and do nothing else.
The result of that, out staging index and our working directory are going to contain the files in their later revised state. The repo is going to be set back to an earlier version.
So if we do a diff between the two, it’s going to tell us about all those changes that have happend between the point where the HEAD is pointing, and all the files that are sitting in our staging index and working directory.
mixed(default)
It moves the HEAD pointer to the specified commit, and it also changes the staging index to match the repo. It does not change our working directory. At this point, the staging index and the repo will be set in one place. Our working directory has all those changes that we’ve made. It’s just waiting for us to stage it and then commit it.
hard
changes staging index and working directory to match repo. Use this one with caution. It really is for when things have gone completely wrong, and you really want to reset everything back to a specific point in time and you don’t mind losing whatever came after it.
If you need to reset a remote push, try git push origin -f
. See detail.
To sync your local repo with remote repo after force push, use
git reset --hard origin/master
Remove untracking files
$ git clean -n #告知哪些file要被remove
$ git clean -f #remove files
.gitignore
assets/videos/
# ignore all files in a directory with trailing slash
log/*.log
# won't ignore log/archive/access.log
一般需要ignore的file:
- compiled source code
- packages and compressed files
- logs and databases
- operating system generated files
- user-uploaded assets(image, PDFs, videos)
把系统需要ignore的file放在.gitignore_global下,这样每个git repo只要ignore项目特定的文件就好。
$ git config --global core.excludesfile ~/.gitignore_global
已经tracked file如果要需要保留在repo,但是ignore之后的update,除了在.gitignore
添加信息之外,还要
$ git rm --cached <file>
#tell git rm this file from staging index
要track empty folder, touch .gitkeep到该目录。
navigating the commit tree
List the contents of a tree object
$ git ls-tree <tree-ish>
查看一个commit的详情
$ git show <checksum>
$ git show --format=oneline <checksum>
#如果tree-ish是目录,返回该文件夹的子文件夹目录
#如果tree-ish是文件,返回文件内容
$ git show <tree-ish>
Compare commits
会展现两个commits之间所有的变化。还可以在branches之间做比较。
$ git diff <checksum> #过去某个
$ git diff <checksum> <file> #查看特定文件变化
$ git diff <checksum>..<checksum> #特定两次commits之间变化,后面还可以跟文件
$ git diff --stat --summary <checksum>..<checksum>
$ git diff --ignore-space-change <checksum>..<checksum> #忽略空格变化
$ git diff -b <checksum>..<checksum> #同上
$ git diff --ignore-all-change <checksum>..<checksum>
$ git diff -w <checksum>..<checksum> #同上
Branching
Concept
- branches are cheap
- try new ideas
- isolate features or sections of work
- one working directory
- fast context switching
create and checkout to a new branch
$ git checkout -b <new_branch>
compare branches
$ git diff <branch1>..<branch2>
check whether branch includes other branches
$ git branch --merged
<branch1>
<branch2>
*<branch3>
here branch3 includes all commits from branch1 and branch2
Rename branch
git branch -m <branch1> <branch2>
Delete branch
# https://stackoverflow.com/questions/2003505/how-do-i-delete-a-git-branch-locally-and-remotely#targetText=Simply%20do%20git%20push%20origin,local%20branch%20ONLY!...
$ git checkout master # checkout to master
$ git branch -d <branch> # delete the other branch
$ git branch -D <branch> # alias for --delete --force "irrespective of its merged status."
# delete remove branch
git push -d <remote_name> <branch_name> # in most cases the remote name is origin
git push -D <remote_name> <branch_name>
Merging Branches
checkout to the branch to be merged (most cases master master branch)
$ git merge <branch to merge>
If the branch to be merged has no change, git will do a Faster-forward merge. If you want the merge to become a new commit, use --no-ff
option.
$ git merge --no-ff <branch to merge>
You can check whether it can do a Fast-forward, it will do the Fast-forward if it can, otherwise it will abort.
$ git merge --ff-only <branch to merge>
If the to-be-merged branch e.g. master has different with the merging branch e.g. dev, but no conflicts, then git merge <branch>
will form a new commit.
Merging conflicts
一个文件的不同位置被做了改动,git可以把他们自动merge到一起。但是如果相同位置有不同版本,则需要人工介入解决conflicts。
有三种解决conflicts的方法
-
abort merge
$ git merge --abort
- resolve the conflicts manually
- use a merge tool
strategies to reduce marge conflicts
- keep lines short
- keep commits small and focused
- beware stray edits to whitespace
- spaces, tabs, line returns
- merge often
- merge了之后,branch还可以继续使用,master也可以继续编辑,频繁的merge可以减少conflicts。
- track changes to master
- 把master的change merge到当前工作的branch
stash
switch branch时候,还有些edits没有到commit的程度,可以把他们暂存在stash里。
-
保存
$ git stash save 'comments'
-
查看stash列表
$ git stash list
-
查看stash内容
$ git stash show <stash@{0}> $ git stash show -p <stash@{0}> # 查看修改详情
-
取出stash内容到working directory
$ git stash pop <stash@{0}># 取出并删除stash,如果不指明,默认取第一个。 $ git stash apply
-
删除stash
$ git stash drop stash@{0} $ git stash clear # 删除所有
Read more: