Alok Menghrajani
Previously: security engineer at Square, co-author of HackLang, put the 's' in https at Facebook. Maker of CTFs.
This blog does not use any tracking cookies and does not serve any ads. Enjoy your anonymity; I have no idea who you are, where you came from, and where you are headed to. Let's dream of an Internet from times past.
Home | Contact me | Github | RSS feed | Consulting services | Tools & games
I was migrating a large set of configuration files from one format
to another and I discovered that git's ORIG_HEAD
is a
useful variable when dealing with merge conflicts, specifically
if the merge conflict involves deleted files.
The migration was partially manual. The process took a few days and fellow engineers were editing the same files, hence the conflicts when rebasing / merging.
Here is a recreation of the conflicts I encountered and how I solved them.
Create an empty git repo:
$ mkdir my_repo; cd my_repo $ git init $ echo 'hello' > a.txt $ echo 'world' >> a.txt $ git add a.txt $ git commit -m 'first commit'
Migrate a.txt to b.txt in a branch:
$ git co -b my_branch $ tr '[:lower:]' '[:upper:]' < a.txt > b.txt $ git rm a.txt $ git add b.txt $ git commit -m 'work in progress'
Simulate changes by other engineers:
$ git co master $ echo 'mountain' >> a.txt $ sort -o a.txt a.txt $ git add a.txt $ git commit -m 'second commit' $ echo "yolo" >> a.txt $ git add a.txt $ git commit -m 'third commit'
Rebase and solve conflict:
$ git co my_branch $ git rebase master First, rewinding head to replay your work on top of it... Applying: work in progress Using index info to reconstruct a base tree... M a.txt Falling back to patching base and 3-way merge... CONFLICT (modify/delete): a.txt deleted in work in progress and modified in HEAD. Version HEAD of a.txt left in tree. Failed to merge in the changes. Patch failed at 0001 work in progress The copy of the patch that failed is found in: .../my_repo/.git/rebase-apply/patch When you have resolved this problem, run "git rebase --continue". If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort". $ cat a.txt (shows the whole file) hello world mountain yolo $ cat .../my_repo/.git/rebase-apply/patch (shows the changes I made) c699b5960ea45b6a712a495fa15ac6bde1f00abf diff --git a/a.txt b/a.txt deleted file mode 100644 index 94954abda49de8615a048f8d2e64b5de848e27a1..0000000000000000000000000000000000000000 --- a/a.txt +++ /dev/null @@ -1,2 +0,0 @@ -hello -world diff --git a/b.txt b/b.txt new file mode 100644 index 0000000000000000000000000000000000000000..d10a988a38fa4a3ab59866f5105d3264e4649c79 --- /dev/null +++ b/b.txt @@ -0,0 +1,2 @@ +HELLO +WORLD $ git diff ORIG_HEAD^..HEAD (shows what actually changed) diff --git a/a.txt b/a.txt index 94954ab..d48f0a4 100644 --- a/a.txt +++ b/a.txt @@ -1,2 +1,4 @@ hello world +mountain +yolo
We can now resolve the conflict without having to process the entire file again, which saves time if the migration involves a manual process.
$ echo 'mountain' | tr '[:lower:]' '[:upper:]' >> b.txt $ echo 'yolo' | tr '[:lower:]' '[:upper:]' >> b.txt $ git rm a.txt; git add b.txt; git rebase --continue