Git Notes

Add directory to an empty git repo

  1. Create the repo
  2. Go to the folder and run:
git init -b main
git add .
git commit -m 'Initial commit'
git remote add origin git@github.com:youruser/yourrepo.git
git push -u origin main

Resource: https://docs.github.com/en/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line

Commit empty directory to repo

mkdir directory
touch directory/.gitkeep
git add directory
git commit -m "Adding directory"
git push origin main

Resource: https://www.digitalocean.com/community/questions/how-to-add-and-commit-an-empty-directory-in-my-git-repository

Merge develop branch into main

git checkout develop
git merge main

At this point, if there are any merge conflicts, you can resolve them.

git checkout main
git merge develop
git push origin main

Resource: https://stackoverflow.com/questions/14168677/merge-development-branch-with-master

Merge specific files from develop branch into main

git checkout main
git checkout source_branch <paths>...

For example, this will get the .gitignore from develop:

git checkout develop .gitignore

Resource: https://jasonrudolph.com/blog/2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/

Cherry Picking

git-cherry-pick is used when you want to take a commit from one branch and apply it to another branch. This can be thought of as a more surgical version of git merge (applying one commit vs applying multiple commits).

A great example can be found here.

Syncing a fork

When you're introducing changes to another open source project, sometimes your fork gets out of sync with the original project. To fix this, do the following:

git fetch upstream
git checkout master
git merge upstream/master

In the event that you get this error:

fatal: 'upstream' does not appear to be a git repository

Check if the upstream for the original project is set:

git remote -v

If it isn't, get the url for the git repo and run it with this command:

git remote add upstream https://github.com/<original project>

For example, if I was working on my copy of the xssValidator project, and wanted to add the upstream for the original:

git remote add upstream https://github.com/nVisium/xssValidator

Remove latest commit from a git repo

Pushed too soon or by accident? Let's fix that.
Non-rebase approach:

  1. git reset --hard HEAD^
  2. git push origin +master

Rebase approach:

  1. git rebase -i HEAD~2
  2. Delete the commit (should be the second line in the text file)
  3. git push origin +<branchName> - for example: git push origin +master

Note: + is used to force a push to only one branch.
Resources: https://git-scm.com/docs/git-push

Redo git commits that have been pushed to remote

  1. Check out the branch you want your commits to be in: git checkout <branch>
  2. Find git ref id one commit before the commit you want to change
  3. git rebase -i <ref #>
  4. Remove commits you do not want in this new branch
  5. Edit the messages for commits as needed.
  6. Save the file.
  7. git commit --amend - change the commit message to what you want
  8. git rebase --continue
  9. Once done with commits, git push -u origin <name of branch>

Merge file from one branch to another

git checkout <branch to merge from> <file name>

Update branch with another

  1. git checkout <branch to overwrite>
  2. git rebase origin/master - to rebase all changes on this branch on the tip of master

Amend commit

  1. git add <whatever you forgot to include>
  2. git commit --amend

Stash queued changes to go to another branch && restore them

  1. git stash
  2. Do whatever in other branch
  3. Go to branch that was stashed
  4. git pop

Fix github sync issue:

git stash save --keep-index
git stash drop

Delete file from github history (in case sensitive information goes up on accident):

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch <filename>'
git push origin --force --all

Change authors of pushed commits with rebasing

  1. Find the commit before (chronologically) the first commit that you want to change.
  2. git rebase -i <SHA hash of the commit before the one you want to change>
  3. Change the lines for the commits you want to modify by changing them from pick to edit.
  4. Save the file once you're done.
  5. Change the commit to the author you want to be reflected like so: git commit --amend --author="New Author Name <newauthor@url.com>".
    For example:
    git commit --amend --author="Jayson Grace <jayson.e.grace@gmail.com>"
  6. Once you've changed the author for the commit, continue on through the rebase using git rebase --continue until you've resolved all commits.
  7. You may need to deal with some errors that come up, so be sure to fix those, and then git add the file that you've had to resolve before using git rebase --continue.
  8. Finish by using git push --force

Resource: https://stackoverflow.com/questions/3042437/change-commit-author-at-one-specific-commit

Change author of last commit

git commit --amend --author="Philip J Fry <someone@example.com>"

Resource: https://makandracards.com/makandra/1717-git-change-author-of-a-commit

Undo last commit and keep changes made

git reset HEAD~1

Resource: https://stackoverflow.com/questions/927358/how-to-undo-the-last-commits-in-git

Submodules

Add the existing git repo as a submodule of the current repo:

git submodule add <git repo> <destination path - optional>

This should generate a .gitmodules file and the folder of the repo you intended to submodule.

Update submodules recursively

