Skip to content

Latest commit

 

History

History
473 lines (372 loc) · 12.6 KB

git.md

File metadata and controls

473 lines (372 loc) · 12.6 KB

Deleting commits

# order
# 1. r
# 2. fixup/squash
# 3. fixup/squash
git rebase -i HEAD^
# ||
git rebase -i HEAD~3

# [optional]
git rebase --edit-todo
git rebase --continue
git rebase origin master

# up to root
git rebase -i --root master

Changing author

# order
# 1. e
git rebase -i HEAD^

git commit --amend --author="foo <>"
git rebase --continue
git push --force

Deny push --force

git config --system receive.denyDeletes true
git config --system receive.denyNonFastForwards true

git log -G 'source_searches_cwd' general.c
git diff 3185942a~ 3185942a general.c

Add existing repository to remote

git remote add github git@github.com:nevesnunes/foo.git
git remove -v
git push github master

Apply gitignore changes

git rm --cached -f -r .

git add -A
git status

Remove objects

# directories
git clean -fd

# ignored files
git clean -fX

# ignored and non-ignored files
git clean -fx

# rewrite history by object ids
p=foo/bar \
&& git log --all --pretty=format:%H -- "$p" \
    | xargs -I{} git ls-tree {} "$p" \
    | awk '{print $3}' \
    | xargs -I{} bash -c 'java \
        -jar ~/opt/bfg.jar \
        --delete-files \
        --no-blob-protection \
        --strip-blobs-with-ids <(printf "%s\n" "$1") .' _ {}

interactive mode

  • patch: pick hunks (i.e. blocks of lines) to add to commit
    • stage: e = pick lines in current hunk
git add --patch ./foo
git commit -m '.'

cherry-pick

  • copies commits from one branch to another branch

Pull request

# 1. Update devel, to ensure you have the commit to cherry pick:
git checkout devel
git --fetch upstream
git merge upstream/devel
git checkout $old_release_from_stable
git pull
git checkout -b cherry-pick/2.5/$pr_number_from_devel
git cherry-pick -x $sha_from_devel

# 2. Add a changelog entry for the change, and commit it

# 3. Push your branch to your fork:
git push origin cherry-pick/2.5/$pr_number_from_devel

# 4. Submit PR for cherry-pick/2.5/$pr_number_from_devel against the stable-2.5 branch

Multiple commits

git checkout $devel_branch
# reset branch to f (currently includes a)
git reset --hard f
# rebase every commit after b and transplant it onto a
git rebase --onto a b

https://stackoverflow.com/questions/1670970/how-to-cherry-pick-multiple-commits/12646996#12646996

list files by commit info

# last commit date
ls -1 foo* | while read -r i; do printf '%s ' "$i" && git log -1 --format=%cd "$i" | cat -v -; done

list submodule commits

git log -p --submodule=log | awk '
/^commit/ { add=1 } # Start of commit message
/^diff --git/ { add=0 } # Start of diff snippet
{ if (add) { buf = buf "\n" $0 } } # Add lines if part of commit message
END { print buf }
'

gitlab ci local

(
cd ~/opt
wget https://s3.amazonaws.com/gitlab-runner-downloads/master/binaries/gitlab-runner-linux-amd64
chmod +x gitlab-runner-linux-amd64
)
gitlab-runner register --executor docker --docker-image foo
# Input: gitlab-ci.yml job name = foo
gitlab-runner exec docker --docker-pull-policy="if-not-present" ...
gitlab-runner exec shell foo

