Cause a conflict on purpose and resolve it

kind: drill

In a shared practice repository, two people change the same line of the same file on two branches. Merge both into main and resolve the conflict.

Solution

The first merge is a fast-forward or a clean merge; the second reports the conflict. Resolve by reading both versions and deciding what the code should do — often the answer is a third version containing both intentions. Then git add, git commit, and run the build before you push.

Produce a diverged branch and repair it

kind: drill

Commit locally, then commit something else to main through the web interface, then try to push.

Solution

The push is rejected. git status reports "diverged". git pull creates a merge commit joining both lines, then the push works. Note what you did not do: --force, which would have deleted the web commit.

Recover a commit made on main by mistake

kind: drill

Commit directly to main, then move that commit onto a branch and restore main.

Solution
git switch -c fix/oops        # branch now contains the commit
git switch main
git reset --hard origin/main  # main back to the remote state

reset --hard discards local changes on main — safe here precisely because the commit is already saved on the new branch. Check with git log on both before you reset.

Resolve the same conflict in IntelliJ

kind: drill

This script builds a repository in which main and a feature branch each changed Attendance.java — one change apart, one change on the same line. Run it in a terminal, then open the folder conflict-ij in IntelliJ.

mkdir conflict-ij && cd conflict-ij
git init -q -b main
cat > Attendance.java <<'EOF'
public class Attendance {

    static String title() {
        return "Attendance";
    }

    static int average(int members, int groups) {
        return members / groups;
    }
}
EOF
git add Attendance.java && git commit -q -m "feat: add attendance average"

git switch -q -c feature/guard-empty-groups
cat > Attendance.java <<'EOF'
/** Attendance figures for one course. */
public class Attendance {

    static String title() {
        return "Attendance";
    }

    static int average(int members, int groups) {
        return groups == 0 ? 0 : members / groups;
    }
}
EOF
git commit -q -am "fix: guard against a course without groups"

git switch -q main
cat > Attendance.java <<'EOF'
public class Attendance {

    static String title() {
        return "Attendance per course";
    }

    static int average(int members, int groups) {
        return Math.round((float) members / groups);
    }
}
EOF
git commit -q -am "feat: round the average instead of truncating it"
  1. In IntelliJ, merge feature/guard-empty-groups into main through the branch name in the title bar.

  2. In the Files Merged with Conflicts dialog, click Merge… — not one of the Accept buttons.

  3. Click Apply Non-Conflicting Changes. Note which two changes arrive in the middle pane and which line stays red.

  4. Resolve the red line so that both intentions survive, finish the file and complete the merge.

  5. In the terminal: git status and git log --oneline --graph. Write down the git command behind each of your clicks.

  6. Repeat from a fresh copy, but this time choose Abort Merge halfway. What does git status report afterwards?

Solution

Apply Non-Conflicting Changes brings in the Javadoc line from the feature branch and the new title from main — each changed by one side only. The return line in average stays red, because both branches changed it.

Neither side alone is right: main rounds, the feature branch guards against zero groups. The resolution keeps both:

        return groups == 0 ? 0 : Math.round((float) members / groups);

The clicks and the commands behind them:

Click Command

Merge 'feature/guard-empty-groups' into 'main'

git merge feature/guard-empty-groups

finishing the file in the merge tool

git add Attendance.java

committing the merge

git commit

Abort Merge

git merge --abort

Afterwards the log shows a merge commit with two parents, and git status reports a clean working tree. After the abort, git status reports the same clean tree as before the merge: nothing was lost, nothing was merged.

Accept Yours would have kept `main’s file — rounding without the guard, and without the Javadoc line, which never was in conflict.

Repair a rejected push in IntelliJ

kind: drill

Push the practice repository to GitHub. Change one line in the web interface and commit it there. Change a different line locally, commit, and push from IntelliJ (Git | Push).

Solution

IntelliJ shows the Push Rejected dialog. Merge fetches the web commit, merges it — without a conflict, the two changes touch different lines — and pushes. That is git pull followed by git push. The log shows the merge commit joining the web commit and yours. Had you fetched first (Git | Fetch), the VCS widget would have warned you before the push: a blue arrow for the incoming commit, a green one for yours. Force pushing was available and was not needed.

Establish the team routine

kind: project

Agree in your team on when everyone pulls, how conflicts are resolved and who merges, and write it into the project README.