2016-02-09 16:30:29 +00:00
|
|
|
Consider two use cases:
|
|
|
|
|
|
|
|
1. Using a v6 repo with locked files on a crippled filesystem not
|
|
|
|
supporting symlinks. For the files to be usable, they need to be
|
|
|
|
unlocked. But, the user may not want to unlock the files everywhere,
|
|
|
|
just on this one crippled system.
|
|
|
|
2. [[todo/hide_missing_files]]
|
|
|
|
|
|
|
|
Both of these could be met by making `git-annex sync` maintain an adjusted
|
2016-02-09 17:45:40 +00:00
|
|
|
version of the original branch, eg `adjusted/master`.
|
|
|
|
|
2016-02-09 18:37:59 +00:00
|
|
|
There would be a filter function. For #1 above it would simply convert all
|
|
|
|
annex symlinks to annex file pointers. For #2 above it would omit files
|
|
|
|
whose content is not currently in the annex. Sometimes, both #1 and #2 would
|
|
|
|
be wanted.
|
|
|
|
|
2016-02-09 18:24:32 +00:00
|
|
|
[Alternatively, it could stay on the master branch, and only adjust the
|
|
|
|
work tree and index. See WORKTREE notes below for how this choice would
|
|
|
|
play out.]
|
|
|
|
|
2016-02-09 17:45:40 +00:00
|
|
|
[[!toc]]
|
|
|
|
|
2016-02-22 17:04:02 +00:00
|
|
|
## filtering
|
|
|
|
|
2016-02-22 19:24:06 +00:00
|
|
|
master adjusted/master
|
2016-02-22 17:04:02 +00:00
|
|
|
A
|
2016-02-22 19:24:06 +00:00
|
|
|
|--------------->A'
|
|
|
|
| |
|
2016-02-22 17:04:02 +00:00
|
|
|
|
2016-02-22 19:24:06 +00:00
|
|
|
When generating commit A', reuse the date of A and use a standard author,
|
|
|
|
committer, and message. This means that two users with the adjusted branch
|
|
|
|
checked out and using the same filters will get identical shas for A', and
|
|
|
|
so can collaborate on them.
|
2016-02-22 17:04:02 +00:00
|
|
|
|
|
|
|
## commit
|
|
|
|
|
|
|
|
When committing changes, a commit is made as usual to the adjusted branch.
|
2016-02-22 19:24:06 +00:00
|
|
|
So, the user can `git commit` as usual. This does not touch the
|
|
|
|
original branch yet.
|
2016-02-22 17:04:02 +00:00
|
|
|
|
|
|
|
Then we need to get from that commit to one with the filters reversed,
|
|
|
|
which should be the same as if the adjusted branch had not been used.
|
|
|
|
This commit gets added onto the original branch.
|
|
|
|
|
|
|
|
So, the branches would look like this:
|
|
|
|
|
2016-02-22 19:24:06 +00:00
|
|
|
master adjusted/master
|
2016-02-22 17:04:02 +00:00
|
|
|
A
|
2016-02-22 19:24:06 +00:00
|
|
|
|--------------->A'
|
|
|
|
| |
|
|
|
|
| C (new commit)
|
|
|
|
B < - - - - - - -
|
|
|
|
|
|
|
|
|
|--------------->B'
|
|
|
|
| |
|
2016-02-22 17:04:02 +00:00
|
|
|
|
|
|
|
Note particularly that B does not have A' or C in its history;
|
|
|
|
the adjusted branch is not evident from outside.
|
2016-02-09 17:45:40 +00:00
|
|
|
|
2016-02-22 17:04:02 +00:00
|
|
|
Also note that B gets filtered and the adjusted branch is rebased on top of
|
|
|
|
it, so C does not remain in the adjusted branch history either. This will
|
|
|
|
make other checkouts that are in the same adjusted branch end up with the
|
|
|
|
same B' commit when they pull B.
|
|
|
|
|
2016-02-22 19:24:06 +00:00
|
|
|
There may be multiple commits made to the adjusted branch before any get
|
|
|
|
applied back to the original branch. This is handled by reverse filtering
|
2016-03-11 20:00:14 +00:00
|
|
|
commits one at a time and rebasing the others on top.
|
2016-02-22 19:24:06 +00:00
|
|
|
|
|
|
|
master adjusted/master
|
|
|
|
A
|
|
|
|
|--------------->A'
|
|
|
|
| |
|
|
|
|
| C1
|
|
|
|
| |
|
|
|
|
| C2
|
|
|
|
|
|
|
|
|
|
|
|
master adjusted/master
|
|
|
|
A
|
|
|
|
|--------------->A'
|
|
|
|
| |
|
|
|
|
| C1
|
|
|
|
B1< - - - - - - -
|
|
|
|
|
|
|
|
|
|--------------->B1'
|
|
|
|
| |
|
|
|
|
| C2'
|
|
|
|
B2< - - - - - - -
|
|
|
|
|
|
|
|
|
|--------------->B2'
|
|
|
|
|
|
|
|
|
2016-02-22 17:04:02 +00:00
|
|
|
[WORKTREE: A pre-commit hook would be needed to update the staged changes,
|
|
|
|
reversing the filter before the commit is made. All the other complications
|
|
|
|
above are avoided.]
|
|
|
|
|
|
|
|
## merge
|
2016-02-09 16:30:29 +00:00
|
|
|
|
2016-02-22 19:24:06 +00:00
|
|
|
This would be done by `git annex merge` and `git annex sync`, with the goal
|
|
|
|
of merging origin/master into master, and updating adjusted/master.
|
2016-02-09 17:45:40 +00:00
|
|
|
|
2016-02-22 17:04:02 +00:00
|
|
|
Note that the adjusted files db needs to be updated to reflect the changes
|
|
|
|
that are merged in, for object add/remove to work as described below.
|
|
|
|
|
|
|
|
When merging, there should never be any commits present on the
|
|
|
|
adjusted/master branch that have not yet been filtered over to the master
|
2016-02-22 19:24:06 +00:00
|
|
|
branch. If there are any such commits, just filter them into master before
|
|
|
|
beginning the merge. There may be staged changes, or changes in the work tree.
|
2016-02-22 17:04:02 +00:00
|
|
|
|
|
|
|
First filter the new commit:
|
|
|
|
|
2016-03-31 22:54:35 +00:00
|
|
|
origin/master adjusted/master master
|
|
|
|
A A
|
|
|
|
|--------------->A' |
|
|
|
|
| | |
|
2016-02-22 19:24:06 +00:00
|
|
|
| |
|
|
|
|
B
|
|
|
|
|
|
|
|
|
|---------->B'
|
2016-02-22 17:04:02 +00:00
|
|
|
|
|
|
|
Then, merge that into adjusted/master:
|
|
|
|
|
2016-03-31 22:54:35 +00:00
|
|
|
origin/master adjusted/master master
|
|
|
|
A A
|
|
|
|
|--------------->A' |
|
|
|
|
| | |
|
2016-02-22 19:24:06 +00:00
|
|
|
| |
|
|
|
|
B |
|
|
|
|
| |
|
|
|
|
|----------->B'->B''
|
|
|
|
|
|
|
|
That merge will take care of updating the work tree.
|
2016-02-22 17:04:02 +00:00
|
|
|
|
2016-02-22 19:24:06 +00:00
|
|
|
(What if there is a merge conflict between A' and B'? Normally such a merge
|
|
|
|
conflict should only affect the work tree/index, so can be resolved without
|
|
|
|
making a commit, but B'' may end up being made to resolve a merge
|
|
|
|
conflict.)
|
2016-02-22 17:04:02 +00:00
|
|
|
|
2016-03-31 22:54:35 +00:00
|
|
|
Once the merge is done, we have a merge commit B'' on adjusted/master.
|
|
|
|
To finish, redo that commit so it does not have A' as its parent.
|
2016-02-29 21:30:37 +00:00
|
|
|
|
2016-03-31 22:54:35 +00:00
|
|
|
origin/master adjusted/master master
|
|
|
|
A A
|
|
|
|
|--------------->A' |
|
|
|
|
| | |
|
2016-02-22 19:24:06 +00:00
|
|
|
| |
|
|
|
|
B
|
|
|
|
|
|
|
|
|
|--------------->B''
|
|
|
|
| |
|
|
|
|
|
2016-03-31 18:56:10 +00:00
|
|
|
Finally, update master, by reverse filtering B''.
|
2016-03-31 22:54:35 +00:00
|
|
|
|
|
|
|
origin/master adjusted/master master
|
|
|
|
A A
|
|
|
|
|--------------->A' |
|
|
|
|
| | |
|
|
|
|
| | |
|
|
|
|
B |
|
|
|
|
| |
|
|
|
|
|--------------->B'' - - - - - - -> B
|
|
|
|
| |
|
2016-02-22 19:24:06 +00:00
|
|
|
|
|
|
|
Notice how similar this is to the commit graph. So, "fast-forward"
|
|
|
|
merging the same B commit from origin/master will lead to an identical
|
|
|
|
sha for B' as the original committer got.
|
2016-02-22 17:04:02 +00:00
|
|
|
|
2016-02-09 17:45:40 +00:00
|
|
|
Since the adjusted/master branch is not present on the remote, if the user
|
|
|
|
does a `git pull`, it won't merge in changes from origin/master. Which is
|
|
|
|
good because the filter needs to be applied first.
|
|
|
|
|
|
|
|
However, if the user does `git merge origin/master`, they'll get into a
|
|
|
|
state where the filter has not been applied. The post-merge hook could be
|
|
|
|
used to clean up after that. Or, let the user foot-shoot this way; they can
|
|
|
|
always reset back once they notice the mistake.
|
|
|
|
|
2016-02-22 17:04:02 +00:00
|
|
|
[WORKTREE: `git pull` would update the work tree, and may lead to conflicts
|
|
|
|
between the adjusted work tree and pulled changes. A post-merge hook would
|
|
|
|
be needed to re-adjust the work tree, and there would be a window where eg,
|
|
|
|
not present files would appear in the work tree.]
|
|
|
|
|
2016-03-31 22:54:35 +00:00
|
|
|
## another merge scenario
|
|
|
|
|
|
|
|
Another merge scenario is when there's a new commit C on adjusted/master,
|
|
|
|
and also a new commit B on origin/master.
|
|
|
|
|
|
|
|
Start by adjusting B':
|
|
|
|
|
|
|
|
origin/master adjusted/master master
|
|
|
|
A A
|
|
|
|
|--------------->A' |
|
|
|
|
| | |
|
|
|
|
| C'
|
|
|
|
B
|
|
|
|
|
|
|
|
|
|---------->B'
|
|
|
|
|
|
|
|
Then, merge B' into adjusted/master:
|
|
|
|
|
|
|
|
origin/master adjusted/master master
|
|
|
|
A A
|
|
|
|
|--------------->A' |
|
|
|
|
| | |
|
|
|
|
| C'
|
|
|
|
B |
|
|
|
|
| |
|
|
|
|
|----------->B'->M'
|
|
|
|
|
|
|
|
Here M' is the correct tree, but it has A' as its grandparent,
|
|
|
|
which is the adjusted branch commit, so needs to be dropped in order to
|
|
|
|
get a commit that can be put on master.
|
|
|
|
|
|
|
|
We don't want to lose commit C', but it's an adjusted
|
|
|
|
commit, so needs to be de-adjusted.
|
|
|
|
|
|
|
|
origin/master adjusted/master master
|
|
|
|
A A
|
|
|
|
|--------------->A' |
|
|
|
|
| | |
|
|
|
|
| C'- - - - - - - - > C
|
|
|
|
B |
|
|
|
|
| |
|
|
|
|
|----------->B'->M'
|
|
|
|
|
|
|
|
|
|
|
|
|
Now, we generate a merge commit, between B and C, with known result M'
|
|
|
|
(so no actual merging done here).
|
|
|
|
|
|
|
|
origin/master adjusted/master master
|
|
|
|
A A
|
|
|
|
|--------------->A' |
|
|
|
|
| | |
|
|
|
|
| C'- - - - - - - - > C
|
|
|
|
B |
|
|
|
|
| |
|
|
|
|
|--------------->M'<-----------------|
|
|
|
|
|
|
|
|
|
|
|
|
|
Finally, update master, by reverse filtering M'. The resulting commit
|
|
|
|
on master will also be a merge between B and C.
|
|
|
|
|
2016-02-09 17:45:40 +00:00
|
|
|
## annex object add/remove
|
|
|
|
|
2016-02-09 16:30:29 +00:00
|
|
|
When objects are added/removed from the annex, the associated file has to
|
|
|
|
be looked up, and the filter applied to it. So, dropping a file with the
|
|
|
|
missing file filter would cause it to be removed from the adjusted branch,
|
|
|
|
and receiving a file's content would cause it to appear in the adjusted
|
2016-03-29 17:30:29 +00:00
|
|
|
branch. TODO
|
2016-02-09 16:30:29 +00:00
|
|
|
|
2016-02-09 18:24:32 +00:00
|
|
|
These changes would need to be committed to the adjusted branch, otherwise
|
|
|
|
`git diff` would show them.
|
|
|
|
|
|
|
|
[WORKTREE: Simply adjust the work tree (and index) per the filter.]
|
|
|
|
|
2016-03-12 00:12:31 +00:00
|
|
|
## reverse filtering commits
|
|
|
|
|
|
|
|
A user's commits on the adjusted branch have to be reverse filtered
|
|
|
|
to get changes to apply to the master branch.
|
|
|
|
|
|
|
|
This reversal of one filter can be done as just another filter.
|
|
|
|
Since only files touched by the commit will be reverse filtered, it doesn't
|
|
|
|
need to reverse all changes made by the original filter.
|
|
|
|
|
|
|
|
For example, reversing the unlock filter might lock the file. Or, it might
|
|
|
|
do nothing, which would make all committed files remain unlocked.
|
2016-03-04 15:31:26 +00:00
|
|
|
|
2016-02-09 17:45:40 +00:00
|
|
|
## push
|
|
|
|
|
|
|
|
The new master branch can then be pushed out to remotes. The
|
|
|
|
adjusted/master branch is not pushed to remotes. `git-annex sync` should
|
|
|
|
automatically push master when adjusted/master is checked out.
|
|
|
|
|
2016-02-09 17:51:49 +00:00
|
|
|
When push.default is "simple" (the new default), running `git push` when in
|
|
|
|
adjusted/master won't push anything. It would with "matching". Pity. (I
|
|
|
|
continue to feel git picked the wrong default here.) Users may find that
|
|
|
|
surprising. Users of `git-annex sync` won't need to worry about it though.
|
|
|
|
|
2016-02-09 18:24:32 +00:00
|
|
|
[WORKTREE: push works as usual]
|
|
|
|
|
|
|
|
## acting on filtered-out files
|
|
|
|
|
|
|
|
If a file is filtered out due to not existing, there should be a way
|
|
|
|
for `git annex get` to get it. Since the filtered out file is not in the
|
|
|
|
index, that would not normally work. What to do?
|
|
|
|
|
|
|
|
Maybe instead of making a branch where the file is deleted, it would be
|
|
|
|
better to delete it from the work tree, but keep the branch as-is. Then
|
|
|
|
`git annex get` would see the file, as it's in the index.
|
|
|
|
|
|
|
|
But, not maintaining an adjusted branch complicates other things. See
|
|
|
|
WORKTREE notes throughout this page. Overall, the WORKTREE approach seems
|
|
|
|
too problimatic.
|
|
|
|
|
|
|
|
Ah, but we know that when filter #2 is in place, any file that `git annex
|
|
|
|
get` could act on is not in the index. So, it could look at the master branch
|
|
|
|
instead. (Same for `git annex move --from` and `git annex copy --from`)
|
|
|
|
|
2016-02-09 18:37:59 +00:00
|
|
|
OTOH, if filter #1 is in place and not #2, a file might be renamed in the
|
|
|
|
index, and `git annex get $newname` should work. So, it should look at the
|
|
|
|
index in that case.
|
|
|
|
|
2016-02-09 17:45:40 +00:00
|
|
|
## problems
|
|
|
|
|
2016-02-09 16:30:29 +00:00
|
|
|
Using `git checkout` when in an adjusted branch is problimatic, because a
|
|
|
|
non-adjusted branch would then be checked out. But, we can just say, if
|
2016-03-29 17:30:29 +00:00
|
|
|
you want to get into an adjusted branch, you have to run git annex adjust
|
|
|
|
Or, could make a post-checkout hook. This is would mostly be confusing when
|
|
|
|
git-annex init switched into the adjusted branch due to lack of symlink
|
|
|
|
support.
|
2016-02-09 16:30:29 +00:00
|
|
|
|
2016-03-12 00:16:02 +00:00
|
|
|
After a commit to an adjusted branch, `git push` won't do anything. The
|
|
|
|
user has to know to git-annex sync. (Even if a pre-commit hook propigated
|
|
|
|
the commit back to the master branch, `git push` wouldn't push it with the
|
|
|
|
default "matching" push strategy.)
|
|
|
|
|
2016-02-09 16:30:29 +00:00
|
|
|
Tags are bit of a problem. If the user tags an ajusted branch, the tag
|
2016-02-09 18:24:32 +00:00
|
|
|
includes the local adjustments.
|
|
|
|
[WORKTREE: not a problem]
|
2016-02-09 16:30:29 +00:00
|
|
|
|
2016-02-09 17:04:10 +00:00
|
|
|
If the user refers to commit shas (in, eg commit messages), those won't be
|
2016-02-09 18:24:32 +00:00
|
|
|
visible to anyone else.
|
|
|
|
[WORKTREE: not a problem]
|
2016-02-09 17:04:10 +00:00
|
|
|
|
2016-02-09 20:26:55 +00:00
|
|
|
When a pull modifies a file, its content won't be available, and so it
|
|
|
|
would be hidden temporarily by filter #2. So the file would seem to vanish,
|
|
|
|
and come back later, which could be confusing. Could be fixed as discussed
|
|
|
|
in [[todo/deferred_update_mode]]. Arguably, it's just as confusing for the
|
|
|
|
file to remain visible but have its content temporarily replaced with a
|
|
|
|
annex pointer.
|
|
|
|
|
2016-02-09 16:45:48 +00:00
|
|
|
## integration with view branches
|
|
|
|
|
|
|
|
Entering a view from an adjusted branch should probably carry the filtering
|
|
|
|
over into the creation/updating of the view branch.
|
|
|
|
|
|
|
|
Could go a step further, and implement view branches as another branch
|
|
|
|
adjusting filter, albeit an extreme one. This might improve view branches.
|
|
|
|
For example, it's not currently possible to update a view branch with
|
|
|
|
changes fetched from a remote, and this could get us there.
|
2016-02-09 18:24:32 +00:00
|
|
|
|
2016-03-12 00:12:31 +00:00
|
|
|
This would need the reverse filter to be able to change metadata,
|
|
|
|
so that a commit that moved files in the view updates their metadata.
|
2016-02-23 17:21:38 +00:00
|
|
|
|
2016-02-09 18:24:32 +00:00
|
|
|
[WORKTREE: Wouldn't be able to integrate, unless view branches are changed
|
|
|
|
into adjusted view worktrees.]
|
2016-02-09 18:37:59 +00:00
|
|
|
|
2016-03-03 18:17:37 +00:00
|
|
|
## TODOs
|
|
|
|
|
|
|
|
* Interface in webapp to enable adjustments.
|
2016-03-29 20:44:09 +00:00
|
|
|
* Upgrade from direct mode to v6 in unlocked branch.
|
2016-03-29 22:03:02 +00:00
|
|
|
* Honor annex.thin when entering an adjusted branch.
|
2016-03-31 18:56:10 +00:00
|
|
|
* Cloning a repo that has an adjusted branch checked out gets into an ugly
|
|
|
|
state.
|
2016-03-31 22:54:35 +00:00
|
|
|
* There are potentially races in code that assumes a branch like
|
|
|
|
master is not being changed by someone else. In particular,
|
|
|
|
propigateAdjustedCommits rebases the adjusted branch on top of master.
|
|
|
|
That is called by sync. The assumption is that any changes in master
|
|
|
|
have already been handled by updateAdjustedBranch. But, if another remote
|
|
|
|
pushed a new master at just the right time, the adjusted branch could be
|
|
|
|
rebased on top of a master that it doesn't incorporate, which is wrong.
|