git Notes - ipatch/dotfiles GitHub Wiki

Contents

Contents / Sub commands

Contents / Tooling

Gotchas 😬 πŸ”

Working with multiple forks in a single git repo

Use Case Working with the Marlin Firmware

Git allows me to track multiple remote forks in a single git repo which is helpful for containing different branches of different forks of a single project within a single local dir / git repo. However there are some caveats when setting up a project this way. These notes should not be taken as gospel but rather considered a reasonable practice, and not even considered a best practice, for the fact that I haven't extensively use git for such means.

For my particular use case, I forked the Marlin Firmware for a GitHub to work on my local changes of the Marlin source for my specific 3d printer. I setup my fork to be the origin of the marlin fork, and set the upstream to be the official Marlin repo, so that I can pull in upstream changes from the official marlin repo at my leasure, while maintaining my local changes and not creating an entire mess of the project. That said, InsanityAutomation maintains an active fork of the Marlin repo specific to Creality printers, which I would also like to checkout branches and experiment with features from his / her fork. I might have forked and cloned InsanityAutomation's fork of Marlin as well within a completely separate local directory on my box, and that seems like a code smell for maintaining separate local directories of essentially the same proect, so instead forking forks and forgetting what is exactly where, since IA forked the same git project as myself, and I setup my local fork of Marlin to track his fork of Marlin, so I only have one directory on my box containing the Marlin source, but have setup multiple remotes tracking multiple forks of the Marlin firmware.

Example

To list all remotes can be considered remote git projects that are forked from the Marlin source.

git remotes
Output
InsanityAutomation      https://github.com/InsanityAutomation/Marlin (fetch)
InsanityAutomation      https://github.com/InsanityAutomation/Marlin (push)
origin  https://github.com/ipatch/Marlin.git (fetch)
origin  https://github.com/ipatch/Marlin.git (push)
upstream        https://github.com/MarlinFirmware/Marlin (fetch)
upstream        https://github.com/MarlinFirmware/Marlin (push)

The remotes can be modified with the git subcommands

