Link

Git for Experts

Some advanced repository manipulations.

Table of contents

  1. Ensure SSH Agent is running
  2. Split a subdirectory to its own branch
  3. Merge a branch into a subdirectory
  4. Revert a mass commit
  5. Add git tags retrospectively
  6. Git submodules
    1. Add a submodule
    2. Download submodules after cloning project
    3. Update submodules with remote updates
    4. Update submodules with local changes
  7. Recover lost commits

Ensure SSH Agent is running

Not strictly Git, but useful when running on a server. Add to .bashrc:

export SSH_AUTH_SOCK=~/.ssh/ssh-agent.$HOSTNAME.sock
ssh-add -l 2>/dev/null >/dev/null
if [ $? -ge 2 ]; then
  ssh-agent -a "$SSH_AUTH_SOCK" >/dev/null
fi

Split a subdirectory to its own branch

This creates a new branch with the files in the subdirectory moved to the root directory, while keeping git history for those files.

git subtree split -P [subfolder/subsubfolder] -b [new-branch]

Merge a branch into a subdirectory

This keeps the history too

git checkout branchA
git checkout -b master
git merge -s ours --no-commit origin/branchB
git read-tree --prefix=directoryB/ -u origin/branchB
git commit -m "Merge branchB into the directoryB subdirectory"

git branch -D branchA
git branch -D branchB
git push origin --delete branchA
git push origin --delete branchB

Revert a mass commit

Note: below is number one not lowercase L

SUBMODULES=$(ls -1 components/)
for SUBMODULE in ${SUBMODULES[@]}
do
    pushd components/${SUBMODULE}
    git revert --no-edit $(git log --oneline | grep "Add .keep file for empty directories" | awk '{ print $1 }')
    popd
done

Add git tags retrospectively

GIT_COMMITTER_DATE="$(git show 0219549 --format=%aD | head -1)" git tag -a v2.0.0 0219549 -m "v2.0.0"
git push origin v2.0.0

Git submodules

Several commands related to managing submodules

Add a submodule

git submodule add -b master git@github.com:stellirin/my-sub-module.git my/sub/module

Download submodules after cloning project

git submodule update --init --recursive

Update submodules with remote updates

git submodule update --remote my/sub/module

Note: below is number one not lowercase L

SUBMODULES=$(ls -1 my/sub/)
for SUBMODULE in ${SUBMODULES[@]}
do
    git submodule update --remote my/sub/${SUBMODULE}
done

Update submodules with local changes

Use git commit and git push as normal from within the submodule. Later, from the project directory simply git add the submodule. For example:

pushd my/sub/module
git add --all
git commit -m "My awesome commit"
git push
popd
 
git add my/sub/module
git commit -m "Update submodule reference for my/sub/module"
git push

Recover lost commits

use git reflog to see a complete history of all commands that produced a commit.

This includes those times you made a commit while headless. You can even see the different commits produced when running git commit --amend multiple times!