[meta:edit-log]: # "2019/08/01,2019/08/27"
[meta:title]: # "git Git GIT"
[meta:keywords]: # "git, tip, command-line"
[meta:description]: # "Some tip for hacking Git."
Here's some tip for hacking Git:
a powerful tool to manage text across some time within a team
## understand what git is about, if not, read the official doc:
The commit
- who authored, who committed?
- when authored, when committed?
- what's commit hash?
- what's git objects, the file in `.git/objects/`, and the relation to commit?
The branch
- what's branch, is branch linear?
- what's local branch, what's remote branch?
The rebase
- that data get changed, is the commit the same?
The conflict
- why conflict happen?
- common conflict kind?
- how to avoid/reduce?
## use `git fetch`, ditch `git pull`
`git pull` is a failed combo command,
usually it'll cost you current un-committed change,
and result in a hard reset.
so to skip the hassle, just `git fetch` to get the `future`,
then `git reset --hard @{upstream}` when you're clear to get the change
## use `rebase`, ditch `merge` (except for pull-request)
consider this when working with long branches (16+ commit).
merge cause messy history,
and not able to do rebase is also a sign of bad git commit habit
focus the change, sort the commit, and use rebase
## master `cherry-pick`, learn `interactive rebase`
if you do `cherry-pick` enough times, you got `rebase`
if you change commit content during multiple `cherry-pick`, you got `interactive rebase`
moving commit can clean up the repo history
reordering & regrouping commits gives high quality history
if there's some later use for the commit history,
and the quality of commit message matters,
do both regularly
## decide what commit strategy to use
- big commit (squash):
- if the change is big and mixed up,
and not needed to see the code separately,
like a repo reset, or a huge break change
- grouped small commit:
- use this when developing 2 or more related features,
and better when the feature code is in separated file/folder,
if you develop and commit like:
```
ADD: feat-B
ADD: feat-A
UPD: feat-A
UPD: feat-B
CHG: feat-B
CHG: feat-A
FIX: feat-B
FIX: feat-A
```
later you may sort the commit to like: (or squash the fix)
```
ADD: feat-A
UPD: feat-A
CHG: feat-A
FIX: feat-A
ADD: feat-B
UPD: feat-B
CHG: feat-B
FIX: feat-B
```
## know your `.git/config`, limit your global `git config`
- use specified ssh key for this repo
- this let's you manage different git repo with different auth/ssh-key,
with out extra hack, one time only,
edit the config like:
```
[core]
sshCommand = ssh -i ~/.ssh/key-for-repo-a.pri
```
- lock down option for cross platform repo
- force filesystem tracking to be case-sensitive,
force output EOL to `\n`,
edit the config like:
```
[core]
ignorecase = false
symlinks = false
autocrlf = input
eol = lf
```
- fetch only specified branches
- for some big and active git repo,
you may not need to get all the branches,
or when the fetching is slow,
edit the config like:
```
[remote "origin"]
url = git@github.com:user/repo.git
fetch = +refs/heads/master:refs/remotes/origin/master
fetch = +refs/heads/test:refs/remotes/origin/test
fetch = +refs/heads/feat-a/*:refs/remotes/origin/feat-a/*
fetch = +refs/heads/feat-b/*:refs/remotes/origin/feat-b/*
# fetch = +refs/heads/*:refs/remotes/origin/* # do not fetch all
```