git submodule update --init --recursive

Note: this does not get the latest commit.

Update submodules to latest commit

Latest and greatest:

git submodule update --remote --merge

Pre git 1.8:

git submodule foreach git pull origin master

Another older way:

git fetch
git merge origin/master

Whichever way you choose, be sure to run this command to add and commit the changes for the repo in which the submodule exists:

git add submodule_name
git commit -m "updating submodule to latest"

Resources:
https://stackoverflow.com/questions/8191299/update-a-submodule-to-the-latest-commit - new solution
https://stackoverflow.com/questions/5828324/update-git-submodule-to-latest-commit-on-origin - old solution
https://git-scm.com/book/en/v2/Git-Tools-Submodules - the other older way

Clone a repo with submodules in it

git clone --recurse-submodules <repo with submodules>

Remove a submodule

git submodule deinit <path_to_submodule>
git rm <path_to_submodule>
git commit-m "Removed submodule "
rm -rf .git/modules/<path_to_submodule>

Resource: https://gist.github.com/myusuf3/7f645819ded92bda6677

Add changes to a previous commit

git commit --amend

If you don't want to change the commit message:

git commit --amend --no-edit

One-liner with changes to message

git commit --amend -m "new commit message goes here"

You can also omit the -m and the message following it if you want to edit the commit in a text editor.

Update changes to a pushed commit

git push origin +<branch>

Alternatively:

git push -f origin <branch>

Resource: https://medium.com/@igor_marques/git-basics-adding-more-changes-to-your-last-commit-1629344cb9a8

Anonymous clone of git repo

git clone git://github.com/SomeUser/SomeRepo.git

Resource: https://superuser.com/questions/557903/clone-github-repository-without-account

Gitlab

Get content of a commit

This is helpful when you run something like Gitleaks, and want to be able to look at specific commits. Unfortunately, the UI does not seem to provide a place to do this.

https://gitlab.com/projectname/reponame/commit/commitid

Create deploy token

This can be used if you need to automatically clone into a private gitlab repo as part of a CI/CD pipeline. Be sure to set an expiration date if you can get away with it for security.

  1. Login
  2. Go to repo
  3. Settings
  4. Repository
  5. Expand button next to Deploy Tokens
  6. Set scopes based on your criteria
  7. Click Create deploy token

Use it to clone the repo:
git clone https://<gitlab+deploy-token-number>:<token_password>@gitlab.com/group/repo.git

Resource: https://docs.gitlab.com/ee/user/project/deploy_tokens/#creating-a-deploy-token

Github

Create key

ssh-keygen -t ed25519 -C "<your email>" -f ~/.ssh/personal_github

Add new key to SSH agent

eval "$(ssh-agent -s)"

Add a section to ~/.ssh/config for the key you just created:

Host github.com-l50
   HostName github.com
   User git
   IdentityFile ~/.ssh/personal_github
   IdentitiesOnly yes

If you're running OSX, run this command to add your new key to your keychain:

ssh-add ~/.ssh/personal_github

Finally, add your public key to github.

Resources:
https://docs.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent
https://gist.github.com/Jonalogy/54091c98946cfe4f8cdab2bea79430f9
https://stackoverflow.com/questions/64043238/enter-pin-for-authenticator-issue-related-to-ssh - fix for issue created by using ssh-add -K

Collect information needed to add ssh key

Generate an ssh key using the information under CREATE SSH KEY found on this page

echo "Your public key:"
cat ~/.ssh/id_rsa.pub
echo
echo "Your ssh key fingerprint is:"
ssh-keygen -lf ~/.ssh/id_rsa | awk '{ print $2 }'

Change release commit

If you create a release and have to make some changes and then re-release, here's what you need to do:

git tag -f -a <tagname> # i.e. v1.0.0
git push
git push -f --tags

Resource: https://stackoverflow.com/questions/30152632/how-to-change-a-release-on-github-point-to-the-latest-commit

Show staged changes

Useful if you have already run a git add and are trying to remember the changes you've made.

git diff --staged

Resource: https://stackoverflow.com/questions/3527856/show-git-diff-on-file-in-staging-area

Find shield for project

https://shields.io/

Squash last x commits together

git reset --soft HEAD~x

For example, this will squash the last 3 commits together:

git reset --soft HEAD~3

Resource: https://stackoverflow.com/questions/5189560/squash-my-last-x-commits-together-using-git

This has a good methodology for squashing without rebasing:
https://blog.oddbit.com/post/2019-06-17-avoid-rebase-hell-squashing-wi/

Gitignore

Show line of gitignore ignoring a file

git check-ignore -v filename

Resource:
https://stackoverflow.com/questions/12144633/explain-which-gitignore-rule-is-ignoring-my-file

