Git
Git Basics
Basics
clone a repository
git clone git@github.com:entorb/rememberthemilk.git
perform a commit
git add . git commit -m "my commit message" git push
Git Settings
!!! End of Line !!!
Force Git for Windows to use Linux end of line: LF (\n) instead of CRLF (\r\n)
git config --global core.autocrlf false git config --global core.eol lf
To use git to fix bad line endings, add a .gitattributes file to the repo with this contents:
* text=auto eol=lf
colorful output
git config color.ui true
log: one line per commit
git config format.pretty oneline
Branching
# create new branch git checkout -b history-change # del branch git checkout main git branch -d history-change
Rename branch master to main
1. at github.com in the settings of the repo, rename the default branch name, for example at https://github.com/entorb/tools/settings/branches
2. update in local repo
git branch -m master main git fetch origin git branch -u origin/main main git remote set-head origin -a
3. set default branch name in local git
git config --global init.defaultBranch main
History
Reports
Git Log
git log git log --pretty=oneline --abbrev-commit # list commits including the change summary, e.g. 1 file changed, 16 insertions(+), 2 deletions(-) git log --date=short --pretty=format:"%cd %h %s" --shortstat
Git Rev-list
# Get the total commits by week git rev-list --count HEAD --since=4.week git rev-list --count main --since="Dec 1 2021" --before="Jan 3 2022"
Report of merges
var1 git --no-pager log --merges --pretty=format:'MyRepoName %cs %ae %s' | grep -v 'dependabot' >> ../git-merge-report.csv var2 git --no-pager log --grep='#' --pretty=format:'MyRepoName %cs %ae %s' --after 2022-01-01 >> ../git-merge-report.csv # note: in one repo the '--merges' flag did not find all merge PRs, so using --grep='#' instead
Checking History
Display all commits that modified a certain file
git log --no-decorate --pretty=format:"%h%x09%ad%x09%an%x09%s" --date=iso -- data/de-districts/de-district_timeseries-02000.tsv # %x09 : tab
Modifiying History
Merge 2 repos
see https://github.com/entorb/tools/blob/main/git-tools/git-merge-2-repos.cmd
delete a dir from historiy using git-filter-repo
preferred as of 2022 history cleanup using git-filter-repo
pip install git-filter-repo git clone xxx cd xxx # backup .git/config cp .git/config ../config git-filter-repo --prune-empty always --invert-paths --path draft --path old --path maps/out # restore .git/config cp ../config .git/config git reflog expire --expire=now --all git gc --prune=now --aggressive git push -f
to remove certain files matching a glob from history
git-filter-repo --prune-empty always --invert-paths --path-glob "*.creds" --path-glob "data/*/*.json"
afterwards revert your local repo to the remote one
git fetch origin git reset --hard origin/main git pull
combine changes to README.md etc into single commit
see https://github.com/entorb/tools/blob/main/git-tools/git-hist-combine.sh
delete a dir from historiy using bfg
note: better use git-filter-rep (see above)
using bfg
https://github.com/entorb/tools/blob/main/git-tools/git-bfg-cleanup-delete-history-of-dir.cmd git reflog expire --expire=now --all git gc --prune=now --aggressive
squash/merge old commits
git rebase -i --root # this opens a list of all commits in you editor # replace pick by squash for the ones to
delete complete commits history
First Method from [1]
# Check out to a temporary branch: git checkout --orphan TEMP_BRANCH # Add all the files: git add -A # Commit the changes: git commit -am "Initial commit" # Delete the old branch: git branch -D main # Rename the temporary branch to main: git branch -m main # Finally, force update to our repository: git push -f origin main
Second Method via "deleting .git folder" also from [2]
# Clone the project, e.g. `myproject` is my project repository: git clone https://github/heiswayi/myproject.git # Since all of the commits history are in the `.git` folder, we have to remove it: cd myproject # And delete the `.git` folder: rm -rf .git # Now, re-initialize the repository: git init git remote add origin https://github.com/heiswayi/myproject.git git remote -v # Add all the files and commit the changes: git add --all git commit -am "Initial commit" # Force push update to the main branch of our project repository: git push -f origin main
Alternative method:
https://www.willandskill.se/en/deleting-your-git-commit-history-without-removing-repo-on-github-bitbucket/
Hacks
Merge GitHub Dependabot PRs
# switch to main branche and pull updates
current_branch=$(git branch --show-current)
if [ "$current_branch" != "main" ]; then
echo "branch was: $current_branch"
git checkout main
fi
git pull
# update origin
git fetch origin
# list all branches that start with "dependabot/" but not "springframework" and save to c:/tmp/dependabot-branches.txt
git branch -r | grep /dependabot/ | grep -v springframework >c:/tmp/dependabot-branches.txt
# create empty file
echo "" >c:/tmp/dependabot-changes.txt
while read -r branch; do
# remove "origin/" from the branch name
branch_name="${branch#origin/}"
echo "# $branch_name"
echo "# $branch_name" >>c:/tmp/dependabot-changes.txt
# switch to branch and pull latest version
git checkout "$branch_name"
git pull
# show changes to file pom.xml only
git diff main --unified=0 pom.xml >>c:/tmp/dependabot-changes.txt
echo ""
echo "" >>c:/tmp/dependabot-changes.txt
done <c:/tmp/dependabot-branches.txt
# back to main branch
git checkout main
# filter on changes only
grep -e '^[#\+\-] ' c:/tmp/dependabot-changes.txt >c:/tmp/dependabot-changes-filtered.txt
Cleanup
Remove branch not (any more) on main
prunes tracking branches not on the remote. from https://stackoverflow.com/posts/28464339/timeline
git remote prune origin
list branches that have been merged into the current branch.
git branch --merged
Reverting
reset to a commit
get hash of commit git log --oneline git reset --hard HEAD~1 # git push -f
revert a commit
get hash of commit git log --oneline git revert <commit hash> # git push -f
Reset branch to remote branch
from [3] Setting your branch to exactly match the remote branch can be done in two steps:
git fetch origin git reset --hard origin/main # git push -f
Fixing/Overwriting authors/emails
list authors
git shortlog -sn --all git log --pretty --author="my@mail.com"
perform the history rewrite using global git config (from https://stackoverflow.com/questions/750172/how-do-i-change-the-author-and-committer-name-email-for-multiple-commits/1320317#1320317)
git rebase -r --root --exec "git commit --amend --no-edit --reset-author"
Squashing
Squash last 3 commits
git reset --soft HEAD~3 && git commit
revert local git to remote repository
from [4]
git reset --hard HEAD git clean -f -d git pull
GIT Commit to an existing Tag
from https://gist.github.com/danielestevez/2044589
1) Create a branch with the tag
git branch {tagname}-branch {tagname}
git checkout {tagname}-branch
2) Include the fix manually if it's just a change ....
git add .
git ci -m "Fix included"
or cherry-pick the commit, whatever is easier
git cherry-pick {num_commit}
3) Delete and recreate the tag locally
git tag -d {tagname}
git tag {tagname}
4) Delete and recreate the tag remotely
git push origin :{tagname} // deletes original remote tag
git push origin {tagname} // creates new remote tag
5) Update local repository with the updated tag (suggestion by @wyattis)
git fetch --tags
This is based on https://gist.github.com/739288 thanks to nickfloyd for it
Chmod
set executable flag. see [5]
git update-index --chmod=+x file
Error handling
Error:
git pull --tags origin main [rejected] ... (would clobber existing tag)
Fixed by updating local tags with remote tags
git fetch --tags -f
Tag handling
Delete a tag locally
git tag -d myTag
Delete a tag remotely
git push --delete origin myTag
Clean up via Garbage Collector
git reflog expire --expire=now --all git gc --prune=now --aggressive
Scripts
Re-apply .gitignore
see https://github.com/entorb/tools/blob/main/git-tools/git-gitignore-reapply.cmd
REM Remove everything from the git index in order to refresh your git repository: git rm -r --cached . REM Add everything back into the repo: git add . git commit -m ".gitignore re-applied" git status pause git push
pull on all repos
for D in $(ls -d */); do echo === $D === cd $D # git status current_branch=$(git branch --show-current) if [ "$current_branch" != "master" ] && [ "$current_branch" != "main" ]; then echo "branch was: $current_branch" git checkout main if [ $(git branch --show-current) != "main" ]; then git checkout master fi fi git pull --force cd .. done read -p "Enter to close"
revert on all repos
for D in $(ls -d */); do echo === $D === cd $D current_branch=$(git branch --show-current) if [ "$current_branch" != "main" ]; then echo "branch was: $current_branch" git checkout main fi git fetch origin git reset --hard origin/main git pull cd .. done read -p "Enter to close"
GitHub.com Tipps
create PR for another fork
- on github.com propose an edit for 1 file
- this creates a branch in our repo based on the fork, called patch-1 or similar
- rename the branch at `github.com/<your name>/<your repo>/branches/yours`
- now you can locally pull from your main to fetch the new fork and locally add more modifications
- I suggest keeping "unmodified" base-branches of other forks, so easily create new PRs and branches based on them
- to update the fork from he fork's main, use github.com
Copy commit from parent/upstream repo to forked repo
ensure that the parent repo is listed as upstream:
git remote -v git fetch upstream # Create new branch git checkout -b copy-commit-branch git cherry-pick <commit-hash> # Resolve conflicts (if any): git cherry-pick --continue git push origin copy-commit-branch # Finally create a pull request
Short version
git fetch upstream git cherry-pick <commit-hash> git push
Notes of 2020
very nice tutorial: git - Der einfache Einstieg
Old notes
git init # create an empty git repository in the current folder # set some settings git config --global user.name "Torben Menke" git config --global user.email "torben.menke@XXX.de" git config --global color.ui auto git config -l # shows configuration git add somefile.txt # one file git add somefolder # one folder git add . # all git commit git commit -a -m "message" # commit all, message="message" git pull ssh://tmenke@[IP]/[PATH] main # edit # commit git push ssh://tmenke@[IP]/[PATH] main git log git log --pretty=oneline --abbrev-commit