Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding merge conflicts when merging master into per-host customized branch

Tags:

git

dotfiles

I want to store all my dotfiles in git repository with separate branch for each machine. I have a problem I can't solve that blocks me from using git for that purpose. I'd like to know how other people solved it.

I'm going to have a single master branch which contains only template definitions and definitions which are supposed to be common for all branches, for example:

export EMAIL="@EMAIL@"
export SURFRAW_google_results=1000

I will replace @EMAIL@ with my correct e-mail on machine branches and commit it but SURFRAW_google_results will stay the same. For example, on work branch I'll have this:

export EMAIL="[email protected]"
export SURFRAW_google_results=1000

Now, I decided to change SURFRAW_google_results=1000 to 10. It's supposed to be shared globally, so I first I change it on master:

export EMAIL="@EMAIL@"
export SURFRAW_google_results=10

and then on I rebase work onto master:

$ git checkout work
$ git rebase master

And now I get conflict because the line that is above the line I changed is different:

<<<<<<< a60114eea1c98d2354a07bd4fd0cdd63cba62e93
export EMAIL="@EMAIL@"
export SURFRAW_google_results=10
=======
export EMAIL="[email protected]"
export SURFRAW_google_results=1000
>>>>>>> m

In case of bash I could quickly get away with including a machine-specific part by sourcing mechanism but how about configs that do not support including/sourcing other configs such as .fluxbox/keys or .screenrc?

like image 386
user1042840 Avatar asked Sep 26 '16 17:09

user1042840


1 Answers

Instead of modifying concurrent data directly between branches (which results in conflict as illustrated in this answer), you can considering content filter driver, using .gitattributes declaration.

smudge (image from "Customizing Git - Git Attributes", from "Pro Git book")

The idea is to manage those dotfiles in version, but with template placeholders in place of the actual values (which depends on the branch).
The generated actual dotfiles remains ignored (by the .gitignore).
That means your actual working tree does not get "dirty".

The files with the actual values can also be versioned, but with different names (so no conflicts when merging/rebasing)

The smudge script select the correct value file depending on the branch name, and generate the correct dotfile based on the dotfile template the smudge script is applied on during a git checkout.

To have a smudge acting differently per branch, I would recommend calling a script which starts by looking the name of the current branch.
See an example in my older answer "Best practice - Git + Build automation - Keeping configs separate".

#!/bin/sh
branch=$(git rev-parse --symbolic --abbrev-ref HEAD)

The OP mentions that, for the smudge script to apply on checkout, removing the index is needed. That is true, as I explained here:

the index is the middle-man for moving things from your work-tree to the object-store AND for moving things from the object-store to your work-tree.

By removing the index, you force git to restore it, which means applying any content filter driver if present.

See "git: re-checkout files after creating smudge filter".

like image 67
VonC Avatar answered Nov 15 '22 17:11

VonC