Exclude file from root folder

Add a / in front, i.e. /mose

Resource: https://stackoverflow.com/questions/3637660/how-to-exclude-file-only-from-root-folder-in-git

Git Large File Storage (LFS)

Adding a large file with git-lfs

This is useful if you need to track a file that's over 100MB in size. It's important to follow these steps before you attempt to incorporate the large file into the repo.

git lfs install
git lfs track "large.file"
git add .gitattributes
git add large.file 
git commit -m "Message"
git push origin <branch>

Resource: https://git-lfs.github.com/

Removing a large file from git-lfs

This is useful if you want to track a file that's over 100MB in size but don't want to use git-lfs anymore because it's priced ridiculously (consider s3 as a cheaper alternative).

# Delete all instances of the file in git history
bfg --delete-files <file>
# Uninstall git-lfs from the repo
git lfs uninstall
git rm .gitattributes
# Push the changes
git push origin +master

Resource: https://dustinfreeman.org/blog/rip-lfs/

Show modified files in a commit

git show <commit id>

Resource:
https://stackoverflow.com/questions/424071/how-to-list-all-the-files-in-a-commit

Show contents of file at specific commit

git show <commit id>:/path/to/file

Resource: https://stackoverflow.com/questions/338436/is-there-a-quick-git-command-to-see-an-old-version-of-a-file

Show diff of unpushed commits

git diff origin/master..HEAD

Resource: https://stackoverflow.com/questions/2016901/viewing-unpushed-git-commits

Delete local && remote branch

Delete remote branch:

git push origin --delete <branch-name>

Delete local branch:

git branch -D <branch-name>

Resource: https://stackoverflow.com/questions/2003505/how-do-i-delete-a-git-branch-locally-and-remotely#:~:text=Simply do git push origin,local branch only!...

Clone a subdirectory of a repo

You don't want the whole repo, just a specific directory. Seems sensible, this covers how to do it. Note that this is only available as of git 2.19.

git clone \
  --depth 1 \
  --filter=blob:none \
  --no-checkout \
  https://github.com/cirosantilli/test-git-partial-clone \
;
cd test-git-partial-clone
git checkout master -- d1

Resource: https://stackoverflow.com/questions/600079/git-how-do-i-clone-a-subdirectory-only-of-a-git-repository/52269934#52269934

Use patches

Very useful if you make changes but don't have a remote git repo to push your commits to.

Show source line diffs and output to a file:

git show <COMMIT ID> | tee output

Apply the patch in the output file:

git apply output

Git grep

Super fast tool that is very useful for finding stuff quickly in a repo.

This example will look for the word auth in all tracked files that end with .py:

git grep -n "auth" -- '*.py'

n: Prefix the line number for matching lines

An example to search all tracked .c and .h files for time_t:

git grep 'time_t' -- '*.[ch]'

List all files

git ls-files

Resource: https://github.com/awslabs/git-secrets

Get latest release from github

This example is for the Sliver c2, but you can obviously modify it to meet your needs:

AUTHOR='BishopFox'
REPO_NAME='sliver'
curl -s "https://api.github.com/repos/$AUTHOR/$REPO_NAME/releases/latest | jq -r '.assets[].browser_download_url'

Resources: https://gist.github.com/steinwaywhw/a4cd19cda655b8249d908261a62687f8

Show history of changes to a file

git log -p filename

-p: Show the diff between each revision and its parent

Resources:
https://stackoverflow.com/questions/278192/view-the-change-history-of-a-file-using-git-versioning

Show differences between two revisions of a file

git diff abc123 def456 -- path/to/file.

In this example, abc123 and def456 are the revision IDs.

Resource: https://stackoverflow.com/questions/1964142/how-can-i-list-all-the-different-versions-of-a-file-and-diff-them-also

Find all .git folders in current dir

find . -type d -iname ".git"

Resource: https://www.cyberciti.biz/faq/unix-linux-centos-ubuntu-find-hidden-files-recursively/

Ditch local commits

This is useful if you get an error message about diverged branches or have a merge conflict.

git fetch origin
git reset --hard origin/master

Resource: https://stackoverflow.com/questions/19864934/git-your-branch-and-origin-master-have-diverged-how-to-throw-away-local-com

Restore directory from previous commit

git checkout $COMMIT_ID -- path/to/the/folder/ 

Resource: https://stackoverflow.com/questions/9670745/how-to-restore-a-whole-directory-from-history-of-git-repository

Change permissions for file in repo

FILE=./scripts/moveFile.sh
git update-index --chmod +x $FILE

Resource: https://github.community/t/how-to-execute-a-script-file-using-github-action/16830/4