INDEX
########################################################### 2024-01-26 11:10 ########################################################### Pro Git I'm just going to write notes for misc details in ProGit - if I see anything of value git config --list --show-origin # Show all config and where it is set git commit -a -m "TEXT" # Commit changes (to tracked files) without staging git rm FILE # Deletes a file and removes from staging git rm --cached FILE # Delete a file in staging git log -p # Show log of changes, with patch info - or use "--stat" for "1 file changed" git log --pretty=format:"%h - %an, %ar : %s" # Print change logs in a set format git log --graph # Show branches in a graph git log --since=2.weeks # Get last 2 weeks of changes (can also use date) git log -S FUNC # Find changes around a given keyword - also --author and --grep git commit --amend # Adds stages files to last commit (don't ammend pushed commits) git reset HEAD FILE # Unstage a specific file (alt "restore --staged) git checkout -- FILE # Revert file to the last tracked version (alt "restore FILE) Having multiple sources means you can pull from multiple collaborators Can use different protocols like http, git, ssh etc. git remote -v # Show remote repositories for the repo git remote add NAME URL # Add a new remote git fetch NAME # Pull branches and data from remote repo (e.g. pulls NAME/master branch) git fetch origin # Pulls all changes in origin (but does not merge) git pull # Pulls changes and merges them git push REMOTE BRANCH # Push branch changes to a remote repo (e.g. git push origin master) # Will be rejected if your version is behind changes in remote git remote show origin # Show info about a remote repo, with expected behaviour git remote rename OLD NEW # Rename a remote repo git remote remove NAME Tags point to specific positions in a repo's history (usually for release points) They are either lightweight (commit pointer) or annotated (summed, signed, messaged etc.) git tag # List tags (in alphabetical order) - use "-l" to search git tag NAME # Create lightweight tag (essentially just an alias for a commit) git tag -a NAME -m COMMENT # Create annotated tag git show NAME # Shows tag info and what commit this relates to git log --pretty=online # List commits in a list (extract part of a checksum) git tag -a NAME CHECKSUM # Add a tag to a specific commit # git push does not transfer tags - have to do that explicitly git push origin NAME # Push a specific tag git push origin --tags # Push all local tags (--follow-tags for annotated only) git tag -d NAME # Delete a tag (from local only) git push origin --delete NAME # Delete a tag remotely git push origin :refs/tags/NAME # Also deletes tag remotely (read as NEWVAL:OLDVAL) git checkout NAME # Checkout the commit that a tag points to Can set git aliases in the same way as bash aliases - do "alias.NAME "!COMMAND" for shell git config --global alias.st status # Now "git st" = "git status" git config --global alias.last 'log -1 HEAD' # Now "git last" = show most recent commit A commit points to a tree which points to "blobs" - these represent snapshots of files Each commit points to the previous commit (forming a chain of commits) So branches are just pointers to commits - from this position, write new commits git branch testing # Make a new "testing" branch - just makes a new pointer to current commit # HEAD = pointer to current branch (HEAD -> Branch -> Commit) # Where HEAD is changes what files are in the folder - shows only current branch files git checkout NAME # Move HEAD to another branch git log --all # Show all logs - "git log" usually only shows history of your current branch git log --all --graph --decorate --online # Show branchesq git checkout -b NAME # Can create and checkout branch at same time git switch -c NAME # Alt to "checkout -b" - use "switch -" to return to previous If you make a branch from master and commit some change, you want to merge the branches git checkout master; git merge NAME # Merge some branch into master branch # This is a "fast-forward" as all it does is move the master pointer git branch -d NAME # Deletes the old branch after merging # What if you have another branch on a different path (not directly ahead from master) git merge master # Could make the current branch up to date by pulling from master git checkout master; git merge NAME # OR merge into the branch into master, as before # Git creates a new commit pointing to both old commits (the branch and the old master) # This is a "merge" commit If merge doesn't go smoothly, there are conflicts - automatic merge does not run git status # See where conflict occurs # Open these files manually and there are conflict resolution markers showing how to fix git add FILE # Once these files are edited manually, readd them to fix merge git mergetool # Open a graphical tool for fixing merge issues git branch -v # Show branches, HEAD and last commits on each git branch --merged # Show which branches are effectively the same (can be deleted) git branch --no-merged # Show branches that are not merged (different) # Can rename branches git branch --move OLDNAME NEWNAME git push --set-upstream origin NEWNAME # Add new branch upstream (with NEWNAME) git push origin --delete OLDNAME # Delete (cloned) branch with OLDNAME Often projects have pointers for stable, development and testing - tiers of stability A topic branch is a short-lived branch for a specific feature - silo changes by subject Remote references point to remote objects (e.g. tags in another repo) git ls-remote REMOTE; git remote show REMOTE # Keeps track of state of a remote resource since last communication git push origin OLDNAME:NEWNAME # Push a local OLDNAME branch as NEWNAME on origin git checkout -b BRANCH origin/BRANCH # Download a remote tracked branch and work on it A tracking branch is a branch linked to a specific server - e.g. origin/master git checkout --track REMOTE/BRACH # Same as -b BRANCH REMOTE/BRANCH - alt "checkout BRANCH" git branch -u REMOTE/BRANCH # Link a local branch (that already exists) to a remote server git branch -vv # List tracking branch remote servers git fetch --all # Updates stats on ahead-behind, and downloads all new files git pull # Essentially fetch+merge git push origin --delete BRANCH # Delete a remote branch When you combine branches you either use "merge" or "rebase" or "fastforward" Rebasing is fastforward+merge - so undo dev, fastforward dev to main, redo dev changes, merge git checkout dev; git rebase master # Rebases current "dev" onto master git checkout master; git merge dev # Fast forward "master" to "dev" # Makes for a clean linear history - change is essentially the same as a merge git rebase --onto TO FROM BRANCH # So rebase a branch from one branch to another git checkout TO; git merge BRANCH # Now those 2 branches are the same git rebase TO BRANCH # Similarly merge 2 branches that are directly connected # Do not rebase commits that exist outside your repo - that others may have based work on Advised to have a shared repo everyone has access to - use as a central source of truth Servers usually use bare repositorires - just .git, not files # Local protocol: host on a file directory git clone /srv/git/project.git # Or "file:///srv" (which is slower, uses other internals) git remote add local_proj /srv/git/project.git # Add a local repo to existing project git pull /home/john/project # Pull code from somewhere on server # Smart HTTP: Uses HTTPS and HTTP auth - Uses website logins to access # Dumb HTTP: Serves git like a file server, using hooks - basically readonly mv project.git/hooks/post-update.sample project.git/hooks/post-update # Give read access git update-server-info # SSH protocol: Use ssh to do file transfer - needs SSH access to read data git clone ssh://USER@SERVER/project.git # Git protocol: (fastest ssh no encryption) Run a git daemon - basically opens port 9418 git clone git://example.com/project.git # To set up a git server, you need a bare repo git clone --bare PROJECT my_project.git # Creates a "my_project.git" folder scp -r my_project.git user@git.example.com:/src/git # Copy to server to host it git init --bare --shared # Gives access permissions for repo (does not change contents) git-shell # Limited shell tool to just run git commands - set this for "git" user Can run a basic web server with git (lighttpd/webrick) git instaweb --http=webrick # Serves on 1234 with ruby git instaweb --http=webrick --stop Can manage git repos over email git format-patch -M origin/master # Create patch files for all commits - generate an email cat *.patch | git imap-send # Need to set up "[imap]" section in git config # Now in your email drafts is a patch request to sent git send-email *.patch # Need to set up "[sendmail]" to send direct to SMTP server git apply --check FILE.patch # Modifies current working setup to apply patches git am FILE.patch # Use dif "format-patch" was used (patch contains author info) # "git am" applies changes with author info, and exact commit info etc. git am --resolved # If there are conflicts, it works exactly the same as "git merge" Can cherry pick commits to "rebase for a single commit" - apply remote patches to your branch git cherry-pick HASH # Copies this commit as new # "Rerere" = Reuse recorded resolution - use patterns from old conflict merges to automerge git config --global rerere.enable true # Enable by defualt git rerere # Run manually at conflict When publishing tags, sign - can keep public key as a blob inside the repo gpg --list-keys # List local keys on your system gpg -a --export ID | git hash-object -w --stdin # Store that public key in repo (get blob ID) git tag -a maintainer-pgp-pub HASH # Create a tag with your public key git show maintainer-pgp-ub | gpg --import # Can import your pub key from repo (for later use) git describe master # Generates a "LASTRELEASE-COMMIT" label for current snapshot # To prepare a release, archive current snapshot files git archive master --prefix='project/' | gzip > `git describe master`.tar.gz # Can also do --format=zip to store as a zip file git shortlog --no-merges master --not v1.0.1 # Print release log since v1.0.1 There are other misc commands that are useful git show HEAD^2 # Show 2nd commit behind HEAD (current position) - alt. "HEAD~2" git log master..dev # See commits not yet merged from DEV into MASTER git log origin/master..HEAD # Compare current position to upstream master # Can do this with arbitrary pointers and use ^ for "not in": [A..B = ^A B = B --not A] git log --left-right master...dev # Show commits unmerged on either side git add -i # Interactively add git/remove git files git stash # Revert to last commit, but store changes away in save git stash list # List all stashes git stash apply ID # Restore changes from a stash (all changes unstaged) git stash apply --index ID # Keeps staged files from stash as staged git stash drop ID # Deletes a stash (or use "pop" to apply and delete) git stash -a # Stash untracked and ignored files (use -u for just untracked) git stash branch NAME # Make a branch from a stash git clean # Stash without the saving part - use "-n" to dryrun # To sign keys you need to give git a key to sign things with git config --global user.signingkey KEYID git tag -s v1.5 -m MESSAGE # Then put in gpg password and it signs it git tag -v v1.4.2.1 # Verify a tag (if public key is inside the repo) git commit -a -S -m MESSAGE # Similarly, sign a commit git log --show-signature -1 # Verify commit keys git merge --verify-signatures BRANCH # Merge only if keys exist and are valid git merge --verify-signatures -S BRANCH # Verify, merge and sign the merge git config --local commit.gpgsign true # Force all commits to be signed # Search through commit tree git grep -n SEARCH # Query and show line number git log -S SEARCH --online # Search logs for when an item was introduced git commit --amend --no-edit # Add new changes to commit, with same message git rebase -i HEAD~3 # Open interactive merger to 3 commits back # squash = combine commits, pick = apply that commit (used to rearrange) # Can rewrite lots of history to remove specific info (e.g. API keys) git filter-branch --tree-filter 'rm -f passwords.txt' HEAD # Delete "passwords.txt" globally # Run with --all to run on all branches HEAD = pointer to current branch = pointer to last commit = parent of last commit Index = proposed next commit (staging area) Working dir = actual files (staged+unstaged) git ls-tree -r HEAD # See files inside HEAD pointer git ls-files -s # List files in staging git reset --soft HEAD~ # Moves HEAD to previous commit git reset --mixed HEAD~ # Then updates Index with contents of HEAD (unstage files) git reset --hard HEAD~ # Then updates Working dir with contents in Index (resets files) git reset FILE # Copies file from HEAD to Index (unstages a file - "--hard" resets it) git reset --soft HEAD~2; git commit # Effectively squashes commits Git lets you merge and unmerge with different methods git merge --abort # Remove merge tags and undo auto merge git revert -m 1 HEAD # Like "git reset --hard HEAD~" but without editing history # But this can cause confusion with failed merges if you want to remerge git revert ^M; git merge topic # Solution is to undo the revert and then merge # Can set defaults with merges git merge -Xours BRANCH # Prefer to resolve conflict using BRANCH > master Get history of changes within a specific file with "blame" git blame -L START,END FILE # Show last changes/authors of lines in a file git blame -C FILE # Show blame, even if the file was renamed in commits # Go though change history and debug when a change broke soemthing git bisect start # Start the tracker git bisect bad # Denote where a problem is detected git bisect good TAG # Denote where a problem last did not exist # This walks you through commits till you find where a problem starts git bisect good # Problem does not exist yet - go ahead in history git bisect bad # Problem occurs - go behind in history git bisect reset # Once you find the issue, reset HEAD to where you were before Submodules are git repos inside repos - when a repo needs to be hosted as a folder in another git submodule add REPO # Clones repo into local folder # .gitmodules is created - git does not track contents of that folder but will download it git clone REPO # Clones a repo but doesn't download submodules git submodule init # Link submodule to folder git submodule update # Download data from submodule project (or "submodule update --init") git clone --recurse-submodules REPO # Download repo with all submodules git fetch; git merge origin/master # (inside submodule) update subrepo git submodule update --remote SUBMODULE # Updates submodules for you git config -f .gitmodules submodule.SUBMODULE.branch BRANCH # Track specific branch git pull # Recursively fetches submodule changes but does not update submodules git submodule update --init --recursive # Updates submodule too git pull --recurse-submodules # Pulls and also updates submodules # Usually when you update submodule it leaves subrepo in detatched HEAD (no working branch) git push --recursve-submodules=on-demand # (need to checkout a branch) Push ALL changes Can bundle changes from a repo into a single file git bundle create repo-bundle HEAD master # Creates "repo.bundle" git clone repo.bundle repo # Clones from a file git bundle create commits.bundle master ^COMMIT # Get all commits up to a point git bundle verify ../commits.bundle # Verifies whether it is a valid bundle git fetch ../commits.bundle master:other-master # Add bundles commits to a new branch Git can be configured to use other default tools for internal actions git config diff.exif.textconv exiftool # use exiftool to diff image files # Data is stored in git as hash-object key-value pairs in .git/objects echo 'test content' | git hash-object -w --stdin # Store text with hash index find .git/objects -type f # List all stored objects git cat-file -p ID # Print out contents of hash object (does not arrange data by filenames)