You could use the gitattributes mechanism to define a custom merge driver (like this one for instance) in order to copy automatically the relevant sections.
[merge "aggregate"]
name = agregate both new sections
driver = aggregate.sh %O %A %B
It will be a 3-way merge, which means you can easily diff %A
and %B
against %O
(common ancestor) in order to isolate said new sections, and aggregate them in the result merged file.
That aggregate merge driver needs only to do:
comm -13 $1 $3 >> $2
(The comm utility is part of the GoW -- Gnu on Windows -- distribution, if you are on Windows)
Here is a little demo:
First, let's set up a Git repo, with a file modified in two branches ('master
' and 'abranch
'):
C:proggitests>mkdir agg
C:proggitests>cd agg
C:proggitestsagg>git init r1
Initialized empty Git repository in C:/prog/git/tests/agg/r1/.git/
C:proggitestsagg>cd r1
# Who am I?
C:proggitestsagg
1>git config user.name VonC
C:proggitestsagg
1>git config user.email vonc@xxx
# one file, first commit:
C:proggitestsagg
1>echo test > test.txt
C:proggitestsagg
1>git add .
C:proggitestsagg
1>git commit -m "first commit"
[master c34668d] first commit
1 file changed, 1 insertion(+)
create mode 100644 test.txt
# Let's add one more common line:
C:proggitestsagg
1>echo base >> test.txt
C:proggitestsagg
1>more test.txt
test
base
C:proggitestsagg
1>git add .
C:proggitestsagg
1>git commit -m "base"
[master d1cde8d] base
1 file changed, 1 insertion(+)
Now we create a new branch, and make concurrent modifications in both versions of that file, at the end of it like the OP itsadok specifies in the question.
C:proggitestsagg
1>git checkout -b abranch
Switched to a new branch 'abranch'
C:proggitestsagg
1>echo "modif from abranch" >> test.txt
C:proggitestsagg
1>git add .
C:proggitestsagg
1>git commit -m "abranch contrib"
[abranch a4d2632] abranch contrib
1 file changed, 1 insertion(+)
C:proggitestsagg
1>type test.txt
test
base
"modif from abranch"
# back to master
C:proggitestsagg
1>git checkout master
Switched to branch 'master'
C:proggitestsagg
1>echo "contrib from master" >> test.txt
C:proggitestsagg
1>git add .
C:proggitestsagg
1>git commit -m "contrib from master"
[master 45bec4d] contrib from master
1 file changed, 1 insertion(+)
C:proggitestsagg
1>type test.txt
test
base
"contrib from master"
We have out two branches (note: git lg
is an alias of mine)
C:proggitestsagg
1>git lg
* 45bec4d - (HEAD, master) contrib from master (86 minutes ago) VonC
| * a4d2632 - (abranch) abranch contrib (86 minutes ago) VonC
|/
* d1cde8d - base (87 minutes ago) VonC
* c34668d - first commit (89 minutes ago) VonC
Now let's try a merge:
C:proggitestsagg
1>git merge abranch
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.
C:proggitestsagg
1>more test.txt
test
base
<<<<<<< HEAD
"contrib from master"
=======
"modif from abranch"
>>>>>>> abranch
... Failed as advertised ;) A git merge --abort
will reset the situation.
Let's put in place our merge driver:
C:proggitestsagg
1>git config merge.aggregate.name "aggregate both new sections"
C:proggitestsagg
1>git config merge.aggregate.driver "aggregate.sh %O %A %B"
C:proggitestsagg
1>echo test.txt merge=aggregate > .gitattributes
At this point, a merge still fails:
C:proggitestsagg
1>git merge abranch
aggregate.sh .merge_file_a09308 .merge_file_b09308 .merge_file_c09308: aggregate.sh: command not found
fatal: Failed to execute internal merge
Normal: we need to write that script, and add it to the PATH
:
vim aggregate.sh:
#!/bin/bash
# echo O: $1
# echo A: $2
# echo B: $3
# After http://serverfault.com/q/68684/783
# How can I get diff to show only added and deleted lines?
# On Windows, install GoW (https://github.com/bmatzelle/gow/wiki/)
ob=$(comm -13 $1 $3)
# echo "ob: ${ob}"
echo ${ob} >> $2
----
C:proggitestsagg
1>set PATH=%PATH%;C:proggitestsagg
1
And now, the aggregate
merge driver can operate:
C:proggitestsagg
1>git merge --no-commit abranch
Auto-merging test.txt
Automatic merge went well; stopped before committing as requested
C:proggitestsagg
1>type test.txt
test
base
"contrib from master"
"modif from abranch"
Here you go: the end of the test.txt
file from abranch
has been added to the file on master
.