Last active
August 29, 2015 14:14
-
-
Save theaspect/09d0c0e516d41bfcdb7f to your computer and use it in GitHub Desktop.
Demo history editing in git
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# Constantine Linnick <theaspect@gmail.com> | |
# https://gist.github.com/theaspect/09d0c0e516d41bfcdb7f | |
set -e | |
BASE="$PWD" | |
ORIGIN="$PWD/origin" | |
ALICE="$PWD/alice" | |
BOB="$PWD/bob" | |
# Skip curling funny request messages from whatthecommit.com and waiting after echo | |
FAST=false | |
FUNNY=false | |
function check { | |
if ! hash $1 2>/dev/null; then | |
echo $1 require | |
exit 1 | |
fi | |
} | |
check git | |
if $FUNNY; then check curl; fi; | |
function wait { if ! $FAST; then read -s -n1; fi; } | |
function msg { if $FUNNY; then curl http://whatthecommit.com/index.txt 2>/dev/null; else echo "Message $RANDOM" ; fi; } | |
function command { echo -e "\033[93m$@\033[0m"; } | |
function header { echo -e "\033[1;32m$@\033[0m\n"; } | |
function say { echo -e "\033[32m$@\033[0m\n"; } | |
function sayw { echo -e "\033[32m$@\033[0m\n"; wait; } | |
function git_origin { cd $ORIGIN ; command "git $@"; git --no-pager "$@"; echo -e "\n"; } | |
function git_alice { cd $ALICE ; command "git $@"; git --no-pager "$@"; echo -e "\n"; } | |
function git_bob { cd $BOB ; command "git $@"; git --no-pager "$@"; echo -e "\n"; } | |
function log_origin { git_origin log --date-order --pretty=format:"%C(yellow)%h%Creset%C(green)%Creset%C(auto)%d%Creset %s %C(magenta)<%an>" --decorate --all --graph $@; } | |
function log_alice { git_alice log --date-order --pretty=format:"%C(yellow)%h%Creset%C(green)%Creset%C(auto)%d%Creset %s %C(magenta)<%an>" --decorate --all --graph $@; } | |
function log_bob { git_bob log --date-order --pretty=format:"%C(yellow)%h%Creset%C(green)%Creset%C(auto)%d%Creset %s %C(magenta)<%an>" --decorate --all --graph $@; } | |
function reflog_alice { log_alice "$(git rev-list --reflog --all)"; } | |
function reflog_bob { log_bob "$(git rev-list --reflog --all)"; } | |
function change_alice { cd $ALICE; if [ ! -z "$1" ] ; then echo $RANDOM >> "$1.txt"; echo -e "\033[96mAlice edited $1.txt\033[0m"; else echo $RANDOM >> alice.txt; echo -e "\033[96mAlice edited alice.txt\033[0m"; fi; } | |
function change_bob { cd $BOB; if [ ! -z "$1" ] ; then echo $RANDOM >> "$1.txt"; echo -e "\033[96mBob edited $1.txt\033[0m" ; else echo $RANDOM >> bob.txt ; echo -e "\033[96mBob edited bob.txt\033[0m" ; fi; } | |
function commit_alice { cmsg="$(msg)"; change_alice "$@"; command "git add -A; git --no-pager diff --cached; git commit -m \"$cmsg\""; git add -A; git --no-pager diff --cached; git commit --author="alice <alice@example.com>" -m "$cmsg"; echo -e "\n"; } | |
function commit_bob { cmsg="$(msg)"; change_bob "$@"; command "git add -A; git --no-pager diff --cached; git commit -m \"$cmsg\""; git add -A; git --no-pager diff --cached; git commit --author="bob <bob@example.com>" -m "$cmsg"; echo -e "\n"; } | |
header Init | |
say Cleanup dirs | |
rm -rf "$ORIGIN" "$ALICE" "$BOB" | |
mkdir $ORIGIN | |
mkdir $ALICE | |
mkdir $BOB | |
say Init repos | |
# We cannot to push to non bare repository | |
git_origin init --bare | |
git_alice clone $ORIGIN . | |
git_bob clone $ORIGIN . | |
sayw Branches is simply labels, and nothing disappleras without a traces."\n"\ | |
To better understand this look at cool visualisation "\n"\ | |
at http://tonsky.me/blog/reinventing-git-interface/ "\n"\ | |
"\n"\ | |
Everything is ready, press any key to continue or ^c to stop. "\n"\ | |
During pauses feel free to play with repos and inspect its state | |
header 1. Restore lost commits | |
say Alice did some commits... | |
commit_alice | |
commit_alice | |
commit_alice | |
say and now have small tree | |
log_alice | |
sayw Somehow she droped first two commits | |
git_alice reset --hard HEAD^^ | |
log_alice | |
sayw OH MY GOD, where is whole day work | |
sayw Well, in ref-log. We can collect all revs from ref-log... | |
git_alice rev-list --reflog --all | |
sayw and pass it to git log with '$(git rev-list --reflog --all)' | |
reflog_alice | |
sayw We can checkout to lost commits but HEAD will be detached | |
# Sorting order are not stable even with --topo-order | |
git_alice checkout "$(git rev-list --reflog --topo-order --all | sed -n '1p')" | |
log_alice | |
sayw we can even commit to detached head | |
commit_alice | |
reflog_alice | |
sayw To get commits back, we can create branch... | |
git_alice checkout -b lost_commits | |
log_alice | |
sayw checkout master... | |
git_alice checkout master | |
sayw and merge it... | |
git_alice merge lost_commits | |
sayw Let\'s check | |
log_alice | |
sayw Drop unnecessary branch | |
git_alice branch -d lost_commits | |
git_alice push origin | |
header 2. Remove single pushed commit | |
sayw Alice commited something and pushed to origin | |
commit_alice | |
git_alice push origin | |
log_alice | |
sayw But minute after she wanted to revert last commit in origin | |
sayw If Bob not yet pulled, just reset --hard... | |
git_alice reset HEAD^ --hard | |
log_alice | |
sayw and push --force | |
git_alice push origin --force | |
log_alice | |
header 3. Drop non last shared commit | |
sayw Alice did some work | |
# If file does not exists before it can raise Deleted-Unmerged state and automatic rebase will fail | |
commit_alice bob | |
commit_alice bob | |
git_alice push origin | |
sayw Bob pull origin, push commit, and continue his work | |
git_bob pull origin | |
commit_bob | |
git_bob push origin | |
commit_bob | |
sayw Alice pull Bob\'s changes | |
git_alice pull origin | |
say Alice\'s repo | |
log_alice | |
say Bob\'s repo | |
log_bob | |
sayw Alice wants to drop last changes in Bob\'s file using interactive rebase | |
# Weird way to comment first (NR==1) line in passed todo file by git, during rebase you obviuously do this by hand | |
# See http://git.kernel.org/cgit/git/git.git/tree/git-rebase--interactive.sh?id=821881d88d3012a64a52ece9a8c2571ca00c35cd#n164 | |
# Also without || true all scipt will fail | |
GIT_SEQUENCE_EDITOR="awk '{line=(NR==1)?\"#\" \$0:\$0; print line; print line >> (FILENAME \"~\") }END{system (\"mv \" FILENAME \"~ \" FILENAME)}'" git_alice rebase -i HEAD^^ || true | |
sayw Obviuously we have conflict | |
git_alice diff bob.txt | |
sayw We resolve it... | |
cd $ALICE && sed -i -e "2d;3d;4d;6d" bob.txt | |
git_alice add -A | |
git_alice commit -m "Resolve rebase conflict" | |
sayw and continue rebase | |
# If we do not add -m message editor will popup | |
git_alice rebase --continue | |
sayw Alice\'s history now splitted... | |
log_alice | |
sayw and Alice push force this to origin | |
git_alice push origin --force | |
sayw Bob fetch origin... | |
git_bob fetch origin | |
sayw and see | |
log_bob | |
sayw Bob simply pulls master without conflicts... | |
git_bob pull origin | |
sayw and see | |
log_bob | |
sayw Note, nothing dropped, and old commits still in reflog | |
reflog_bob | |
header The end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment