Skip to content
Laviyx Learn

Try

Git Team and Recovery Practice

Practise team Git with a local remote: push and pull, rejected pushes, rebasing, interactive clean-up, cherry-pick, tags, the reflog, bisect and hooks. Every solution has been run with Git and shows its real output.

Intermediate11 problemsUpdated

Review first: Clone, Fetch and Pull, Pull Requests and Code Review, Rebasing, Interactive Rebase, Cherry-Pick, git reset and the Reflog, Finding Bugs with bisect and blame, Git Hooks, Tags and Releases

  1. 1.Push a new branch

    Beginner

    The setup creates a shared repository, origin.git, and a clone, me. Create a branch add-b, commit b.txt, push it with tracking, and print the branch's upstream.

    Starter code (Terminal)
    git init -q --bare -b main origin.git
    git clone -q origin.git me 2>/dev/null
    git clone -q origin.git mate 2>/dev/null
    cd me
    echo "start" > a.txt
    git add .
    git commit -q -m "Start"
    git push -q -u origin main
    git -C ../mate pull -q 2>/dev/null
    Show hint

    git push -u origin add-b, then git rev-parse --abbrev-ref @{upstream}.

    Show solution
    Terminal
    git switch -q -c add-b
    echo "b" > b.txt
    git add .
    git commit -q -m "Add b"
    git push -q -u origin add-b
    git rev-parse --abbrev-ref @{upstream}
    Output
    origin/add-b
  2. 2.Look before you pull

    Intermediate

    A teammate has pushed a commit from the mate folder. Fetch it, print how many commits you are behind and the new commit's message, then update your branch.

    Starter code (Terminal)
    git init -q --bare -b main origin.git
    git clone -q origin.git me 2>/dev/null
    git clone -q origin.git mate 2>/dev/null
    cd me
    echo "start" > a.txt
    git add .
    git commit -q -m "Start"
    git push -q -u origin main
    git -C ../mate pull -q 2>/dev/null
    git -C ../mate commit -q --allow-empty -m "Mate: update docs"
    git -C ../mate push -q
    Show hint

    git rev-list --count main..origin/main and git log --format=%s main..origin/main.

    Show solution
    Terminal
    git fetch -q
    git rev-list --count main..origin/main
    git log --format=%s main..origin/main
    git pull -q
    git log --format=%s -n 1
    Output
    1
    Mate: update docs
    Mate: update docs
  3. 3.Fix a rejected push

    Intermediate

    You and a teammate have both committed, and your teammate pushed first. Get their work with a rebase, push yours, and print the history messages.

    Starter code (Terminal)
    git init -q --bare -b main origin.git
    git clone -q origin.git me 2>/dev/null
    git clone -q origin.git mate 2>/dev/null
    cd me
    echo "start" > a.txt
    git add .
    git commit -q -m "Start"
    git push -q -u origin main
    git -C ../mate pull -q 2>/dev/null
    echo "mine" > mine.txt
    git add .
    git commit -q -m "My work"
    echo "theirs" > ../mate/theirs.txt
    git -C ../mate add .
    git -C ../mate commit -q -m "Mate's work"
    git -C ../mate push -q
    Show hint

    git pull --rebase replays your commit on top of theirs.

    Show solution
    Terminal
    git pull -q --rebase
    git push -q
    git log --format=%s
    Output
    My work
    Mate's work
    Start
  4. 4.Rebase a feature branch

    Intermediate

    main has moved on since feature started. Rebase feature onto main, then print its history.

    Starter code (Terminal)
    git init -q demo
    cd demo
    echo "start" > a.txt
    git add .
    git commit -q -m "Start"
    git switch -q -c feature
    echo "work" > f.txt
    git add .
    git commit -q -m "Add feature"
    git switch -q main
    echo "more" > m.txt
    git add .
    git commit -q -m "Add more"
    Show hint

    Switch to feature first. You rebase the branch you are on.

    Show solution
    Terminal
    git switch -q feature
    git rebase -q main
    git log --format=%s
    Output
    Add feature
    Add more
    Start
  5. 5.Squash two commits

    Intermediate

    Combine the last two commits into one with the message Second and third, without using an editor, then print the messages and a.txt.

    Starter code (Terminal)
    git init -q demo
    cd demo
    echo "one" > a.txt
    git add .
    git commit -q -m "First"
    echo "two" >> a.txt
    git commit -q -am "Second"
    echo "three" >> a.txt
    git commit -q -am "Third"
    Show hint

    git reset --soft HEAD~2 keeps the changes staged.

    Show solution
    Terminal
    git reset -q --soft HEAD~2
    git commit -q -m "Second and third"
    git log --format=%s
    cat a.txt
    Output
    Second and third
    First
    one
    two
    three
  6. 6.Cherry-pick one fix

    Intermediate

    Copy only the last commit on feature (Add y) to main, then list the files.

    Starter code (Terminal)
    git init -q demo
    cd demo
    echo "start" > a.txt
    git add .
    git commit -q -m "Start"
    git switch -q -c feature
    echo "x" > x.txt
    git add .
    git commit -q -m "Add x"
    echo "y" > y.txt
    git add .
    git commit -q -m "Add y"
    git switch -q main
    Show hint

    git cherry-pick feature copies the commit at the tip of feature.

    Show solution
    Terminal
    git cherry-pick feature > /dev/null
    ls
    git log --format=%s
    Output
    a.txt
    y.txt
    Add y
    Start
  7. 7.Recover from reset --hard

    Intermediate

    Someone ran git reset --hard HEAD~2, and two commits have vanished. Bring them back and print the messages.

    Starter code (Terminal)
    git init -q demo
    cd demo
    echo "one" > a.txt
    git add .
    git commit -q -m "First"
    echo "two" >> a.txt
    git commit -q -am "Second"
    echo "three" >> a.txt
    git commit -q -am "Third"
    git reset -q --hard HEAD~2
    Show hint

    git reflog shows the old position. HEAD@{1} is where HEAD was before the last move.

    Show solution
    Terminal
    git log --format=%s
    git reset -q --hard HEAD@{1}
    git log --format=%s
    Output
    First
    Third
    Second
    First
  8. 8.Recover a deleted branch

    Advanced

    The branch experiment was deleted by mistake. Use the reflog to restore it, then print its latest commit message.

    Starter code (Terminal)
    git init -q demo
    cd demo
    echo "1" > a.txt
    git add .
    git commit -q -m "Start"
    git switch -q -c experiment
    echo "2" > b.txt
    git add .
    git commit -q -m "Try an idea"
    git switch -q main
    git branch -q -D experiment
    Show hint

    Before deleting it, the setup switched back to main, so HEAD@{1} is the last position on experiment.

    Show solution
    Terminal
    git branch experiment HEAD@{1}
    git log --format=%s -n 1 experiment
    Output
    Try an idea
  9. 9.Tag a release

    Beginner

    Create an annotated tag v1.0.0 on the latest commit and v0.9.0 on the commit before it. Print the tags, then print the tag message of v1.0.0.

    Starter code (Terminal)
    git init -q demo
    cd demo
    echo "one" > a.txt
    git add .
    git commit -q -m "First"
    echo "two" >> a.txt
    git commit -q -am "Second"
    echo "three" >> a.txt
    git commit -q -am "Third"
    Show hint

    git tag -a. git tag -n shows tag messages.

    Show solution
    Terminal
    git tag -a v1.0.0 -m "First release"
    git tag -a v0.9.0 HEAD~1 -m "Beta"
    git tag
    git tag -n v1.0.0
    Output
    v0.9.0
    v1.0.0
    v1.0.0          First release
  10. 10.Find the bad commit with bisect

    Advanced

    count.txt must never contain 0. Use git bisect run to find the first bad commit and print its message. The first commit is good, and the latest is bad.

    Starter code (Terminal)
    git init -q demo
    cd demo
    echo "1" > count.txt
    git add .
    git commit -q -m "Add count"
    for n in 2 3; do echo "$n" >> count.txt; git commit -q -am "Add $n"; done
    echo "0" >> count.txt
    git commit -q -am "Add reset value"
    for n in 5 6; do echo "$n" >> count.txt; git commit -q -am "Add $n"; done
    Show hint

    git bisect start HEAD <good>, then git bisect run with a command that fails on bad commits. git rev-list --max-parents=0 HEAD gives the first commit.

    Show solution
    Terminal
    git bisect start HEAD $(git rev-list --max-parents=0 HEAD) > /dev/null
    git bisect run sh -c "! grep -q 0 count.txt" > /dev/null
    git log --format=%s -n 1 refs/bisect/bad
    git bisect reset > /dev/null 2>&1
    Output
    Add reset value
  11. 11.Block debug code with a hook

    Advanced

    Write a pre-commit hook that rejects a commit adding the text console.log. Test it with app.js, and print the number of commits afterwards.

    Starter code (Terminal)
    git init -q demo
    cd demo
    echo "start" > a.txt
    git add .
    git commit -q -m "Start"
    Show hint

    git diff --cached shows the staged changes. exit 1 cancels the commit.

    Show solution
    Terminal
    cat > .git/hooks/pre-commit <<'EOF'
    #!/bin/sh
    if git diff --cached | grep -q '^+.*console\.log'; then
      echo "Remove console.log before committing."
      exit 1
    fi
    EOF
    chmod +x .git/hooks/pre-commit
    echo "console.log('debug')" > app.js
    git add app.js
    git commit -m "Add app"
    git rev-list --count HEAD
    Output
    Remove console.log before committing.
    1