git remote add [NAME OF REMOTE] [https://github.com/[USER]/[PROJECT].git]
echo "example"
git remote add origin https://github.com/ipatch/Marlin.git

If a remote needs to be updated

git remote set-url [NAME OF REMOTE] [UPDATED URL]

❗️ Even though the local git fork is setup to track a remote, such as for my case, my local fork of Marlin is tracking the official git repo / project, I'm also tracking the InsanityAutomation fork of Marlin, thus the multiple remotes, and with out fetching the objects (using that term very loosely here), I will not be able to checkout any of the branches specific to the IA fork of marlin, to checkout a remote fork's branch, first fetch the remotes objects

git fetch [NAME OF REMOTE]
echo "my use case"
git fetch InsanityAutomation

After fetching the objects (I'm considering these to the IA specific branches of the Marlin project). I can fetch a branch specific to the IA fork of Marlin.

git branch --all
git checkout [NAME OF REMOTE/NAME OF BRANCH]
echo "my use case"
git checkout --track InsanityAutomation/CrealityDwin2.0_Bleeding

I've had mixed results with using git checkout --track for pulling in a new upstream branch into a local fork of an upstream project, the below command may also work if issues arise with the above methods

git fetch upstream
git fetch upstream [BRANCH_NAME]
git remote set-branches --add [NAME_OF_REMOTE] [BRANCH_NAME]

echo "verify remote branch exists in local fork/repo"

git branch --all

❗️ I'd highly suggest creating a local branch from the freshly checked out branch so things do not become an entire mess in the future.

Gotchas resumed

To download a single directory folder or directory from GitHub the easiest solution I've found is to use svn checkout

svn checkout https://github.com/ipatch/dotfiles/trunk/install

git can not expand SHELL environment variables stored in the .gitconfig, ie. $HOME will not be expanded in .gitconfig.

When creating folders / directories within a git repo remember there must be a file placed within the directory ie. a .gitkeep file in order for git to start tracking the directory.

To remove files from local & remote git repositories

git rm --cached /path/to/mr-fancy-pants

Make sure to add /path/to/mr-fancy-pants to .gitignore after removing the cached files.

Gotchas working with remote branches πŸ”

🚨 make sure there is a tracking information setup for the branch if trying to fetch remote counterparts without merging them, ie. git remote update will not print any warnings or errors when run on a local branch without a remote counterpart. true story

To setup a remote tracking branch for the local working branch for a git project

git branch --set-upstream-to=origin/[mr-fancy-branch] [mr-fancy-local-branch]

local branches generally have the same name as their remote counterparts.

GitHub Notes πŸ”

To find the date of the first commit for a GitHub repo divide the total number of commits by thirty five 35, ie. (the number of commits displayed per page when viewing the commit history for a project on GitHub).

Ex

2600 / 35 ~= 74.2...

Round 74.2 up to 75 and the first commit for a project will be displayed on the 75th page of the git repo.

https://github.com/mr-fancy-42/repo/master?page=75

To view the history / log of a GitHub wiki

https://github.com/[USER]/[REPO]/wiki/_history
https://github.com/mr-fancy-user/42/wiki/_history

To test and make sure OpenSSH is working properly with GitHub

should output the below,

Hi ipatch! You've successfully authenticated, but GitHub does not provide shell access.

To search for a particular file on GitHub.com

β€œtmux.conf” in:path

Working with other repos πŸ”

If local fork of a project, ie. my fork of asdf is several commits behind the upstream counterpart, upstream commits can be merged into the master branch of the local fork.

  1. Fetch the upstream changes
git fetch upstream master

The above git command will not merge remote changes into local fork.

To merge remote changes into local fork's master branch

git pull upstream master
  1. Switch to local fork's master branch
git checkout master
  1. Merge upstream changes into local fork's master branch
git merge upstream/master

To push remote changes merged into local fork from running prior git commands

git push origin master

GitHub Useful Links πŸ”

git rebse πŸ”

git rebase is useful for working on a forked project from GitHub, and one wants to condence all their local / remote commits to one substantial commit for easy PR's to the maintainers of the main repo of the locally forked project.

git rebase Example

git rebase Use case πŸ”

You have forked a project on GitHub, and your project is ~ 35 commits ahead of it's forked counterpart. You want to squash all local 35 commits into one.

To start an interactive rebase session.

git rebase -i

The above command will open up the $EDITOR and each commit can be marked with a one letter value described in the editor session, ie. s for squash commit.

If the ~ 35 commits have been pushed to GitHub one can push the rebase to a remote repo if no one else is working with the remote repo.

To force push a rebase to GitHub

git push origin +master

If the interactive rebase encouters issues, one will have to handle merge conflicts, usually by running git add --all and then running git rebase --continue to continue with the rebase.

To change the commit message after rebasing

git commit --amend -m "my fancy ammended commit"

To overwrite all local changes with those of the upstream master branch

git pull --rebase upstream master

git rebase Troubleshooting πŸ”

To abort a rebase

git rebase --abort

git reset

To switch / checkout or rollback / revert a paritcular branch / tag / commit

git reset --hard [tag|branch|commit ID]

git Submodules πŸ”

To pull the latest changes from a remote repository for a submodule

git submodule update --recursive --remote
git pull --recurse-submodules # or
git pull upstream master --recurse-submodules # or
git submodule foreach git pull origin master # or

When cloning a git repo that contains submodules, the submodule git repos will always clone with detached HEAD. see this

To add a .wiki GitHub repo as submodule to the parent repo

git submodule add https://github.com/ipatch/theairportwiki.wiki.git .wiki

To remove a link related to a submodule

git ls-files --stage | grep 160000

Output will look something similar to,

160000 e2b695b0432a600ff6d023ed4c9b9f3516673c7f 0	config/base16-shell
160000 911459645f76c7fb977520beddec2d552117e7b2 0	config/config/base16-shell
git rm --cached config/config/base16-shell

To push all git repos including submodules with staged commits

git push --recurse-submodules=on-demand

Troubleshooting git submodules πŸ”

If you run into the below error when working git submodules

mr-fancy-42-repo already exists in the index
  1. Remove the submodule folder / directory
  2. Remove the git cache for the folder / directory
  3. Then reinitialize submodule
rm -rf /path/to/mr-fancy-42-repo
git rm -r /path/to/mr-fancy-42-repo
git submodule add [mr-fancy-42-submodule-repo] /path/to/initialize/submodule/repo

git clone πŸ”

⚠️ When performing a git clone git defaults to cloning all meta data related to the master branch.

To clone a repository with a specified history use the --depth flag, ie. 50 specifies the last number of commits to be cloned into the local git repo.

git clone --depth 50 [email protected]:ipatch/dotfiles.git

To clone a specific branch from a particular repo

git clone -b [branch-name] [remote-repo.git]

To clone repo submodules after a repo has already been cloned.

git submodule update --init --recursive

To clone a repo and all included submodules in the repo

git clone --recurse-submodules https://tld.com/username/repo.git

A git repository can be cloned with a depth of 1 which can be considered a shallow clone of a repo, which will not expose the remote repo branches to the locally cloned repo. That said, there is a bit of a work around to fetch and checkout out a remote branch that does exist locally.

Example

git clone --depth=1 https://github.com/ipatch/KegCop
git config remote.origin.fetch +refs/heads/\*:refs/remotes/origin/\*
git fetch --unshallow
git co dev

An alternative to the above method of checking out remote branches on a locally shallowed cloned repo

git clone --depth=1 https://github.com/ipatch/KegCop --no-single branch

Working with git checkout

git checkout can be used to selectively upgrade a file or a hunk of files from one branch to another.

Example

Some updates were applied to a directory of files on the master branch and one wants to update a branch with only files from a specific directory that were changed on the master branch.

git checkout branch-that-needs-updating
git checkout master -- [./path/to/hunk/dir/of/files]

Files can be selectively updated interactively if preferred.

git checkout branch-that-needs-updating
git checkout -p master -- [./path/to/hunk/dir/of/files]

To undo the applied changes

git reset [./path/to/hunk/dir/files]

git clean πŸ”

To clean artifacts when configuring and building projects from within the git project root

git clean

The above command is useful for cleaning artifacts from running the below commands

  • ./configure
  • make

git rm πŸ”

To remove a file from a git repository, and stop tracking the file with git

git rm mr-fancy-file.txt

git rm use case

You have accidently pushed local files to a remote repository, and now you do not want the files on the remote repository

git rm --cached -r .

The above command will remove all cached files in the working directory. ⚠️ Remember to update the .gitignore for the repo to reflect the new changes.

git merge πŸ”

#git #single #merge #OneFile #checkout #hot #HotFix

To merge in a single file from a remote counterpart from a different branch or even a different remote, ie. upstream

git fetch
git checkout upstream/master [path/to/file]

To continue a merge after fixes have been applied because an automerge / auto merge failed for whatever reason.

git merge --continue

To merge in a single file from a development branch into master.

git checkout master
git checkout --patch dev-branch ./path/to/file

If ./path/to/file does not exist omit the --patch flag

To merge two git repos with unrelated histories

git merge --allow-unrelated-histories

To resolve changes that can not be auto merged, use the_platinum_searcher along with fish and sed to search for certain patterns within the Formula directory

ie. to remove all lines where the first char begins with = and ends with =

for i in *.rb
  sed -i -e 's/^==$//g' $i
end

ie. to remove all lines that start with >>>>>>> [followed-by-a-41-char-hash]

for i in *.rb
  sed -i -e 's/>>>>>>>.*//g' $i
end

ie. to remove all occurences of <<<<<<< HEAD

for i in *.rb
  sed -i -e 's/<<<<<<< HEAD//g' $i
end

git branch πŸ”

To create a new branch and switch to it after creating it with one command to rule them all

git checkout -b "mr-fancy-pants-branch"

To get a list of remote branches for the current git repo / project

git branch -r

As of June 26 2018, I don't think git provides a facility to checkout all remote branches from a remote repo. 🀷 That said, the below two commands pair well 🍷 πŸ§€ with each other.

git branch --all
git checkout "mr-fancy-42-remote-branch"

To list all branches of a git repository

git branch -a

To checkout a remote branch that presently isn't available locally

git co mr-fancy-42-branch/develop

To delete a local git branch

git branch -d mr-fancy-pants

To delete a remote branch

git push origin --delete mr-fancy-pants

To push a locally created branch to its remote counterpart

git push -u origin [mr-fancy-branch]

To rename a branch locally and remotely

git branch -m [old-branch-name] [new-branch-name]

git branch Advanced Usage πŸ™„ πŸ”

To remove a reference from a local repo to a remote branch that no longer exists

git fetch --prune

The above command will update local refs to remote counterparts

To delete all local tracking branches that don't exist on the remote

git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}' | xargs git branch -d

The above command will need to be run bash

git branch rename workflow πŸ”

  1. rename the branch locally
  2. push new branch name to remote repository
  3. delete old-branch locally
  4. delete old-branch remotely

git branch shallow clone πŸ”

When working with a shallow clone of a git repo, remote branches can not be checked out using standard methods. The procedure for checking out a remote branch from a shallow clone is as follows.

git clone --depth 1 [email protected]:user/repo.git
git remote set-branches origin 'remote_branch_name'
git fetch --depth 1 origin remote_branch_name
git checkout remote_branch_name

git pull πŸ”

To undo a git pull

git reset --hard

To reset a repo from its upstream counterpart

git remote update
git reset --hard upstream/master --

git push πŸ”

To push a submodule repo, ie. the repo that houses this wiki πŸ™‹ to a specific remote repo, ie. notabug.org

git push notabug.org master

The remote repo name is contingent on the name of the remote repo in the config file for the git project.

To push local changes to a remote repo and overwrite the remote changes

git push -f [remote-repo-name] [branch]

Ex

git push -f notabug.org master

-f flag force local changes to overwrite remote counterparts.

git stash πŸ”

To create a stash with a specific name

git stash save [mr-fancy-42-stash-name]

To git stash only a specific file

Requires git β‰₯ 2.13

git sash push -m [NAME-OF-STASH] /path/to/stashed/file

To blow up πŸ’£ local changes and overwrite with the remote counterparts

git stash --include-untracked
git pull

🚨 To remove all local entries from the local stash

git stash clear

To list all local entries in the local stash

git stash list

To apply a stash to the current branch

git stash apply

To git stash drop a specific / single stash on the git stash stack / list

fish shell requires escaping curly braces

git stash drop stash@\{42\}

If the applied stash looks good, then it can be removed with the drop command.

git stash drop

git tag πŸ”

To create a git tag for a particular commit

git tag v0.1.0

To print or show all the tags for a git repo

git tags

To push git tags to a remote repo

git push origin master --tags

To checkout and work with a specific tag release of a git repository

git checkout tags/[mr-fancy-tag-name] -b [mr-fancy-branch]

To check out all tags for a particular repo

git fetch --all --tags

To delete a tag

git tag -d [mr-fancy-tag-name]

Example

git checkout tags/v0.0.8

The above command will checkout the release v0.0.8 in a detached head state.

To verify GPG signed tag release

git tag --verify [v[MAJOR.MINOR.PATCH]]

git tag troubleshooting πŸ”

To delete a remote tag stored a git repository somewhere

git push --delete origin [mr-fancy-tag]

To delete a local tag

git tag --delete [mr-fancy-tag]

To make a tag point or reference a particular commit

git tag -a [mr-fancy-tag] [commit-hash-bdeb92d] -m "mr-fancy-tag-message-here"

To push the newly created tag to a remote repository

git push --tags origin master

git remote

To set the origin URL / remote for a git repo

Ex

git remote set-url origin [email protected]:<user_name>/<repo_name>.git

Example

git remote set-url origin [email protected]:ipatch/neomutt.git

To add an additional origin to existing git repo

git remote set-url --add origin [email protected]:truckmonth/dotfiles.git

To add an additional remote with a different name

git remote add gitlab [email protected]:truckmonth/dotfiles.git

To add an upstream repo that Pull Requests can be set to from a local fork

git remote add upstream [email protected]:GitOrg/mr_fancy_42_project.git

The above command is useful for setting up a clone to send local changes to an upstream repo.

To verify the new upstream repo has been added

git remotes

To manually modify the remotes for a git repo

  1. Edit .git/config
  2. Look for the [remote "origin"] heading and edit accordingly.

configuring a remote fork πŸ”

.gitignore πŸ”

To see the value, ie. the file for handling USER specific ignores

git config --list --show-origin

To set a global ignore file for a particular user

git config --global core.excludesfile "$XDG_CONFIG_HOME/git/ignore"

To get the above command to work properly on both a macOS environment and a Linux box, link the /home dir on macOS to the /Users dir, and put /home/[username]/.config/git/ignore in the gitconfig file, and everything should be kosher ✑️

Troubleshooting .gitignore πŸ”

As of git >= 1.8.2 git supports ** in a .gitignore file.

Ex

**/node_modules/*

The above line should ignore all files within a node_modules directory.

If the files are already being tracked 🚐 by git, then they will have be removed from the git cache

Ex

git rm -r --cached node_modules

macOS πŸ”

To avoid pushing the infamous πŸ™ˆ .DS_Store files on macOS add the below line to your .gitignore, πŸ’³

**/.DS_Store

The above line in a .gitignore file will recursively ignore all .DS_Store files from a git repo or in a git project.

Working with diff and patch πŸ”

To apply a git diff file to the current branch of a git repo learn more

git apply mr-fancy.diff

A great πŸ‘Œ write up for working with diff and patch The diff command can be used to update an old file against a new file.

diff originalFile newFile > changes.patch

To update the original file

patch originalFile changes.patch

Comparing two different git branches

A standard install of git from a package manager on a *nix based system will more than likely provide the below visual tools for working with git.

  • gitk
  • git gui

An alternative to using a GUI based tool is to inspect the diff from two different branches using the below workflow

git checkout master
echo "or check brachA"
git merge --no-commit --no-ff branchB

After merging branchB into branchA it should become easy to do a git diff and git status to inspect the changes, if there are any.

Also if the project is hosted on GitHub then GitHub provides a web based diff tool to compare two different branches of a repo

https://github.com/[USER]/[REPO]/compare

Working with git-crypt πŸ”

⚠️ When working with git-crypt and the repo is in a unlocked state, my prompt, theme-neolambda will display a dirty working tree, ie. a +1 in the git prompt, even though there are no files that need to be added or commited.

To unlock a repo using git-crypt

git-crypt unlock

To lock a repo with git-crypt

git-crypt lock

git-crypt workflow πŸ”

  1. Update .gitattributes to include the file that you want encrypted

Ex

mr-fancy-42-secret filter=git-crypt diff=git-crypt
  1. Run, git-crypt init to update the keys for the repo, because the .gitattributes file was updated.
  2. Copy mr-fancy-42-secret file to repo, and then use standard git workflow.

git-crypt Workflow take 2 🎬 πŸ”

the git-crypt two step goes as follows,

  1. Obviously the working repo needs to be initialized using git-crypt with the below command.
cd /path/to/secret/sauce/git/repo
git-crypt init
  1. Create a .gitattributes file within the repo root.
touch .gitattributes

Now this is where things become highly opinionated.

  1. Open the .gitattributes file with preferred text editor.
nvim .gitattributes
  1. Add the below lines to the .gitattribues file
*.shu filter=git-crypt diff=git-crypt

From my experience the above line should recursively encrypt all files throughout the repo that have an extension with .shu.

  1. Save and close the .gitattribues file.

  2. Add, move, copy files with .shu extension to repo

  3. Verify files are encrypted

git-crypt status | grep -i "shu"
screen shot 2018-07-28 at 2 32 17 pm

7b. Files can be force encrypted with the below command

git-crypt status -f

The above command will print error messages if there is any issue with staging or committing the encrypted files.

  1. Stage, commit, push files as required
git add --all
git commit -m "??"
git push

See gotcha section if and when running into issues.

Gotchas πŸ”

Staging a white listed file in a locked repo state

If a file is created, while git-crypt has a repo in a locked state, and even if the file is white listed in the .gitattribues to be encrypted, the file will not be encrypted when staging an "untracked" file in a git repo. From my personal experience I run into the below issue.

screen shot 2018-07-28 at 1 42 31 pm

To get around such mentioned issue, make certain the repo isn't in a "locked state" when adding a new file that conforms to the .gitattributes file for files being encrypted with git-crypt. So before adding a new .shu file to the repo make certain the repo is in an unlocked state.

git-crypt unlock

Then stage the file to be committed.

git add --all
git commit -m "add some secret sauce ?? to the repo

Optional, verify the newly added and committed file has been encrypted git-crypt status | grep -i "shu"

screen shot 2018-07-28 at 1 55 58 pm

The repo still should probably be in a locked state before pushing files to a public repo, so one should lock the repo. The present fish prompt I'm using will display dirty working tree even if all files have been added and committed, that said to alleviate the dirty working tree prompt, lock the repo using git-crypt.

git-crypt lock

Now one can push the encrypted files to a public git repository.

git push

Optional one can verify the files have been encrypted by trying to view the file on the public repo.

screen shot 2018-07-28 at 2 04 24 pm

Updating white listed encrypted files

The repo will need to be placed back in an unencrypted state in order to modify / update file that has been encrypted using git-crypt because the file locally will be in an encrypted state, which can be verified by opening a encrypted file in a text editor.

screen shot 2018-07-28 at 2 09 36 pm

To put the repo back in a state where files can be updated

git-crypt unlock

Then, update white listed encrypted files accordingly. To the best of my knowledge, the repo can remain in an unlocked state if the .gitattribues file has not be modified, and the updates to the white listed encrypted files can be added, committed, and pushed to a public repo, and should remain encrypted on the repo, while the repo is in unlocked state locally. Thus, my reasoning for adding a .shu extension to files that should be white listed for encryption, ie. only one rule needs to be added to the .gitattribues file.

Homework πŸ”

  • write a git hook to unencrypt .shu files, copy the secrect.sause.shu file to secret.sause, ie. without the .shu extension within the same directory and add and verify the secret.sauce file is in the global .gitignore file for the repo.

git GnuPG πŸ”

To restart / kickstart a gpg-agent

gpg-connect-agent reloadagent /bye

git troubleshooting / gpg, gnupg

on my arch linux box i had to type in my personal access (github PAT) every time i ran git push in order persist my credentials through reboots i settle on installing yay -S git-credential-manager-core-bin followed by yay -S pass. with those two utilities and properly configured .gitconfig git with gpg should be able to persist crendentials through reboots, similiar to how macos stores credentials within its keychain(s).

see my todos in the main repo readme for links & refs to setup git-credential-manager with pass

error message / gpg #search term #searchterm

There is no assurance this key belongs to the named user

to resolve the above error message learn more

gpg --edit-key <KEY_ID>
gpg> trust

1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately
m = back to the main menu

Your decision? 5
Do you really want to set this key to ultimate trust? (y/N) y

gpg> quit

Working with git and GnuPG πŸ”

git / gnugpg / Useful Links

../../../ setting up a new computer to work with existing GNUGPG keys

troubleshooting, search query, linux git credential-osxkeychain is not a git command

fcc git setting credential helper


To set the PGP program to GnuPG within a .gitconfig

git config --global gpg.program gpg

To setup a .gitconfig to sign commits for a repo

git config commit.gpgsign true

The above config line will sign all commits and not require -S flag when making a commit.

To setup git to sign all commits from the localhost

git config --global commit.gpgsign true

To setup GnuPG to always sign commits, and to not require a passphrase 🀞, gpg-agent to th rescue β›‘

gpg-agent and gpg as of July 3 2018 share the same version, ie. v2.2.8

brew install pinentry
gpgconf --kill gpg-agent
gpg -K --keyid-format SHORT
gpg2 --gen-key
gpg2 -K --keyid-format SHORT

sec rsa2048/12345678

git config --global user.signingkey 12345678

To sign a commit using GnuPG

git commit -S -m "mr fancy commit message"

Setting up GitHub to work with GnuPG πŸ”

Adding a GnuPG public key to GitHub πŸ”

  1. List the GnuPG keys for both public and private key pairs.
gpg --list-secret-keys --key-id-format LONG
  1. Copy the GPG key ID
sec   rsa2048/012345678ABCDEF0 2018-07-02 [SC]

Ex

echo "012345678ABCDEF0" | pbcopy
  1. Put the GPG public key into the system clipboard.
gpg --armor --export 012345678ABCDEF0 | pbcopy
  1. Then paste the contents of the clipboard into GitHub settings for working with keys.
https://github.com/settings/keys

The above link will only work if logged into GitHub.

Edit config.fish

 set -gx GPG_TTY (tty)

iTerm2 may need to be restarted for gpg to pick up on new passphrase settings, and the passphrase may need to be entered at least once for the gpg-agent to capture the passphrase permanently.

Working with git hooks πŸ”

🚨 When modifying or editing hooks at a $USER scale, I consider it a best practice to run, git init in the project repo in order for updates made withint the hooks dir to ripple down to the project repo.

Working with Identities πŸ”

For a good explanatioin about working with different git user accounts in a .gitconfig see this

TL;DC

Within a git repo run

git identity github

to set the identity for a particular git project.

Global user.name and user.email will need to be unset with this approach

Working with Large git Repositories πŸ”

Ex

To remove unecessary objects from a git repository, ie. the DerivedData and Pods directory from a Objective-C project / repo.

  1. Install bfg
brew install bfg

bfg requires some form of Java to be installed because it is written Scala

  1. Clone and mirror the repo in question
git clone --mirror --recursive [email protected]:[USER]/repo.git
  1. Remove the Pods and DerviedData objects from the repo
bfg --delete-folders 'DerivedData,Pods' repo
  1. Reflog the repo and do a git garbage collection
cd repo.git
git reflog expire --expire=now --all && git gc --prune=now --agressive
  1. Remove references to pull requests for the repo, specific to GitHub
git for-each-ref --format 'delete %(refname)' refs/pull | git update-ref --stdin

The above git command removes references to pull requests which will prevent the newly refloged repo from being pushed to GitHub.

Credit

  1. Push the newly refactored repo to GitHub
git push origin master

Optional

If the repo has already been cloned, and one wants to update it with the newly pushed objects from GitHub

  1. Fetch the remote changes from GitHub
git fetch origin master
  1. Merge the changes into the HEAD of the already cloned repo in question.
git reset --hard origin

Useful Links Working with Large git Repositories πŸ”

git Troubleshooting πŸ”

git Troubleshooting > Undo / Undoing Changes

Scenario I often start working in a project that is using git and forget that I am on the master branch πŸ‘΄πŸ» and begin to modify files ie. update packages in a package.json using npm or what not, and even though I have not stagged or committed the files, without the project being in source control it would be rather difficult to undo the changes I made using npm. All that said, the easiest way I can think of to undo modified / changed files in a git repository that have not been stagged or committed is to run a

git checkout .

The above command will revert the above changes to a clean working state before the npm commands updated the package.json file.

git stash is an alternative way to save changes but also revert back to the clean working tree.

Troubleshooting GnuPG with git πŸ”

If a repo is showing / registering commits as unverified but other repos are showing verified compare the repo configuration files, ie. .git/config of the problematic repo with the working repo. In my particular use case, my dotfiles repo had [user] settings contained within the .git/config that were making the commits for that particular repo univerified. 🀷

To print the files that were changed for a specific commit

git show --pretty="" --name-only [123456f]

The complete git hash is not required, and only the short 7 char git hash is required, however if one can supply 41 char hex sequence that is preferred. πŸ‘

To troubleshoot the below error messages

gpg: WARNING: server 'gpg-agent' is older than us (2.1.18 < 2.2.8)
gpg: Note: Outdated servers may lack important security fixes.
gpg: Note: Use the command "gpgconf --kill all" to restart them.

To restart an outdated gpg service

gpgconf --kill all

Troubleshooting forking, ie. pushing / pull local with remote and upstreams πŸ”

To fix the dreaded This branch is 12800 commits ahead of MrFancyRepo:master

branch-ahead

  1. Pull upstream changes
git reset --hard upstream/master

To sync a local origin with it's upstream counterpart

git remote update
git reset --hard upstream/master --
git push -f origin master
  1. Push local upstream changes to remote origin
git push -f origin master

To fix error: insufficient permission for adding an object to repository database .git/objects

  1. cd /path/to/repo.git
  2. chgrp -R groupname .
  3. chmod -R g+rwX .
  4. find . -type d -exec chmod g+s '{}' +

To fix (shallow update not allowed)

git fetch --unshallow

git fatal The current branch master has multiple upstream branches, refusing to push

git config remote.origin.push HEAD

To restore from a detached head

git checkout master

Make sure to create a local branch if changes have been made.

To remove a file from source control tracking

git rm --cached /path/to/file/to/be/removed.js

To test, and make sure you can properly authenticate with a git server such as github.com or bitbucket.org

To undo the currently staged commits

git reset

Unsorted

Unsorted / backporting a feature PR or bugfix to a prior release

the below block of text probably deserves a blog post of some sort, but don't really have an active blog going at the moment, so i guess this copy paste random braindump will have todo for the time being.

in short, i've been working with the freecad homebrew tap trying to get a working freecad formula file without much luck. there was an official 0.19.2 release earlier in 2021, however that build did not quite work on macos and from what i understand the macos CI was disabled when the CI was using travis due to macos cpu time limitations ie. the (builds were taking too long).

so when attempting to build freecad from the 0.19.2 tarball which brew install will do, because it is the most recent (insert air quotes) stable version of freecad. however the build can fail due to the capitalizations of certain files containing XERCESC instead of XercesC.

i still would prefer to build from the 0.19.2 tarball and use the pr #4960 from upstream freecad repo to fix the brew install issues. however applying the commit patch from the PR that github provides will fail due to the files having multiple changes, and for the fact there the PR fixes a file that isn't part of the 0.19.2 release.

now that, that is out of the way, a couple of useful commands and links below for attempting to backport a PR patch/diff to fix a bug

  1. a pretty good blogpost or tech article about using patch and diff
    https://www.howtogeek.com/415442/how-to-apply-a-patch-to-a-file-and-create-patches-in-linux/

one way to go about backporting the PR is to download the tarball make the necessary changes to the affected files. then extract the tarball again, and then create a patch file using the diff command. homebrew should be able to "slipstream" the patch into the install process.

so to create a patch from the two extracted tarballs of the freecad 0.19.2 release.

echo "below is the cmd i used to create a custom patch file of pr4960 for the 0.19.2 release"

diff -ruN FreeCAD-0.19.2/ FreeCAD-0.19.2.pr4960/ > backport.pr4960

some other useful commands i came across were,

git am ...
git apply ...

πŸ‘† those two commands are useful for working with patch files in a git repository

to generate a .patch file from a working commit id in a git repository

$ git format-patch -1 commit-id

a good stackoverflow answer about resolving whitespace issues with git patches
https://stackoverflow.com/a/34883081/708807

a decent stackoverflow answer about troubleshooting git merge conflicts after attempting to apply patch file
https://stackoverflow.com/a/63148678/708807

a decent writeup on howto resolve git merge conflicts which can happen when attempting to apply a patch file to a working git repository
https://phoenixnap.com/kb/how-to-resolve-merge-conflicts-in-git

Unsorted / Working with Git LFS

  • To setup a git repo to work with git lfs support see
  • To remove git lfs support from a repo see

To completely wipe local origin changes with remote counter parts for a specific branch [credit](https://stackoverflow.com/a/8135023/708807)

git remote
git reset --hard upstream/master --

the above command should sync all commits from upstream master to origin master, so that both branches are even at the time of issuing the commands.

To find the commit for a particular file for when it was first checked in to a git repo

git log --diff-filter=A -- /path/to/file

the complete path to the file must be present, ie. just specifying only a filename will NOT 🌭 work.

Useful Links πŸ”— πŸ”

TODOs πŸ”

  • add a Table on Contents to this document.
  • figure out how to work with submodules, ie. add, commit, push
  • add a git lzy ie. a git lazy command to inclusively add commit and push all changes in all repos, submodules included.
⚠️ **GitHub.com Fallback** ⚠️