gitlab-runner exec: easily test builds locally (#312) · Issues · GitLab.org / gitlab-runner · GitLab

bisect

manually marked by user

# begin
git bisect start
git bisect good 012345678
git bisect bad 012345679

# for each automatic checkout
git bisect good
# ||
git bisect bad

# end
git bisect reset

automatically marked by script

git bisect start 012345678 012345679
git bisect run ./test.sh

For each automatic checkout:

  • on exit status = 0, mark checkout as good
  • on exit status > 0, mark checkout as bad

submodules

# Add reference in main repository
git submodule add git@github.com:foo.git foo
cd foo
git checkout foo_branch
cd ..
git add -A
commit -va

# On another main repository checkout
git pull
git submodule update --init --recursive

Migrate SVN to GIT

svn log --quiet http://foo.com/trunk/foo_project | \
    awk '/^r/{print $3" = foo_user <foo_user@foo_host>"} {next}' | \
    sort -u \
    > authors-transform.txt
git svn clone http://foo.com/ \
    -A authors-transform.txt \
    --tags=./tags/foo_project/ \
    --trunk=./trunk/foo_project/ \
    --username foo_user \
    foo_project
git svn show-ignore -i trunk > .gitignore
git add .gitignore
git commit -m 'Convert svn:ignore to .gitignore'

sync commits

git svn rebase
git pull
git push

unable to stat just written file

git log -p $file

git checkout -- $file
# ||
git show $rev:$file > $file
git clean -d -f .
git reset HEAD $file
git add $file

# ||
git checkout -b wat
git add --force .
git commit -m "wat"
git checkout master
git branch -D wat
  • [cause] silent quarantine by antivirus
    • ~/Downloads/git-antivirus-silent_rm_file.CSV
    • procmon
      ekrn.exe | SetDispositionInformationFile | C:\Users\foo\code\src\PowerShell-lazywinadmin\foo | SUCCESS | Delete: True
      

index

# files in index
git ls-files --stage
# files in working tree
git ls-tree -r HEAD

https://mincong.io/2018/04/28/git-index/

Validate tracked changes

# xref changes
git reflog show HEAD
# ! git symbolic-ref HEAD | grep -q refs/heads/master
git reflog show master
git reflog show stash
git reflog show --all

# compare files in working tree and index
git diff-files

# rebuild index for a given file
git update-index --no-assume-unchanged path/to/file
# || git update-index --no-skip-worktree path/to/file
git rm --cached path/to/file
git reset path/to/file
# || git add -f path/to/file

# rebuild and validate index
git update-index --unmerged --refresh
git ls-files --cached --exclude-standard
git diff-files
git ls-files --others --exclude-standard

# checksum
diff -auw \
    <(git ls-tree -r HEAD | \
        awk '{for(i=3; i<=NF; ++i) printf $i""FS; print ""}') \
    <(git ls-tree -r --name-only HEAD | \
        xargs -n1 sh -c 'echo "$(git hash-object "$1")" "$1"' _)

# author date before file modification date
paste -d '\n' \
    <(git ls-tree -r --name-only HEAD | \
        xargs -n1 sh -c 'echo "$(git log -1 --format="%at" -- "$1")" "$1"' _) \
    <(git ls-tree -r --name-only HEAD | \
        xargs -n1 sh -c 'echo "$(stat --format='%Y' -- "$1")" "$1"' _) | \
    xargs -L2 sh -c '[ "$1" -lt "$3" ] && printf "%s\n%s" "$1 $2" "$3 $4"' _

# commit date before file modification date
paste -d '\n' \
    <(git ls-tree -r --name-only HEAD | \
        xargs -n1 sh -c 'echo "$(git log -1 --format="%ct" -- "$1")" "$1"' _) \
    <(git ls-tree -r --name-only HEAD | \
        xargs -n1 sh -c 'echo "$(stat --format='%Y' -- "$1")" "$1"' _) | \
    xargs -L2 sh -c '[ "$1" -lt "$3" ] && printf -- "%s\n%s" "$1 $2" "$3 $4"' _

manual index blob hash

git-hash-object () {
    local type=blob
    [ "$1" = "-t" ] && shift && type=$1 && shift
    # depending on eol/autocrlf settings, you may want to substitute CRLFs by LFs
    # by using `perl -pe 's/\r$//g'` instead of `cat` in the next 2 commands
    local size=$(cat $1 | wc -c | sed 's/ .*$//')
    ( echo -en "$type $size\0"; cat "$1" ) | sha1sum | sed 's/ .*$//'
}
git-hash-object ./foo

# https://matthew-brett.github.io/curious-git/reading_git_objects.html
git ls-files --stage | xargs -L1 sh -c '
dirname=$(echo "$2" | cut -c-2)
filename=$(echo "$2" | cut -c3-)
echo ".git/objects/$dirname/$filename"
' _ | xargs -I{} python3 -c '
import sys, zlib
print(zlib.decompress(open(sys.argv[1], "rb").read()))
' {}

git ls-files --stage | xargs -L1 sh -c '
dirname=$(echo "$2" | cut -c-2)
filename=$(echo "$2" | cut -c3-)
echo ".git/objects/$dirname/$filename"
' _ | xargs -I{} python3 -c '
from hashlib import sha1
import sys, zlib
print(sha1(zlib.decompress(open(sys.argv[1], "rb").read())).hexdigest())
' {}
def git_blob_hash(data):
    if isinstance(data, str):
        data = data.encode()
    data = data.replace('\r\n', '\n')
    data = b'blob ' + str(len(data)).encode() + b'\0' + data
    h = hashlib.sha1()
    h.update(data)
    return h.hexdigest()

decompress objects

# [Optional] On packed objects
mkdir -p .pack
find .git/objects/pack/ -type f -iname '*.pack' \
    | while IFS= read -r i; do
    mv "$i" .pack/
    git unpack-objects < .pack/"$i"
done

find .git/objects/ -type f | xargs -I{} python3 -c '
import sys, zlib
print(zlib.decompress(open(sys.argv[1], "rb").read()))
' {} | vim -

show changes in commit

https://stackoverflow.com/questions/17563726/how-to-see-the-changes-in-a-git-commit

git diff COMMIT~ COMMIT
git diff COMMIT^!
git show COMMIT

clone using ssh key

git clone git@foo.com:foo-team/foo.git

grep / search

# across commits / history
query=
git rev-list --all | xargs -I{} git grep "$query" {}
subtree=
git rev-list --all -- "$subtree" | xargs -I{} git grep "$query" {} -- "$subtree"

# across branches
query=
git show-ref --heads | awk '{print $2}' | xargs -I{} git grep "$query" {}
# ||
git log -S foo -c
git log -S foo --all -- '*.js'

# changes of specific commit
git log -1 -c $sha1sum

# by filetype, from worktree root
git grep foo -- '/*.js' '/*.cs'

https://stackoverflow.com/questions/2928584/how-to-grep-search-committed-code-in-the-git-history

dump public repository from site

case studies

pull request triggers a merge push

explaining internals