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"
-
In IntelliJ, merge
feature/guard-empty-groupsintomainthrough the branch name in the title bar. -
In the Files Merged with Conflicts dialog, click Merge… — not one of the Accept buttons.
-
Click Apply Non-Conflicting Changes. Note which two changes arrive in the middle pane and which line stays red.
-
Resolve the red line so that both intentions survive, finish the file and complete the merge.
-
In the terminal:
git statusandgit log --oneline --graph. Write down the git command behind each of your clicks. -
Repeat from a fresh copy, but this time choose Abort Merge halfway. What does
git statusreport 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' |
|
finishing the file in the merge tool |
|
committing the merge |
|
Abort Merge |
|
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.