[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
    ```